clojure - 使用 Clojure Transducers 解析大文件 : OutOfMemory Error

标签 clojure transducer

我想解析一个大的 json 文件 (3GB) 并返回该文件中每一行的 HashMap 。我的直觉是使用转换器逐行处理文件,并用一些选定的字段(> 文件中字节的 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就地处理文件。

此外,我需要根据文件格式更改解析器和转换器。

谢谢!

最佳答案

你已经很接近了。我不知道 json/parse-string 的作用,但它是否与 here 中的 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)

关于clojure - 使用 Clojure Transducers 解析大文件 : OutOfMemory Error,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40193129/

相关文章:

Clojure 符号相等

automata - 换能器与NFA的区别

computer-science - 如何模拟不确定的有限换能器?

clojure - 如何调整 next.jdbc 中的 IReduceInit 以使用 cheshire 将 JSON 流式传输到使用 Ring 的 HTTP 响应

java - 检查数据库表中引用的文件的物理存在

Clojure - 打嗝下拉菜单

Java/clojure : Multiple character delimiter, 并保留分隔符

javascript - Clojurescript:具有基数值的 parseInt-Function

clojure - Clojure 中传感器内的 Pmap