elasticsearch自定义打分操作
ES 自定义打分
Elasticsearch 会为 query 的每个文档计算一个相关度得分 score ,并默认按照 score 从高到低的顺序返回搜索结果。 在很多场景下,我们不仅需要搜索到匹配的结果,还需要能够按照某种方式对搜索结果重新打分排序。例如:
- 搜索具有某个关键词的文档,同时考虑到文档的时效性进行综合排序。
- 搜索某个旅游景点附近的酒店,同时根据距离远近和价格等因素综合排序。
- 搜索标题包含 elasticsearch 的文章,同时根据浏览次数和点赞数进行综合排序。
Function score query 就可以让我们实现对最终 score 的自定义打分。
score 自定义打分过程
为了方便,下面把 ES 对 query
匹配的文档进行打分得到的 score 记为 query_score
,而最终搜索结果的 score 记为 result_score
,显然,一般情况下(也就是不使用自定义打分时),result_score
就是 query_score
。
那么当我们使用了自定义打分之后呢?最终结果的 score 即 result_score
的计算过程如下:
1.跟原来一样执行 query
并且得到原来的 query_score
。
2.执行设置的自定义打分函数,并为每个文档得到一个新的分数,本文记为 func_score
。
3.最终结果的分数 result_score
等于 query_score
与 func_score
按某种方式计算的结果(默认是相乘)。
例如,搜索标题包含 elasticsearch 的文档。
不使用自定义打分,则搜索形如:
GET /_search
{"query": {"match": {"title": "elasticsearch"}}
}
假设我们最终得到了三个搜索结果,score 分别是 0.3、0.2、0.1
。
使用自定义打分,即 function_score
,则语法形如:
GET /_search
{"query": {"function_score": {"query": {"match": {"title": "elasticsearch"}}<!-- 设置自定义打分函数,这里先省略,后面再展开讲解 -->"boost_mode": "multiply"}}
}
最终搜索结果 score 的计算过程就是:
1.执行 query
得到原始的分数,与上文假设对应,即 query_score
分别是 0.3、0.2、0.1
。
2.执行自定义的打分函数,这一步会为每个文档得到一个新的分数,假设新的分数即 func_score
分别是 1、3、5
。
3.最终结果的 score 分数即 result_score
= query_score
* func_score
,对应假设的三个搜索结果最终的 score 分别就是 0.3 * 1 = 0.3
、0.2 * 3 = 0.6
、0.1 * 5 = 0.5
,至此我们完成了新的打分过程,而搜索结果也会按照最终的 score 降序排列。
最终的分数 result_score
是由 query_score
与 func_score
进行计算而来,计算方式由参数 boost_mode
定义:
•multiply
: 相乘(默认),result_score = query_score * function_score
•replace
: 替换,result_score = function_score
•sum
: 相加,result_score = query_score + function_score
•avg
: 取两者的平均值,result_score = Avg(query_score, function_score)
•max
: 取两者之中的最大值,result_score = Max(query_score, function_score)
•min
: 取两者之中的最小值,result_score = Min(query_score, function_score)
function_score 打分函数
function_score
提供了以下几种打分的函数:
•weight
: 加权。
•random_score
: 随机打分。
•field_value_factor
: 使用字段的数值参与计算分数。
•decay_function
: 衰减函数 gauss, linear, exp 等。
•script_score
: 自定义脚本。
weight
weight
加权,也就是给每个文档一个权重值。
示例:
{"query": {"function_score": {"query": { "match": { "message": "elasticsearch" } },"weight": 5}}
}
例子中的 weight 是 5 ,即自定义函数得分 func_score
= 5 ,最终结果的 score 等于 query_score
* 5 。
当然这个示例将匹配项全部加权并不会改变搜索结果顺序,我们再看一个例子:
{"query": {"function_score": {"query": { "match": { "message": "elasticsearch" } },"functions": [{"filter": { "match": { "title": "elasticsearch" } },"weight": 5}]}}
}
我们可以通过 filter
去限制 weight
的作用范围,另外我们可以在 functions
中同时使用多个打分函数。
random_score
random_score
随机打分,生成 [0, 1) 之间均匀分布的随机分数值。
示例:
GET /_search
{"query": {"function_score": {"random_score": {}}}
}
虽然是随机值,但是有时候我们需要随机值保持一致,比如所有用户都随机产生搜索结果,但是同一个用户的随机结果前后保持一致,这时只需要为同一个用户指定相同的 seed
即可。
示例:
{"query": {"function_score": {"random_score": {"seed": 10,"field": "_seq_no"}}}
}
默认情况下,即不设置 field
时会使用 Lucene doc ids 作为随机源去生成随机值,但是这会消耗大量内存,官方建议可以设置 field
为 _seq_no
,主要注意的是,即使指定了相同的 seed
,随机值某些情况下也会改变,这是因为一旦字段进行了更新,_seq_no
也会更新,进而导致随机源发生变化。
多个函数组合示例:
GET /_search
{"query": {"function_score": {"query": { "match_all": {} },"boost": "5","functions": [{"filter": { "match": { "test": "bar" } },"random_score": {},"weight": 23},{"filter": { "match": { "test": "cat" } },"weight": 42}],"max_boost": 42,"score_mode": "max","boost_mode": "multiply","min_score": 42}}
}
上例 functions
中设置了两个打分函数:
- 一个是
random_score
随机打分,并且weight
是 23 - 另一个只有
weight
是 42
假设:
•第一个函数随机打分得到了 0.1 ,再与 weight
相乘就是 2.3
•第二个函数只有 weight
,那么这个函数得到的分数就是 weight
的值 42
score_mode
设置为了 max
,意思是取两个打分函数的最大值作为 func_score
,对应上述假设也就是 2.3 和 42 两者中的最大值,即 func_score
= 42
boost_mode
设置为了 multiply
,就是把原来的 query_score
与 func_score
相乘就得到了最终的 score 分数。
参数 score_mode
指定多个打分函数如何组合计算出新的分数:
•multiply
: 分数相乘(默认)
•sum
: 相加
•avg
: 加权平均值
•first
: 使用第一个 filter 函数的分数
•max
: 取最大值
•min
: 取最小值
为了避免新的分数的数值过高,可以通过 max_boost
参数去设置上限。
需要注意的是:不论我们怎么自定义打分,都不会改变原始 query
的匹配行为,我们自定义打分,都是在原始 query
查询结束后,对每一个匹配的文档进行重新算分。
为了排除掉一些分数太低的结果,我们可以通过 min_score
参数设置最小分数阈值。
field_value_factor
field_value_factor
使用字段的数值参与计算分数。
例如使用 likes
点赞数字段进行综合搜索:
{"query": {"function_score": {"query": { "match": { "message": "elasticsearch" } },"field_value_factor": {"field": "likes","factor": 1.2,"missing": 1,"modifier": "log1p"}}}
}
说明:
•field
: 参与计算的字段。
•factor
: 乘积因子,默认为 1 ,将会与 field
的字段值相乘。
•missing
: 如果 field
字段不存在则使用 missing
指定的缺省值。
•modifier
: 计算函数,为了避免分数相差过大,用于平滑分数,可以是以下之一:
•none
: 不处理,默认
•log
: log(factor * field_value)
•log1p
: log(1 + factor * field_value)
•log2p
: log(2 + factor * field_value)
•ln
: ln(factor * field_value)
•ln1p
: ln(1 + factor * field_value)
•ln2p
: ln(2 + factor * field_value)
•square
: 平方,(factor * field_value)^2
•sqrt
: 开方,sqrt(factor * field_value)
•reciprocal
: 求倒数,1/(factor * field_value)
假设某个匹配的文档的点赞数是 1000 ,那么例子中其打分函数生成的分数就是 log(1 + 1.2 * 1000)
,最终的分数是原来的 query 分数与此打分函数分数相差的结果。
decay_function
decay_function
衰减函数,例如:
•以某个数值作为中心点,距离多少的范围之外逐渐衰减(缩小分数)•以某个日期作为中心点,距离多久的范围之外逐渐衰减(缩小分数)
•以某个地理位置点作为中心点,方圆多少距离之外逐渐衰减(缩小分数)
示例:
"DECAY_FUNCTION": {"FIELD_NAME": {"origin": "30, 120","scale": "2km","offset": "0km","decay": 0.33}
}
上例的意思就是在距中心点方圆 2 公里之外,分数减少到三分之一(乘以 decay 的值 0.33)。
•DECAY_FUNCTION
可以是以下任意一种函数:
•linear
: 线性函数
•exp
: 指数函数
•gauss
: 高斯函数
•origin
: 中心点,只能是数值、日期、geo-point
•scale
: 定义到中心点的距离
•offset
: 偏移量,默认 0
•decay
: 衰减指数,默认是 0.5
示例:
GET /_search
{"query": {"function_score": {"gauss": {"@timestamp": {"origin": "2013-09-17","scale": "10d","offset": "5d","decay": 0.5}}}}
}
中心点是 2013-09-17 日期,scale 是 10d 意味着日期范围是 2013-09-12 到 2013-09-22 的文档分数权重是 1 ,日期在 scale + offset = 15d 之外的文档权重是 0.5 。
如果参与计算的字段有多个值,默认选择最靠近中心点的值,也就是离中心点的最近距离,可以通过 multi_value_mode
设置:
•min
: 最近距离
•max
: 最远距离
•avg
: 平均距离
•sum
: 所有距离累加
示例:
GET /_search
{"query": {"function_score": {"query": {"match": {"properties": "大阳台"}},"functions": [{"gauss": {"price": {"origin": "0","scale": "2000"}}},{"gauss": {"location": {"origin": "30, 120","scale": "2km"}}}],"score_mode": "multiply"}}
}
假设这是搜索大阳台的房源,上例设置了 price 价格字段的中心点是 0 ,范围 2000 以内,以及 location 地理位置字段的中心点是 “30, 120” ,方圆 2km 之内,在这个范围之外的匹配结果的 score 分数会进行高斯衰减,即打分降低。
script_score
script_score
自定义脚本打分,可以直接编写脚本打分。
示例:
GET /_search
{"query": {"function_score": {"query": {"match": { "message": "elasticsearch" }},"script_score": {"script": {"source": "Math.log(2 + doc['my-int'].value)"}}}}
}
在脚本中通过 doc['field']
的形式去引用字段,doc['field'].value
就是使用字段值。
可以把额外的参数与脚本内容分开:
GET /_search
{"query": {"function_score": {"query": {"match": { "message": "elasticsearch" }},"script_score": {"script": {"params": {"a": 5,"b": 1.2},"source": "params.a / Math.pow(params.b, doc['my-int'].value)"}}}}
}
本文原创作者:奇想派、一名努力分享的程序员。
文章首发平台:微信公众号【编程达人】
原创不易!各位小伙伴觉得文章不错的话,不妨关注公众号,进行点赞(在看)、转发三连走起!谢谢大家!
elasticsearch自定义打分操作相关推荐
- ElasticSearch painless脚本实现自定义打分排序
背景: 遇到了这样一个需求,对于历史购买的商品优先排序 自定义打分排序规则 自定义打分规则,其实就是可以根据打分规则进行排序.注意:只能对索引的keyword属性进行排序,TEXT类型的要加.keyW ...
- 【Elasticsearch】Elasticsearch自定义评分的N种方法
1.概述 首先参考文章:[Elasticsearch]Elasticsearch 相关度评分 TF&IDF 然后转载文章:实战 | Elasticsearch自定义评分的N种方法 2.三个问题 ...
- ElasticSearch自定义词库
由于网络词语层出不穷,ik分词器有时并不能完全识别网络词汇,如下: 按照网络词语,王者荣耀应该被识别为一个词语,而不是被拆分成2个. 所以这时需要自定义词库来解决以上问题. 自定义词库 自定义扩展词库 ...
- Hadoop集群中增加与ElasticSearch连接的操作
在没有引入elasticsearch-hadoop-xxx.jar相应的Jar包时,的在Hive中执行ElasticSearch外部表操作,会报如下的异常: Exception in thread & ...
- elasticsearch 自定义_id
elasticsearch 自定义ID: curl -s -XPUT localhost:9200/web -d ' {"mappings": {"blog": ...
- ant4 多个form 验证_ant-design表单处理和常用方法及自定义验证操作
首先要说一下antdesign这个框架API和demo丰富,而且开发环境提供对应的warning来纠正用户的错误.是一个很好的组件库. 关于表单验证方面是依赖于 async-validator 库.百 ...
- 【Elasticsearch】打分策略详解与explain手把手计算
一.目的 一个搜索引擎使用的时候必定需要排序这个模块,一般情况下在不选择按照某一字段排序的情况下,都是按照打分的高低进行一个默认排序的,所以如果正式使用的话,必须对默认排序的打分策略有一个详细的了解才 ...
- 【Es】ElasticSearch 自定义分词器
1.分词器 转载:https://blog.csdn.net/gwd1154978352/article/details/83343933 分词器首先看文章:[Elasticsearch]Elasti ...
- vue页面返回消息头获取_vue在响应头response中获取自定义headers操作
日常开发,我们可能会为了安全问题,保证第三方无法通过伪造返回报文欺骗前端,需要在返回报文中添加自定义参数,用于验证身份,后端添加自定义参数,前端校验自定义参数通过后才会执行相应的操作. 系统为了安全会 ...
最新文章
- 局域网交换(交换机三大原理.基本配置)
- ACID、数据库隔离级别
- python 内置模块 增加_模块的内置方法--Python提高班
- The jar file has no source attachment
- 这怕是我看过的最好的关于 “ 拜占庭将军问题 ” 的文章
- python windows 安装scrapy_Windows下安装Scrapy
- linux db2创建存储过程语法,EF基础一-db2存储过程中循环语句while do...-oracle 创建DBLINK_169IT.COM...
- 东北大哥在线反套路hhhhhh | 今日最佳
- 用OpenStack构建南方电网广东公司能源云
- 厉害了网页扫码,所有方法都给你总结到这了,赶紧收藏
- 玩转Kinetis之教你将K60主频超到200MHz以上
- 如何用计算机解一元三次方程,利用Excel电子表格解一元三次方程
- Windows许可证过期(‘slmgr.vbs‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件)
- 串口转以太网服务器市场现状研究分析与发展前景预测报告
- 戴尔7040linux改装win7,戴尔OptiPlex 3060台式机win10改win7系统(完美支持usb)
- 怎么批量删除群共享里的文件
- CnPeng杂说:油条的来历
- 计算机教学反思杂文,懒教学反思随笔
- 职业教育/培训研究报告(精选七篇)
- 2022 IDC报告出炉 思腾合力一举拿下全国服务器市场双项榜单
热门文章
- 【Go语言入门100题】038 新世界 (5 分) Go语言|Golang
- NBA常规赛总抢断排行榜(数据截止至11年4月14日)
- 【原创】MacOS 安装 homebrew-cask
- 廖雪峰python教程学习之习题解析
- 仿京东、饿了么 左右联动菜单列表自定义View
- 独家 | PHM数据竞赛首个中国夺冠团队经验分享(常用模型赛题详解PPT视频)...
- 微信6.5.7手机号码如何解绑
- 有赞android电话面试,有赞校招面试总结
- 9岁有赞:新零售业务快速增长 推新品牌扶持计划
- 分鱼问题c语言,五人分鱼问题(附答案)