kibana官方沒有外掛的開發教程,Tim Rose的教程寫的十分詳盡,也是官方推薦的。由於這個系列的教程是英文版的,且基於kibana4,近日需要做kibana的開發,硬啃下這些教程之後,且根據kibana6.3.2版本做了些改進,記錄下來,留下個爪。由於本人水平有限,錯漏的地方歡迎大家指出。
原文連結:www.timroes.de/writing-kib…
原文標題:Writing Kibana 4 Plugins – Visualizations using Data
簡單視覺化外掛
你需要先閱讀簡單視覺化外掛,才能閱讀本文。
在前面的章節(在閱讀本文前,一定要先閱讀),你已經學會了如何建立一個簡單的視覺化外掛,但並不從elasticsearch獲取 任何資料。在這一章,我們將寫另外一個外掛,像其他外掛一樣,需要消費elasticsearch的資料。
我們將寫一個很簡單的標籤雲外掛,我們會把桶的名稱作為標籤展示出來,度量聚合資料的大小將決定這個標籤字型的大小。如果你對桶和度量還不是很熟悉,可以參考一下我這篇k4v教程。
這篇教程的原始碼可以在GitHub找到
在整個教程當中,我會用tr-k4p-tagcloud
這個名字。你需要用一個全域性唯一的名字來替代他。
標籤雲視覺化外掛
首先我們要想想,我們需要以何種方式來視覺化何種資料,這意味著,我們需要考慮,我們的視化外掛,會呈現什麼桶和什麼度量的資料。
我們會盡量保持外掛的簡單性,所以只採用了一個桶和一個度量。桶聚合決定了什麼標籤會被展示出來(一個桶就是一個標籤),維度聚合決定了標籤的大小,即聚合的度量結果越高,所顯示的標籤就會越大。
決定用多少維度和桶的聚合資料是很重要的,如果你能內嵌聚合,你一會還要再外掛中定義。
定義和註冊外掛
跟前面章節的一樣,第一步是建立index.js
,package.json
,和註冊一個簡單的視覺化provider。下面我們只展示主要的provider程式碼片段(你可以在public/tagclouc.js
中找到):
function TagcloudProvider(Private) {
var TemplateVisType = Private(require('ui/template_vis_type/TemplateVisType'));
return new TemplateVisType({
name: 'trTagcloud', // The internal id of the visualization (must be unique)
title: 'Tagcloud', // The title of the visualization, shown to the user
description: 'Tagcloud visualization', // The description of this vis
icon: 'fa-cloud', // The font awesome icon of this visualization
template: require('plugins/tr-k4p-tagcloud/tagcloud.html')
});
}
require('ui/registry/vis_types').register(TagcloudProvider);
複製程式碼
跟前面的教程相比較,這裡又兩個不一樣的地方:
- 我們在定義模組的時候,丟棄了
define()
函式(AMD 模組定義)。就像前面說的,這個是非必要的,由於我們使用了webpack作為打包工具,這也意味著你不再需要在模組中返回provider函式。 - 我們去除了
requiresSearch: false
選項,我們的tagcloud外掛需要從elasticsearch中獲取資料,所以我們的外掛就可以像其他使用資料的外掛一樣來進行查詢。由於requiresSearch: true
是預設選項,所以我們去掉這個選項就行了。
現在我們需要來建立public/tagcloud.html
,現在可以讓他置空。第一部分的程式碼可以在在github的tag0.1.0找到。
定義資料結構
一個需要使用聚合資料的外掛,你需要明確的指出,你的外掛需要什麼樣的聚合資料,或者說,什麼樣的資料是被我的外掛接受的。這所謂的資料結構需要在外掛定義的時候給出,我們來修改一下外掛定義:
function TagcloudProvider(Private) {
var TemplateVisType = /* ... */;
// Include the Schemas class, which will be used to define schemas
var Schemas = Private(require('ui/Vis/Schemas'));
return new TemplateVisType({
/* every attribute shown above */,
schemas: new Schemas([
{
group: 'metrics',
name: 'tagsize',
title: 'Tagsize',
min: 1,
max: 1,
aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality', 'std_dev']
},
{
group: 'buckets',
name: 'tags',
title: 'Tags',
min: 1,
max: 1,
aggFilter: '!geohash_grid'
}
])
});
}
複製程式碼
為了定義資料結構,我們需要例項化一個Schemas
物件,我們需要傳一個陣列作為建構函式的引數,陣列的每個物件定義了一個你所需要的聚合資料,每個聚合物件有如下屬性:
- group
metrics
或者buckets
二選一,定義了這個物件所屬的聚合資料型別 - name 這個聚合資料的名字(id)。以後你可以用這個屬性來引用不同的聚合資料
- title 這個是展示給使用者看的,當他新增一個單項聚合的時候,這個會告訴他,這個資料將會被怎麼使用,再本例中,桶資料會被用作標籤,維度資料則影響的是標籤的字型大小
- min/max 使用者能夠新增的此聚合的範圍,例如,使用者新增一個直方圖,一個桶聚合的名稱叫“圖列”。這個是沒有限制的,即沒有最大值限制,就像使用者想要有多少個直方圖的條數,就能有多少個。在本例中,我們各種資料只允許一個聚合資料,由於我們的外掛的工作方式。
- 過濾器 決定了哪種聚合資料是合法的。他的值是一個這裡所允許的聚合型別的陣列(下面可以看見),或者是一個所不允許的聚合型別的陣列(每一個一定要以一個下劃線為字首),在接下來的場景中,其他的聚合型別是允許的。如果這個陣列只有一個值,那你也可以把他宣告稱一個字串(正如桶聚合所示)。
這裡也還有其他的一些欄位你可以使用的,但是在本例中不會被用到。
你可以宣告的維度聚合的aggFilter
型別有:svg, cardinality, count, max, median, min, percentileranks, percentiles, stddev, sum
桶聚合的aggFilter
的型別有:** datehistogram, daterange, filters, geohashgrid, histogram, iprange, range, significant_terms, terms**
在github的tag0.2.0上可以找到這一步的程式碼。
編輯控制器controller
為了給我們的視覺化外掛天價一些邏輯,我們會再次需要一個angular的controller。與之前不同的是,我們會把這個controller放在一個單獨的檔案下(因為他會變得大一點),因此,我們需要在tancloud.js
中新增如下程式碼:
require('plugins/tr-k4p-tagcloud/tagcloudController')
複製程式碼
現在我們需要建立一個新檔案public/tagcloudController.js
,先寫上一個空白的controller:
var module = require('ui/modules').get('tr-k4p-tagcloud');
module.controller('TagcloudController', function($scope) {
// Your logic will go here
});
複製程式碼
在模板中載入控制器(public/tagcloud.html)
:
<div ng-controller="TagcloudController"></div>
複製程式碼
現在外掛的模板就可以載入控制器了。
獲取資料
我們需要從angular的scope中繼承兩個變數,一個是從之前章節就知道的vis
,這個變數包含了外掛的資訊,和使用者的設定資訊。另外一個變數就是esResponse
,這變數儲存了Elasticsearch
的返回資料,kibana'會自動請求elasticsearch,帶上當前的query和filters,以及使用者的聚合資訊。
我們的外掛需要把返回資料和使用者的設定,通過視覺化的方式展示出來,我們可以訪問$scope.esResponse.aggregations
變數來獲取我們的查詢所返回資料。我們需要獲取聚合資料中的id,為了獲取指定聚合資料的id,我們需要$scope.vis.aggs
中的一些方法來找到is。
在我們的場景中,首先我們需要獲取全部的桶資料(就是所有的tag名稱),我們可以通過如下方式,來獲取tags聚合的id
$scope.vis.aggs.bySchemaName['tags'][0].id
複製程式碼
bySchemaName 物件包含一個聚合資料設定的名字(在schema中指定的)的對映,tags屬性是一個使用者輸入的全部聚合設定的陣列,由於我們已經把這個屬性的最大值和最小值都設定成了1,我們現在也只有一個物件可以獲取他的id了。我們用這個id在esResponse
中查詢我們需要的資料。
我們一般是設定一個watch
來監聽esResponse
的變化來更新資料,現在我們來把這個tag當成一個list展示出來:
$scope.$watch('esResponse', function(resp) {
if (!resp) {
$scope.tags = null;
return;
}
// Retrieve the id of the configured tags aggregation
var tagsAggId = $scope.vis.aggs.bySchemaName['tags'][0].id;
// Get the buckets of that aggregation
var buckets = resp.aggregations[tagsAggId].buckets;
// Transform all buckets into tag objects
$scope.tags = buckets.map(function(bucket) {
return {
label: bucket.key
};
});
});
複製程式碼
這樣我們的$scope.tags
就是一個陣列,陣列裡的物件是有一個屬性為label,值是bucket.key。相應的,我們也要修改tagcloud.html
:
<div ng-controller="TagcloudController">
<span ng-repeat="tag in tags">{{tag.label}}</span>
</div>
複製程式碼
完整的程式碼(包括一些css)可以在GitHub倉庫的0.3.0
獲取維度聚合資料相對來說要簡單一點,但也遵循這同樣的步驟。首先,我們需要要拿到的桶數的維度聚合資料的一個引用:
var metricsAgg = $scope.vis.aggs.bySchemaName['tagsize'][0];
複製程式碼
注意:我們並沒有讀取id,反而讀取了整個聚合物件,同樣的我們也只是讀取了陣列中的第一個元素,因為我們只允許配置一個維度聚合。我們可以來完善剛剛的桶資料,給桶資料加上維度資料:
$scope.tags = buckets.map(function(bucket) {
return {
label: bucket.key,
value: metricsAgg.getValue(bucket)
};
});
複製程式碼
我們可以呼叫維度聚合物件上的getValue方法,引數是桶bucket,返回值就是這個桶資料想對應的維度資料了。之後我們就可以拿到一個tags的陣列,裡面的物件都是一個label和一個值。現在剩下的事情就是為我們每個tag計算一個font-size,首選需要統計tag的最大值和最小值,在收集tags陣列的時候,我們會設定一個最大的font-size和最小的font-size,然後計算出每個tag相應的字型大小,由於這個跟kibana沒有直接關聯,只是angular的controller的一些東西,就不在這裡展示了,我們會放在GitHub的0.4.0中的tagcloudController.js
和tagcloud.html
中。
資料累加
tag雲是是一個很簡單的讀取資料的外掛。他只有一個維度資料和一個桶資料,沒有多維度,也沒有內嵌的聚合,等等。在一個更復雜的外掛中你會遇到上述的全部狀況,那我們現在就來試試處理這些複雜的資料:
- 可以通過
$scope.vis.aggs
物件來獲取配置的視覺化物件,下面的bySchemaName
,bySchemaGroup
,byTypeName
(例如,count,terms等等),這些屬性去獲取,scheme裡配置的不同name的聚合資料 - 聚合物件的
getValue
方法可以獲取bucket物件的資料。
一般來說,還有很多其他的方法,來適應更加複雜的視覺化場景,(例如你可以使用聚合物件的getKey
方法來獲取key或者bucket)。這些方法需要等一等,在官方的外掛開發文件中找到。閱讀原始碼,經常是最好的方法,在開發的過程中打個斷點,然後在瀏覽器的dev-tool上面觀察這些物件。
點選過濾
最後一個我們想新增的功能就是tags過濾,當使用者點選tag的時候,儀表盤上應該新增一個該tag的值的過濾器。
第一步,我們要建立一個過濾器來實現過濾服務,我們會使用Private
服務(這個服務是負責為需要的模組例項化angular服務,在前面章節已經說過了),來例項化一個filter服務,controller中需要做如下修改:
module.controller('TagcloudController', function($scope, Private) {
var filterManager = Private(require('ui/filter_manager'));
// ...
});
複製程式碼
filter manger
有一個add
方法,可以呼叫來實現新增過濾器,首先我們修改HTML來當使用者點選一個標籤的時候,呼叫一個方法:
<span ng-click="filter(tag)" ng-repeat="tag in tags" ...>
複製程式碼
完整的filter方法:
$scope.filter = function(tag) {
// Add a new filter via the filter manager
filterManager.add(
// The field to filter for, we can get it from the config
$scope.vis.aggs.bySchemaName['tags'][0].params.field,
// The value to filter for, we will read out the bucket key from the tag
tag.label,
// Whether the filter is negated. If you want to create a negated filter pass '-' here
null,
// The index pattern for the filter
$scope.vis.indexPattern.title
);
};
複製程式碼
這一步的完整程式碼可以在GitHub的0.5.0找到。
接下來
現在你已經可以寫一個展示來自elasticsearch資料的視覺化外掛了。寫外掛的時候,要時刻注意,什麼樣的scheme是你想展示的,要保證只允許配置你程式碼中處理了的scheme。所以,如果你允許多個bucket聚合,那你就要把每一個bucket都要在程式碼中進行處理,這樣的話,你就需要從$scope.vis.aggs.bySchemaName['foobar']
獲取資料,而不是僅僅獲取第一個。