Использование Clojure Tranducers для анализа больших файлов: ошибка OutOfMemory
Я хочу проанализировать большой файл JSON (3 ГБ) и вернуть хэш-карту для каждой строки в этом файле. Моя интуиция заключалась в том, чтобы использовать преобразователь для построчной обработки файла и создания вектора с некоторыми выбранными полями (> 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 ГБ до сбоя процесса.
Подходят ли преобразователи в этом случае? Есть ли лучшая альтернатива?
Одно из моих требований вернуть новую структуру в конце функции. Таким образом, я не могу использовать dosq для обработки файла на месте.
Кроме того, мне нужно изменить парсер и преобразователь в соответствии с форматом файла.
Спасибо!
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)