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。

在这种情况下传感器是否合适?有更好的选择吗?

我的要求之一是在函数末尾返回新结构。因此,我不能使用 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 回答