Json 用“jq”对内存中不适合的大文件进行“排序”的最佳方法是什么`

Json 用“jq”对内存中不适合的大文件进行“排序”的最佳方法是什么`,json,sorting,jq,Json,Sorting,Jq,我正在处理一个每行有一个JSON对象的文本文件,我想使用jq来选择、按键1对_进行分组,并按键1对_进行排序。该文件如下所示: # /tmp/sample.json {"key1": "value11", "key2": "value21", "key3": "value31"} {"key1": "value11", "key2": "value22", "key3": "value32"} {"key1": "value11", "key2": "value22", "key3": "val

我正在处理一个每行有一个JSON对象的文本文件,我想使用jq来选择、按键1对_进行分组,并按键1对_进行排序。该文件如下所示:

# /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"}
...
我正在以下位置通过Hadoop MapReduce运行该文件:

上面的内容可以提供给Unix sort进行排序:

3 {"key1": "value11", "size": 3}
2 {"key1": "value13", "size": 2}
1 {"key1": "value16", "size": 1}
1 {"key1": "value17", "size": 1}
这很有效。现在,我不想依赖Unix排序,我正在寻找一种使用jq的排序方式的方法。我发现这可能很有挑战性,因为据我所知,sort_by需要一个数组作为输入,这意味着数组加载到内存中。由于文件可能不适合内存,我正在寻找一种使用jq的sort_by而不读取内存中整个文件的方法。特别是,我对一种高效的流式排序方式感兴趣,或者说对


如果没有这样的方法,那么就我所知是,它结合了jq和Unix排序,正如我上面所展示的。显然,sort_by与Unix sort一样工作会很好,但我没有办法找到答案。

[以下内容是在问题更新之前编写的,以解释输入由多个JSON实体组成。]

为了简化一些,下面假设您有一个由单个JSON数组组成的大型文件。因为,假设这个文件太大,无法读入内存,所以第一步是让每个顶级数组元素单独在一行上。这可以使用jq的-stream命令行选项来完成,如中所述,例如,可能沿着以下几行:

jq -cn --stream 'fromstream( inputs|(.[0] |= .[1:]) | select(. != [[]]) )'
下一步是使用sortby值作为这些行的前缀,如Q中包含的链接中所述。也就是说,jq可以很容易地使用

接下来,运行操作系统排序


最后,如果您确实需要将结果作为单个大数组,可以使用文本处理工具,例如awk。

流式排序是不可能的。如果您的第一个元素需要排在最后,您必须存储它直到您可以输出它,这是没有办法的。排序是通过在大数据上使用磁盘进行欺骗;jq不行。谢谢你,@peak。你正在处理一个比我面临的更具挑战性的问题。我很感激。我的用例稍微简单一些,因为文件每行包含一个JSON对象。我更新了我的问题以反映这一点。再次感谢。
#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
3 {"key1": "value11", "size": 3}
2 {"key1": "value13", "size": 2}
1 {"key1": "value16", "size": 1}
1 {"key1": "value17", "size": 1}
jq -cn --stream 'fromstream( inputs|(.[0] |= .[1:]) | select(. != [[]]) )'