Каков наилучший способ `sort_by` огромного файла, который не помещается в памяти с` jq` - PullRequest
1 голос
/ 19 февраля 2020

Я работаю с текстовым файлом, который содержит один объект JSON на строку, и я хочу использовать jq для выбора, group_by (key1) и sort_by (key1) файла. Файл выглядит так:

# /tmp/sample.json
{"key1": "value11", "key2": "value21", "key3": "value31"}
{"key1": "value11", "key2": "value22", "key3": "value32"}
{"key1": "value11", "key2": "value22", "key3": "value32"}
{"key1": "value13", "key2": "value23", "key3": "value33"}
{"key1": "value13", "key2": "value24", "key3": "value34"}
{"key1": "value16", "key2": "value26", "key3": "value36"}
{"key1": "value17", "key2": "value27", "key3": "value37"}
...

Я запускаю файл через oop MapReduce в аналогично этому вопросу :

hadoop jar $HADOOP_HOME/hadoop-streaming.jar \
    -files $HOME/bin/jq,$HOME/proj-map.jq,$HOME/proj-reduce.jq \
    -mapper "./jq -c --from-file=proj-map.jq" \
    -reducer "./jq -ncr --from-file=proj-reduce.jq" \
    -input  /tmp/sample.json \
    -output /tmp/sample.json.output

с

#proj-map.jq
# some transformation
{key1, key2}

и

#proj-reduce.jq
# by @peak -- https://stackoverflow.com/a/45715729/948914
# sort-free stream-oriented variant of group_by/1
# f should always evaluate to a string.
# Output: a stream of arrays, one array per group
def GROUPS_BY(stream; f): reduce stream as $x ({}; .[$x|f] += [$x] ) | .[] ;

GROUPS_BY(inputs|.key1; .) | {key1: .[0], size: length} | (.size|tostring) + "\t" + tostring

Выше приведено то, что я могу передать в сортировку Unix для сортировки:

3 {"key1": "value11", "size": 3}
2 {"key1": "value13", "size": 2}
1 {"key1": "value16", "size": 1}
1 {"key1": "value17", "size": 1}

Это работает. Теперь я не хочу полагаться на Unix sort, и я ищу способ использовать jq's sort_by(). Я понял, что это может быть сложно, потому что, насколько я понимаю, sort_by() требует массив в качестве входных данных, что подразумевает, что массив загружается в память. Поскольку файл может не помещаться в памяти, я ищу способ использования jq sort_by() без чтения всего файла в памяти. В частности, меня интересует эффективный способ сортировки потокового типа, похожий на Unix sort или streaming group_by() ,

Если такого пути нет, насколько мне известно, этот ответ , который объединяет jq и Unix sort, как я показал выше. Очевидно, было бы здорово, если бы sort_by работал как Unix sort, но у меня нет средств, чтобы это выяснить.

1 Ответ

1 голос
/ 19 февраля 2020

[Следующее было написано до того, как вопрос был обновлен, чтобы объяснить, что входные данные состоят из нескольких JSON сущностей.]

Для упрощения, в следующем предполагается, что у вас есть огромный файл, состоящий из один массив JSON. Поскольку, по предположению, этот файл слишком большой для чтения в память, первым шагом будет получение каждого элемента массива верхнего уровня в строке отдельно. Это можно сделать с помощью опции командной строки jq * --stream, как описано в jq FAQ , например, возможно, в соответствии с:

jq -cn --stream 'fromstream( inputs|(.[0] |= .[1:]) | select(. != [[]]) )'

Следующим шагом является префикс каждого из этих строк со значением «sort by», как описано в ссылке, включенной в Q. (То есть, jq может легко использоваться.)

Далее запустите операционную систему sort.

Наконец, если вам действительно нужен результат в виде одного большого массива, вы можете использовать инструмент обработки текста (например, awk).

...