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

この記事は[Elastic Stack (Elasticsearch)その2 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/elasticsearch2)、2日目の記事です。

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

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

<img width="1443" alt="スクリーンショット 2019-12-02 12.23.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264679/0d351737-e867-3692-b1c8-092dbcdde28f.png">

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

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

## 前提条件

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

- 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チャートなら…

- [Line, Area, and Bar charts | Kibana Guide [7.4] | Elastic](https://www.elastic.co/guide/en/kibana/7.4/xy-chart.html)

<img width="748" alt="スクリーンショット 2019-12-02 12.27.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264679/16e0371d-f5bd-26fb-eb6f-96e97d8c64c4.png">

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

<img width="1456" alt="スクリーンショット 2019-12-02 14.21.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264679/4a1ed815-dfc1-8ccc-7801-7107634fe3db.png">

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

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

<img width="1455" alt="スクリーンショット 2019-12-02 14.23.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264679/320f35d4-355c-5731-6e84-6e3a365fdc80.png">

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

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

<img width="1456" alt="スクリーンショット 2019-12-02 14.42.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264679/a347e19e-8b38-b3e5-62f7-910a061ae33d.png">

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

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

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

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

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

<img width="1457" alt="スクリーンショット 2019-12-02 14.56.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264679/74b18f19-1bb8-3b60-2e75-22e83ccb637b.png">

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

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

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

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

<img width="1455" alt="スクリーンショット 2019-12-02 14.53.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264679/44f6fca1-b13c-48cf-11b2-8ffd907aebd7.png">

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

以上より、合計値は3
```

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

<img width="1457" alt="スクリーンショット 2019-12-02 14.56.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264679/74b18f19-1bb8-3b60-2e75-22e83ccb637b.png">

```
それぞれのドキュメントの計算結果は
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は空いてるようなので、小ネタ持ってる方、気楽に参加、いかがでしょうか？
ではでは〜