所讨论的JSON文件相当大(约1.5GB),但在开始附近的已知位置(.meta.view.approvals)有一些元数据。
如何使用jq或gojq来提取该位置的对象而无需加载将整个文件放入内存,而不必等待整个文件的处理停止在提取出感兴趣的项目之后?
寻找泛型方法,但我感兴趣的特定文件是行。Json在https://data.montgomerycountymd.gov/api/views/4mse-ku6q/rows.json我的副本在2023年1月12日被检索;文件大小为1459382170字节,.meta.view的值为。文件中的createdAt为1403103517
命令行选项jq、gojq和jm也很有趣,只要它们在内存和CPU使用方面都是经济的。
将jq(或gojq)的流解析器与first/1
结合使用,如下所示。
这减少了执行时间和内存需求,例如,与使用非流解析器相比:从50秒到几微秒,从4,112MB RAM (mrss)到3MB。
指出:
- jq和gojq不会产生相同的结果,因为gojq不尊重对象内键的顺序。
- 下面显示的性能统计数据是针对行的。Q.
以下是在3GHz机器上显示命令调用和关键性能统计数据的记录摘录。
+ /usr/bin/time -lp gojq -n --stream 'first(fromstream(3|truncate_stream(inputs| select(.[0][0:3] == ["meta","view", "approvals"]) )))' rows.json
user 0.00
sys 0.00
3702784 maximum resident set size
1531904 peak memory footprint
+ /usr/bin/time -lp jq -n --stream 'first(fromstream(3|truncate_stream(inputs| select(.[0][0:3] == ["meta","view", "approvals"]) )))' rows.json
user 0.00
sys 0.00
1990656 maximum resident set size
1114112 peak memory footprint
/usr/bin/time -lp jq .meta.view.approvals rows.json
user 39.90
sys 11.82
4112465920 maximum resident set size
6080188416 peak memory footprint
/usr/bin/time -lp gojq -n --stream '
fromstream(3|truncate_stream(inputs | select(.[0][0:3] == ["meta","view", "approvals"]) ))' rows.json
user 495.30
sys 273.72
7858896896 maximum resident set size
38385831936 peak memory footprint
下面的jm命令产生的结果基本相同:
/usr/bin/time -lp jm --pointer /meta/view/approvals rows.json
user 0.05
sys 0.07
13594624 maximum resident set size
7548928 peak memory footprint
另一种选择是使用first_run/2
定义如下:
# Emit the first run of the items in the stream for which the condition is truthy
def first_run(stream; condition):
label $out
| foreach stream as $x (null;
($x|condition) as $y
| if $y
then [$x]
elif . then break $out
else .
end;
if . then .[0] else empty end);