【问题标题】:Kibana: exporting and sorting embedded JSON using curl and jqKibana:使用 curl 和 jq 导出和排序嵌入的 JSON
【发布时间】:2017-08-22 16:48:17
【问题描述】:

上下文:

我在 Ubuntu Xenial (16.04) 上使用 Kibana (v5.5.1)。我想在 Git 中管理对 Kibana 对象的更改(添加/删除/更新仪表板、可视化、搜索等)。

(Kibana 的“快照”功能使用二进制格式,所以不是一个选项。)

我想将 Kibana 对象导出为 JSON 并在 Git 中添加/更新它们。

我使用curljq

curl -s -XGET "http://localhost:9200/.kibana/dashboard/Metricbeat-Docker"| jq --sort-keys '.'

没关系:我得到了 diff-friendly 排序的 JSON,我可以将其存储在 Git 中,然后再导入回 Elastic。

这是我得到的示例输出:

{
  "_id": "eslogs-*",
  "_index": ".kibana",
  "_source": {
    "fields": "[{\"name\":\"total_shards\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true,\"searchable\":false,\"aggregatable\":false},{\"name\":\"took_millis\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true,\"searchable\":false,\"aggregatable\":false},{\"name\":\"source\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false,\"searchable\":true,\"aggregatable\":false}]",
    "notExpandable": true,
    "timeFieldName": "@timestamp",
    "title": "eslogs-*"
  },
  "_type": "index-pattern",
  "_version": 1,
  "found": true
}

但是,由于 JSON 中的字段排序是随机的,因此在每次导出时,我都会得到太多由字段排序引起的错误差异。为了使 diff 变得简单,我必须对另外 2 件事进行排序:

  1. 对“_source”对象内的字段排序。

  2. 按“名称”字段对“_source.fields”内的嵌入 JSON 文本进行排序。

关于 (2) 我可以像这样使用 jq-r 选项:

curl -s -XGET "http://localhost:9200/.kibana/index-pattern/eslogs-*" | jq  -r '._source.fields' | jq -c '. |= sort_by(.name)'

这给了我一个很好的排序 JSON。

我尝试将排序后的嵌入 JSON 文本放入一个 shell 变量中,然后使用 --arg 将其“注入”到 jq,但随后出现“参数太长”错误。

所以我的问题是:

如何将所有这些要求组合到一个命令行脚本中,该脚本执行以下所有操作:

  1. 遍历所有 Kibana 对象
  2. 对每个 JSON 对象中的字段顺序进行排序
  3. 对“_source.fields”中嵌入的 JSON 文本进行排序

你有什么足够简单、可读和优雅的想法吗?

谢谢。

【问题讨论】:

    标签: curl elasticsearch kibana jq


    【解决方案1】:

    -S 选项的特点是它只影响输出,对正在处理的对象没有任何影响。由于内部的 json 字符串不是对象,所以 jq 无法对其中的那些对象中的键进行排序。如果您希望 jq 通过 -S 选项对它们进行排序,则必须先将其作为对象输出,然后使用另一个调用将其转换回 json。

    $ jq -S '._source.fields |= (fromjson | sort_by(.name))' input.json | \
    jq '._source.fields |= tojson'
    

    然而,这远非理想。相反,您可以利用 jq 默认情况下保留对象键的插入顺序这一事实。因此,您可以定义一个函数,该函数将获取一个对象并使用排序键重新创建它。然后将其应用于要排序的对象。然后将其递归地应用于树中的所有对象。

    def sort_object: (objects | . as $in | reduce keys[] as $k ({}; .[$k] = $in[$k])) // .;
    def sort_object_recursive: walk((objects | sort_object) // .);
    ._source.fields |= (fromjson | sort_by(.name)) | sort_object_recursive | ._source.fields |= tojson
    

    这会产生以下输出:

    {
      "_id": "eslogs-*",
      "_index": ".kibana",
      "_source": {
        "fields": "[{\"aggregatable\":false,\"analyzed\":true,\"count\":0,\"doc_values\":false,\"indexed\":true,\"name\":\"source\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"took_millis\",\"scripted\":false,\"searchable\":false,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"total_shards\",\"scripted\":false,\"searchable\":false,\"type\":\"number\"}]",
        "notExpandable": true,
        "timeFieldName": "@timestamp",
        "title": "eslogs-*"
      },
      "_type": "index-pattern",
      "_version": 1,
      "found": true
    }
    

    请务必在您的~/.jq 文件中包含walk/1 的定义。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-10-17
      • 2019-07-07
      • 2020-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-23
      相关资源
      最近更新 更多