Upgrade to Pro — share decks privately, control downloads, hide ads and more …

elasticsearch で作るランキング

7a1631691f372ed25308ba9ccd727b2d?s=47 iwagami
June 27, 2016

elasticsearch で作るランキング

7a1631691f372ed25308ba9ccd727b2d?s=128

iwagami

June 27, 2016
Tweet

Transcript

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

  2. 誰よ • iwag • Scala/finagler/elasticsearch

  3. スクリプト • 検索、更新、取得時にスクリプト(groovy 等) でな んでもできる • Scripting • 言語:groovyなど

    ◦ Ruby っぽい ◦ 他にも lucence script, native(Java) ◦ import して Java の関数呼んだりできる
  4. 更新 • insert, update ◦ リンク • ドキュメントの値(ctx._source) を読み書き加工

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

  6. ランキング

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

  8. 作り方:例 • apache ログを時間で aggregation ◦ 重い… • バッチで1時間ごとに計算 ◦

    秘伝の技術になりがち • 1時間ごとの増減値(配列)をドキュメントに持たせ る (今日のお話) •
  9. データ構造 • お気に入り数の配列とその時刻(時)の配列 time_array: [ 160624T16, 160624T15, 160624T10, 160624T08 ...

    ] fav_array: [160624T16's fav数, 160624T15's fav数, 160624T10's fav数, …, 160624T08's fav数, ... ]
  10. スクリプトと検索クエリ 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<fav_array.length; i++) { if (from < time_array[i] && time_array[i] < to) sum += fav_array[i]; } return sum; { "fuction_score":{ "query":{ "term”: { “category":”ゲーム” }, "functions":{ "script_score":{ "script":"fav_array=doc['fav_array']. values; ... " } } } } }
  11. ヒント

  12. スクリプトめっっっっちゃ重い • フィールド >>> プラグイン(Native) >>>>>>>>>>>>> スクリプト(groovy) • プラグイン ◦

    結構簡単に作れる ◦ 更新に再起動がいるので今回は断念
  13. フィルタを使ってスクリプト実行を減らす • デフォルト ◦ 全ドキュメントに対して スクリプトが実行され る→重い • フィルタ ◦

    script_scoreにはフィ ルタを付けれる ◦ フィルタされた要素だ けスクリプトを実行す "fuction_score":{ "functions":{ "filter":{ "exists":"fav_array" }, "script_score":{ "script":"fav_array=doc['fav_array'].values; ... " } } }
  14. スクリプト中では絶対 doc を使う • doc は fielddata 、ヒープにキャッシュされる ◦ 設定で制御できるらしいがデフォルトで使っている

    • _fields, _source も使えるがインデックスから読ん でくるので遅い ◦ ドキュメントでも使うなって言ってる • ただ doc は制限多い ◦ オブジェクトが使えない、number or string のみ
  15. 更新

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

  17. 更新のスクリプト 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); }
  18. ヒント

  19. コンフリクトを気にしない • ESはドキュメント単位でのロック • 正直大雑把だけどめちゃくちゃ楽… • コンフリクトした場合→ retry • バズった時大変なことにならないのか?

    ◦ ESへのメッセージはすべてその前にキューで直列化して いるのでほぼコンフリクトは発生しない ◦ 遅延は発生するが。。。
  20. パフォーマンス • 更新時のスクリプトはパフォーマンスを気にしなく て良い ◦ せいぜい更新1回 • スクリプトの計算よりインデックスへのストアのほ うが重い

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

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

    = “....”;
  23. まとめ

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

  25. おまけ

  26. ホットエントリ(みたいなもの) もつくれます • スクリプト付きフィルタを使う • 例 ◦ 直近1時間のお気入り数が10以上でフィルタ ◦ 適当に並べる

    • あってるかは不明…