はじめに
こんにちは、検索基盤部 検索研究ブロックの真鍋です。ヤフー株式会社から一部出向していて、主にZOZOTOWNの検索機能へのランキングモデルの導入に従事しています。
本記事では、Elasticsearch上でランキングモデルを扱うための有名なプラグインの仕組みと、同プラグインにZOZOが実装した機能を紹介します。
まず、本記事の背景を説明します。ZOZOTOWNでキーワード検索すると、結果の商品が並びます。結果の商品は非常に多数になることも多いので、ユーザ体験を損なわないためには、その並び順も重要です。ここで言うランキングモデルとは、この並び順の決定のために、商品のスコアを計算する式のことを指します。このような式は機械学習によって生成され、非常に複雑になることもあります。そのため、検索エンジンの標準機能では実行できず、プラグインを導入して初めて実行できることもあります。
ZOZOTOWNでは検索エンジンとしてElasticsearchを使用しています。そして、Elasticsearch上でランキングモデルを実行するために、OpenSource Connectionsが提供するLearning to Rank pluginを使用しています。以下、このプラグインを指して、単に本プラグインと呼びます。
本記事の前半では、本プラグインの仕組みを説明します。まずランキングモデルを実行する仕組みを紹介し、次にランキングモデルを学習するための特徴量の値を出力する仕組みを紹介します。後半では、ZOZOが本プラグインに実装した、特徴量キャッシュの機能を紹介します。これは、ランキングモデルの実行と特徴量の値の出力を併用する際に、後者を効率化するための機能です。
具体的なコードとしては、本プラグインのバージョンv1.5.8-es7.16.2を例に説明します。
本記事では本プラグインの詳しい使い方は紹介しませんが、過去の記事で紹介しておりますので、ぜひ合わせてご覧ください。
ランキングモデルの実行の仕組み
まず、本プラグインでランキングモデルを実行する仕組みを紹介します。本プラグインでランキングモデルを実行するには、例えば以下のクエリをElasticsearchに送信します(本プラグインの公式ドキュメントより引用)。
{
"query": {
"match": {
"_all": "rambo"
}
},
"rescore": {
"window_size": 1000,
"query": {
"rescore_query": {
"sltr": {
"params": {
"keywords": "rambo"
},
"model": "my_model"
}
}
}
}
}
https://elasticsearch-learning-to-rank.readthedocs.io/en/latest/searching-with-your-model.html#rescore-top-n-with-sltr
このクエリでは、以下のことが指定されています。
- クエリキーワードがrambo
- 既存の検索結果の上位1,000件をランキングモデルで並べ替える
- その際に使うランキングモデルの名前がmy_model
LtrQueryParserPluginによるクエリのパースと、RankerQueryオブジェクトの生成
例のクエリは、まず本プラグインのコードのうち LtrQueryParserPlugin に入力されます。LtrQueryParserPlugin はElasticsearch本体が提供するインタフェース SearchPlugin を実装しています。このため、LtrQueryParserPlugin はElasticsearch本体の SearchModule から見えるようになっています。
SearchModule はクエリの各要素(例のクエリで言うと match や sltr)をどのクラスにパースさせるかを管理しています。具体的には、組み込みのクラスのほか、各プラグインが SearchModule#getQueries で指定してくるクラスも考慮します。
LtrQueryParserPlugin#getQueries では、以下の通り sltr 要素を StoredLtrQueryBuilder にパースさせるという指定をしています。ただし、StoredLtrQueryBuilder.NAME は sltr であることに注意してください。この指定のため、次は本プラグイン独自の StoredLtrQueryBuilder に制御が移ります。
new QuerySpec<>(StoredLtrQueryBuilder.NAME,
(input) -> new StoredLtrQueryBuilder(getFeatureStoreLoader(), input),
(ctx) -> StoredLtrQueryBuilder.fromXContent(getFeatureStoreLoader(), ctx)),
https://github.com/o19s/elasticsearch-learning-to-rank/blob/37d8542c78b816c67a34fd206e6f4dc08ba7006f/src/main/java/com/o19s/es/ltr/LtrQueryParserPlugin.java#L144-L146
StoredLtrQueryBuilder
StoredLtrQueryBuilder はクエリのJSONをパースし、メモリ上の表現(後述の RankerQuery)をビルドするのに使います。ビルドのために、以下の主要なメンバーを持っています。
続きはこちら