繁体   English   中英

使用 jq 展平嵌套的 JSON

[英]Flatten nested JSON using jq

我想将嵌套的 json 对象展平,例如{"a":{"b":1}}{"ab":1}以便在 solr 中消化它。

我有 11 TB 的 json 文件,它们都是嵌套的并且在字段名称中包含点,这意味着不是 elasticsearch(点)也不是 solr(没有_childDocument_符号嵌套)可以按_childDocument_消化它。

其他解决方案是用下划线替换字段名称中的点并将其推送到elasticsearch,但我对 solr 的体验要好得多,因此我更喜欢 flatten 解决方案(除非 solr 可以按原样消化那些嵌套的 jsons??)。

仅当消化过程比 solr 花费的时间少得多时,我才会更喜欢 elasticsearch,因为我的首要任务是尽可能快地消化(因此我选择了 jq 而不是在 python 中编写脚本)。

请帮忙。

编辑:

我认为这对示例 3&4 为我解决了这个问题: https : //lucidworks.com/blog/2014/08/12/indexing-custom-json-data/

我会尽快尝试。

您还可以使用以下 jq 命令以这种方式展平嵌套的 JSON 对象:

[leaf_paths as $path | {"key": $path | join("."), "value": getpath($path)}] | from_entries

它的工作方式是: leaf_paths返回一个数组流,这些数组表示给定 JSON 文档上出现“叶元素”的路径,即没有子元素的元素,例如数字、字符串和布尔值。 我们将该流传输到具有keyvalue属性的对象中,其中key包含路径数组的元素,作为由点连接的字符串, value包含该路径上的元素。 最后,我们将整个事物放入一个数组中并在from_entries上运行from_entries ,它将{key, value}对象数组转换为包含这些键值对的对象。

这只是 Santiago 的 jq 的一个变体:

. as $in 
| reduce leaf_paths as $path ({};
     . + { ($path | map(tostring) | join(".")): $in | getpath($path) })

它避免了键/值构建和销毁的开销。

(如果您可以访问 jq 1.5 之后的 jq 版本,则可以省略“map(tostring)”。)

关于这两个 jq 解决方案的两个要点:

  1. 数组也被展平。 例如,给定{"a": {"b": [0,1,2]}}作为输入,输出将是:

     { "ab0": 0, "ab1": 1, "ab2": 2 }
  2. 如果原始 JSON 中的任何键包含句点,则可能发生键冲突; 此类冲突通常会导致值丢失。 例如,使用以下输入时会发生这种情况:

     {"ab":0, "a": {"b": 1}}

这是一个使用tostreamselectjoinreducesetpath的解决方案

  reduce ( tostream | select(length==2) | .[0] |= [join(".")] ) as [$p,$v] (
     {}
     ; setpath($p; $v)
  )

事实证明, curl -XPOST 'http://localhost:8983/solr/flat/update/json/docs' -d @json_file就是这样做的:

{
    "a.b":[1],
    "id":"24e3e780-3a9e-4fa7-9159-fc5294e803cd",
    "_version_":1535841499921514496
}

编辑 1: solr 6.0.1 with bin/solr -e cloud 集合名称是flat ,其余的都是默认的( data-driven-schema也是默认的)。

编辑 2:我使用的最终脚本: find . -name '*.json' -exec curl -XPOST 'http://localhost:8983/solr/collection1/update/json/docs' -d @{} \\; find . -name '*.json' -exec curl -XPOST 'http://localhost:8983/solr/collection1/update/json/docs' -d @{} \\; .

编辑 3:也可以与 xargs 并行并使用 jq: find . -name '*.json' -print0 | xargs -0 -n 1 -P 8 -I {} sh -c "cat {} | jq '. + {id: .ab}' | curl -XPOST 'http://localhost:8983/solr/collection/update/json/docs' -d @-"添加 id 字段find . -name '*.json' -print0 | xargs -0 -n 1 -P 8 -I {} sh -c "cat {} | jq '. + {id: .ab}' | curl -XPOST 'http://localhost:8983/solr/collection/update/json/docs' -d @-" find . -name '*.json' -print0 | xargs -0 -n 1 -P 8 -I {} sh -c "cat {} | jq '. + {id: .ab}' | curl -XPOST 'http://localhost:8983/solr/collection/update/json/docs' -d @-" find . -name '*.json' -print0 | xargs -0 -n 1 -P 8 -I {} sh -c "cat {} | jq '. + {id: .ab}' | curl -XPOST 'http://localhost:8983/solr/collection/update/json/docs' -d @-"其中-P是并行系数。 我使用 jq 设置了一个 id,因此同一文档的多次上传不会在集合中创建重复项(当我搜索-P的最佳值时,它在集合中创建了重复项)

我最近编写了一个名为jqg的脚本,它可以将任意复杂的 JSON平并使用正则表达式搜索结果; 要简单地展平 JSON,您的正则表达式将是 ' . ',匹配一切。 与上面的答案不同,该脚本将处理嵌入数组、 falsenull值,并且可以选择将空数组和对象 ( [] & {} ) 视为叶节点。

$ 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使用 jq 1.6 进行了测试

注意:我是jqg脚本的作者。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM