2K Views
June 06, 17
スライド概要
第20回 Lucene/Solr勉強会 https://solr.doorkeeper.jp/events/59743 発表資料
2023年10月からSpeaker Deckに移行しました。最新情報はこちらをご覧ください。 https://speakerdeck.com/lycorptech_jp
Solrで多様なランキングモデルを活用するためのプラグイン開発 2017/06/05 第20回 Lucene/Solr勉強会 #SolrJP ヤフー株式会社 矢野 友貴
自己紹介 • 氏名 • 矢野 友貴 (やの ゆうき) • 所属 • ヤフー株式会社 D&S統括本部 • ふつーのエンジニア • Solr歴は1年ぐらい (Solrチョットデキル) • 前回登壇した石川さんのチームに所属 • 主に検索ランキング周り担当 石川さんのスライド https://www.slideshare.net/TakahiroIshikawa6/solratomicupdate50000 1
余談: Lucene/Solr Revolution 2017 • 今回のネタ、今年のLucene/Solr Revolutionに投稿してましたが… • 結果はrejectでしたorz 2
アジェンダ • Solrのランキング周りの話 • Yahoo!JAPANで開発中のランキングプラグインの話 3
Solrのランキング周り 4
検索とランキング • ランキング = 特定の基準に従って検索結果をソート • ヒットした文書毎にスコア計算をして並べ替える • ランキングのモチベーション • 検索の質の改善 • 検索意図との関連度をスコア化 • ex) 機械学習によるランキングモデル • 検索のカスタマイズ • 業務要件に応じた補正をスコア化 • ex) 広告費用を加味した補正 5
Solrとスコア計算 • Solrでは大きく分けて2つある (はず) • Similarity • TF-IDF, BM25のような統計情報ベースのスコア • FunctionQuery • 四則演算や条件式で定義したカスタムスコア • 実際はDisMaxクエリとか他にも色々と方法はあるが。。。 • 突き詰めると最終的に上の2つに行き着く 6
Solrとスコア計算 (cont’d) • 実際のユースケースではスコア計算に色々な要望がでてくる • ヒットした結果をサービス固有なロジックで並び替えたい • 機械学習モデルとかもっとリッチなスコア計算をしたい • スコア計算を自由にカスタマイズするには? • 独自Similarityを実装する • RankQueryを使ったプラグインを実装する 7
Solrでのランキングフロー • Solrのランキングの登場人物はざっくり2つ • Query/Weight/Scorer query • スコア計算 • Collector/LeafCollector Collector • ドキュメント選択 • (Similarityは割愛) Leaf Collector Query Weight Scorer index (segment) ※実際はCollectorを生成するのはSolrIndexSearcherだが便宜上Queryと繋いでいる 8
Solrでのランキングフロー (cont‘d) • Query/Weight/Scorer • Query => Weight => Scorerと生成される • 後にいく程担当範囲が狭くなる • Scorerが具体的なセグメントを担当 • 対象ドキュメントの走査とスコア計算 • 実装によってクエリの当て方が変わる (ex. フレーズ検索) query 検索全体 shard毎 segment毎 Query Weight Scorer 検索クエリを解析して Queryを生成 shardのコンテキスト に基いて生成 index (segment) segmentのコンテキスト に基いて生成 9
Solrでのランキングフロー (cont’d) • Collector/LeafCollector • Scorerが返すスコアを元にドキュメントを選択 • 優先度キューを用いてスコアの高い文書を選ぶ TopDocsCollector (Collector) PriorityQueue topDocs LeafCollector collect Scorer 候補文書の絞込 topNの選択 documents index (segment) 10
RankQueryの仕組み • RankQuery = Solrのランキングを拡張するための機能 • Queryをラッピングして諸々の処理を書き換える RankQuery query Query query Query Collector Weight Collector Weight Leaf Collector Scorer Leaf Collector Scorer index (segment) rq={!xxx} Queryをラップすることで CollectorやWeightの生成 を差し替えられるようになる index (segment) 11
RankQueryの例 (ReRankプラグイン) • リランキング用のクエリで再検索してスコア補正 • score = firstPassScore + reRankWeight * secondPassScore reRankQuery=barの条件 でスコアを再計算して補正 q=foo&rq={!rerank reRankQuery=bar} LeafCollector Scorer (q=foo) ReRankCollector collect PriorityQueue ReRankQueryRescorer topDocs Scorer (q=bar) rescore q=fooの条件で スコアを計算 index https://cwiki.apache.org/confluence/display/solr/Query+Re-Ranking 補正後のスコアで再ソート (リランキング) documents 12
RankQueryの例 (LTRプラグイン) • Solr6.4から追加されたプラグイン • 「LTR = Learning To Rank」、Solrで機械学習モデルを扱う • Bloombergの人によってコントリビュートされた https://issues.apache.org/jira/browse/SOLR-8542 13
RankQueryの例 (LTRプラグイン) (cont‘d) • 学習済モデルを事前に登録し, リランキングで利用 • リクエストパラメタでモデル名を指定して切り替え • 現状では線形モデルとアンサンブル木モデルに対応している 事前にモデル定義をアップロード model.json 検索時に利用する モデルを指定 ...&rq={!ltr model=xxx}&... ModelStore LTRRescorer ModelScorer (model = xxx) LTRScoringModel (model = xxx) 対応するモデルにスコア計算を委譲 https://cwiki.apache.org/confluence/display/solr/Learning+To+Rank 14
Yahoo!JAPANで開発中の ランキングプラグイン 15
アプローチ • RankQueryを用いたプラグインとして実装 • 他のプラグインと同じように主要な処理を差し替える • 多様なサービスニーズに応えるために以下を実現する (したい) • 柔軟なスコア計算の定義 => DSLによるモデル記述 • リッチな特徴量 => ポスティングリストから取れる情報を使う • 高速なランキング => 動的コンパイル, (高速化アルゴリズム) 16
ランキングプラグインの概要 • 大きく3つのコンポーネントに分かれる ランキング Scorer スコアリング Evaluator モデリング Parser Collector profiles Rescorer Feature … Model Matcher profile.json index models 17
ランキング処理 • 基本的な対応方針は他のRankQuery系プラグインと同じ • Queryをラッピングして, 独自のCollectorに差し替える • 他のプラグインと地味に異なる点 • collectでもスコア計算を差し替え可能 • topDocsでscore+fieldのような複合ソートに対応 ランキング Scorer Evaluator Collector Rescorer 18
スコアリング処理 • スコア計算はLTRプラグインのアプローチに近い • 特徴ベクトルを展開 => モデルでスコア計算 • 以下の3ステップでスコアを計算 1. ポスティングリストから単語情報を展開 • position, freq, norm, payload • フィールド値とかもここで展開 2. 1.の情報を元に各特徴量を計算 3. 2.の情報を元にモデルでスコア計算 スコアリング Evaluator Feature … Matcher index 19
モデリング処理 • プラグインでは各モデルとprofileという単位で管理 • 検索時にランキングで用いるprofileを指定して使う • profileの指定に従い以下のような前処理を事前に行う • 対応するmodelファイルのロード • スコア計算式のコンパイル モデリング profile.json Parser profiles Model models 20
検索モデルの記述方法 • プラグインでは2通りの記述方法を提供 1. DSL (Domain Specific Language) • プログラマブルな記述方法 • 自由にルールを記述したいときに使う 2. 特化モデル (今回は割愛) • 特定のモデルフォーマットに限定した記述方法 • 表現に制約があるがその代わり計算が速い 21
モデル記述とDSL • モデル定義を行うための簡易言語 • 四則演算, 条件式, if文, 数学関数とかに対応 • FunctionQueryをもっとhuman-readableに噛み砕いた感じ • 基本的なモデルもDSLを用いて表現可能 • 線形モデル : 足し算と掛け算の繰り返し • アンサンブル木モデル : ネストしたif文 22
モデル記述とDSL (cont‘d) • 内部はJavaCCを用いて実装 • SolrのQueryParserの実装と似た感じ • ただしそのままインタプリタ実行すると重い。。。 • 各モデル式をコンパイルして高速化 • javax.tools.JavaCompilerで動的コンパイルする モデル式 解析 評価木 実行 変換 Javaコード コンパイル byteコード 実行 23
モデル記述とDSL (cont‘d) • 動的コンパイルする利点 • インタプリタ実行時の評価ノードの再帰呼出しを回避 • モデル毎にJITコンパイルのプロファイリングして最適化 • 実際にコンパイルすると20〜50%程度レイテンシが改善 • CPU使用率が下がるため特に高負荷時に差がつく 高負荷時には 倍ぐらい差がつく 24
LTRプラグインとの比較 ランキング スコアリング モデリング LTRプラグイン Yahooプラグイン collectの書き換え ✕ ◯ topDocsの書き換え ◯ ◯ field-sortへの対応 △ (topDocsが未対応) ◯ フィールド参照 ◯ ◯ クエリパラメタ ◯ ◯ FunctionQueryとの連携 ◯ (SolrFeatureで使える) △ (DSLで担保) pos, payloadの利用 △ (Query依存) ◯ (ただし素性実装が必要) 複数モデルの切り替え ◯ ◯ 機械学習モデルの利用 ◯ ◯ カスタムモデルの利用 △ (継承 or FunctionQuery) ◯ (DSLで書ける) モデル分割 △ (FunctionQueryでできる?) ◯ (DSLで書ける) 高速化の工夫 ✕ (ナイーブ実装) ◯ (特化モデル) 素性ダンプ ◯ △ (実装中) ※だいぶ個人的なバイアスかかってると思います 25
今後の予定 • ランキングプラグインはまだまだ絶賛開発中 • ランキングの基本部分はほぼほぼ動くレベル • これからやりたいこと • 特徴ベクトルをダンプしてHadoop/Sparkとかに流す • 機械学習のPDCAサイクルを回すため • 特徴の追加実装とか拡張性を高める • 外部jarとかで気楽に拡張できるようにしたい • Solr本体側への還元 (LTRプラグインのパッチとして) • (個人的には) 将来的にプラグイン自体も公開したい 26
追記: SOLR-10811 • 今日話さなかった特化モデルの方はパッチ出しました https://issues.apache.org/jira/browse/SOLR-10811 27
まとめ • Solrのランキング周りを紹介 • 独自ランキングを作りたいならRankQueryを使おう • LTRプラグインの登場で機械学習も身近に • Yahoo!JAPANのランキングプラグインを紹介 • DSLで自由なモデル記述 • 高速化も結構がんばってます • 成果をSolrコミュニティに還元する予定 28
最後に (お約束) We are Hiring! https://about.yahoo.co.jp/hr/ 29