elasticsearch基础评分细则explain解析

基础score计算公式

词频

词频是指词在文档中出现的频率,频率越高权重越高
公式:
tf(t in d) = √frequency

在文档d中t出现的次数,具体值是开根号过后的

逆向文档频率

词在集合所有文档中出现的评率,出现次数越多权重越低(词的稀有度)
idf(t) = 1 + log ( numDocs / (docFreq + 1))

numDocs : 索引中文档数量
docFreq : 所有包含该词的文档数

字段长度归一值

字段越短,字段的权重 越高

norm(d) = 1 / √numTerms

字段长度归一值( norm )是字段中词数平方根的倒数。

索引时字段层权重提升

查询权重提升可以用 boost 关键字,但是也可以在建立索引时就直接提升权重,不建议这样做。

查询归一因子(queryNorm)

把不同查询结果比较,计算termd对于整个query的重要性。让稀少的term相对于大众化的term更高。但是在排序按官方的说法可以不去管它

查询协调因子 (coord)

这个的作用是匹配到的词越多,权重越高(虽然相加也是一样的,但是这种算法拉开了命中数量间的权重差距)

可以为那些查询词包含度高的文档提供奖励,文档里出现的查询词越多,它越有机会成为好的匹配结果。

设想查询 quick brown fox ,每个词的权重都是 1.5 。如果没有协调因子,最终评分会是文档里所有词权重的总和。例如:

文档里有 fox → 评分: 1.5
文档里有 quick fox → 评分: 3.0
文档里有 quick brown fox → 评分: 4.5
协调因子将评分与文档里匹配词的数量相乘,然后除以查询里所有词的数量,如果使用协调因子,评分会变成:

文档里有 fox → 评分: 1.5 * 1 / 3 = 0.5
文档里有 quick fox → 评分: 3.0 * 2 / 3 = 2.0
文档里有 quick brown fox → 评分: 4.5 * 3 / 3 = 4.5
协调因子能使包含所有三个词的文档比只包含两个词的文档评分要高出很多

查询时权重提升 (t.getBoost)

提升某一个查询语句的重要度默认为1,boost参数设置

实用评分函数

1
2
3
4
5
6
7
8
9
score(q,d)  =  
queryNorm(q) ........................ 查询归一因子
· coord(q,d) ........................ 查询协调因子
· ∑ ( ........................ 西格玛求和
tf(t in d) ...................... 词频
· idf(t)² ...................... 逆向词频
· t.getBoost() .................... 权重提升
· norm(t,d) .......................字段长度归一值
) (t in q)

实际应用调整

在实际使用过程中我们应该善用explain可以清晰的看见打分的规则

比如这个索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
GET index_name/_search?explain=true&format=yaml
{
"from" : 0,
"size": 1,
"query": {
"function_score": {
"query": {
"bool": {
"must": {
"multi_match": {
"query": "双11海报",
"type": "best_fields",
"fields": [
"title",
"keyword^0.01"
],
"minimum_should_match": "70%"
}
},
"filter": []
}
},
"functions": [
{
"field_value_factor": {
"field": "cl_num",
"modifier": "log1p",
"factor": 1.1
}
},
{
"field_value_factor": {
"field": "dl_num",
"modifier": "log1p",
"factor": 1.1
}
},
{
"gauss":
{
"mtime":
{
"origin":"now",
"offset":"1d",
"scale":"1d"
}
}
}
],

"max_boost" : 20
}
}
}

总评分

截图中可以看见这个素材的综合评分是 96.66913

它是由一个基础的 source 乘上一个系数得出的

乘可以通过修改boost_mode改成其他的算法

1
2
3
4
5
6
7
8
9
10
11

multiply
评分 _score 与函数值的积(默认)
sum
评分 _score 与函数值的和
min
评分 _score 与函数值间的较小值
max
评分 _score 与函数值间的较大值
replace
函数值替代评分 _score

source评分

因为我们 fields 的是2个字段所以,这里分别对 title和keyword评分,keyword是乘上了系数后的结果

max of 取最大评分这个值也可以通过修改 "type": "best_fields", 为其它值来控制比如相加。

点开title的评分细则可以看见

title评分11.724932,它是3个因子相加得出的。这3个因子是我们的搜索词 双11海报 分词后的 双,11,海报 分别进行计算得到的,再继续展开可以发现termd在整个query中查询其实就是 tf+idf+boost得出的。
ps:tf/idf是整个搜索算法的灵魂,相应的公式也是有学术论文进行讲解的,高版本的es会使用bm25

自定义系数评分

其实这个 自定义系数评分 是我杜撰的一个名字,它是非关键词搜索评分,但是我感觉前者更容易理解。
从截图中可以看见这个评分也是由3个因子相加得出的,通过max_boost 我限制了他的最大值是20。这3个因子分别是我们查询语句中的 functions 里面的 field_value_factor 评分和 gauss 评分展开它们都有详细的公式

分阶段性我终结了下我这个query语句它的大体打分公式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

默认多词匹配公式
_source =
max(
(title = ∑(
boost +
idf +
tf
) (t in q)
)
,
(keyword = ∑(
boost +
idf +
tf
) (t in q)

)

素材关键词权重
_source =
max(
(title = ∑(
boost +
idf +
tf
) (t in q)
)
,
(keyword = ∑(
boost +
idf +
tf
) (t in q)
)*素材关键词权重
)

作品热度权重调整

_source * min((收藏权重*下载权重), 20)

收藏权重 = log1p(收藏数 * 收藏权重参数)
下载权重 = log1p(下载数 * 下载权重参数)



时间周期权重(高斯函数)

_source * min((收藏权重*下载权重*时间周期权重), 20)

时间周期权重会在 `最大权重天数` 内保持为整数 1
`最大权重天数` 以外左右偏移 `衰减天数` 逐步为0

在实际生产过程中我们需要不断的去尝试这里面可以认为控制的可变因子,然后找到最合适项目中可以使用的值,我做了一个这样的工具方便运营调整参数直观的看见结果。

参考

https://www.elastic.co/guide/cn/elasticsearch/guide/current/practical-scoring-function.html#query-norm

queryNorm
https://gist.github.com/softwaredoug/938f1bdf8d13a5145215

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

请我喝杯咖啡吧~