Elasticsearch Machine Learningのアラート通知用OSS es-ml-alert-pluginを公開した

[plugin-url]:https://github.com/serive/elastic-ml-alert-plugin

私が所属する[Airitech株式会社](https://www.airitech.co.jp/)の[Synthetic Monitoring サービス](https://www.airitech.co.jp/)では、ElasticsearchのMachine LearningとWatcher機能を利用して、Webサイトの性能改善、劣化の自動検知及び通知を実現しています。

通知の設定は、Wathcerを使い実現するのですが、今のElasticsearchのVersionで実現するにはかなり大変です。
そこで、通知を管理できるKibanaプラグインを開発してOSSとして公開しました。
今日はその「[es-ml-alert-plugin][plugin-url]」を紹介します。

# X-Pack Machine Learning及びWatcherとは
本題に入る前に、[X-Pack Machine Learning(以下X-Pack ML)](https://www.elastic.co/jp/blog/introducing-machine-learning-for-the-elastic-stack)と[Watcher](https://www.elastic.co/guide/jp/x-pack/current/watcher-getting-started.html)の紹介です。
![Elasticsearch-Logo-Color-V-sm-cut-mini.png](https://qiita-image-store.s3.amazonaws.com/0/69235/a12250f5-fa01-5a8f-2147-9f56ebfc88e6.png)

[X-Pack ML](https://www.elastic.co/jp/blog/introducing-machine-learning-for-the-elastic-stack)は、Elasticsearch上で動作する有償のプラグインで、機械学習による時系列データの異常値検知機能を提供するものです。
最大の売りは、機械学習の知識がなくても、異常検知が使えます！という点で、UIから設定するだけで、異常検知が利用できます。

※参考
・[X-Pack ML紹介ブログ](https://www.elastic.co/jp/blog/introducing-machine-learning-for-the-elastic-stack) ・[X-Pack ML紹介動画](https://www.elastic.co/jp/videos/intro-to-machine-learning-workshop)

[Watcher](https://www.elastic.co/guide/jp/x-pack/current/watcher-getting-started.html)もElasticsearch上で動作する有償のプラグインの一つです。定期的にElasticsearchにクエリを行い、結果に応じて通知することが可能になります。
以下の動画が使い方を詳しく教えてくれます。

・[Watcherの使い方1](https://www.youtube.com/watch?v=gD7MGt5jgDY)　
・[Watcherの使い方2](https://www.youtube.com/watch?v=-UVUzGMpyoo)　
・[Watcherの使い方3](https://www.youtube.com/watch?v=n2de2e01m2w)

・・・結構、大変な作業だと思ってもらえるかと思います。
6.xからはKibanaのUIもサポートされたので、閾値超過のジョブ設定は楽になりました。
が、X-Pack Machine Learning用のアラートを書こうかと思うと、まだまだ難しい。
そこで、プラグインの出番です。

# [es-ml-alert-plugin][plugin-url]はどんな時に使うOSSなのか？
以下のユースケースで便利に使えるOSSです。

* X-Pack Machine Learningのリアルタイム異常値検知機能を使って、解析したい
* 異常を検知したら、リアルタイムに通知を飛ばしたい<br> メールとかSlackで通知！
* 通知内容に、ML JobやDashboardへのリンクURLを入れて、解析をスムーズに行えるようにしたい

ちなみに自前で設定を作成すると、以下のような設定を作ることとなります。
<details>
<summary>X-Pack Watcherによる異常検知アラート設定</summary><div>

```json:wathcer-setting
{
  "trigger": {
    "schedule": {
      "cron": "0 * * * * ?"
    }
  },
  "input": {
    "search": {
      "request": {
        "search_type": "query_then_fetch",
        "indices": [
          ".ml-anomalies-*"
        ],
        "types": [],
        "body": {
          "sort": [
            {
              "timestamp": {
                "order": "asc"
              }
            }
          ],
          "query": {
            "bool": {
              "must": [
                {
                  "match": {
                    "result_type": "record"
                  }
                },
                {
                  "match": {
                    "job_id": "{{ctx.metadata.job_id}}"
                  }
                },
                {
                  "range": {
                    "record_score": {
                      "gt": "{{ctx.metadata.threshold}}"
                    }
                  }
                },
                {
                  "range": {
                    "timestamp": {
                      "from": "now-{{ctx.metadata.detect_interval}}-{{ctx.metadata.ml_process_time}}",
                      "to": "now-{{ctx.metadata.ml_process_time}}"
                    }
                  }
                }
              ]
            }
          }
        }
      }
    }
  },
  "condition": {
    "compare": {
      "ctx.payload.hits.total": {
        "gt": 0
      }
    }
  },
  "actions": {
    "notify_slack": {
      "transform": {
        "script": {
          "id": "create_partition_notify_for_slack"
        }
      },
      "slack": {
        "message": {
          "to": [
            "#elastic-notify"
          ],
          "text": "Elasticsearch ML Anomaly Detection",
          "attachments": [
            {
              "color": "{{ctx.payload.severityColor}}",
              "title": "{{ctx.payload.severity}}",
              "text": "{{ctx.payload.message}}"
            }
          ]
        }
      }
    }
  },
  "metadata": {
    "quate": "'",
    "link_dashboards": [
      {
        "id": "AWAAR4Z1hIAnOgqnarfW",
        "title": "Performance-Monitoring-Timeseries-hcperf"
      }
    ],
    "subject": "Webサイトの性能が改善しました。",
    "kibana_display_term": 28800,
    "detect_interval": "7d",
    "description": "Webサイトの性能が改善した際に通知します。",
    "threshold": 75,
    "locale": "Asia/Tokyo",
    "kibana_url": "http://localhost:15601/",
    "alert_type": "mla",
    "ml_process_time": "28924s",
    "double_quate": "\"",
    "job_id": "improve-perf",
    "compareOption": {
      "compareType": "gte",
      "operator": "≧"
    },
    "filterByActualValue": false,
    "date_format": "yyyy/MM/dd HH:mm:ss",
    "link_saved_searches": [
      {
        "id": "53f0e7c0-ead5-11e7-b520-6b73813f8f5b",
        "title": "Performance-Result-Summary"
      }
    ],
    "actualValueThreshold": 0.5
  }
}
```
</div></details>
(※この定義の解説もそのうち紹介します)

長い・・・。
これを作成、管理するのはかなり大変です。

そこでこのような設定追加をUIのみでできるようにしたのが、[es-ml-alert-plugin][plugin-url]です！

# [es-ml-alert-plugin][plugin-url]の使い方
## インストール
以下からお使いのElasticsearchのVersionに合う媒体をdownloadしてインストールします。

```sh:linux
sudo bin/kibana-plugin install file://<path to plugin>/es_ml_alert-x.x.x_y.y.y.zip
```

```sh:windows
.\bin\kibana-plugin install file://<path to plugin>/es_ml_alert-x.x.x_y.y.y.zip
```

## ML用アラート通知の設定
インストール後にKibanaを起動すると、メニューに「Ml Alert」と表示されます。
![メニュー.png](https://qiita-image-store.s3.amazonaws.com/0/69235/b2574e1c-0b09-c2ed-0bf9-1179a6c0f93f.png)

「Ml Alert」を選択すると、設定画面が表示されます。アラート通知したいX-Pack MLのJobを選択してください。
![job選択-2.png](https://qiita-image-store.s3.amazonaws.com/0/69235/ff4bec77-0d1d-d639-71be-0e9374955dfd.png)

次は、通知先の設定です。
(※あらかじめ[elasticsearch.ymlに通知を飛ばすためのアカウント設定](https://github.com/serive/elastic-ml-alert-plugin#elasticsearch%E3%81%B8%E3%81%AE%E3%83%A1%E3%83%BC%E3%83%AB%E8%A8%AD%E5%AE%9A%E8%BF%BD%E5%8A%A0%E3%83%A1%E3%83%BC%E3%83%AB%E9%80%9A%E7%9F%A5%E3%82%92%E8%A1%8C%E3%81%86%E5%A0%B4%E5%90%88)を実施しておく必要があります。)

![通知設定.png](https://qiita-image-store.s3.amazonaws.com/0/69235/416fe8d7-ffab-37b3-7307-85301b7aa9c5.png)

最後に通知条件を設定します。
![閾値設定.png](https://qiita-image-store.s3.amazonaws.com/0/69235/e96881e4-b964-637c-0b45-7581cc55dfff.png)
こちらの図ではCriticalな異常のみ検知するように設定しています。

保存ボタンを押下すれば完了です！これでリアルタイムに検知した異常値に対し、指定した方法でアラートが飛びます。
以下はSlackで通知したときのサンプルです。

![34381424-c49b2726-eb4b-11e7-8bb0-110d1c494851.png](https://qiita-image-store.s3.amazonaws.com/0/69235/6c2a7eef-708c-0ab8-0a4f-f699da6dff9f.png)

リアルタイムにML jobへのリンクも含んだSlack通知が飛ぶようになります。
この通知には、「Anomaly Explorer」や「Single Metric Viewer」へのリンクも自動で追加します。
リンクを押下すると検知した異常値に絞り込んだ画面を表示できます。
![SingleMetricViewerリンク-ぼかし.png](https://qiita-image-store.s3.amazonaws.com/0/69235/15a55f05-3d08-2273-7d9a-eab44f2ce91c.png)

こちらは、Slack通知のリンクから遷移した「Single Metric Viewer」の例です。
異常値を検知した系列にのみ絞り込んで表示しています。

このようにWatcher用のjson定義を自分で書くことなく、UIで設定するだけでWatcherによるリアルタイムアラート通知を実現することができました。

## 便利なオプションを追加で設定
### 通知内容にDashboardやSaved Searchのリンクを追加する。
Slackに通知する際に、通知内容に異常を検知したJobへのリンクや、関連した値を可視化したDashboardへのリンクを含めると、通知から解析の流れがスムーズにできます。

そこで、設定画面の下部に注目してください。
リンクしたいDashboardやSaved Search設定を追加できるボタンがあります。
![リンク設定.png](https://qiita-image-store.s3.amazonaws.com/0/69235/e514fd5a-9176-83bb-c793-008dcf334fd4.png)

「Dashboard一覧から選択」ボタン押下時の画面です。リンクしたいDashboardを選択します。
![dashboard選択.png](https://qiita-image-store.s3.amazonaws.com/0/69235/0ed11993-e19d-5f59-fea4-a99d6bd82638.png)

これで、Slackやメール通知内容に、追加したDashboardやSaved Searchへのリンクが入ります。

ちなみにSplit DataをJob設定で追加している場合は、異常検知した際の条件値で、DashboardやSaved Search画面を絞り込んだ状態で開きます。
異常が起きている値、期間にのみ絞った画面表示とすることで、解析を効率化できます。
以下は異常値検知したWebページに絞り込んだDashboardをクリックした場合の画面表示です。
![dashboardリンク2-ぼかし.png](https://qiita-image-store.s3.amazonaws.com/0/69235/127160e8-0496-0331-7957-d15010cbc3a5.png)

## 異常検知スコアだけでなく、実際の測定値も通知条件に含める。
X-Pack MLの出力するSeverity(Anomaly Score)は実際の値の大小に関係がなく、通常の値からどれくらいの変動があったかで評価が決まります。

例えばWebパフォーマンス計測結果が0.1秒から0.2秒に変わったことも、1秒が2秒に変わったこともどちらも2倍ということで、同じ異常値となってしまいます。
前者はネットワーク遅延などにより頻繁に発生するので、コンテンツの問題で発生する後者が埋もれてしまいます。

このような場合、アラート時に異常検知スコアだけでなく、計測結果が0.5秒以上といったように、実値による条件も一緒に設定することで、見なくてよい検知結果の通知を出さないようにすることができます。
しかし、Kibanaのジョブ設定ではSeverity(Anomaly Score)でしか判定できません。
そこでプラグインで対応しました。

設定画面の「詳細設定」を選択すると、「実際の値でフィルターする場合」の設定があるので、こちらに閾値としたい値を入れます。
![実値でフィルタ.png](https://qiita-image-store.s3.amazonaws.com/0/69235/c1a32a68-962a-dba8-ff61-167de4e17bdb.png)

これで、異常検知スコアが高いかつ、実値が0.5以上の場合にのみ、通知が飛ぶようになります。

## 管理機能の利用
作成したアラート通知を管理するにあたって、以下のような設定変更がしたくなることがあります。

* どのJobに対して作成した通知か確認したい。
* 可視化Dashboardを追加したので、通知先に追加したい。
* 新しくProjectのメンバが入ってきたのでアラート通知先に追加したい。

このような運用時に必要となる機能も追加しています。
### 一覧機能
このように、どのML jobに対してアラートを作ったかを確認しながら管理ができます。
Watcher用の管理画面では、このようなカテゴリごとの表示ができないので、管理時に便利です。
![34380816-8a6eafd6-eb47-11e7-9aaf-dd781c57cbf7.png](https://qiita-image-store.s3.amazonaws.com/0/69235/639aaf86-871b-3ed1-0562-1278a92e9348.png)

### 一括編集機能
複数のアラート通知に対し、まとめて編集や、Activate Deactivateなどを実施することができます。
![一括編集.png](https://qiita-image-store.s3.amazonaws.com/0/69235/398100ea-af14-0a96-a4b4-9f6503a3e6fa.png)

可視化Dashboardを追加した後には、関係するアラート通知にまとめてリンク先に追加する必要があります。
一括編集を使えば選択したアラート通知にまとめてリンク先の追加ができるのでラクチンです。
アラート通知先も同じようにまとめて追加できます。

## 今後の改善予定
通知先がSlackとメールだけの対応となっているので、LINE連携や、その他のプラットフォームとの連携ができるように改善したいと思っています。

また先日Elstic{on} Tokyoにて、X-Pack MLチームリーダのSophie Changさんに見せたところ、
「いいね」もらったので、英語対応したいと思っています。

こんな機能あったらほしいというものがあれば、[githubのissue](https://github.com/serive/elastic-ml-alert-plugin/issues)を上げてもらえるとうれしいです。

# 最後に
最後までお読みいただきありがとうございました。

X-Pack MLを使っているけど、アラート通知設定が大変と思っている人たちの助けになるようなプラグイン提供できるように、これからも改善していこうと思っています。

今年のブログ投稿もこれで最後かな。
では、みなさん、よいお年を！