Slide 1

Slide 1 text

elasticsearchで ランキングを作ろう iwag 2016/06/27 elasticsearch勉強会 #16

Slide 2

Slide 2 text

誰よ ● iwag ● Scala/finagler/elasticsearch

Slide 3

Slide 3 text

スクリプト ● 検索、更新、取得時にスクリプト(groovy 等) でな んでもできる ● Scripting ● 言語:groovyなど ○ Ruby っぽい ○ 他にも lucence script, native(Java) ○ import して Java の関数呼んだりできる

Slide 4

Slide 4 text

更新 ● insert, update ○ リンク ● ドキュメントの値(ctx._source) を読み書き加工

Slide 5

Slide 5 text

検索 ● スコア計算 ○ ドキュメントの値を読んでスコアを算出する ● スクリプト付きフィルタ ● 値の取得(スクリプトフィールド) ○

Slide 6

Slide 6 text

ランキング

Slide 7

Slide 7 text

ランキングとは ● 現在時刻から24時間のお気に入り増減数の順 ● 1時間ごとに更新

Slide 8

Slide 8 text

作り方:例 ● apache ログを時間で aggregation ○ 重い… ● バッチで1時間ごとに計算 ○ 秘伝の技術になりがち ● 1時間ごとの増減値(配列)をドキュメントに持たせ る (今日のお話) ●

Slide 9

Slide 9 text

データ構造 ● お気に入り数の配列とその時刻(時)の配列 time_array: [ 160624T16, 160624T15, 160624T10, 160624T08 ... ] fav_array: [160624T16's fav数, 160624T15's fav数, 160624T10's fav数, …, 160624T08's fav数, ... ]

Slide 10

Slide 10 text

スクリプトと検索クエリ fav_array=doc['fav_array'].values; time_array=doc['time_array'].values; // from, to はパラメータで来ます。 from〜to to = new DateTime().getMillis; from = to - 24時間前; sum = 0; for (i=0; i

Slide 11

Slide 11 text

ヒント

Slide 12

Slide 12 text

スクリプトめっっっっちゃ重い ● フィールド >>> プラグイン(Native) >>>>>>>>>>>>> スクリプト(groovy) ● プラグイン ○ 結構簡単に作れる ○ 更新に再起動がいるので今回は断念

Slide 13

Slide 13 text

フィルタを使ってスクリプト実行を減らす ● デフォルト ○ 全ドキュメントに対して スクリプトが実行され る→重い ● フィルタ ○ script_scoreにはフィ ルタを付けれる ○ フィルタされた要素だ けスクリプトを実行す "fuction_score":{ "functions":{ "filter":{ "exists":"fav_array" }, "script_score":{ "script":"fav_array=doc['fav_array'].values; ... " } } }

Slide 14

Slide 14 text

スクリプト中では絶対 doc を使う ● doc は fielddata 、ヒープにキャッシュされる ○ 設定で制御できるらしいがデフォルトで使っている ● _fields, _source も使えるがインデックスから読ん でくるので遅い ○ ドキュメントでも使うなって言ってる ● ただ doc は制限多い ○ オブジェクトが使えない、number or string のみ

Slide 15

Slide 15 text

更新

Slide 16

Slide 16 text

前提 ● クリック時にスクリプト付き(+1) updateが飛ぶ

Slide 17

Slide 17 text

更新のスクリプト if(ctx._source['fav_array']==null || ctx._source['time_array']) = ... now = new DateTime().getMillis()/3600; if (ctx._source.time_array[0] == now) { ctx._source.fav_array[0] += 1; } else { ctx._source.time_array.add(0, now); ctx._source.fav_array[0].add(0, 1); }

Slide 18

Slide 18 text

ヒント

Slide 19

Slide 19 text

コンフリクトを気にしない ● ESはドキュメント単位でのロック ● 正直大雑把だけどめちゃくちゃ楽… ● コンフリクトした場合→ retry ● バズった時大変なことにならないのか? ○ ESへのメッセージはすべてその前にキューで直列化して いるのでほぼコンフリクトは発生しない ○ 遅延は発生するが。。。

Slide 20

Slide 20 text

パフォーマンス ● 更新時のスクリプトはパフォーマンスを気にしなく て良い ○ せいぜい更新1回 ● スクリプトの計算よりインデックスへのストアのほ うが重い

Slide 21

Slide 21 text

古いデータどうするのか? ● バッチで48時間以上前のデータは消している ● クエリ付き update があるとうれしいなという要望

Slide 22

Slide 22 text

デバッグどうするのか ● スクリプトでloggerが使える ○ https://www.elastic.co/blog/elasticsearch-logging-secrets ● デバッグ用フィールド ○ スクリプト中で ctx._source.debug = “....”;

Slide 23

Slide 23 text

まとめ

Slide 24

Slide 24 text

まとめ ● elasticsearch のスクリプトの話をしました ● ランキングの作り方を紹介しました ● スクリプトを活用する上でのヒントを紹介しました

Slide 25

Slide 25 text

おまけ

Slide 26

Slide 26 text

ホットエントリ(みたいなもの) もつくれます ● スクリプト付きフィルタを使う ● 例 ○ 直近1時間のお気入り数が10以上でフィルタ ○ 適当に並べる ● あってるかは不明…