使用 Vega 自定义可视化

编辑

使用 Vega 自定义可视化

编辑

VegaVega-Lite 都是用于创建自定义可视化的语法。建议具有手动编写 Elasticsearch 查询经验的高级用户使用。对于刚接触这两种语法的用户,Vega-Lite 是一个很好的起点,但它们不兼容。

VegaVega-Lite 面板可以显示一个或多个数据源,包括 Elasticsearch、Elastic Map Service、URL 或静态数据,并支持 Kibana 扩展,这些扩展允许您将面板嵌入到仪表板上并添加交互式工具。

当您想使用以下内容创建可视化时,请使用 VegaVega-Lite

  • 使用 nestedparent/child 映射的聚合
  • 没有数据视图的聚合
  • 使用自定义时间过滤器的查询
  • 复杂的计算
  • 从 _source 中提取的数据,而不是聚合
  • 散点图、桑基图和自定义地图
  • 不受支持的可视主题

这些语法有一些限制:它们不支持表格,并且不能有条件地运行查询。

Vega UI

VegaVega-Lite 都使用 JSON,但 Kibana 通过集成 HJSON 使输入更简单。HJSON 支持以下内容:

  • 可选引号
  • 双引号或单引号
  • 可选逗号
  • 使用 // 或 /* 语法的注释
  • 多行字符串

教程:创建自定义面板

编辑

了解如何将 Vega-Lite 与 Kibana 过滤器和 Elasticsearch 数据连接起来,然后学习如何使用 Vega 创建更多的 Kibana 交互。

在编辑规范时,请小步进行,并经常保存您的工作。小的更改可能会导致意想不到的结果。要保存,请单击工具栏中的 保存

在开始之前,添加您将在规范中使用的电子商务示例数据,然后创建仪表板。

  1. 安装电子商务示例数据集.
  2. 转到 仪表板
  3. 仪表板 页面上,单击 创建仪表板
打开并设置 Vega-Lite
编辑

打开 Vega-Lite 并更改时间范围。

  1. 在仪表板上,单击 选择类型,然后选择 自定义可视化

    预先填充的折线图显示文档总数。

  2. 确保 时间过滤器过去 7 天

教程:从 Elasticsearch 搜索查询创建堆积面积图

编辑

了解如何从 Vega-Lite 查询 Elasticsearch,并将结果显示在堆积面积图中。

  1. Vega-Lite 规范中,将 index: _all 替换为以下内容,然后单击 更新
index: kibana_sample_data_ecommerce

会出现一条具有零结果的平线。

要从 kibana_sample_data_ecommerce 数据视图中添加数据字段,请替换以下内容,然后单击 更新

  • %timefield%: @timestamp 替换为 %timefield%: order_date
  • field: @timestamp 替换为 field: order_date
添加聚合
编辑

要创建堆积面积图,请添加聚合。

要检查您的工作,请在单独的浏览器选项卡上打开并使用 控制台

  1. 在新选项卡上打开 Kibana。
  2. 使用导航菜单或 全局搜索字段 转到 开发工具 页面。
  3. 控制台 编辑器中,输入聚合,然后单击 单击以发送请求
POST kibana_sample_data_ecommerce/_search
{
  "query": {
    "range": {
      "order_date": {
        "gte": "now-7d"
      }
    }
  },
  "aggs": {
    "time_buckets": {
      "date_histogram": {
        "field": "order_date",
        "fixed_interval": "1d",
        "extended_bounds": {
          "min": "now-7d"
        },
        "min_doc_count": 0
      }
    }
  },
  "size": 0
}

添加 词项聚合,然后单击 单击以发送请求

POST kibana_sample_data_ecommerce/_search
{
  "query": {
    "range": {
      "order_date": {
        "gte": "now-7d"
      }
    }
  },
  "aggs": {
    "categories": {
      "terms": { "field": "category.keyword" },
      "aggs": {
        "time_buckets": {
          "date_histogram": {
            "field": "order_date",
            "fixed_interval": "1d",
            "extended_bounds": {
              "min": "now-7d"
            },
            "min_doc_count": 0
          }
        }
      }
    }
  },
  "size": 0
}

响应格式与第一个聚合查询不同

{
  "aggregations" : {
    "categories" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [{
        "key" : "Men's Clothing",
        "doc_count" : 1661,
        "time_buckets" : {
          "buckets" : [{
            "key_as_string" : "2020-06-30T00:00:00.000Z",
            "key" : 1593475200000,
            "doc_count" : 19
          }, {
            "key_as_string" : "2020-07-01T00:00:00.000Z",
            "key" : 1593561600000,
            "doc_count" : 71
          }]
        }
      }]
    }
  }
}

Vega-Lite 规范中,输入聚合,然后单击 更新

  data: {
    url: {
      %context%: true
      %timefield%: order_date
      index: kibana_sample_data_ecommerce
      body: {
        aggs: {
          categories: {
            terms: { field: "category.keyword" }
            aggs: {
              time_buckets: {
                date_histogram: {
                  field: order_date
                  interval: {%autointerval%: true}
                  extended_bounds: {
                    min: {%timefilter%: "min"}
                    max: {%timefilter%: "max"}
                  }
                  min_doc_count: 0
                }
              }
            }
          }
        }
        size: 0
      }
    }
    format: {property: "aggregations.categories.buckets" }
  }

有关查询的信息,请参阅 在 Vega 中编写 Elasticsearch 查询的参考

调试警告
编辑

为了生成数据,Vega-Lite 使用 source_0data_0source_0 包含来自 Elasticsearch 查询的结果,而 data_0 包含图表上显示的视觉编码结果。要调试警告,请比较 source_0data_0

  1. 在工具栏中,单击 检查
  2. 查看 下拉列表中,选择 Vega 调试
  3. 从下拉列表中,选择 source_0

    Table for data_0 with columns key
  4. 要与视觉编码的数据进行比较,请从下拉列表中选择 data_0

    Table for data_0 where the key is NaN instead of a string

    key 无法转换,因为该属性是类别(男士服装女士服装等),而不是时间戳。

添加并调试编码块
编辑

Vega-Lite 规范中,添加 encoding

  encoding: {
    x: {
      field: time_buckets.buckets.key
      type: temporal
      axis: { title: null }
    }
    y: {
      field: time_buckets.buckets.doc_count
      type: quantitative
      axis: { title: "Document count" }
    }
  }
  1. 单击 检查,然后从 查看 下拉列表中选择 Vega 调试
  2. 从下拉列表中,选择 data_0

    Table for data_0 showing that the column time_buckets.buckets.key is undefined

Vega-Lite 无法提取 time_buckets.buckets 内部数组。

提取 time_buckets.buckets 内部数组
编辑

在 Kibana 7.9 及更高版本中,使用 Vega-Lite flatten 转换 来提取 time_buckets.buckets 内部数组。

如果您使用的是 Kibana 7.8 及更早版本,则 flatten 转换仅在 Vega 中可用。

Vega-Lite 规范中,添加 transform 块,然后单击 更新

  transform: [{
    flatten: ["time_buckets.buckets"]
  }]
  1. 单击 检查,然后从 查看 下拉列表中选择 Vega 调试
  2. 从下拉列表中,选择 data_0

    Table showing data_0 with multiple pages of results

    Vega-Lite 显示 未定义 值,因为存在重复的名称。

  3. 要解决重复名称的问题,请添加 transformencoding 块,然后单击 更新
  transform: [{
    flatten: ["time_buckets.buckets"],
    as: ["buckets"]
  }]

  mark: area

  encoding: {
    x: {
      field: buckets.key
      type: temporal
      axis: { title: null }
    }
    y: {
      field: buckets.doc_count
      type: quantitative
      axis: { title: "Document count" }
    }
    color: {
      field: key
      type: nominal
    }
  }
添加悬停状态和工具提示
编辑

使用 Vega-Lite 规范,您可以使用 selection 块向堆积面积图添加悬停状态和工具提示。

Vega-Lite 规范中,添加 encoding 块,然后单击 更新

  encoding: {
    tooltip: [{
      field: buckets.key
      type: temporal
      title: "Date"
    }, {
      field: key
      type: nominal
      title: "Category"
    }, {
      field: buckets.doc_count
      type: quantitative
      title: "Count"
    }]
  }

当您将鼠标悬停在堆积面积图上的面积系列时,会出现一个多行工具提示,但无法指示最近的点。要指示最近的点,请添加第二层。

添加复合标记,然后单击 更新

  layer: [{
    mark: area
  }, {
    mark: point
  }]

这些点无法堆叠并与堆积面积图对齐。

更改 y encoding

    y: {
      field: buckets.doc_count
      type: quantitative
      axis: { title: "Document count" }
      stack: true
    }

mark: point 内添加 selection

  layer: [{
    mark: area
  }, {
    mark: point

    selection: {
      pointhover: {
        type: single
        on: mouseover
        clear: mouseout
        empty: none
        fields: ["buckets.key", "key"]
        nearest: true
      }
    }

    encoding: {
      size: {
        condition: {
          selection: pointhover
          value: 100
        }
        value: 5
      }
      fill: {
        condition: {
          selection: pointhover
          value: white
        }
      }
    }
  }]

在堆积面积图周围移动光标。这些点能够指示最近的点。

Vega-Lite tutorial selection enabled

选择由信号控制。要查看信号,请单击工具栏中的 检查

展开最终 Vega-Lite 规范
{
  $schema: https://vega.github.io/schema/vega-lite/v4.json
  title: Event counts from ecommerce
  data: {
    url: {
      %context%: true
      %timefield%: order_date
      index: kibana_sample_data_ecommerce
      body: {
        aggs: {
          categories: {
            terms: { field: "category.keyword" }
            aggs: {
              time_buckets: {
                date_histogram: {
                  field: order_date
                  interval: {%autointerval%: true}
                  extended_bounds: {
                    min: {%timefilter%: "min"}
                    max: {%timefilter%: "max"}
                  }
                  min_doc_count: 0
                }
              }
            }
          }
        }
        size: 0
      }
    }
    format: {property: "aggregations.categories.buckets" }
  }

  transform: [{
    flatten: ["time_buckets.buckets"]
    as: ["buckets"]
  }]

  encoding: {
    x: {
      field: buckets.key
      type: temporal
      axis: { title: null }
    }
    y: {
      field: buckets.doc_count
      type: quantitative
      axis: { title: "Document count" }
      stack: true
    }
    color: {
      field: key
      type: nominal
      title: "Category"
    }
    tooltip: [{
      field: buckets.key
      type: temporal
      title: "Date"
    }, {
      field: key
      type: nominal
      title: "Category"
    }, {
      field: buckets.doc_count
      type: quantitative
      title: "Count"
    }]
  }

  layer: [{
    mark: area
  }, {
    mark: point

    selection: {
      pointhover: {
        type: single
        on: mouseover
        clear: mouseout
        empty: none
        fields: ["buckets.key", "key"]
        nearest: true
      }
    }

    encoding: {
      size: {
        condition: {
          selection: pointhover
          value: 100
        }
        value: 5
      }
      fill: {
        condition: {
          selection: pointhover
          value: white
        }
      }
    }
  }]
}

教程:从 Vega 更新 Kibana 过滤器

编辑

要使用 Elasticsearch 搜索查询构建面积图,请编辑 Vega 规范,然后添加单击和拖动处理程序以更新 Kibana 过滤器。

Vega 规范中,输入以下内容,然后单击 更新

{
  $schema: "https://vega.github.io/schema/vega/v5.json"
  data: [{
    name: source_0
  }]

  scales: [{
    name: x
    type: time
    range: width
  }, {
    name: y
    type: linear
    range: height
  }]

  axes: [{
    orient: bottom
    scale: x
  }, {
    orient: left
    scale: y
  }]

  marks: [
    {
      type: area
      from: {
        data: source_0
      }
      encode: {
        update: {
        }
      }
    }
  ]
}

使用 data 块添加 Elasticsearch 搜索查询,然后单击 更新

  data: [
    {
      name: source_0
      url: {
        %context%: true
        %timefield%: order_date
        index: kibana_sample_data_ecommerce
        body: {
          aggs: {
            time_buckets: {
              date_histogram: {
                field: order_date
                fixed_interval: "3h"
                extended_bounds: {
                  min: {%timefilter%: "min"}
                  max: {%timefilter%: "max"}
                }
                min_doc_count: 0
              }
            }
          }
          size: 0
        }
      }
      format: { property: "aggregations.time_buckets.buckets" }
    }
  ]
更改 x 轴和 y 轴
编辑

显示 x 轴和 y 轴的标签。

Vega 规范中,添加 scales 块,然后单击 更新

  scales: [{
    name: x
    type: time
    range: width
    domain: {
      data: source_0
      field: key
    }
  }, {
    name: y
    type: linear
    range: height
    domain: {
      data: source_0
      field: doc_count
    }
  }]

添加 keydoc_count 字段作为 X 轴和 Y 轴的值,然后单击 更新

  marks: [
    {
      type: area
      from: {
        data: source_0
      }
      encode: {
        update: {
          x: {
            scale: x
            field: key
          }
          y: {
            scale: y
            value: 0
          }
          y2: {
            scale: y
            field: doc_count
          }
        }
      }
    }
  ]
vega tutorial 3
marks 部分添加块
编辑

在面积图上显示可点击的点以筛选特定日期。

Vega 规范中,添加到 marks 代码块,然后单击 更新

  {
    name: point
    type: symbol
    style: ["point"]
    from: {
      data: source_0
    }
    encode: {
      update: {
        x: {
          scale: x
          field: key
        }
        y: {
          scale: y
          field: doc_count
        }
        size: {
          value: 100
        }
        fill: {
          value: black
        }
      }
    }
  }
创建信号
编辑

要使点可点击,请创建一个 Vega 信号。您可以在用于更新的表达式中访问点击的 datum

Vega 规范中,添加一个 signals 代码块,以指定光标点击添加具有三个小时间隔的时间过滤器,然后单击 更新

  signals: [
    {
      name: point_click
      on: [{
        events: {
          source: scope
          type: click
          markname: point
        }
        update: '''kibanaSetTimeFilter(datum.key, datum.key + 3 * 60 * 60 * 1000)'''
      }]
    }
  ]

该事件使用 kibanaSetTimeFilter 自定义函数生成一个过滤器,该过滤器在点击时应用于整个仪表板。

要使面积图具有交互性,请找到 marks 代码块,然后更新 point 并将 cursor: { value: "pointer" } 添加到 encoding

  {
    name: point
    type: symbol
    style: ["point"]
    from: {
      data: source_0
    }
    encode: {
      update: {
        ...
        cursor: { value: "pointer" }
      }
    }
  }
添加拖动交互
编辑

要允许用户基于时间范围进行过滤,请添加拖动交互,这需要额外的信号和一个矩形覆盖。

vega tutorial 4

Vega 规范中,添加一个 signal 来跟踪光标的 X 位置

    {
      name: currentX
      value: -1
      on: [{
        events: {
          type: mousemove
          source: view
        },
        update: "clamp(x(), 0, width)"
      }, {
        events: {
          type: mouseout
          source: view
        }
        update: "-1"
      }]
    }

要指示当前光标位置,请添加一个 mark 代码块

    {
      type: rule
      interactive: false
      encode: {
        update: {
          y: {value: 0}
          y2: {signal: "height"}
          stroke: {value: "gray"}
          strokeDash: {
            value: [2, 1]
          }
          x: {signal: "max(currentX,0)"}
          defined: {signal: "currentX > 0"}
        }
      }
    }

要跟踪选定的时间范围,请添加一个信号,该信号会更新直到用户释放光标或按下 Return 键

    {
      name: selected
      value: [0, 0]
      on: [{
        events: {
          type: mousedown
          source: view
        }
        update: "[clamp(x(), 0, width), clamp(x(), 0, width)]"
      }, {
        events: {
          type: mousemove
          source: window
          consume: true
          between: [{
            type: mousedown
            source: view
          }, {
            merge: [{
              type: mouseup
              source: window
            }, {
              type: keydown
              source: window
              filter: "event.key === 'Escape'"
            }]
          }]
        }
        update: "[selected[0], clamp(x(), 0, width)]"
      }, {
        events: {
          type: keydown
          source: window
          filter: "event.key === 'Escape'"
        }
        update: "[0, 0]"
      }]
    }

有一个信号可以跟踪用户的时间范围。

要直观地指示范围,请添加一个仅在有条件时才出现的标记

    {
      type: rect
      name: selectedRect
      encode: {
        update: {
          height: {signal: "height"}
          fill: {value: "#333"}
          fillOpacity: {value: 0.2}
          x: {signal: "selected[0]"}
          x2: {signal: "selected[1]"}
          defined: {signal: "selected[0] !== selected[1]"}
        }
      }
    }

添加一个信号,该信号在拖动时释放光标时更新 Kibana 时间过滤器

    {
      name: applyTimeFilter
      value: null
      on: [{
        events: {
          type: mouseup
          source: view
        }
        update: '''selected[0] !== selected[1] ? kibanaSetTimeFilter(
               invert('x',selected[0]),
               invert('x',selected[1])) : null'''
      }]
    }
展开最终的 Vega 规范
{
  $schema: "https://vega.github.io/schema/vega/v5.json"
  data: [
    {
      name: source_0
      url: {
        %context%: true
        %timefield%: order_date
        index: kibana_sample_data_ecommerce
        body: {
          aggs: {
            time_buckets: {
              date_histogram: {
                field: order_date
                fixed_interval: "3h"
                extended_bounds: {
                  min: {%timefilter%: "min"}
                  max: {%timefilter%: "max"}
                }
                min_doc_count: 0
              }
            }
          }
          size: 0
        }
      }
      format: { property: "aggregations.time_buckets.buckets" }
    }
  ]

  scales: [{
    name: x
    type: time
    range: width
    domain: {
      data: source_0
      field: key
    }
  }, {
    name: y
    type: linear
    range: height
    domain: {
      data: source_0
      field: doc_count
    }
  }]

  axes: [{
    orient: bottom
    scale: x
  }, {
    orient: left
    scale: y
  }]

  marks: [
    {
      type: area
      from: {
        data: source_0
      }
      encode: {
        update: {
          x: {
            scale: x
            field: key
          }
          y: {
            scale: y
            value: 0
          }
          y2: {
            scale: y
            field: doc_count
          }
        }
      }
    },
    {
      name: point
      type: symbol
      style: ["point"]
      from: {
        data: source_0
      }
      encode: {
        update: {
          x: {
            scale: x
            field: key
          }
          y: {
            scale: y
            field: doc_count
          }
          size: {
            value: 100
          }
          fill: {
            value: black
          }
          cursor: { value: "pointer" }
        }
      }
    },
    {
      type: rule
      interactive: false
      encode: {
        update: {
          y: {value: 0}
          y2: {signal: "height"}
          stroke: {value: "gray"}
          strokeDash: {
            value: [2, 1]
          }
          x: {signal: "max(currentX,0)"}
          defined: {signal: "currentX > 0"}
        }
      }
    },
    {
      type: rect
      name: selectedRect
      encode: {
        update: {
          height: {signal: "height"}
          fill: {value: "#333"}
          fillOpacity: {value: 0.2}
          x: {signal: "selected[0]"}
          x2: {signal: "selected[1]"}
          defined: {signal: "selected[0] !== selected[1]"}
        }
      }
    }
  ]

  signals: [
    {
      name: point_click
      on: [{
        events: {
          source: scope
          type: click
          markname: point
        }
        update: '''kibanaSetTimeFilter(datum.key, datum.key + 3 * 60 * 60 * 1000)'''
      }]
    }
    {
      name: currentX
      value: -1
      on: [{
        events: {
          type: mousemove
          source: view
        },
        update: "clamp(x(), 0, width)"
      }, {
        events: {
          type: mouseout
          source: view
        }
        update: "-1"
      }]
    }
    {
      name: selected
      value: [0, 0]
      on: [{
        events: {
          type: mousedown
          source: view
        }
        update: "[clamp(x(), 0, width), clamp(x(), 0, width)]"
      }, {
        events: {
          type: mousemove
          source: window
          consume: true
          between: [{
            type: mousedown
            source: view
          }, {
            merge: [{
              type: mouseup
              source: window
            }, {
              type: keydown
              source: window
              filter: "event.key === 'Escape'"
            }]
          }]
        }
        update: "[selected[0], clamp(x(), 0, width)]"
      }, {
        events: {
          type: keydown
          source: window
          filter: "event.key === 'Escape'"
        }
        update: "[0, 0]"
      }]
    }
    {
      name: applyTimeFilter
      value: null
      on: [{
        events: {
          type: mouseup
          source: view
        }
        update: '''selected[0] !== selected[1] ? kibanaSetTimeFilter(
               invert('x',selected[0]),
               invert('x',selected[1])) : null'''
      }]
    }
  ]
}

Vega 参考

编辑

了解有关 Kibana 扩展、其他 Vega 资源和示例的更多信息。

Kibana 扩展的参考
编辑

Kibana 扩展了 Vega 和 Vega-Lite,并提供以下支持

  • 自动调整大小
  • 与 Kibana 匹配的默认主题
  • 使用仪表板中的时间范围和过滤器编写 Elasticsearch 查询
  • [预览] 此功能为技术预览版,可能会在未来的版本中更改或删除。Elastic 将努力解决任何问题,但技术预览版中的功能不受正式 GA 功能的支持 SLA 的约束。 在 Vega 地图中使用 Elastic Map Service
  • 其他工具提示样式
  • 启用从任何域加载 URL 的高级设置
  • 使用 Kibana 检查器或浏览器控制台进行调试支持
  • (仅限 Vega) 可以更新时间范围和仪表板过滤器的表达式函数
自动调整大小
编辑

大多数用户都希望他们的 Vega 可视化占据所有可用空间,因此与 Vega 示例不同,widthheight 在 Kibana 中不是必需的参数,因为在大多数情况下,您的规范将与默认的 Kibana 设置合并

autosize: {
  type: fit
  contains: padding
}
width: container
height: container

如果出现以下情况,则 应用这些默认设置

  • 您的规范使用 type=map
  • 您的规范是 Vega-Lite 并且包含 facet、row、column、repeat 或 concat 运算符。在这些情况下,提供 widthheight 将会影响子大小。

要手动设置宽度或高度,请设置 autosize: none 并提供精确的像素大小,包括标题、图例和坐标轴的填充。

autosize: none
width: 600
height: 200
padding: {
  top: 20
  bottom: 20
  left: 55
  right: 150
}

要了解更多信息,请阅读 Vega 自动调整大小Vega-Lite 自动调整大小

Vega-Lite 中的自动调整大小具有 一些限制,这些限制可能会影响可视化的宽度和高度,但这些限制在 Vega 中不存在。如果您需要完全控制,请使用 浏览器控制台 VEGA_DEBUG.vega_spec 输出将您的规范转换为 Vega。要禁用这些警告,您可以向您的规范添加额外的选项

与 Kibana 匹配的默认主题
编辑

Kibana 注册一个 ID 为 elastic 的默认 Vega 配色方案,并为每种 mark 类型设置默认颜色。 通过提供不同的 strokefillcolor (Vega-Lite) 值来覆盖它。

在 Vega 中编写 Elasticsearch 查询
编辑

Kibana 使用指定为 url 的直接 Elasticsearch 查询扩展了 Vega 数据元素。

Kibana 无法支持动态加载的数据,否则这些数据可以在 Vega 中工作。所有数据都会在传递给 Vega 渲染器之前获取。

要在 Vega 中定义 Elasticsearch 查询,请将 url 设置为对象。Kibana 会解析该对象以查找特殊的标记,这些标记允许您的查询与 Kibana 集成。

标记包括以下内容

  • %context%: true:在顶层设置,并将 query 部分替换为仪表板中的过滤器
  • %timefield%: <name>:在顶层设置,将查询与仪表板时间过滤器集成
  • {%timefilter%: true}:替换为具有上限和下限的 Elasticsearch 范围查询
  • {%timefilter%: "min" | "max"}:仅替换为上限或下限
  • {%timefilter: true, shift: -1, unit: 'hour'}:生成过去一小时的时间范围查询
  • {%autointerval%: true}:替换为包含 Kibana 自动时间间隔的字符串,例如 1h
  • {%autointerval%: 10}:替换为将时间大致划分为 10 个范围的字符串,从而使您可以影响自动间隔
  • "%dashboard_context-must_clause%":由包含过滤器的对象替换的字符串
  • "%dashboard_context-filter_clause%":由包含过滤器的对象替换的字符串
  • "%dashboard_context-must_not_clause%":由包含过滤器的对象替换的字符串

Vega 支持 interval 参数,该参数在 Elasticsearch 8.0.0 及更高版本中不受支持。 要使用间隔,请改用 fixed_intervalcalendar_interval

例如,以下查询计算特定索引中的文档数

// An object instead of a string for the URL value
// is treated as a context-aware Elasticsearch query.
url: {
  // Specify the time filter.
  %timefield%: @timestamp
  // Apply dashboard context filters when set
  %context%: true

  // Which indexes to search
  index: kibana_sample_data_logs
  // The body element may contain "aggs" and "query" keys
  body: {
    aggs: {
      time_buckets: {
        date_histogram: {
          // Use date histogram aggregation on @timestamp field
          field: @timestamp 
          // interval value will depend on the time filter
          // Use an integer to set approximate bucket count
          interval: { %autointerval%: true }
          // Make sure we get an entire range, even if it has no data
          extended_bounds: {
            min: { %timefilter%: "min" }
            max: { %timefilter%: "max" }
          }
          // Use this for linear (e.g. line, area) graphs
          // Without it, empty buckets will not show up
          min_doc_count: 0
        }
      }
    }
    // Speed up the response by only including aggregation results
    size: 0
  }
}

@timestamp — 过滤时间范围并将其分解为直方图存储桶。

完整结果包括以下结构

{
  "aggregations": {
    "time_buckets": {
      "buckets": [{
          "key_as_string": "2015-11-30T22:00:00.000Z",
          "key": 1448920800000,
          "doc_count": 28
        }, {
          "key_as_string": "2015-11-30T23:00:00.000Z",
          "key": 1448924400000, 
          "doc_count": 330
        }, ...

"key" — 您可以按原样使用而无需通过 Vega 日期表达式进行转换的 Unix 时间戳。

对于大多数可视化,您只需要存储桶值的列表。 要仅关注所需的数据,请使用 format: {property: "aggregations.time_buckets.buckets"}

指定具有单个范围和仪表板上下文的查询。 该查询等效于 "%context%": true, "%timefield%": "@timestamp",但时间范围向后移动了 10 分钟

{
  body: {
    query: {
      bool: {
        must: [
          // This string will be replaced
          // with the auto-generated "MUST" clause
          "%dashboard_context-must_clause%"
          {
            range: {
              // apply timefilter (upper right corner)
              // to the @timestamp variable
              @timestamp: {
                // "%timefilter%" will be replaced with
                // the current values of the time filter
                // (from the upper right corner)
                "%timefilter%": true
                // Only work with %timefilter%
                // Shift current timefilter by 10 units back
                shift: 10
                // week, day (default), hour, minute, second
                unit: minute
              }
            }
          }
        ]
        must_not: [
          // This string will be replaced with
          // the auto-generated "MUST-NOT" clause
          "%dashboard_context-must_not_clause%"
        ]
        filter: [
          // This string will be replaced
          // with the auto-generated "FILTER" clause
          "%dashboard_context-filter_clause%"
        ]
      }
    }
  }
}

当使用 "%context%": true 或为 "%timefield%" 定义值时,正文不能包含查询。 要在 VEGA 规范中自定义查询(例如,添加额外的过滤器或移动时间过滤器),请定义您的查询并使用占位符,如上面的示例所示。 一旦解析,占位符将被仪表板或可视化的实际上下文替换。

"%timefilter%" 也可用于指定单个最小值或最大值。 date_histogram 的 extended_bounds 可以设置为两个值 - 最小值和最大值。 您可以使用 "min": {"%timefilter%": "min"} 而不是硬编码一个值,它将被当前时间范围的开始替换。 还支持 shiftunit 值。 "interval" 也可以动态设置,具体取决于当前选择的范围:"interval": {"%autointerval%": 10} 将尝试获取大约 10-15 个数据点(存储桶)。

访问 Elastic Map Service 文件
编辑

[预览] 此功能为技术预览版,可能会在未来的版本中更改或删除。Elastic 将努力解决任何问题,但技术预览版中的功能不受正式 GA 功能的支持 SLA 的约束。 通过相同的机制访问 Elastic Map Service 文件

url: {
  // "type" defaults to "elasticsearch" otherwise
  %type%: emsfile
  // Name of the file, exactly as in https://maps.elastic.co
  name: World Countries
}
// The result is either a topojson file or a geojson file.
// Refer to the Default format for the file at https://maps.elastic.co
// Get its features to use this data source with the "shape" marks
// https://vega.github.io/vega/docs/marks/shape/
// For a topojson file use
format: {type: "topojson", feature: "data"}

// For a geojson file use
format: {property: "features"}

带有地图的 Vega

编辑

[预览] 此功能为技术预览版,可能会在未来的版本中更改或删除。Elastic 将努力解决任何问题,但技术预览版中的功能不受正式 GA 功能的支持 SLA 的约束。 要启用 地图,图表必须在主机配置中指定 type=map

{
  "config": {
    "kibana": {
      "type": "map",

      // Initial map position
      "latitude": 40.7,   // default 0
      "longitude": -74,   // default 0
      "zoom": 7,          // default 2

      // Defaults to 'true', disables the base map layer.
      "mapStyle": false,

      // When 'mapStyle' is 'undefined' or 'true', sets the EMS-layer for the map.
      // May either be: "road_map", "road_map_desaturated", "dark_map".
      // If 'emsTileServiceId' is 'undefined', it falls back to the auto-switch-dark-light behavior.
      "emsTileServiceId": "road_map",

      // default 0
      "minZoom": 5,

      // defaults to the maximum for the given style,
      // or 25 when base is disabled
      "maxZoom": 13,

      // Defaults to 'true', shows +/- buttons to zoom in/out
      "zoomControl": false,

      // Defaults to 'false', disables mouse wheel zoom. If set to
      // 'true', map may zoom unexpectedly while scrolling dashboard
      "scrollWheelZoom": false,

      // When false, repaints on each move frame.
      // Makes the graph slower when moving the map
      "delayRepaint": true, // default true
    }
  },
  /* the rest of Vega JSON */
}

可视化会自动注入一个 "projection",您可以使用它来计算所有地理感知标记的位置。此外,您可以使用 latitudelongitudezoom 信号。这些信号可以在图表中,也可以更新以修改地图的位置。

[预览] 此功能为技术预览版,可能会在未来的版本中更改或删除。Elastic 将努力解决任何问题,但技术预览版中的功能不受正式 GA 功能的支持 SLA 的约束。 您可以使用 Vega 数据元素通过将 url.data 设置为 emsFile 来访问 Vega 地图中 Elastic Maps Service (EMS) 行政边界的矢量形状

  "data": [
    {
      "name": "countries",
      "url": {
        // "type" defaults to "elasticsearch" otherwise
        %type%: emsfile
        // Name of the file, exactly as in the Region map visualization
        name: World Countries
      },
      // The result is a topojson file, get its features to use
      // this data source with the "shape" marks
      // https://vega.github.io/vega/docs/marks/shape/
      "format": {"type": "topojson", "feature": "data"},
    }
  ],
  "marks": [
    {
      "type": "shape",
      "from": {"data": "countries"},
      "transform": [{"type": "geoshape", "projection": "projection"}]
    }
  ]
其他工具提示样式
编辑

Kibana 安装了 Vega 工具提示插件,因此工具提示可以按照此处记录的方式定义。除此之外,Kibana 还支持用于更改工具提示位置和填充的配置选项

{
  config: {
    kibana: {
      tooltips: {
        position: 'top',
        padding: 15,
        textTruncate: true,
      }
    }
  }
}
启用从任何域加载 URL
编辑

Vega 可以从任何 URL 加载数据。要启用此功能,请在 kibana.yml 中设置 vis_type_vega.enableExternalUrls: true,然后重启 Kibana。

外部 URL 加载的文件必须允许 CORS。远程 URL 必须包含 Access-Control-Allow-Origin,它允许来自 Kibana URL 的请求。

您可以使用占位符 %timefilter_min%%timefilter_max%,将当前时间范围作为毫秒时间戳添加到外部 URL 中,例如 http://example.com?min=%timefilter_min%

Vega 检查器
编辑

使用上下文菜单中的 检查 工具来深入了解不同的元素。

检查 Elasticsearch 请求
编辑

Vega 使用 Elasticsearch 搜索 API 从 Elasticsearch 获取文档和聚合结果。要对这些请求进行故障排除,请单击 检查,它会显示最近的请求。如果您的规范包含多个请求,您可以使用 视图 下拉菜单在视图之间切换。

vega tutorial inspect requests
Vega 调试
编辑

通过 Vega 调试 视图,您可以检查 数据集信号值 的运行时数据。

运行时数据是从 运行时作用域 读取的。

vega tutorial inspect data sets

要调试更复杂的规范,请访问 view 变量。有关更多信息,请参阅 Vega 浏览器调试过程

请求帮助解决 Vega 规范
编辑

由于 Elasticsearch 中数据的动态特性,除非您可以共享数据集,否则很难帮助您解决 Vega 规范的问题。为此,请单击 检查,选择 Vega 调试 视图,然后选择 规范

vega tutorial getting help

要复制响应,请单击 复制到剪贴板。将复制的数据粘贴到 gist.github.com,可以使用 .json 扩展名。使用 [raw] 按钮,并在请求帮助时共享该链接。

浏览器调试控制台
编辑

[预览] 此功能处于技术预览阶段,可能会在未来的版本中更改或删除。Elastic 将努力解决任何问题,但技术预览中的功能不受官方 GA 功能的支持 SLA 的约束。 使用浏览器调试工具(例如,在 Chrome 中使用 F12 或 Ctrl+Shift+J)来检查 VEGA_DEBUG 变量

  • view — 访问 Vega View 对象。有关如何在运行时检查数据和信号,请参阅 Vega 调试指南。对于 Vega-Lite,VEGA_DEBUG.view.data('source_0') 获取预转换数据,而 VEGA_DEBUG.view.data('data_0') 获取编码数据。对于 Vega,它使用 Vega 规范中定义的数据名称。
  • vega_spec — Kibana 进行一些修改后的 Vega JSON 图形规范。对于 Vega-Lite,这是 Vega-Lite 编译器的输出。
  • vegalite_spec — 如果这是一个 Vega-Lite 图形,则这是 Vega-Lite 编译之前的图形的 JSON 规范。
(仅限 Vega)可以更新时间范围和仪表板过滤器的表达式函数
编辑

Kibana 已使用这些函数扩展了 Vega 表达式语言。这些函数将触发获取新数据,默认情况下,这将重置 Vega 信号。要保留设置的信号值,请在 Vega 配置中设置 restoreSignalValuesOnRefresh: true

/**
  * @param {object} query Elastic Query DSL snippet, as used in the query DSL editor
  * @param {string} [index] as defined in Kibana, or default if missing
  * @param {string} Custom label of the filter shown in the filter bar
  */
kibanaAddFilter(query, index, alias)

/**
  * @param {object} query Elastic Query DSL snippet, as used in the query DSL editor
  * @param {string} [index] as defined in Kibana, or default if missing
  */
kibanaRemoveFilter(query, index)

kibanaRemoveAllFilters()

/**
  * Update dashboard time filter to the new values
  * @param {number|string|Date} start
  * @param {number|string|Date} end
  */
kibanaSetTimeFilter(start, end)
其他配置选项
编辑
{
  config: {
    kibana: {
      // Placement of the Vega-defined signal bindings.
      // Can be `left`, `right`, `top`, or `bottom` (default).
      controlsLocation: top
      // Can be `vertical` or `horizontal` (default).
      controlsDirection: vertical
      // If true, hides most of Vega and Vega-Lite warnings
      hideWarnings: true
      // Vega renderer to use: `svg` or `canvas` (default)
      renderer: canvas
      // Defaults to 'false', restores Vega signal values on refresh
      restoreSignalValuesOnRefresh: false
    }
  }
}

资源和示例

编辑

要了解有关 Vega 和 Vega-Lite 的更多信息,请参阅资源和示例。

Vega 编辑器
编辑

Vega 编辑器 包含 Vega 和 Vega-Lite 的示例,但不支持任何 Kibana 特定的功能,如 Elasticsearch 请求和交互式底图。

Vega-Lite 资源
编辑
Vega 资源
编辑

当您在 Kibana 中使用示例时,可能需要修改 "data" 部分以使用绝对 URL。例如,将 "url": "data/world-110m.json" 替换为 "url": "https://vega.github.io/editor/data/world-110m.json"