1. 程式人生 > 其它 >Kibana:Vega 視覺化入門 - 定製自己的視覺化圖

Kibana:Vega 視覺化入門 - 定製自己的視覺化圖

Kibana 提供了很多開箱即用的視覺化工具。它們可以讓我們很方便地建立我們想要的分析圖表。如果我們想定製一個我們自己的視覺化圖,那該怎麼辦呢?傳統的方法是建立自己的外掛來擴充我們自己的需求,但是這種開發的成本及週期都比較長。很幸運的是,Kibana 提供了一種很方便的視覺化工具 : Vega。在今天的文章中,我們將來介紹如何建立一個屬於我們自己的 Vega 視覺化圖。

 
什麼是 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}
      }
    }
  } ]
}

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。

我們可以做一些簡單的查詢,比如:

GET logstash-0/_search
{
  "size": 5,
  "_source": ["@timestamp", "extension"]
}

我們可以看到有一個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:

上面顯示的是一個點,這是因為我們還沒對 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/