Elasticsearch Kibana でデータの可視化
Elasticsearch と Kibana で実現するデータの可視化とその設定例
Kibana でデータの可視化ということで、ググればたくさん出てきますが、私なりにまとめたいと思います。今回可視化するのはツィート情報です。ツィート情報を Elasticsearch にインデックスして、Kibanaで、可視化してみたいと思います。
こんな感じのダッシュボード作ります。
Elasticsearchのインストールと起動
ツィート情報のインデックスには、Twitter River Plugin for Elasticsearch を使用します。まずは、Elasticsearch をここからダウンロードして解凍し、Twitter River プラグインをインストールして起動します。
# Install Elasticsearch.
$ tar zvxf elasticsearch-1.1.1.tar.gz# Install Twitter River Plugin.
$ cd elasticsearch-1.1.1
$ bin/plugin -install elasticsearch/elasticsearch-river-twitter/2.0.0# Run Elasticsearch.
$ bin/elasticsearch
Kibana のインストールと起動
Kibana をここからダウンロードして解凍します。Kibana はHTMLとJavaScript だけなので、一般的なHTTPサーバーであれば起動できます。ここでは、お手軽に Python のSimpleHTTPServer を使用して Kibana を起動します。
今回は、Elasticsearch も Kibanaも同じローカル内で起動するのでKibanaの設定は特に何も変更せずそのまま起動するだけでOKです。
# Install Kibana.
$ tar zvxf kibana-3.0.1.tar.gz# Run Kibana.
$ cd kibana-3.0.1
$ python -m SimpleHTTPServer
上記コマンドでHTTPサーバーを起動後、ブラウザで http://localhost:8000/ にアクセスしてKibanaのWelcomページが表示されればOKです。
SimpleHTTPServerは起動するポート番号を変更することも出来ます。
$ python -m SimpleHTTPServer 8080
コマンドのエイリアス作っておくとちょっと便利。
alias simplehttpd=’python -m SimpleHTTPServer’
参考:Kibana を ES プラグインとしてインストールする
見つけたので勝手に掲載させてもらいました。確かにこの方が簡単ですね。
手順を調べたのでメモ。
# Kibana プラグインのインストール
$ bin/plugin -url http://download.elasticsearch.org/kibana/kibana/kibana-latest.zip -install elasticsearch/kibana3# ブラウザアクセスURL
http://localhost:9200/_plugin/kibana3/
NOTE:古いバージョンがインストールされてしまうので、インストールするとき、-url で最新版を指定した方が良さそうです。
インデックスの作成とマッピング定義
日本語を含むツィート情報をインデックス、グラフ化したいのでTwitter River プラグインで作成されるマッピング定義をちょっとカスタマイズしました。下記の内容を twitter.json と名前を付けてファイルに保存してあとで使います。
{
"settings": {
"analysis": {
"tokenizer": {
"ngram_tokenizer": {
"type": "nGram",
"min_gram": 3,
"max_gram": 3,
"token_chars": ["letter", "digit"]
}
},
"analyzer": {
"facet_analyzer": {
"type": "custom",
"char_filter": ["html_strip"],
"tokenizer": "keyword",
"filter": ["cjk_width", "lowercase"]
},
"ngram_analyzer": {
"type": "custom",
"char_filter": ["html_strip"],
"tokenizer": "ngram_tokenizer",
"filter": ["cjk_width", "lowercase"]
}
}
}
},
"mappings": {
"status" : {
"_all": {
"enabled": true,
"analyzer": "ngram_analyzer"
},
"properties" : {
"created_at" : {
"type" : "date",
"format" : "dateOptionalTime"
},
"hashtag" : {
"properties" : {
"end" : {
"type" : "long"
},
"start" : {
"type" : "long"
},
"text" : {
"type" : "string",
"index": "analyzed",
"analyzer": "facet_analyzer"
}
}
},
"in_reply" : {
"properties" : {
"status" : {
"type" : "long"
},
"user_id" : {
"type" : "long"
},
"user_screen_name" : {
"type" : "string",
"index": "analyzed",
"analyzer": "facet_analyzer"
}
}
},
"language" : {
"type" : "string",
"index": "analyzed",
"analyzer": "facet_analyzer"
},
"link" : {
"properties" : {
"display_url" : {
"type" : "string"
},
"end" : {
"type" : "long"
},
"expand_url" : {
"type" : "string"
},
"start" : {
"type" : "long"
},
"url" : {
"type" : "string"
}
}
},
"location" : {
"type" : "geo_point"
},
"mention" : {
"properties" : {
"end" : {
"type" : "long"
},
"id" : {
"type" : "long"
},
"name" : {
"type" : "string",
"index": "not_analyzed"
},
"screen_name" : {
"type" : "string",
"index" : "not_analyzed"
},
"start" : {
"type" : "long"
}
}
},
"place" : {
"properties" : {
"country" : {
"type" : "string"
},
"country_code" : {
"type" : "string"
},
"full_name" : {
"type" : "string"
},
"id" : {
"type" : "string"
},
"name" : {
"type" : "string"
},
"type" : {
"type" : "string"
},
"url" : {
"type" : "string"
}
}
},
"retweet" : {
"properties" : {
"id" : {
"type" : "long"
},
"retweet_count" : {
"type" : "long"
},
"user_id" : {
"type" : "long"
},
"user_screen_name" : {
"type" : "string"
}
}
},
"retweet_count" : {
"type" : "long"
},
"source" : {
"type" : "string",
"index": "analyzed",
"analyzer": "facet_analyzer"
},
"text" : {
"type" : "string",
"index": "analyzed",
"analyzer": "ngram_analyzer"
},
"truncated" : {
"type" : "boolean"
},
"user" : {
"properties" : {
"description" : {
"type" : "string",
"index": "analyzed",
"analyzer": "ngram_analyzer"
},
"id" : {
"type" : "long"
},
"location" : {
"type" : "string",
"index": "analyzed",
"analyzer": "facet_analyzer"
},
"name" : {
"type" : "string",
"index": "not_analyzed"
},
"profile_image_url" : {
"type" : "string"
},
"profile_image_url_https" : {
"type" : "string"
},
"screen_name" : {
"type" : "string",
"index" : "not_analyzed"
}
}
}
}
}
}
}
ちょっと長くなってしまいましたが、ポイントは3つ。
- グラフ化に使用する属性で値をそのまま使う属性
Twitter ユーザー名(user.name)など String 型で、属性の値をそのままを使用してグラフ化したい属性は、index オプションを “not_analyzed” に設定します。 - グラフ化に使用する属性で値を正規化する属性
ハッシュタグ (hashtag.text) など String 型で、属性の値を正規化してグラフ化に使用したい属性は、analyzer をカスタマイズします。上記の設定では、”facet_analyzer” というカスタムアナライザーを用意しましたのでこれを使用します。ハッシュタグなどのユーザーが入力する値は、多少の違っていてもなるべく正規化して、同じデータとして集計したいので、1とは別にしています。 - 絞り込み条件で日本語全文検索に使用する属性
ツィートの内容(text)などの日本語を含む String 型の文章で、日本語全文検索したい属性は、analyzer をカスタマイズします。上記の設定では、Nグラムで日本語全文検索可能な “ngram_analyzer” を用意しましたのでこれを使用します。
なぜこのような設定が必要かというと、1、2についてはグラフ化にファセットの結果を使用するため、デフォルトのアナライザーで解析された属性のファセット結果を使用すると、解析後の最小単語単位の文字列毎に集計されてしまうからです。ん〜何を言っているかわかりづらいなぁ。
たとえば...デフォルトのアナライザーで解析すると次のようになります。
Original: "news sports"
Analyzed: "news", "sports"
この場合、"news sports"で集計されず、"news"、"sports"それぞれで集計されます。さらに日本語は1文字づつに分解されてしまうため使い物になりません。
3については日本語でデータを絞り込みたいから。
ツィート情報のインデックス
それでは、準備も整ったのでインデックスを作成してツィート情報をElasticsearchに流し込みます。
まずは、twitter インデックスに先ほど twitter.json ファイルに保存したマッピング情報を使用して、status ドキュメントタイプを作成します。
# Create Index & Mapping.
$ curl -XPUT 'localhost:9200/twitter' -d @twitter.json
つぎに、Twitter River プラグインを使ってツィートフィード用の River を作成します。アクセストークンなどの認証キーは事前に準備してください。次の例では、”news”または、”ニュース”を含み言語が日本語のツィートを対象に、先ほど作成したstatus ドキュメントタイプにデータをフィードする例です。
curl -X PUT 'localhost:9200/_river/twitter/_meta' -d '{
"type" : "twitter",
"twitter" : {
"oauth": {
"consumer_key" : "*** YOUR Consumer key HERE ***",
"consumer_secret" : "*** YOUR Consumer secret HERE ***",
"access_token" : "*** YOUR Access token HERE ***",
"access_token_secret" : "*** YOUR Access token secret HERE ***"
},
"filter" : {
"tracks" : "news, ニュース",
"language": "ja"
}
},
"index": {
"index" : "twitter",
"type": "status",
"bulk_size": 100
}
}'
コマンドを実行するとすぐにフィードが開始されますので、少し待ってください。
NOTE: language を指定したい場合は、tracks または、follow、locations のいずれかの条件が必要です。
また、フィードを停止するには次のコマンドを実行します。インデックスは削除されませんのでご安心を。
$ curl -XDELETE 'localhost:9200/_river/twitter
Kibana のダッシュボードの作成
ではさっそく、ダッシュボードを作成して行きます。まずはブラウザーで、http://localhost:8000/ にアクセスしてください。せっかくなのでブランクから作成してみたいと思います。
ブランクらか作成するには、表示された画面下にある、”Blank Dashboard” リンクをクリックします。
“Blank Dashboard” リンクをクリックすると、下の図のような殺風景な画面が表示されます。
ダッシュボードの基本設定
まずは、ダッシュボードの名前など基本的な情報を設定するために画面右上の歯車アイコンをクリックして設定画面を表示します。
ダッシュボードの設定には、General、Index、Rows、Controls、Timepicker がありますので、それぞれ設定してきます。
Dashboard Settings : General
主にダッシュボードの名前と見た目のスタイルを設定します。
Dashboard Settings : Index
主にデフォルトのインデックスの設定をします。twitter という名前のインデックスを作成しましたので、ここに設定します。
Dashboard Settings: Rows
グラフなどを配置する為のスペース作成します。1つのRow には、複数の Panel (グラフなど)を配置できます。とりあえず、ツィートグラフを配置する為の Graph Row と ツィート情報一覧を表示する為の Status Row を作成しました。
Dashboard Settings: Controls
とりあえずデフォルトのままで良いかと。ここでは、ダッシュボードの設定の保存先やロード先など設定できます。
Dashboard Settings: Timepicker
Time Field をインデックス情報にあわせて、created_at に設定します。ここで設定したフィールドの値を使用して、日付や日時でデータを絞り込んだり出来るようになります。
最後にSaveボタンをクリックして反映してください。
ツィート情報一覧パネル
ダッシュボードのRowsの設定で作成した Status Row にツィート情報の詳細な内容を表示します。画面下の領域の”Add panel to empty row”ボタンをクリックしてパネル作成画面を表示します。
パネル作成画面では、Select Panel Type に “table” を選択し、”Title” と “Span” を設定します。Span はパネルの横幅の設定です。12を設定すると横幅いっぱいに表示されます。
保存してダッシュボード画面に戻ると、ツィート情報の一覧が表示されます。デフォルトでは、_source フィールドの内容がそのまま表示されますので、画面左の “Fields” から表示したい内容を選択してください。
ツィート数ヒストグラムパネル
次に、ツィート数を時系列に棒グラフで表したツィート数ヒストグラムを作成します。Graph Row に作成してください。Select Panel Type に ”histogram” を選択し、Title、Span、Time Field を以下の図のように設定します。
保存してダッシュボードに戻ると時系列のグラフが表示されます。インターバルを ”1s” に設定するとそれっぽく表示されます。
ハッシュタグ円グラフパネル
ハッシュタグを円グラフ化したパネルを追加します。Select Panel Type に “terms” を選択し、以下の図のように設定します。
保存すると下記の図ような円グラフが表示されます。ちなみに円グラフに表示するアイテム数を変更するには、画面中央の “length” の値を変更します。
メンションユーザー円グラフパネル
メンションの多いユーザーの円グラフを作成します。作成手順は、ハッシュタグ円グラフパネルを参考に作成してください。対象フィールドは、”mention.name” または、”mention.screen_name”です。
ツィートユーザー円グラフパネル
ツィート数の多いユーザーの円グラフを作成します。作成手順は、ハッシュタグ円グラフパネルを参考に作成してください。対象フィールドは、”user.name” または、”user.screen_name” です。
完成!
以上の手順で以下の図のようなダッシュボードが完成したかと思います。最後に画面右上の保存アイコンをクリックしてダッシュボードの設定を保存すれば完成です。
NOTE: 保存せずに画面をリロードしたりしてしまうと、設定内容は元に戻ってしまいますので、こまめに保存した方が良さそうです。
使い方など
画面上部のQueryで、データを絞り込んだり、各種グラフをクリックして絞り込んだり、期間で絞ったりして分析できるようになりました。
また、画面上部の “Time filter” にある “Auto-Refresh” を設定すると、インデックスされた情報をリアルタイムに更新してダッシュボードで確認することが出来ます。
まとめ
マーケティング担当者など情報を分析する担当者が、直接 Kibana の画面を使用してダッシュボードを作成するのは難しそうな印象です。実際にはKibanaに精通した管理者が分析担当者の要望などをヒアリングして設定したものを使ってもらうと言った運用になりそうな気がします。