使用 jq 处理大型 JSON 流
Process large JSON stream with jq
我从 curl
得到一个非常大的 JSON 流(几 GB)并尝试用 jq
处理它。
我想用jq
解析的相关输出打包在一个表示结果结构的文档中:
{
"results":[
{
"columns": ["n"],
// get this
"data": [
{"row": [{"key1": "row1", "key2": "row1"}], "meta": [{"key": "value"}]},
{"row": [{"key1": "row2", "key2": "row2"}], "meta": [{"key": "value"}]}
// ... millions of rows
]
}
],
"errors": []
}
我想用 jq
提取 row
数据。这很简单:
curl XYZ | jq -r -c '.results[0].data[0].row[]'
结果:
{"key1": "row1", "key2": "row1"}
{"key1": "row2", "key2": "row2"}
但是,这总是要等到 curl
完成。
我使用了 --stream
选项来处理这个问题。我尝试了以下命令,但也在等待从 curl
:
返回完整对象
curl XYZ | jq -n --stream 'fromstream(1|truncate_stream(inputs)) | .[].data[].row[]'
有没有办法 'jump' 到 data
字段并开始一个接一个地解析 row
而无需等待结束标记?
(1) 您将使用的香草过滤器如下:
jq -r -c '.results[0].data[].row'
(2) 此处使用流解析器的一种方法是使用它来处理 .results[0].data
的输出,但这两个步骤的组合可能会比普通方法慢。
(3) 要生成您想要的输出,您可以 运行:
jq -nc --stream '
fromstream(inputs
| select( [.[0][0,2,4]] == ["results", "data", "row"])
| del(.[0][0:5]) )'
(4) 或者,您可能希望尝试以下方法:
jq -nc --stream 'inputs
| select(length==2)
| select( [.[0][0,2,4]] == ["results", "data", "row"])
| [ .[0][6], .[1]] '
对于说明性输入,最后一次调用的输出为:
["key1","row1"]
["key2","row1"]
["key1","row2"]
["key2","row2"]
获得:
{"key1": "row1", "key2": "row1"}
{"key1": "row2", "key2": "row2"}
发件人:
{
"results":[
{
"columns": ["n"],
"data": [
{"row": [{"key1": "row1", "key2": "row1"}], "meta": [{"key": "value"}]},
{"row": [{"key1": "row2", "key2": "row2"}], "meta": [{"key": "value"}]}
]
}
],
"errors": []
}
执行以下操作,等效于 jq -c '.results[].data[].row[]'
,但使用流式处理:
jq -cn --stream 'fromstream(1|truncate_stream(inputs | select(.[0][0] == "results" and .[0][2] == "data" and .[0][4] == "row") | del(.[0][0:5])))'
这样做的是:
- 将 JSON 转换为流(使用
--stream
)
- Select路径
.results[].data[].row[]
(含select(.[0][0] == "results" and .[0][2] == "data" and .[0][4] == "row"
)
- 丢弃路径的那些初始部分,例如
"results",0,"data",0,"row"
(带有 del(.[0][0:5])
)
- 最后使用 jq FAQ
中的 fromstream(1|truncate_stream(…))
模式将生成的 jq 流转回预期的 JSON
例如:
echo '
{
"results":[
{
"columns": ["n"],
"data": [
{"row": [{"key1": "row1", "key2": "row1"}], "meta": [{"key": "value"}]},
{"row": [{"key1": "row2", "key2": "row2"}], "meta": [{"key": "value"}]}
]
}
],
"errors": []
}
' | jq -cn --stream '
fromstream(1|truncate_stream(
inputs | select(
.[0][0] == "results" and
.[0][2] == "data" and
.[0][4] == "row"
) | del(.[0][0:5])
))'
生成所需的输出。
我从 curl
得到一个非常大的 JSON 流(几 GB)并尝试用 jq
处理它。
我想用jq
解析的相关输出打包在一个表示结果结构的文档中:
{
"results":[
{
"columns": ["n"],
// get this
"data": [
{"row": [{"key1": "row1", "key2": "row1"}], "meta": [{"key": "value"}]},
{"row": [{"key1": "row2", "key2": "row2"}], "meta": [{"key": "value"}]}
// ... millions of rows
]
}
],
"errors": []
}
我想用 jq
提取 row
数据。这很简单:
curl XYZ | jq -r -c '.results[0].data[0].row[]'
结果:
{"key1": "row1", "key2": "row1"}
{"key1": "row2", "key2": "row2"}
但是,这总是要等到 curl
完成。
我使用了 --stream
选项来处理这个问题。我尝试了以下命令,但也在等待从 curl
:
curl XYZ | jq -n --stream 'fromstream(1|truncate_stream(inputs)) | .[].data[].row[]'
有没有办法 'jump' 到 data
字段并开始一个接一个地解析 row
而无需等待结束标记?
(1) 您将使用的香草过滤器如下:
jq -r -c '.results[0].data[].row'
(2) 此处使用流解析器的一种方法是使用它来处理 .results[0].data
的输出,但这两个步骤的组合可能会比普通方法慢。
(3) 要生成您想要的输出,您可以 运行:
jq -nc --stream '
fromstream(inputs
| select( [.[0][0,2,4]] == ["results", "data", "row"])
| del(.[0][0:5]) )'
(4) 或者,您可能希望尝试以下方法:
jq -nc --stream 'inputs
| select(length==2)
| select( [.[0][0,2,4]] == ["results", "data", "row"])
| [ .[0][6], .[1]] '
对于说明性输入,最后一次调用的输出为:
["key1","row1"]
["key2","row1"]
["key1","row2"]
["key2","row2"]
获得:
{"key1": "row1", "key2": "row1"}
{"key1": "row2", "key2": "row2"}
发件人:
{
"results":[
{
"columns": ["n"],
"data": [
{"row": [{"key1": "row1", "key2": "row1"}], "meta": [{"key": "value"}]},
{"row": [{"key1": "row2", "key2": "row2"}], "meta": [{"key": "value"}]}
]
}
],
"errors": []
}
执行以下操作,等效于 jq -c '.results[].data[].row[]'
,但使用流式处理:
jq -cn --stream 'fromstream(1|truncate_stream(inputs | select(.[0][0] == "results" and .[0][2] == "data" and .[0][4] == "row") | del(.[0][0:5])))'
这样做的是:
- 将 JSON 转换为流(使用
--stream
) - Select路径
.results[].data[].row[]
(含select(.[0][0] == "results" and .[0][2] == "data" and .[0][4] == "row"
) - 丢弃路径的那些初始部分,例如
"results",0,"data",0,"row"
(带有del(.[0][0:5])
) - 最后使用 jq FAQ 中的
fromstream(1|truncate_stream(…))
模式将生成的 jq 流转回预期的 JSON
例如:
echo '
{
"results":[
{
"columns": ["n"],
"data": [
{"row": [{"key1": "row1", "key2": "row1"}], "meta": [{"key": "value"}]},
{"row": [{"key1": "row2", "key2": "row2"}], "meta": [{"key": "value"}]}
]
}
],
"errors": []
}
' | jq -cn --stream '
fromstream(1|truncate_stream(
inputs | select(
.[0][0] == "results" and
.[0][2] == "data" and
.[0][4] == "row"
) | del(.[0][0:5])
))'
生成所需的输出。