【最佳实践】Vega:定制开箱即用的 Kibana 可视化分析图标

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: Kibana 提供了很多开箱即用的可视化工具。它们可以让我们很方便地创建我们想要的分析图表。如果我们想定制一个我们自己的可视化图,那该怎么办呢?传统的方法是创建自己的插件来扩充我们自己的需求,但是这种开发的成本及周期都比较长。很幸运的是,Kibana 提供了一种很方便的可视化工具 : Vega。在今天的文章中,我们将来介绍如何创建一个属于我们自己的 Vega 可视化图。

文本作者:刘晓国,Elastic 公司社区布道师。新加坡国立大学硕士,西北工业大学硕士,曾就职于新加坡科技,康柏电脑,通用汽车,爱立信,诺基亚,Linaro,Ubuntu,Vantiq 等企业。

什么是 Vega

我们可以在网站 http://vega.github.io/ 找到关于 Vega 的详细说明。

Vega 声明式语法是一种可视化数据的强大方法。可视化内容以JSON描述,并使用 HTML5 Canvas 或 SVG 生成交互式视图。 它是Kibana 6.2中的一项新功能,你现在可以使用 Elasticsearch 数据构建丰富的Vega 和 Vega-Lite 可视化。 因此,让我们从几个简单的示例开始学习 Vega 语言。

深圳

首先,打开 Vega编辑器 --- 一种方便的工具来尝试原始Vega(它没有 Elasticsearch 定制)。 复制以下代码,您将看到 "Hello Vega!。 右侧面板中的文本。

{
  "$schema": "https://vega.github.io/schema/vega/v3.json",
  "width": 100, "height": 30,
  "background": "#eef2e8",
  "padding": 5,
  "marks": [
    {
      "type": "text",
      "encode": {
        "update": {
          "text":     { "value": "Hello Vega!" },
          "align":    { "value": "center"},
          "baseline": { "value": "middle"},
          "stroke":   { "value": "#A32299" },
          "angle":    { "value": 15 },
          "x":        { "signal": "width/2" },
          "y":        { "signal": "height/2" }
        }
      }
    }
  ]
}

深圳

marks 是绘图图元的数组,例如文本,线条和矩形。每个标记都有在编码集(encode-set)中指定的大量参数。在“update”阶段,将每个参数设置为常数(值)或计算结果(信号)。对于文本(text)标记,我们指定文本字符串,确保文本相对于给定坐标正确放置,旋转并设置文本颜色。 x和y坐标是根据图形的宽度和高度计算的,将文本放在中间。还有许多其他文本标记参数。还有一个交互式文本标记演示图,可以尝试不同的参数值。

$schema 只是所需的 Vega 引擎版本的ID。背景使图形不透明。width 和 height 设置初始绘图画布的大小。在某些情况下,最终的图形大小可能会根据内容和自动调整大小选项而更改。请注意,Kibana 的默认 autosize 的值是 fit 而不是 pad,因此高度和宽度是可选的。 padding 参数除了宽度和高度外,还在图形周围添加了一些空间。

数据驱动图

我们的下一步是使用矩形标记绘制数据驱动的图形。 数据部分允许使用硬编码或URL的多个数据源。 在 Kibana 中,你也可以使用直接 Elasticsearch 查询。 我们的 vals 数据表有 4 行和 2 列-category 和 count。 我们使用 category 将条形图放置在 x 轴上,并把 count 设置为条形图的高度。 请注意,它们的坐标 0 在顶部,向下则增加。

{
  "$schema":"https://vega.github.io/schema/vega/v3.json",
  "width": 300, "height": 100,
  "data": [ {
    "name": "vals",
    "values": [
      {"category": 50,  "count": 30},
      {"category": 100, "count": 80},
      {"category": 150, "count": 10},
      {"category": 200, "count": 50}
    ]
  } ],
  "marks": [ {
    "type": "rect",
    "from": { "data": "vals" },
    "encode": {
      "update": {
        "x":     {"field": "category"},
        "width": {"value": 30},
        "y":     {"field": "count"},
        "y2":    {"value": 0}
      }
    }
  } ]
}

深圳

rect 标记将 vals 指定为数据源。 每个源数据值(也称为表格的行或 datum,见下面的例子)绘制一次标记。 与之前的图不同,x 和 y 参数不是硬编码的,而是来自基准的字段。

缩放比例 - scaling

scaling 是Vega中最重要但有些棘手的概念之一。 在前面的示例中,屏幕像素坐标已硬编码在数据中。 尽管它使事情变得更简单,但实际数据几乎永远不会以这种形式出现。 取而代之的是,源数据以其自己的单位(例如事件数)进入,并且由图形决定是否将源值缩放为所需的图形大小(以像素为单位)。
在此示例中,我们使用线性比例尺---本质上是一个数学函数,用于将源数据域中的值(在此图中,count 为1000..8000,包括 count = 0)转换为所需范围( 在我们的例子中,图形的高度为0..99)。 在 y 和 y2 参数中都添加 “scale”:“yscale” 使用 yscale 定标器将 count 转换为屏幕坐标(0变为99,而8000-源数据中的最大值-变为0)。 请注意,height range参数是一种特殊情况,将值翻转以使 0 出现在图形的底部.

{
  "$schema":"https://vega.github.io/schema/vega/v3.json",
  "width": 400, "height": 100,
  "data": [ {
    "name": "vals",
    "values": [
      {"category": 50,  "count": 3000},
      {"category": 100, "count": 8000},
      {"category": 150, "count": 1000},
      {"category": 200, "count": 5000}
    ]
  } ],
 "scales": [
    {
      "name": "yscale",
      "type": "linear",
      "zero": true,
      "domain": {"data": "vals", "field": "count"},
      "range": "height"
    }
  ],
  "marks": [ {
    "type": "rect",
    "from": { "data": "vals" },
    "encode": {
      "update": {
        "x":     {"field": "category"},
        "width": {"value": 30},
        "y":     {"scale": "yscale", "field": "count"},
        "y2":    {"scale": "yscale", "value": 0}
      }
    }
  } ]
}

深圳

Band scaling

对于我们的教程,我们将需要15种以上的 Vega scale 类型中的另一种---band scale。 当我们有一组值(如类别)需要使用band表示时,将使用此比例尺,每个带占据图形总宽度的相同比例宽度。 在此,带比例为4个唯一类别中的每个类别赋予相同的比例宽度(大约400/4,在条之间和两端减去5%的填充)。 {"scale":"xscale","band":1} 获取标记的 width 参数的乐队宽度的100%。

{
  "$schema":"https://vega.github.io/schema/vega/v3.json",
  "width": 400, "height": 100,
  "data": [ {
    "name": "vals",
    "values": [
      {"category": "Oranges", "count": 3000},
      {"category": "Pears",   "count": 8000},
      {"category": "Apples",  "count": 1000},
      {"category": "Peaches", "count": 5000}
    ]
  } ],
 "scales": [
    {
      "name": "yscale",
      "type": "linear",
      "zero": true,
      "domain": {"data": "vals", "field": "count"},
      "range": "height"
    },
    {
      "name": "xscale",
      "type": "band",
      "domain": {"data": "vals", "field": "category"},
      "range": "width",
      "padding": 0.05
    }
  ],
  "marks": [ {
    "type": "rect",
    "from": { "data": "vals" },
    "encode": {
      "update": {
        "x":     {"scale": "xscale", "field": "category"},
        "width": {"scale": "xscale", "band": 1},
        "y":     {"scale": "yscale", "field": "count"},
        "y2":    {"scale": "yscale", "value": 0}
      }
    }
  } 
 ]
}

深圳

没有轴标签,典型的图形就不会完整。 轴定义使用我们之前定义的比例尺,因此添加它们就像通过其名称引用比例尺并指定放置侧一样简单。 将此代码作为顶级元素添加到最后一个代码示例中。

"axes": [
    {"scale": "yscale", "orient": "left"},
    {"scale": "xscale", "orient": "bottom"}
 ],
{
  "$schema":"https://vega.github.io/schema/vega/v3.json",
  "width": 400, "height": 100,
  "data": [ {
    "name": "vals",
    "values": [
      {"category": "Oranges", "count": 3000},
      {"category": "Pears",   "count": 8000},
      {"category": "Apples",  "count": 1000},
      {"category": "Peaches", "count": 5000}
    ]
  } ],
 "scales": [
    {
      "name": "yscale",
      "type": "linear",
      "zero": true,
      "domain": {"data": "vals", "field": "count"},
      "range": "height"
    },
    {
      "name": "xscale",
      "type": "band",
      "domain": {"data": "vals", "field": "category"},
      "range": "width",
      "padding": 0.05
    }
  ],
  "marks": [ {
    "type": "rect",
    "from": { "data": "vals" },
    "encode": {
      "update": {
        "x":     {"scale": "xscale", "field": "category"},
        "width": {"scale": "xscale", "band": 1},
        "y":     {"scale": "yscale", "field": "count"},
        "y2":    {"scale": "yscale", "value": 0}
      }
    }
  } 
 ],
 "axes": [
    {"scale": "yscale", "orient": "left"},
    {"scale": "xscale", "orient": "bottom"}
  ]
}

深圳

数据转换和条件

数据通常需要进行其他操作才能用于绘图。 Vega 提供了许多转换来帮助你。 让我们使用最常见的公式转换为每个源数据动态添加一个随机 count 字段。 另外,在此图中,我们将操纵条的填充颜色,如果该值小于333,则将其变为红色;如果该值小于666,则将其变为黄色;如果该值大于666,则将其变为绿色。请注意,可能是 而是使用比例尺将源数据的域映射到颜色集或配色方案。

{
  "$schema":"https://vega.github.io/schema/vega/v3.json",
  "width": 400, "height": 200,
  "data": [ {
    "name": "vals",
    "values": [
      {"category": "Oranges"},
      {"category": "Pears"},
      {"category": "Apples"},
      {"category": "Peaches"},
      {"category": "Bananas"},
      {"category": "Grapes"}
    ],
    "transform": [
      {"type": "formula", "as": "count", "expr": "random()*1000"}
    ]
  } ],
 "scales": [
    {
      "name": "yscale",
      "type": "linear",
      "zero": true,
      "domain": {"data": "vals", "field": "count"},
      "range": "height"
    },
    {
      "name": "xscale",
      "type": "band",
      "domain": {"data": "vals", "field": "category"},
      "range": "width",
      "padding": 0.05
    }
  ],
  "axes": [
    {"scale": "yscale", "orient": "left"},
    {"scale": "xscale", "orient": "bottom"}
  ],
  "marks": [ {
    "type": "rect",
    "from": { "data": "vals" },
    "encode": {
      "update": {
        "x":     {"scale": "xscale", "field": "category"},
        "width": {"scale": "xscale", "band": 1},
        "y":     {"scale": "yscale", "field": "count"},
        "y2":    {"scale": "yscale", "value": 0},
        "fill":  [
          {"test": "datum.count < 333", "value": "red"},
          {"test": "datum.count < 666", "value": "yellow"},
          {"value": "green"}
        ]
      }
    }
  } ]
}

深圳

在 Kibana 中使用 Vega

在上面,我们在 Vega 编辑器中,实践了一把。我们现在在 Kibana 中来看看是啥样的。

深圳

点击上面的 Create new visualization 按钮:

深圳

我们使用如下的例子:

{
 "$schema": "https://vega/github.io/schema/vega-lite/v2.json",
  "data": {
    "values": [
      {"a": "A", "b": 28}, 
      {"a": "B", "b": 55}, 
      {"a": "C", "b": 43},
      {"a": "D", "b": 91}, 
      {"a": "E", "b": 81}, 
      {"a": "F", "b": 53},
      {"a": "G", "b": 19}, 
      {"a": "H", "b": 87}, 
      {"a": "I", "b": 52}
    ]
  },
  "mark": "bar",
  "encoding": {
    "x": {"field": "a", "type": "ordinal"},
    "y": {"field": "b", "type": "quantitative"}
  }
}

深圳

我们可以把上面的 mark 改为 line:

深圳

我们可以把上面的 mark 改为 area:

深圳

我们可以把上面的 mark 改为 tick:

深圳

我们可以把上面的 mark 改为 point

深圳

我们再接着使用如下的数据:

{
 "$schema": "https://vega/github.io/schema/vega-lite/v2.json",
  "data": {
    "values": [
      {"a": "2001-01-01", "b": 28, “c": "P"}, 
      {"a": "2001-01-02", "b": 95, "c": "Q"}, 
      {"a": "2001-01-03", "b": 43, "c": "R"},
      {"a": "2001-01-04", "b": 91, "c": "Q"}, 
      {"a": "2001-01-05", "b": 81, "c": "P"}, 
      {"a": "2001-01-06", "b": 53, "c": "P"},
      {"a": "2001-01-07", "b": 19, "c": "R"}, 
      {"a": "2001-01-08", "b": 87, "c": "Q"}, 
      {"a": "2001-01-09", "b": 52, "c": "P"},
      {"a": "2001-01-10", "b": 81, "c": "Q"},
      {"a": "2001-01-11", "b": 53, "c": "R"},
      {"a": "2001-01-12", "b": 19, "c": "P"},
      {"a": "2001-01-13", "b": 87, "c": "Q"},
      {"a": "2001-01-14", "b": 52, "c": "R"}
    ]
  },
  "mark": "bar",
  "encoding": {
    "x": {"field": "a", "type": "ordinal"},
    "y": {"field": "b", "type": "quantitative"}
  }
}

深圳

我们再接着修改:

{
 "$schema": "https://vega/github.io/schema/vega-lite/v2.json",
  "data": {
    "values": [
      {"a": "2001-01-01", "b": 28, “c": "P"}, 
      {"a": "2001-01-02", "b": 95, "c": "Q"}, 
      {"a": "2001-01-03", "b": 43, "c": "R"},
      {"a": "2001-01-04", "b": 91, "c": "Q"}, 
      {"a": "2001-01-05", "b": 81, "c": "P"}, 
      {"a": "2001-01-06", "b": 53, "c": "P"},
      {"a": "2001-01-07", "b": 19, "c": "R"}, 
      {"a": "2001-01-08", "b": 87, "c": "Q"}, 
      {"a": "2001-01-09", "b": 52, "c": "P"},
      {"a": "2001-01-10", "b": 81, "c": "Q"},
      {"a": "2001-01-11", "b": 53, "c": "R"},
      {"a": "2001-01-12", "b": 19, "c": "P"},
      {"a": "2001-01-13", "b": 87, "c": "Q"},
      {"a": "2001-01-14", "b": 52, "c": "R"}
    ]
  },
  "mark": "line",
  "encoding": {
    "x": {"field": "a", "type": "temporal", axis: {title: null, labelAngle:30} },
    "y": {"field": "b", "type": "quantitative"}
  }
}

在这里,我们去到上面 x 轴上显示的 "a",因为我们已经有时间的标识了。同时,我们把时间标签倾斜30度。

深圳

我们再接着修改数据:

{
 "$schema": "https://vega/github.io/schema/vega-lite/v2.json",
  "data": {
    "values": [
      {"a": "2001-01-01", "b": 28, “c": "P"}, 
      {"a": "2001-01-02", "b": 95, "c": "Q"}, 
      {"a": "2001-01-03", "b": 43, "c": "R"},
      {"a": "2001-01-04", "b": 91, "c": "Q"}, 
      {"a": "2001-01-05", "b": 81, "c": "P"}, 
      {"a": "2001-01-06", "b": 53, "c": "P"},
      {"a": "2001-01-07", "b": 19, "c": "R"}, 
      {"a": "2001-01-08", "b": 87, "c": "Q"}, 
      {"a": "2001-01-09", "b": 52, "c": "P"},
      {"a": "2001-01-10", "b": 81, "c": "Q"},
      {"a": "2001-01-11", "b": 53, "c": "R"},
      {"a": "2001-01-12", "b": 19, "c": "P"},
      {"a": "2001-01-13", "b": 87, "c": "Q"},
      {"a": "2001-01-14", "b": 52, "c": "R"}
    ]
  },
  "mark": "line",
  "encoding": {
    "x": {"field": "a", "type": "temporal", axis: {title: null, labelAngle:30} },
    "y": {"field": "b", "type": "quantitative"},
    "color": {"field": "c", "type": "nominal"}
  }
}

在这里,我们在 encoding 里添加一个叫做 color 的项:

深圳

上面的线感觉特别粗糙,我们可以进行插值。我们把 mark 这行修改为:

"mark": { "type": "line", "interpolate": "natural"},

深圳

我们也可以通过线的粗细来表示不同的类:

深圳

我们也可以用不同 graph 来分别表达:

深圳

针对颜色,我们可以可以设置不同的 color scheme:

深圳

使用 Elasticsearch 和 Kibana 进行动态数据

现在您已经了解了基础知识,让我们尝试使用一些随机生成的 Elasticsearch 数据创建基于时间的折线图。 这与你在 Kibana 中创建新的 Vega 图时最初看到的内容相似,不同之处在于,我们将使用 Vega 语言而不是 Vega-Lite 的 Kibana 默认值(Vega的简化高级版本)。

创建随机的 Logstash 日志数据

如果你还不知道如何生成这些随机的数据,请参阅我之前的文章 “Logstash:运用 makelogs 创建测试日志”。我们使用如下的命令来生成20000个数据。我们首先为我们刚才生成的一个叫做 logstash-0 的索引创建一个 index pattern:

深圳

深圳

深圳

这样我们就生产了我们想要的 index pattern。
我们可以做一些简单的查询,比如:

<p style="text-align:center"><img src="https://ucc.alicdn.com/pic/developer-ecology/998ee5af1c634cae84df66686c318e20.png" width="500" height="300" alt="深圳"/></p>

我们可以看到有一个timestamp 及文件的扩展名类型 extension。请注意上面的 hits.hits。这个也是我们在下面想要用到的。

运用 Vega 来展示数据

在上面的 Vega 实验中,我们对 values 数据进行硬编码,而不是使用 url 进行实际查询。 这样,我们可以继续在不支持 Kibana Elasticsearch 查询的 Vega 编辑器中进行测试。 如果你将值替换为url部分,则该图将在 Kibana 内部变得完全动态,如下所示。

{
 "$schema": "https://vega/github.io/schema/vega-lite/v2.json",
  data:  {
   "url": {
      "index": "logstash-*",
      "body": {
        "size": 100,
        "_source": ["@timestamp", "extension"]
      }
    }
    "format":{"property":"hits.hits"}
  },
  "transform": [
    {
      "calculate": "toDate(datum._source['@timestamp'])", "as": "time"
    },
    {
      "calculate": "datum._source.extension", "as": "ext"
    }
  ],
  "mark": "circle",
  "encoding": {
  }
}

在上面,我们替换之前 values 的硬编码,取而代之的是查询 logstash-* 索引。我们先查询 100 个数据,同时,我们只对 hits.hits 的内容感兴趣。另外我们通过 transform 把@timestamp 转换为 time,extension 转换为 ext。运行 Vega:

深圳


image.png

上面显示的是一个点,这是因为我们还没对 x 及 y 轴做任何的设置。
我们可以在浏览器中的 Developer Tools 里进行查看:

深圳

接下来我们配置 x 及 y 轴:

{
 "$schema": "https://vega/github.io/schema/vega-lite/v2.json",
  data:  {
   "url": {
      "index": "logstash-*",
      "body": {
        "size": 100,
        "_source": ["@timestamp", "extension"]
      }
    }
    "format":{"property":"hits.hits"}
  },
  "transform": [
    {
      "calculate": "toDate(datum._source['@timestamp'])", "as": "time"
    },
    {
      "calculate": "datum._source.extension", "as": "ext"
    }
  ],
  "mark": "circle",
  "encoding": {
     x: { field: "time", type: "temporal" }
     y: { field: "ext", type: "nominal" }
  }
}

深圳

就像我们上面的那样,我们可以添加颜色及形状:

{
 "$schema": "https://vega/github.io/schema/vega-lite/v2.json",
  data:  {
   "url": {
      "index": "logstash-*",
      "body": {
        "size": 100,
        "_source": ["@timestamp", "extension"]
      }
    }
    "format":{"property":"hits.hits"}
  },
  "transform": [
    {
      "calculate": "toDate(datum._source['@timestamp'])", "as": "time"
    },
    {
      "calculate": "datum._source.extension", "as": "ext"
    }
  ],
  "mark": "point",
  "encoding": {
     x: { field: "time", type: "temporal" }
     y: { field: "ext", type: "nominal" }
     color: {field: "ext", type: "nominal"}
     shape: {field: "ext", type: "nominal" }
  }
}

深圳

目前我们的数据还不能和 search field 相关联,比如我们搜索 extension:css,但是我们的显示的图还是不会变好。另外,当我们选择右上角的时间选择时,我们的也不会变化。为了能关联起来,我们添加如下的两个字段到 url 中:

      "%context%": true,
      "%timefield%": "@timestamp",
{
 "$schema": "https://vega/github.io/schema/vega-lite/v2.json",
  data:  {
   "url": {
      "%context%": true,
      "%timefield%": "@timestamp",
      "index": "logstash-*",
      "body": {
        "size": 100,
        "_source": ["@timestamp", "extension"]
      }
    }
    "format":{"property":"hits.hits"}
  },
  "transform": [
    {
      "calculate": "toDate(datum._source['@timestamp'])", "as": "time"
    },
    {
      "calculate": "datum._source.extension", "as": "ext"
    }
  ],
  "mark": "point",
  "encoding": {
     x: { field: "time", type: "temporal" }
     y: { field: "ext", type: "nominal" }
     color: {field: "ext", type: "nominal"}
     shape: {field: "ext", type: "nominal" }
  }
}

深圳

通过上面的关联,我们可以看出来,我们少了很多的数据,通过搜索 extension:css。
我们发现 x 轴的 time 是没有啥用处。我们可以去掉它。我们同时旋转时间的标签30度:

{
 "$schema": "https://vega/github.io/schema/vega-lite/v2.json",
  data:  {
   "url": {
      "%context%": true,
      "%timefield%": "@timestamp",
      "index": "logstash-*",
      "body": {
        "size": 100,
        "_source": ["@timestamp", "extension"]
      }
    }
    "format":{"property":"hits.hits"}
  },
  "transform": [
    {
      "calculate": "toDate(datum._source['@timestamp'])", "as": "time"
    },
    {
      "calculate": "datum._source.extension", "as": "ext"
    }
  ],
  "mark": "point",
  "encoding": {
     x: { field: "time", type: "temporal", axis: {title: null, labelAngle:30 }}
     y: { field: "ext", type: "nominal" }
     color: {field: "ext", type: "nominal"}
     shape: {field: "ext", type: "nominal" }
  }
}

深圳

接下来,我们尝试使用更多的数据,并使用 Elasticsearch 所提供的强大的 aggregation 功能。首先我们在 Kibana 中做如下的搜索:

GET logstash-0/_search
{
  "size": 0,
  "aggs": {
    "table": {
      "composite": {
        "size": 10000, 
        "sources": [
          {
            "time": {
              "date_histogram": {
                "field": "@timestamp",
                "calendar_interval": "1d"
              }
            }
          },
          {
            "ext": {
              "terms": {
                "field": "extension.keyword"
              }
            }
          }
        ]
      }
    }
  }
}

它显示的结果为:

{
  "took" : 6,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 10000,
      "relation" : "gte"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "table" : {
      "after_key" : {
        "time" : 1591920000000,
        "ext" : "jpg"
      },
      "buckets" : [
        {
          "key" : {
            "time" : 1591574400000,
            "ext" : "css"
          },
          "doc_count" : 159
        },
        {
          "key" : {
            "time" : 1591574400000,
            "ext" : "gif"
          },
          "doc_count" : 71
        },
        {
          "key" : {
            "time" : 1591574400000,
            "ext" : "jpg"
          },
          "doc_count" : 592
        },
        {
          "key" : {
            "time" : 1591574400000,
            "ext" : "php"
          },
          "doc_count" : 25
        },
        {
          "key" : {
            "time" : 1591574400000,
            "ext" : "png"
          },
          "doc_count" : 80
        },
        {
          "key" : {
            "time" : 1591660800000,
            "ext" : "css"
          },
          "doc_count" : 1043
        },
        {
          "key" : {
            "time" : 1591660800000,
            "ext" : "gif"
          },
          "doc_count" : 458
        },
        {
          "key" : {
            "time" : 1591660800000,
            "ext" : "jpg"
          },
          "doc_count" : 4365
        },
        {
          "key" : {
            "time" : 1591660800000,
            "ext" : "php"
          },
          "doc_count" : 234
        },
        {
          "key" : {
            "time" : 1591660800000,
            "ext" : "png"
          },
          "doc_count" : 598
        },
        {
          "key" : {
            "time" : 1591747200000,
            "ext" : "css"
          },
          "doc_count" : 1048
        },
        {
          "key" : {
            "time" : 1591747200000,
            "ext" : "gif"
          },
          "doc_count" : 427
        },
        {
          "key" : {
            "time" : 1591747200000,
            "ext" : "jpg"
          },
          "doc_count" : 4301
        },
        {
          "key" : {
            "time" : 1591747200000,
            "ext" : "php"
          },
          "doc_count" : 199
        },
        {
          "key" : {
            "time" : 1591747200000,
            "ext" : "png"
          },
          "doc_count" : 639
        },
        {
          "key" : {
            "time" : 1591833600000,
            "ext" : "css"
          },
          "doc_count" : 936
        },
        {
          "key" : {
            "time" : 1591833600000,
            "ext" : "gif"
          },
          "doc_count" : 340
        },
        {
          "key" : {
            "time" : 1591833600000,
            "ext" : "jpg"
          },
          "doc_count" : 3715
        },
        {
          "key" : {
            "time" : 1591833600000,
            "ext" : "php"
          },
          "doc_count" : 192
        },
        {
          "key" : {
            "time" : 1591833600000,
            "ext" : "png"
          },
          "doc_count" : 579
        },
        {
          "key" : {
            "time" : 1591920000000,
            "ext" : "jpg"
          },
          "doc_count" : 6
        }
      ]
    }
  }
}

请注意上面的数据结构,在接下来的 Vega 中将被采用。
重新书写我们的 Vega:

{
 "$schema": "https://vega/github.io/schema/vega-lite/v2.json",
  data:  {
   "url": {
      "%context%": true,
      "%timefield%": "@timestamp",
      "index": "logstash-*",
      "body": {
        "size": 0,
        "aggs": {
          "table": {
            "composite": {
              "size": 10000, 
              "sources": [
                {
                  "time": {
                    "date_histogram": {
                      "field": "@timestamp",
                      "interval": {%autointerval%:400}
                    }
                  }
                },
                {
                  "ext": {
                    "terms": {
                      "field": "extension.keyword"
                    }
                  }
                }
              ]
            }
          }
        }
      }
    }
    "format":{"property":"aggregations.table.buckets"}
  },
  "transform": [
    {
      "calculate": "toDate(datum.key.time)", "as": "time"
    },
    {
      "calculate": "datum.key.ext", "as": "ext"
    }
  ],
  "mark": "area",
  "encoding": {
     x: { 
       field: "time", 
       type: "temporal"
     },
     y: {
       axis: {title: "Document count"}
       field: "doc_count", 
       type: "quantitative" 
    }
    color: {field: "ext", type: "nominal"}
  }
}

请注意上面的有些地方已经根据 aggregation 的结果做了相应的调整。展示的结果是:

深圳

最后,我们取消 x 轴上的 time,并且,我们把所有的数据都 stack 起来:

{
 "$schema": "https://vega/github.io/schema/vega-lite/v2.json",
  data:  {
   "url": {
      "%context%": true,
      "%timefield%": "@timestamp",
      "index": "logstash-*",
      "body": {
        "size": 0,
        "aggs": {
          "table": {
            "composite": {
              "size": 10000, 
              "sources": [
                {
                  "time": {
                    "date_histogram": {
                      "field": "@timestamp",
                      "interval": {%autointerval%:400}
                    }
                  }
                },
                {
                  "ext": {
                    "terms": {
                      "field": "extension.keyword"
                    }
                  }
                }
              ]
            }
          }
        }
      }
    }
    "format":{"property":"aggregations.table.buckets"}
  },
  "transform": [
    {
      "calculate": "toDate(datum.key.time)", "as": "time"
    },
    {
      "calculate": "datum.key.ext", "as": "ext"
    }
  ],
  "mark": "area",
  "encoding": {
     x: { 
       field: "time", 
       type: "temporal",
       axis: {title: null}
     },
     y: {
       axis: {title: "Document count"},
       field: "doc_count", 
       type: "quantitative" ,
       stack: normalize
    }
    color: {field: "ext", type: "nominal"}
  }
}

深圳

我们是使用 makelogs 拉丝生成的数据。它生成的数据是在一天内的,并且是平均的。从上面,我们可以看出来各个文件的比例。
好了。今天的文章就写到这里。希望大家也学到了一些东西。

更多资料:
【1】https://vega.github.io/vega-lite/tutorials/getting_started.html
【2】https://www.elastic.co/blog/getting-started-with-vega-visualizations-in-kibana
【3】 https://www.elastic.co/guide/en/kibana/master/vega-graph.html
【4】https://vega.github.io/vega/examples/
【5】https://vega.github.io/vega-lite/examples/

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
7月前
|
数据可视化 Dubbo Java
微服务框架(二十五)Kibana 可视化图表及 Timelion 插件
此系列文章将会描述Java框架Spring Boot、服务治理框架Dubbo、应用容器引擎Docker,及使用Spring Boot集成Dubbo、Mybatis等开源框架,其中穿插着Spring Boot中日志切面等技术的实现,然后通过gitlab-CI以持续集成为Docker镜像。 本文为Kibana 可视化图表及 Timelion 插件使用 本系列文章中所使用的框架版本为Spring Bo...
|
7月前
|
设计模式 敏捷开发 JavaScript
开箱即用的中后台管理模版,建议收藏!
开箱即用的中后台管理模版,建议收藏!
204 0
|
存储 SQL 数据可视化
7-TDengine集成Grafana实现日志数据可视化
7-TDengine集成Grafana实现日志数据可视化
1014 0
7-TDengine集成Grafana实现日志数据可视化
|
7月前
|
JSON 数据可视化 前端开发
构建一个动态数据可视化仪表板
构建一个动态数据可视化仪表板
|
JSON 移动开发 缓存
20+个可视化搭建工具,一次玩个够
无论大公司还是小公司,我们开发前端工程时候,项目工程又很多类似的功能或者页面,开发经常是加班加点搬砖去做一些无成长反复操作的工作,看键盘上 ctrle 键已经被磨掉了漆,C 和V 也马上磨白了,那对于开发如何把这些重复的工作用机器去解决?在前端资源紧缺的情况下,是否可直接有工具直接就可以搭建出我想要的前端页面?于是业界的页面可视化搭建工具就出现了,本文会介绍目前最流行的页面可视化搭建工具,也会提供一些开源的可视化搭建项目供大家参考。
2035 0
20+个可视化搭建工具,一次玩个够
|
7月前
|
存储 监控 数据可视化
无需重新学习,使用 Kibana 查询/可视化 SLS 数据
本文演示了使用 Kibana 连接 SLS ES 兼容接口进行查询和分析的方法。
66944 22
|
4月前
|
Prometheus 数据可视化 Cloud Native
构建交互式的 Grafana 仪表盘
【8月更文第29天】Grafana 是一个功能强大的数据可视化工具,它支持多种数据源并能够创建高度定制化的仪表盘。通过使用交互式面板,用户可以更直观地探索数据并进行数据分析。本文将介绍如何设计和实现用户友好的交互式面板,以提高数据分析效率,并提供具体的代码示例。
188 2
|
4月前
|
Prometheus 监控 Cloud Native
Grafana 入门指南:快速上手监控仪表盘
【8月更文第29天】Grafana 是一款开源的数据可视化和监控工具,它允许用户轻松地创建美观的仪表盘和图表,以便更好地理解和监控数据。无论您是需要监控系统性能指标、应用程序日志还是业务关键指标,Grafana 都能提供灵活而强大的解决方案。本指南将带领您快速上手 Grafana,包括安装、配置以及创建第一个监控面板。
707 1
|
6月前
|
弹性计算 运维 监控
阿里云运维第一步(监控):开箱即用的监控
监控运维是一个体系化的工作,完善这个体系非一日之功。但是我们的业务不可一日无监控“裸奔”,在阿里云怎么样快速低成本的建立第一道资源监控的护城河?开箱即用的云监控,将会是你进入阿里云的第一个可靠的小伙伴。
14167 19
|
6月前
|
存储 Prometheus 监控
【监控】grafana图表使用快速上手
【监控】grafana图表使用快速上手
193 0