前言
上一章介绍了 Elasticsearch 的读写优化技巧。本章将深入探讨与 Elasticsearch 相关的 BM25 相关性评分公式。
我们将全面解析 BM25 如何在查询时影响文档评分。BM25 是 Elasticsearch 的核心内容之一,内容可能较为难懂,请耐心阅读。
分片对 Elasticsearch 相关性评分的影响
默认情况下,文档的评分是基于当前分片进行计算的。即,同一个 term 在不同的分片上评分会不一致。
我们来看下面这个例子。
创建一个 test_22
索引,并将分片数设置为 3
GET test_22/_search
{
"explain": true,
"query": {
"match": {
"name": "hello"
}
}
}
紧接着,我们写入 3 条数据
PUT test_22/_doc/1
{
"name": "hello es"
}
PUT test_22/_doc/2
{
"name": "hello php"
}
PUT test_22/_doc/4
{
"name": "hello world p"
}
OK,现在让我们来搜索 hello
GET test_22/_search
{
"query": {
"match": {
"name": "hello"
}
}
}
结果可能会让你感到意外。
文档1的得分为0.2876821,文档2得分为0.19856803,文档4得分为0.16853255。
是不是感到困惑?文档1和文档2的结构相似,为什么文档1的得分更高呢?而文档4仅仅多了一个 P,它的得分却是最低的?
文档1为什么比文档2得分更高?
因为文档1 在分片2上,文档2、文档4在分片1上。这就是我上述所说的,得分是基于文档所在分片计算的。这与逆文档词频有关,下文会介绍。
查询参数最外层,添加 "explain": true
,即可看到文档所在分片。
GET test_22/_search
{
"explain": true,
"query": {
"match": {
"name": "hello"
}
}
}
文档2为什么比文档4得分更高?
文档2和文档4在同一个分片中,但是文档2的平均长度小于文档4。因此,文档2的得分比文档4更高。
简单来说:在一句话中出现 hello
的权重要高于在一段话中出现 hello
的权重。
这里提到的平均长度是以
term
为维度进行计算的。例如,文档2的平均长度为2,而文档4的平均长度为3。
BM25 算法和它的变量
上面提到的例子根源于 BM25 公式。接下来,我将重点介绍 BM25 公式的相关内容。
ES 的评分使用以下公式:
接下来,我将逐一介绍公式中的每个参数。
-
q i q_i qi
表示当前查询的第几个term
。例如,我们搜索hello world
,它包含 2 个term
:
hello
对应 q 0 q_0 q0,world
对应 q 1 q_1 q1。 -
I D F ( q i ) IDF(q_i) IDF(qi)
逆文档词频 (Inverse Document Frequency),其计算公式为:
l n ( 1 + ( d o c C o u n t − f ( q i ) + 0.5 ) f ( q i ) + 0.5 ) ln(1+\frac{(docCount - f(q_i) + 0.5)}{f(q_i) + 0.5})