假设有个网站允许用户搜索博客的内容, 以下面两篇博客内容文档为例:
PUT /my_index/my_type/1
{
"title": "Quick brown rabbits",
"body": "Brown rabbits are commonly seen."
}
PUT /my_index/my_type/2
{
"title": "Keeping pets healthy",
"body": "My quick brown fox eats rabbits on a regular basis."
}
用户输入词组 “Brown fox” 然后点击搜索按钮。事先,我们并不知道用户的搜索项是会在 title
还是在 body
字段中被找到,但是,用户很有可能是想搜索相关的词组。用肉眼判断,文档 2 的匹配度更高,因为它同时包括要查找的两个词:
bool
查询
{
"query": {
"bool": {
"should": [
{ "match": { "title": "Brown fox" }},
{ "match": { "body": "Brown fox" }}
]
}
}
}
但是我们发现查询的结果是文档 1 的评分更高:
{
"hits": [
{
"_id": "1",
"_score": 0.14809652,
"_source": {
"title": "Quick brown rabbits",
"body": "Brown rabbits are commonly seen."
}
},
{
"_id": "2",
"_score": 0.09256032,
"_source": {
"title": "Keeping pets healthy",
"body": "My quick brown fox eats rabbits on a regular basis."
}
}
]
}
为了理解导致这样的原因, 需要回想一下 bool
是如何计算评分的:
- 它会执行
should
语句中的两个查询。 - 加和两个查询的评分。
- 乘以匹配语句的总数。
- 除以所有语句总数(这里为:2)。
文档 1 的两个字段都包含 brown
这个词,所以两个 match
语句都能成功匹配并且有一个评分。文档 2 的 body
字段同时包含 brown
和 fox
这两个词,但 title
字段没有包含任何词。这样, body
查询结果中的高分,加上 title
查询中的 0 分,然后乘以二分之一,就得到比文档 1 更低的整体评分。
最佳查询语句
{
"query": {
"dis_max": {
"queries": [
{ "match": { "title": "Quick pets" }},
{ "match": { "body": "Quick pets" }}
],
"tie_breaker": 0.3
}
}
}
dis_max
查询使用 单个 最佳匹配语句的评分_score
作为整体评分。
tie_breaker
将其他匹配语句的评分也考虑其中
dis_max
即分离 最大化查询(Disjunction Max Query) 。分离(Disjunction)的意思是 或(or) ,这与可以把结合(conjunction)理解成 与(and) 相对应。分离最大化查询(Disjunction Max Query)指的是: 将任何与任一查询匹配的文档作为结果返回,但只将最佳匹配的评分作为查询的评分结果返回 。
tie_breaker
参数提供了一种 dis_max
和 bool
之间的折中选择,它的评分方式如下:
- 获得最佳匹配语句的评分
_score
。 - 将其他匹配语句的评分结果与
tie_breaker
相乘。 - 对以上评分求和并规范化。
有了 tie_breaker
,会考虑所有匹配语句,但最佳匹配语句依然占最终结果里的很大一部分。
tie_breaker
可以是0
到1
之间的浮点数,其中0
代表使用dis_max
最佳匹配语句的普通逻辑,1
表示所有匹配语句同等重要。最佳的精确值需要根据数据与查询调试得出,但是合理值应该与零接近(处于0.1 - 0.4
之间),这样就不会颠覆dis_max
最佳匹配性质的根本。