ES自定义搜索结果打分机制
Elasticsearch 虽提供强大搜索功能,但默认排序在复杂业务场景下渐显局限。电商需综合商品热度、评分等因素排序;新闻平台看重时效性与权威性;企业知识管理系统要考虑文档重要性等。Function Score Query 应运而生,它允许开发者依据业务规则自定义打分机制,实现精准个性化排序,以满足多样化需求,提升用户搜索体验与业务竞争力。
ES的query结果中的存在一个相关度得分score,默认按照score从高到低排序
Function score query可以实现对最终score的自定义打分
打分逻辑
三个名词概念, 本文中将会用到
- ES的默认打分 def_score
- 函数打分值 fun_score
- 最终文档排序使用的打分 ult_score
在不使用function score query的情况下 def_score 等于 ult_score
使用function score query后, ult_score的计算过程如下:
- 执行query获取 def_score
- 执行自定义的打分函数,每个文档获取一个新的打分值,记为 fun_score
- fun_score 和 def_score 按照某种计算方式(默认相乘),计算得出 ult_score
基本使用方式:
1 | POST index/_search |
计算方式由boost_mode定义
- multiply : 相乘(默认),ult_score = def_score * fun_score
- replace : 替换,ult_score = fun_score
- sum : 相加,ult_score = def_score + fun_score
- avg : 取两者的平均值,ult_score = Avg(def_score, fun_score)
- max : 取两者之中的最大值,ult_score = Max(def_score, fun_score)
- min : 取两者之中的最小值,ult_score = Min(def_score, fun_score)
打分函数
权重 weight
基本使用:
1 | POST index/_search |
这种方式会给所有匹配文档加权, 等于是将所有def_score进行了等比放大,并不会影响排序结果
通过filter去控制哪些文档进行加权
1 | POST index/_search |
这种情况下,只有brand_name 等于 西门子的文档的def_score会被加权, 这种方式可以让我们想要的文档排序是排到前面去
随机打分 random_score
random_score函数会生成 [0,1) 区间的随机数
基本使用
1 | POST index/_search |
这种情况下,每次的排序结果都会不同
如果在某些情况下需要同一用户的随机结果保持前后一致,可以通过为每个用户指定seed来实现
1 | POST index/_search |
这种写法可以实现我们上面的要求,但是es会报警告
大概意思为7.0之后,设置seed必须提供field参数
这是因为不设置field时,会使用Lucene doc ids作为随机源,会消耗大量内存
官方建议设置field为 _seq_no (索引序列号)
注意 : 如果索引进行了更新,则_seq_no也会进行更新,则随机数也会改变
1 | POST index/_search |
字段值打分 field_value_factor
使用文档中指定字段的值计算ult_score
比如brand表中有用于排序的sort字段,我们想要匹配文档按照sort字段进行排序,可以这么写
1 | POST index/_search |
- field : 指定字段
- factor : 乘积因子, 与指定字段值相乘, 默认为1
- 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)
在上面的写法中 , 假设文档A的 def_score = 0.8 , sort = 5
则 ult_score = 0.8 * ln( 1.5 * 5 ) = 1.612
衰减函数 decay_function
以某一数值(日期,数值,位置)作为中心点, 按照设置的比例逐渐衰减
基本使用
1 | POST index/_search |
三种函数 :
- linear :线性函数
- exp: 指数函数
- gauss: 高斯函数
参数含义:
- origin : 中心点 (数值, 日期 ,坐标 )
- scale : 到中心点的距离
- offset : 偏移量
- decay: 衰减指数
origin 等于 2000-01-05, scale 等于 10天
意味着 created_at 在 2000-01-01 到 2000-01-10 区间内的文档的权重为 1
created_at在 scale + offset = 15天 之外的文档的权重为0.5
script_score 脚本打分
自由度最高的一种打分函数
1 | POST index/_search |
使用 doc[‘field_name’].value 引用指定字段的值
source可以设置为任意的算法
<更新>
去除硬编码, 使用params参数使脚本更灵活,使source不用重复编译
1 | POST index/_search |
注意:脚本编译有频率限制,编译非常耗时,这是es的自我保护机制 ; 默认情况下,每 5 分钟最多可以编译 150 个脚本
调整方法:
1 | PUT _cluster/settings |
使用存储脚本的API来存储和检索脚本 , 存储的脚本可缩短编译时间并加快搜索速度。
1 | POST /_scripts/calc_score |
使用存储的脚本
1 |
|
删除
1 | DELETE _scripts/calc_score |