6

大きなjsonファイル(3GB)を解析し、このファイルの各行のハッシュマップを返したい. 私の直感は、トランスデューサを使用してファイルを行ごとに処理し、いくつかの選択されたフィールド (ファイル内のバイトの 5% 以上) を含むベクトルを構築することでした。

ただし、次のコードは OutOfMemory 例外をスローします。

ファイル.json

{"experiments": {"results": ...}}
{"experiments": {"results": ...}}
{"experiments": {"results": ...}}

パーサー.clj

(defn load-with!
  "Load a file using a parser, a structure and a transducer."
  [parser structure xform path]
  (with-open [r (clojure.java.io/reader path)]
    (into structure xform (parser r))))

(def xf (map #(get-in % ["experiments" "results"])))
(def parser (comp (partial map cheshire.core/parse-string) line-seq))

(load-with! parser (vector) xf "file.json")

JVisualVM でプロセスを視覚化すると、プロセスがクラッシュする前にヒープが時間の経過とともに大きくなり、25 GB を超えます。

この場合、変換器は適切ですか? より良い代替手段はありますか?

関数の最後に新しい構造を返すという私の要件の 1 つです。したがって、doseq を使用してファイルをその場で処理することはできません。

さらに、ファイル形式に応じてパーサーとトランスデューサーを変更する必要があります。

ありがとうございました !

4

1 に答える 1

1

あなたはかなり近いです。何が何をするのかわかりませんが、ここからjson/parse-stringと同じであれば、このコードはあなたが上でやろうとしていることです。json/read-str

次のようなものを目指していたようです。

(require '[clojure.data.json :as json])
(require '[clojure.java.io :as java])

(defn load-with!
  "Load a file using a parser, a structure and a transducer."
  [parser structure xform path]
  (with-open [r (java/reader path)]
    (into structure (xform (parser r)))))

(def xf (partial map #(get-in % ["experiments" "results"])))

(def parser (comp (partial map json/read-str) line-seq))


(load-with! parser [] xf "file.json")

これらは、すべてのビジネスの詳細をここでの最小限の例に切り取ったことによる間違いだったと思います. 以下のコードを使用して、上記のコードで OOM エラーが発生した大きなファイルを処理できました。

(require '[clojure.data.json :as json])
(require '[clojure.java.io :as java])

(def structure (atom []))

(defn do-it! [xform path]
  (with-open [r (java/reader path)]
    (doseq [line (line-seq r)]
      (swap! structure conj (xform line)))))

(defn xf [line]
  (-> (json/read-str line)
      (get-in ["experiments" "results"])))

(do-it! xf "file.json")

(take 10 @structure)
于 2016-10-23T03:32:14.107 に答える