我有一個sql查詢返回大量的行。我想將查詢的結果保存到磁盤上的csv文件中。但是,因爲有太多的行在內存用完之前,所有行都可以通過sql查詢進行聚合。在clojure中寫入大文件到磁盤
它看起來像這樣,和查詢部分時失敗:
(-> query format-transformer csv-writer)
我有一個sql查詢返回大量的行。我想將查詢的結果保存到磁盤上的csv文件中。但是,因爲有太多的行在內存用完之前,所有行都可以通過sql查詢進行聚合。在clojure中寫入大文件到磁盤
它看起來像這樣,和查詢部分時失敗:
(-> query format-transformer csv-writer)
我想通了從#clojure IRC頻道一些幫助。你需要兩個庫:
(ns myproj.example
(:require [[clojure.java.jdbc :as sql]
[clojure.data.csv :as csv]]))
訣竅是處理每一行,因爲它返回,然後丟棄它。 java jdbc庫具有查詢功能,該功能使用:row-fn
和:result-set-fn
選項提供此功能。
(defn sql->csv [title]
(with-open [w (clojure.java.io/writer (str title ".csv") :append true)]
(sql/query ds (second query)
:row-fn (fn [row]
(csv/write-csv w [(mapv str (vals row))]))
:result-set-fn dorun)))
有趣的部分是:row-fn
和:result-set-fn
。每當從查詢返回一行時,:row-fn
被調度。每一行都是{:column1 "data" :column2 "data2"}
形式的地圖。我們將地圖更改爲write-csv可以使用的內容(嵌套向量):[(mapv str (:vals row)])
。然後write-csv將它附加到您提供的文件中。
:result-set-fn
對於不吹你的堆是至關重要的。通過將其設置爲dorun
,您可以告訴它在處理完成後丟棄頭部。
這個特定的實現不提供列標題,這是留給讀者的一個練習(我的太尷尬了,在公共論壇上發佈)。
我會假設你的':row-fn'現在打開並關閉每一行的文件。更糟糕的是,它必須掃描到您正在編寫的每行文件的末尾。我沒有對它進行測試,但我認爲如果您將'with-open'調用放到'sql/query'之外就可以提高效率。根據最新的[docs](https://clojure.github.io/java.jdbc/),我也認爲你實際上想設置':result-set-fn'而不是':row-set-fn' #clojure.java.jdbc /查詢)。我猜''result-set-fn'的默認'doall'可能會發生相同的變化,或者您使用的是舊版本。 – schaueho
@schaueho:好的,謝謝。我已經測試過這些變化,並且它在'with-open'內更快。我試着將'write-csv'函數放在':result-set-fn'中,但最終返回的行數和nils一樣多。 – dan