Использование 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)
Другие вопросы по тегам