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)
本文读到这,你应该已经对自定义打分的过程有了一个基本印象(query
原始分数、自定义函数得分、最终结果 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" } } } }