Чтение в очень, очень большом NDJSON - PullRequest
0 голосов
/ 26 июня 2018

У меня есть файл NDJSON размером 33 ГБ, который мне нужно прочитать в data.table в R. Он сжат в файл 2 ГБ, в идеале я бы хотел сохранить его сжатым.

Структура не так важназа исключением того, что (при импорте через jsonlite::stream_in) нужные мне данные находятся в нескольких простых столбцах.Подавляющее большинство данных хранится в list с в трех столбцах, которые я хочу отбросить как можно скорее.

Мои две проблемы: как я могу распараллелить чтение и какмогу ли я ограничить использование памяти (сейчас мой рабочий на этом файле использует 175 ГБ памяти)?

Что я сейчас делаю:

dt.x <- data.table(flatten(stream_in(gzfile("source.gz"))[, -c(5:7)]))

Идеи:

Может быть, есть какой-то способ игнорировать часть NDJSON во время stream_in?

Могу ли я проанализировать соединение gzfile, например, с помощью regex, прежде чем оно перейдет к stream_in, чтобыудалить лишние данные?

Могу ли я сделать что-то вроде readLines в соединении gzfile для чтения данных 1 миллион строк на одного работника?

РЕДАКТИРОВАТЬ: если это вообще возможно, моя цельэто сделать этот портативный для других пользователей и держать его полностью в пределах R.

1 Ответ

0 голосов
/ 26 июня 2018

Использование jqr с readr

Вот расшифровка, иллюстрирующая, как использовать jqr для чтения сжатого файла NDJSON (он же JSONL):

$ R --vanilla
> library(readr)
> library(jqr)
> read_lines("objects.json.gz") %>% jq('.a')
[
    1,
    2,
    3
]
> 

Использование read_file() дает тот же результат,Поскольку эти функции должны разархивировать весь файл, требования к памяти будут существенными.

Чтение каждой сущности JSON отдельно

Поскольку файл представляет собой NDJSON, мы можем радикально уменьшить объем оперативной памяти, необходимый для чтенияв одном объекте JSON за один раз:

con = file("objects.json", "r");
while ( length(line <- readLines(con, n = 1)) > 0) {
   print( line %>% jq('.a') );
}

jq

Возможно, существуют лучшие способы использования jqr, но если целью является эффективность как пространства, так и времени, то, возможно, лучше всегоиспользуйте версию командной строки jq.

Count

Если вам нужно заранее подсчитать количество строк в (разархивированном) файле, то для экономии памяти я бы, вероятно, использовал system2 и wc, если возможно;в противном случае вы можете запустить фрагмент кода следующим образом:

n<-0;
con = file("objects.json", "r");
while (TRUE) {
   readLines(con, n = 1);
   if (length(line) == 0) { break; }
    n <- n+1;
}
...