Как получить максимальное значение поля даты в большом файле json? - PullRequest
2 голосов
/ 09 мая 2020

У меня есть большой файл JSON размером около 500 МБ, который является ответом на вызов URL. Мне нужно получить максимальное значение поля «дата» в файле JSON в массиве «результатов» с помощью сценария оболочки ( bash). В настоящее время используется jq, как показано ниже. Ниже работает хорошо для файлов меньшего размера, но для файлов большего размера возвращается значение null.

maxDate=$(cat ${jsonfilePath} | jq '[ .results[]?.date ] | max') 

Пожалуйста, помогите. Спасибо! Я новичок в сценариях оболочки, json, jq.

образец / ввод json содержимое файла:

{
    "results": [
        {
            "Id": "123",
            "date": 1588910400000,
            "col": "test"
        },
        {
            "Id": "1234",
            "date": 1588910412345,
            "col": "test2"
        }
    ],
    "col2": 123
}

Ответы [ 3 ]

2 голосов
/ 09 мая 2020

Если задана опция --stream в командной строке, JQ не будет загружать весь ввод в память, вместо этого он будет читать входной токен по токену, создавая массивы следующим образом:

[["results",0,"Id"],"123"]
[["results",0,"date"],1588910400000]
...
[["results",1,"date"],1588910412345]
...

Благодаря этой функции мы можем выбрать из ввода только date s и определить максимальное значение, не исчерпывая память (за счет скорости). Например:

jq -n --stream 'reduce (inputs|select(.[0][-1]=="date" and length==2)[1]) as $d (null; [.,$d]|max)' file
1 голос
/ 09 мая 2020

500 МБ не должно быть настолько большим, чтобы требовать параметр --stream, который обычно замедляет работу. Вот быстрое и эффективное (*) решение, которое не использует опцию потоковой передачи, а вместо этого использует общую c ориентированную на поток функцию max_by, определенную следующим образом:

# max_by(empty;1) yields null
def max_by(s; f):
  reduce s as $s (null;
    if . == null then {s: $s, m: ($s|f)}
    else  ($s|f) as $m
    | if $m > .m then {s: $s, m: $m} else . end
    end)
  | .s ;

С этим в нашем наборе инструментов мы можем просто написать:

max_by(.results[].date; .)

Это, конечно, предполагает, что существует поле «результатов», содержащее массив из JSON объектов. (**) Из постановки задачи может показаться, что это предположение не всегда выполняется, поэтому вы, вероятно, захотите изменить какой бы подход вы ни выбрали соответственно (например, проверив, есть ли поле результатов, имеет ли оно значение массива и т. c.)


(*) Использование max_by / 2 здесь более эффективно, как с точки зрения пространства, так и времени, чем использование встроенного max_by / 1.

(**) Отсутствие подполя «дата» не имеет значения, поскольку null меньше каждого числа.

0 голосов
/ 09 мая 2020
 jq '.results | max_by(.date) | .date' "$jsonfilePath"

- это более эффективный способ получить максимальное значение даты из этого JSON, которое может работать лучше для вас. Он избегает бесполезного использования Cat, не создает временный массив только значений даты и, следовательно, требует только одного прохода через массив.

...