es painless 排序_通过painless脚本控制elasticsearch搜索结果的评分 互联网技术圈 互联网技术圈...

本文介绍了如何通过Elasticsearch的Painless脚本控制搜索结果的评分,从而实现自定义排序。以用户信息索引为例,展示了如何编写脚本根据关键词在字段中的位置和字段长度来调整评分,最终通过`function_score`查询实现理想排序。
摘要由CSDN通过智能技术生成

14953425865573-300x199.jpg

为了控制搜索结果的相关度,elasticsearch 提供了多种方式,通过脚本实现自定义评分逻辑是终极方式。脚本返回一个评分值,该值再与原_score再进行加法等运算。脚本编写很简单,我们跟随一个例子(基于5.5版本)来看看如何通过脚本实现自定义排序。

创建 user_info索引,只有一个 name 字段,并且不分词:

PUT user_info

{

"mappings":{

"user": {

"properties": {

"name":{

"type":"keyword"

}

}

}

}

}

写入测试数据

POST /user_info/_bulk

{"index" : {"_type":"user","_id":"1"}}

{"name":"高波"}

{"index" : {"_type":"user","_id":"2"}}

{"name":"高大山"}

{"index" : {"_type":"user","_id":"3"}}

{"name":"闫高峰"}

{"index" : {"_type":"user","_id":"4"}}

{"name":"李高峰"}

{"index" : {"_type":"user","_id":"5"}}

{"name":"安建高"}

{"index" : {"_type":"user","_id":"6"}}

{"name":"高峰玉成"}

对于搜索结果,理想的顺序是:

高波

高大山

高峰玉成

李高峰

闫高峰

安建高

执行搜索:

GETuser_info/_search?size=20

{

"query": {

"query_string" : {

"query" : "(name:(*高*))"

}

}

}

返回结果如下:

{

"hits": {

"total": 6,

"max_score": 1.0,

"hits": [

{

"_index": "user_info",

"_type": "user",

"_id": "5",

"_score": 1.0,

"_source": {

"name": "安建高"

}

},

{

"_index": "user_info",

"_type": "user",

"_id": "AWIEksAoMnf4TVgYEH8P",

"_score": 1.0,

"_source": {

"name": "高峰玉成"

}

},

{

"_index": "user_info",

"_type": "user",

"_id": "2",

"_score": 1.0,

"_source": {

"name": "高大山"

}

},

{

"_index": "user_info",

"_type": "user",

"_id": "4",

"_score": 1.0,

"_source": {

"name": "李高峰"

}

},

{

"_index": "user_info",

"_type": "user",

"_id": "1",

"_score": 1.0,

"_source": {

"name": "高波"

}

},

{

"_index": "user_info",

"_type": "user",

"_id": "3",

"_score": 1.0,

"_source": {

"name": "闫高峰"

}

}

]

}

}

得分都是1.0,我们期望的返回顺序与两个原则有关:

1.关键词出现的位置越靠前,排序应该越靠前

2.字段值约短,说明匹配度越高,排序应该越靠前

下面我们通过脚本来实现自定义评分。

elasticsearch 支持多种脚本语言,经历各版本演变后,从5.0开始实现了自己专用的语言:Painless。Groovy已弃用,这次示例使用Painless实现,Painless是内置支持的。脚本内容可以通过多种途径传给 es,包括 rest 接口,或者放到 config/scripts目录等,默认开启情况如下:

script.inline: false

script.stored: false

script.file: true

通过本地文件的方式放置到 config/scripts 目录默认开启。脚本目录中放置的任何文件将在节点启动后自动编译。默认每60秒扫描一次,间隔时间通过 resource.reload.interval设置。编写脚本文件,命名为:user_info_score.painless

doubleposition_score = 0;

double similarity_score = 0;

int pos = doc['name'].value.indexOf(params.keyword);

if (pos != -1)

{

position_score = 10 - pos;

if (position_score < 0) position_score = 0;//出现位置大于10的忽略其重要性

}

double similarity = Math.abs(1.0*doc['name'].value.length() - params.keyword.length());

similarity_score = 10 - similarity;

if (similarity_score < 0) similarity_score = 0; //相似度差10个字符的忽略其重要性

//在下面调节各分值的权重

return position_score*0.6+similarity_score*0.4;

获取文档值:doc[‘name’].value

实现比较简单,根据位置和相似度分别计算评分,将结果乘不同权重再相加。

再次查询:

GETuser_info/_search?size=20

{

"query": {

"function_score": {

"query": {

"query_string": {

"query": "(name:(*高*))"

}

},

"script_score": {

"script": {

"lang": "painless",

"file": "user_info_score",

"params":{

"keyword":"高"

}

}

},

"boost_mode": "sum"

}

}

}

function_score 查询 是用来控制评分过程的终极武器,它允许为每个与主查询匹配的文档应用一个函数, 以达到改变甚至完全替换原始查询评分 _score 的目的。

script_score 用自定义脚本完全控制评分计算,实现所需逻辑

lang 指定脚本语言

inline, stored, file 指定脚本的源。 这里使用文件方式,脚本名称为:user_info_score 注意这里要去掉.painless扩展名

params 指定作为变量传递到脚本中的任何命名参数。

boost_mode 新计算的分数与_score的结合方式,取值可以是:

multiply 相乘(默认)

replace 替换_score

sum 相加

avg 取平均值

max 取最大值

min 取最小值

搜索结果:

{

"hits": {

"total": 6,

"max_score": 10.6,

"hits": [

{

"_index": "user_info",

"_type": "user",

"_id": "1",

"_score": 10.6,

"_source": {

"name": "高波"

}

},

{

"_index": "user_info",

"_type": "user",

"_id": "2",

"_score": 10.2,

"_source": {

"name": "高大山"

}

},

{

"_index": "user_info",

"_type": "user",

"_id": "AWIEksAoMnf4TVgYEH8P",

"_score": 9.8,

"_source": {

"name": "高峰玉成"

}

},

{

"_index": "user_info",

"_type": "user",

"_id": "4",

"_score": 9.6,

"_source": {

"name": "李高峰"

}

},

{

"_index": "user_info",

"_type": "user",

"_id": "3",

"_score": 9.6,

"_source": {

"name": "闫高峰"

}

},

{

"_index": "user_info",

"_type": "user",

"_id": "5",

"_score": 9.0,

"_source": {

"name": "安建高"

}

}

]

}

}

Painless语法参考链接:

https://www.elastic.co/guide/en/elasticsearch/painless/5.5/painless-syntax.html

https://www.elastic.co/guide/en/elasticsearch/painless/5.5/index.html

https://www.elastic.co/guide/en/elasticsearch/painless/5.5/painless-api-reference.html

其他:

https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html

https://www.elastic.co/guide/en/elasticsearch/reference/5.5/modules-scripting-using.html#modules-scripting-file-scripts

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值