LoginSignup
17
13

More than 3 years have passed since last update.

Elasticsearch で Learning-to-Rank を試してみた!

Last updated at Posted at 2019-12-21

この記事は、ただの集団 AdventCalendar 2019の21日目の記事です。

はじめに

担当日前日に「Elasticsearch で Learning-to-rank やりたいので、環境構築の手順とその使い方についてまとめてね。ヨロピコ!」と振られたので、今回は Elasticsearch with learning-to-rank の構築手順とその使い方を紹介します。

今回作成したものはコチラ

Learning-to-rank とは

検索エンジンにおける learning-to-rank とは、機械学習と検索するデータを使って、検索結果のランキングの順序を改善する手法のことです。順序学習やランキング学習とも呼ばれています。

今回は、Elasticsearch の learning-to-rank のプラグイン を使います。learning-to-rank のレポジトリにある demo を使って、ランキング改善を体験してみたいと思います。

環境構築

demo を試すために、事前に以下の環境構築をします。

プラグイン入り Elasticsearch の構築は、docker image を使うと楽です。

以下、Elasticsearch with Learning-to-Rank docker image のサンプル

FROM elasticsearch:7.4.1

RUN bin/elasticsearch-plugin install -b http://es-learn-to-rank.labs.o19s.com/ltr-1.1.2-es7.4.1.zip

環境構築後、Learning-to-Rank のレポジトリをクローンして demo ディレクトリに移動しましょう。

$ git clone https://github.com/o19s/elasticsearch-learning-to-rank.git
$ cd elasticsearch-learning-to-rank/demo

demo ディレクトリへ移動後、順番にスクリプトを実行して Learning-to-Rank を体験しましょう!

データとライブラリの準備

prepare.py を実行して、検索データと学習モデルを作成するライブラリ(Ranklib)をダウンロードします。

$ python prepare.py

実行すると、映画のデータ(tmdb.json)とランキング学習のライブラリ(RankLibPlus-0.1.0.jar)をダウンロードします。(tmdb.jsonはサイズが大きいのでダウンロードに時間がかかるので注意!)
ダウンロード完了後、Elasticsearch の環境を整えます。

Elasticsearch の環境を整える

Learning-to-Rank のプラグインを導入した Elasticsearch を立ち上げ、データを入れます。Elasticsearch 起動後、index_ml_tmdb.py を実行してインデックスの設定とデータの挿入を行います。以下のスクリプトを実行すると、tmdb.json を Elasticsearch にインサートします。

$ python index_ml_tmdb.py

インデックスの設定とデータの挿入が完了したら、次は学習に使う feature 変換のクエリを設定します。以下のスクリプトを実行すると、学習に使う field を設定します。(設定されるフィールドは demo/1.json と demo/2.json 参照。demo では、title と overview の検索スコアを feature として設定している。)

$ python load_features.py

データを feature に変換する field の準備ができたら、モデル作成を行います。

Elasticsearch にモデルをデプロイする

train.py を実行してモデルを作成して、Elasticsearch にデプロイします。

$ python train.py

train.py では、以下の処理が実行されます。

  • 前処理
    • sample_judgements.txt をパースして、ranklib format に変換する。
  • モデル生成
    • Ranklib を実行して、モデル作成を行います。
  • モデルのデプロイ
    • Easticsearch にモデルを導入する。

前処理

demo では、sample_judgements.txt を学習して、検索結果のランキングを改善します。
sample_judgements.txt は、検索クエリ(qid)に対する検索結果(#7555 Rambo, #1370 Rambo III, ...)を表しており、検索クエリと検索結果のペアごとに評価値(grade)を設定しています。demo では、以下3種のクエリがあります。

# qid:1: rambo
# qid:2: rocky
# qid:3: bullwinkle

各クエリの検索結果に対して、grade を設定します。(数字が大きいほど良い。)

# grade (0-4)   queryid docId   title
4   qid:1 # 7555    Rambo
3   qid:1 # 1370    Rambo III
3   qid:1 # 1369    Rambo: First Blood Part II
3   qid:1 # 1368    First Blood
0   qid:1 # 136278  Blood
0   qid:1 # 102947  First Daughter
0   qid:1 # 13969   First Daughter
0   qid:1 # 61645   First Love
0   qid:1 # 14423   First Sunday
0   qid:1 # 54156   First Desires
4   qid:2 # 1366    Rocky
3   qid:2 # 1246    Rocky Balboa
3   qid:2 # 60375   Rocky VI
3   qid:2 # 1371    Rocky III
3   qid:2 # 1375    Rocky V
3   qid:2 # 1374    Rocky IV
0   qid:2 # 110123  Incredible Rocky Mountain Race
0   qid:2 # 17711   The Adventures of Rocky & Bullwinkle
0   qid:2 # 36685   The Rocky Horror Picture Show
4   qid:3 # 17711   The Adventures of Rocky & Bullwinkle
0   qid:3 # 1246    Rocky Balboa
0   qid:3 # 60375   Rocky VI
0   qid:3 # 1371    Rocky III
0   qid:3 # 1375    Rocky V
0   qid:3 # 1374    Rocky IV

このデータを Ranklib Format に変換すると、以下のようなデータになります。

4       qid:1   1:12.318474     2:10.573917 # 7555      rambo
3       qid:1   1:10.357875     2:11.950391 # 1370      rambo
3       qid:1   1:7.010513      2:11.220095 # 1369      rambo
3       qid:1   1:0.0   2:11.220095 # 1368      rambo
0       qid:1   1:0.0   2:0.0 # 136278  rambo
0       qid:1   1:0.0   2:0.0 # 102947  rambo
0       qid:1   1:0.0   2:0.0 # 13969   rambo
0       qid:1   1:0.0   2:0.0 # 61645   rambo
0       qid:1   1:0.0   2:0.0 # 14423   rambo
0       qid:1   1:0.0   2:0.0 # 54156   rambo
4       qid:2   1:10.686391     2:8.814846 # 1366       rocky
3       qid:2   1:8.985554      2:9.984511 # 1246       rocky
3       qid:2   1:8.985554      2:8.067703 # 60375      rocky
3       qid:2   1:8.985554      2:5.660549 # 1371       rocky
3       qid:2   1:8.985554      2:7.300772 # 1375       rocky
3       qid:2   1:8.985554      2:8.814846 # 1374       rocky
0       qid:2   1:6.815921      2:0.0 # 110123  rocky
0       qid:2   1:6.0816855     2:8.725066 # 17711      rocky
0       qid:2   1:6.0816855     2:5.9764795 # 36685     rocky
4       qid:3   1:7.6720834     2:12.722421 # 17711     bullwinkle
0       qid:3   1:0.0   2:0.0 # 1246    bullwinkle
0       qid:3   1:0.0   2:0.0 # 60375   bullwinkle
0       qid:3   1:0.0   2:0.0 # 1371    bullwinkle
0       qid:3   1:0.0   2:0.0 # 1375    bullwinkle
0       qid:3   1:0.0   2:0.0 # 1374    bullwinkle

このデータを使ってモデル作成を行います。

モデル生成

モデルを作成する。demo では、以下のモデルが生成されます。

  • MART
  • RankNet
  • RankBoost
  • AdaRank
  • coord Ascent
  • LambdaMART
  • ListNET
  • Random Forest
  • Linear Regression

(各モデルの詳細について、今回は割愛します。)

モデルのアップロード

Elasticsearch にモデルをアップロードする。Post リクエストで生成したモデルをアップロードする。以下サンプル。

POST _ltr/_featureset/movie_features/_createmodel
{
    "model": {
        "name": "test_9",
        "model": {
            "type": "model/ranklib",
            "definition": "## Linear Regression\n## Lambda = 1.0E-10\n0:0.2943936467995844 1:0.2943936467995844 2:0.12167703031808977"
        }
    }
}

アップロードしたモデルを使って検索するときは、model.name を指定します。

検索する

実際に検索して、Learning-to-Rank による検索結果の改善を体験してみましょう!search.py を実行すると、以下の検索結果が得られます。

$ python search.py Rambo
{"query": {"multi_match": {"query": "Rambo", "fields": ["title", "overview"]}}, "rescore": {"query": {"rescore_query": {"sltr": {"params": {"keywords": "Rambo"}, "model": "test_6"}}}}}
Rambo
Rambo III
Rambo: First Blood Part II
First Blood
In the Line of Duty: The F.B.I. Murders
Son of Rambow
Spud 
$

わかりづらいので、Learning-to-Rank あり/なしを比較した結果を用意しました。それぞれ以下の結果が得られます。

## search with learning-to-rank
1 Rambo
2 Rambo III
3 Rambo: First Blood Part II
4 First Blood
5 In the Line of Duty: The F.B.I. Murders
6 Son of Rambow
7 Spud

## search without learning-to-rank
1 Rambo
2 Rambo III
3 First Blood
4 Rambo: First Blood Part II
5 In the Line of Duty: The F.B.I. Murders
6 Son of Rambow
7 Spud

学習結果が反映されてますね!!

まとめ

今回は、Elasticsearch で Learning-to-rank を試す手順の紹介と、Learning-to-Rank を検索エンジンに反映までやりました。今回使ったライブラリをお手軽に試せるようにレポジトリにまとめましたので、使っていただければ幸いです。
また、この記事では実行手順を紹介しましたが、機会があれば Learning-to-Rank の各ロジックや今回使ったライブラリの仕組みの詳細を紹介したいです。

17
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
13