使用jq展平嵌套的JSON
我想将一个嵌套的json对象展平,例如,使用jq展平嵌套的JSON,json,
elasticsearch,solr,jq,flatten,Json,
elasticsearch,Solr,Jq,Flatten,我想将一个嵌套的json对象展平,例如,{“a”:{“b”:1}到{“a.b”:1},以便在solr中消化它 我有11 TB的json文件,它们都是嵌套的,并且在字段名中包含点,这意味着elasticsearch(点)和solr(嵌套时没有\u childDocument\u符号)都不能按原样消化它 其他解决方案是用下划线替换字段名中的点,并将其推到elasticsearch,但我对solr有更好的经验,因此我更喜欢扁平化解决方案(除非solr可以按原样消化嵌套的JSON??) 我更喜欢elas
{“a”:{“b”:1}
到{“a.b”:1}
,以便在solr中消化它
我有11 TB的json文件,它们都是嵌套的,并且在字段名中包含点,这意味着elasticsearch(点)和solr(嵌套时没有\u childDocument\u
符号)都不能按原样消化它
其他解决方案是用下划线替换字段名中的点,并将其推到elasticsearch,但我对solr有更好的经验,因此我更喜欢扁平化解决方案(除非solr可以按原样消化嵌套的JSON??)
我更喜欢elasticsearch,因为我的首要任务是尽可能快地进行消化(因此我选择jq而不是用python编写脚本)
请帮忙
编辑:
我认为示例3和示例4为我解决了这个问题:
我很快就会试试。结果是,
curl-XPOST'http://localhost:8983/solr/flat/update/json/docs'-d@json_文件
就是这样做的:
{
"a.b":[1],
"id":"24e3e780-3a9e-4fa7-9159-fc5294e803cd",
"_version_":1535841499921514496
}
使用bin/solr-e cloud
编辑1:solr 6.0.1。集合名称是flat
,其余的都是默认的(使用数据驱动模式,这也是默认的)
编辑2:我使用的最后一个脚本:find-名称'*.json'-execcurl-XPOST'http://localhost:8983/solr/collection1/update/json/docs“-d{}\代码>
编辑3:还可以与xargs并行,并使用jq:find添加id字段-名称'*.json'-print0 | xargs-0-n1-p8-I{}sh-c“cat{}| jq.+{id:.a.b}'| curl-XPOST'http://localhost:8983/solr/collection/update/json/docs“-d@-”
其中-P
是并行度因子。我使用jq设置了一个id,这样同一文档的多次上载不会在集合中创建重复项(当我搜索-P
的最佳值时,它在集合中创建了重复项)您还可以使用以下jq命令以这种方式展平嵌套的JSON对象:
[leaf_paths as $path | {"key": $path | join("."), "value": getpath($path)}] | from_entries
它的工作方式是:leaf_paths
返回一个数组流,表示给定JSON文档中出现“叶元素”的路径,即没有子元素的元素,如数字、字符串和布尔值。我们使用key
和value
属性将数据流导入对象,其中key
包含路径数组的元素,这些元素以点连接的字符串形式存在,value
包含该路径的元素。最后,我们将整个东西放在一个数组中,并从其上的_entries运行,它将{key,value}
对象数组转换为包含这些键值对的对象。这只是Santiago jq的一个变体:
. as $in
| reduce leaf_paths as $path ({};
. + { ($path | map(tostring) | join(".")): $in | getpath($path) })
它避免了键/值构造和销毁的开销
(如果您可以访问jq 1.5之后的版本,可以省略“map(tostring)”。)
关于这两种jq解决方案,有两点很重要:
阵列也被展平。
例如,给定{“a”:{“b”:[0,1,2]}
作为输入,输出将是:
{
"a.b.0": 0,
"a.b.1": 1,
"a.b.2": 2
}
如果原始JSON中的任何键包含句点,则键冲突是可能的;此类碰撞通常会导致值丢失。例如,使用以下输入时会发生这种情况:
{"a.b":0, "a": {"b": 1}}
这里有一个解决方案,它使用tostream、select、join、reduce和setpath
reduce ( tostream | select(length==2) | .[0] |= [join(".")] ) as [$p,$v] (
{}
; setpath($p; $v)
)
我最近编写了一个名为的脚本,它可以展平任意复杂的JSON,并使用正则表达式搜索结果;为了简单地展平JSON,您的正则表达式应该是“
”,它匹配所有内容。与上面的答案不同,脚本将处理嵌入式数组、false
和null
值,并且可以选择将空数组和对象([]
&{}
)作为叶节点
$ jq . test/odd-values.json
{
"one": {
"start-string": "foo",
"null-value": null,
"integer-number": 101
},
"two": [
{
"two-a": {
"non-integer-number": 101.75,
"number-zero": 0
},
"true-boolean": true,
"two-b": {
"false-boolean": false
}
}
],
"three": {
"empty-string": "",
"empty-object": {},
"empty-array": []
},
"end-string": "bar"
}
$ jqg . test/odd-values.json
{
"one.start-string": "foo",
"one.null-value": null,
"one.integer-number": 101,
"two.0.two-a.non-integer-number": 101.75,
"two.0.two-a.number-zero": 0,
"two.0.true-boolean": true,
"two.0.two-b.false-boolean": false,
"three.empty-string": "",
"three.empty-object": {},
"three.empty-array": [],
"end-string": "bar"
}
jqg
使用jq1.6进行测试
注意:我是jqg
脚本的作者。当JSON包含数组时,此解决方案不起作用。例如:{“a”:{“b”:[1]}
为其引发错误:jq:error(at:1):字符串(“.”)和数字(0)不能添加到创建答案中,尽管这会过滤掉任何计算结果为false
,即false
,null
,等等的值。这是因为叶路径
是路径(标量)的缩写
,虽然标量
确实选择了这些,但是路径
只返回它们不为false的条目。长话短说,将leaf_路径
替换为路径(type!=“object”和type!=“array”)
以包含所有内容。@SteveAmerige-答案已更新,因此它将适用于jq 1.4及更高版本。