elasticsearch,solr,jq,flatten,Json,elasticsearch,Solr,Jq,Flatten" /> elasticsearch,solr,jq,flatten,Json,elasticsearch,Solr,Jq,Flatten" />

使用jq展平嵌套的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

我想将一个嵌套的json对象展平,例如,
{“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}}
    

  • 这里有一个解决方案,它使用tostreamselectjoinreducesetpath

      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及更高版本。