Kibana JSON inputを使って秒単位で格納されたデータを分単位に変換してグラフ表示する


この記事はElastic Stack (Elasticsearch)その2 Advent Calendar 2019、2日目の記事です。

KibanaのVisualizeでMetricを編集していると、Advancedの中にJSON inputという欄があって、(何これ?)と思っている方が多いと思います。少なくとも僕はそう思ってました。

「さて、どう使うんだろう?」と思ってGoogleで検索してみます。Elastic Stackは人気のあるOSSで、使い方を検索すればだいたい日本語記事が見つかるんです。プロダクトとして魅力あるだけではなくて、そこも素敵なところなんで…

うわっ...日本語の検索結果、少なすぎ...?

というわけで、この記事ではKibana JSON inputの簡単な使い方とその使いどころを紹介していきます。

前提条件

以下で起動したdocker-elkの環境を前提とします。
なお、docker-elkについては、kaibaさんが書かれた昨日のAdvent Calendarの記事『(5分でできるElastic stack(Elasticsearch, Logstash, Kibana)環境構築 - Qiita』が詳しいので、そちらを参照ください。

  • Elasticsearch
    • バージョン 7.4.1
  • Kibana
    • バージョン 7.4.1
git clone https://github.com/deviantony/docker-elk.git
cd docker-elk
git checkout d7f5deb6ff308436715aa0c79f81938659e2a07e
docker-compose up

JSON inputの使い方

実はJSON inputの簡単な使い方はKibanaの各Visualizeのドキュメントに記載してあります。例えば、Line/Area/Barチャートなら…

こんな感じで、動的にドキュメントの値を書き換えられることが例示されています。この例ではドキュメント内のgradeフィールドの値を1.2倍にしています。他にもAggregationの種類によってscript以外のオプションを指定することもできるようです。1

秒単位で格納されたデータを分単位に変換して表示してみる

一番わかりやすいMetric Visualizationで試してみます。

ドキュメントの登録

まずは秒単位の数値フィールドを持つドキュメントを幾つか登録してみます。
KibanaのDev Tools->Consoleから以下を実行します。

POST _bulk
{ "index" : { "_index" : "documents-in-seconds", "_id" : "1" } }
{ "number_field_in_seconds" : 34 }
{ "index" : { "_index" : "documents-in-seconds", "_id" : "2" } }
{ "number_field_in_seconds" : 56 }
{ "index" : { "_index" : "documents-in-seconds", "_id" : "3" } }
{ "number_field_in_seconds" : 13 }
{ "index" : { "_index" : "documents-in-seconds", "_id" : "4" } }
{ "number_field_in_seconds" : 67 }
{ "index" : { "_index" : "documents-in-seconds", "_id" : "5" } }
{ "number_field_in_seconds" : 150 }

Index Patternの作成

メニューから、Management -> Kibana -> Index Patterns -> Create Index Patternと選択し、新しいIndex Pattern、documents-in-secondsを作成します。

秒単位のままで表示するVisualizeの作成

メニューからVisualize -> Create new Visualization -> Metric -> Index Patternとしてdocuments-in-secondsを選択して、Visualize作成画面に移動します。

Metricに以下の設定を入力し、反映します。

  • Aggregation
    • Sum
  • Field
    • number_field_in_seconds
  • Custom label
    • 合計(秒)

number_field_in_secondsを足し合わせた結果が320であることが分かりました。

分単位に変換して表示するVisualizeの作成

先ほどのVisualizeを編集していきます。

MetricのAdvancedをクリックし、JSON inputの欄に以下を入力し、反映します。

{ "script" : "doc['number_field_in_seconds'].value / 60.0" }

分単位に変換した結果が表示されました!

おまけ: 計算の際には数値の型に気をつけること

最後に、例の中でなぜ60ではなく60.0で割っているのかを補足しておきます。
JSON inputでscriptを指定すると、ドキュメント1件1件に対してそれを計算した後にAggregationする順序になります。
そのため、整数 / 整数の場合、各ドキュメントの計算結果が整数の切り捨てになり、想定した計算結果ではなくなることがあります。

60で割った結果は以下の通りです。

それぞれのドキュメントの計算結果は
34 / 60 = 0
56 / 60 = 0
13 / 60 = 0
67 / 60 = 1
150 / 60 = 2

以上より、合計値は3

60.0で割った結果は以下の通りです。

それぞれのドキュメントの計算結果は
34 / 60 = 0.5666...
56 / 60 = 0.9333...
13 / 60 = 0.2166...
67 / 60 = 1.1166...
150 / 60 = 2.5

以上より、合計値は5.333...

計算結果が想定しない整数値だった場合は、思い出してみてください。

おわりに

どうしても、Elasticsearchに格納ずみのドキュメントを更新できない場合に使えるかもしれない、JSON inputでした。(そして、Scripted Fieldsのことも忘れないであげて...)

明日のAdvent Calendarその2は空いてるようなので、小ネタ持ってる方、気楽に参加、いかがでしょうか?
ではでは〜


  1. まだ他のオプションを使ったことがないので、使ったことがある人は共有して欲しいなぁ…