我尝试在Elasticsearch中使用Learning-to-Rank!

此文是《集体 AdventCalendar 2019》的第21天文章。

首先

因为在最近的一天里,我被委托负责”我想在Elasticsearch上进行Learning-to-rank,所以请总结一下环境搭建的步骤和使用方法。拜托了!”所以这次我将介绍Elasticsearch与learning-to-rank的构建步骤和使用方法。

这次制作的是这个。

学习排序是指

在搜索引擎中,学习排序是一种利用机器学习和搜索数据来改善搜索结果排名顺序的方法。它也被称为顺序学习或排序学习。

这次,我们将使用 Elasticsearch 的 learning-to-rank 插件。我想通过使用 learning-to-rank 仓库中的示例,体验一下排序的改善。

环境建设

为了测试demo,我们需要事先进行以下环境搭建。

    • Java の実行環境

 

    • Python3 の実行環境

 

    • Elasticsearch に learning-to-rank プラグインを導入

https://github.com/elastic/elasticsearch
https://github.com/o19s/elasticsearch-learning-to-rank

使用带有插件的 Elasticsearch 的构建,使用 Docker 镜像会更方便。

    https://hub.docker.com/_/elasticsearch

以下是Elasticsearch带有Learning-to-Rank Docker镜像的示例。

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 存储库克隆并移动到演示目录下。

$ 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

完成设置索引和插入数据后,接下来需要设置用于学习的特征转换查询。执行以下脚本可设置用于学习的字段。(设置的字段可参考 demo/1.json 和 demo/2.json。在 demo 中,将标题和概述的搜索分数设置为特征。)

$ python load_features.py

當將數據準備好轉換為特徵欄位時,我們將開始建立模型。

将模型部署到Elasticsearch中

运行 train.py 脚本以创建模型,并将其部署到 Elasticsearch 中。

$ python train.py

在train.py文件中,将执行以下处理。

    • 前処理

sample_judgements.txt をパースして、ranklib format に変換する。

モデル生成

Ranklib を実行して、モデル作成を行います。

モデルのデプロイ

Easticsearch にモデルを導入する。

数据预处理 (Data preprocessing)

在demo中,我们将使用sample_judgements.txt进行学习,以改善搜索结果的排名。sample_judgements.txt包含了针对搜索查询(qid)的搜索结果(#7555 Rambo,#1370 Rambo III,…),并为每个搜索查询和搜索结果的组合设置了评分(grade)。demo中包含以下三种查询。

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

对于每个查询的搜索结果,请设置一个等级(数字越大越好)。

# 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 格式,将会得到以下数据。

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

我将使用这些数据来进行模型创建。

生成模型 mó

创建模型。在演示中,将生成以下模型。

    • 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 的各个逻辑以及本次使用的库的机制。

广告
将在 10 秒后关闭
bannerAds