我希望能够解析一个大的json文件(3GB),并为文件中的每一行返回一个哈希映射。我的想法是使用转换器逐行处理文件,并构造一个包含某些选定字段的向量(文件中的> 5%字节)。然而,以下代码抛出了OutOfMemory异常:
file.json
{"experiments": {"results": ...}}
{"experiments": {"results": ...}}
{"experiments": {"results": ...}}
parser.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。
在这种情况下,转换器(transducers)是否合适?有没有更好的替代方案?
我的一个要求是在函数结束时返回新结构。因此,我不能使用doseq来就地处理文件。
此外,我需要根据文件格式更改解析器和转换器。
谢谢!
(r)
可能不是你想要的,它将读取器作为函数调用。 - Michiel Borkentget-in
。请注意,into
是非惰性的。您能否懒处理文件?使用for
、map
或sequence
转换器函数,您能否创建一个映射条目的惰性序列?如果正确处理它们,您可以在不将所有文件内容保存在内存中的情况下处理每个条目。 - Mars