插入这样两组数据 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." }
使用搜索语句
{ "query": { "bool": { "should": [ { "match": { "title": "Brown fox" }}, { "match": { "body": "Brown fox" }} ] } } }
理论上2文档的其实是我们需要的,但是搜索出的结果是
{ "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
子句中的两个查询文档1在两个字段中都包含了brown
,因此两个match
查询都匹配成功并拥有了一个分值。文档2在body
字段中包含了brown
以及fox
,但是在title
字段中没有出现任何搜索的单词。因此对body
字段查询得到的高分加上对title
字段查询得到的零分,然后在乘以匹配的查询子句数量1,最后除以总的查询子句数量2,导致整体分值比文档1的低。
在这个例子中,title
和body
字段是互相竞争的。我们想要找到一个最佳匹配(Best-matching)的字段。
如果我们不是合并来自每个字段的分值,而是使用最佳匹配字段的分值作为整个查询的整体分值呢?这就会让包含有我们寻找的两个单词的字段有更高的权重,而不是在不同的字段中重复出现的相同单词。
相比使用bool
查询,我们可以使用dis_max
查询(Disjuction Max Query)。Disjuction的意思"OR"(而Conjunction的意思是"AND"),因此Disjuction Max Query的意思就是返回匹配了任何查询的文档,并且分值是产生了最佳匹配的查询所对应的分值:
{ "query": { "dis_max": { "queries": [ { "match": { "title": "Brown fox" }}, { "match": { "body": "Brown fox" }} ] } } }
它会产生我们期望的结果:
{ "hits": [ { "_id": "2", "_score": 0.21509302, "_source": { "title": "Keeping pets healthy", "body": "My quick brown fox eats rabbits on a regular basis." } }, { "_id": "1", "_score": 0.12713557, "_source": { "title": "Quick brown rabbits", "body": "Brown rabbits are commonly seen." } } ] }
如果用户搜索的是"quick pets",那么会发生什么呢?两份文档都包含了单词quick
,但是只有文档2包含了单词pets
。两份文档都没能在一个字段中同时包含搜索的两个单词。
一个像下面那样的简单dis_max
查询会选择出拥有最佳匹配字段的查询子句,而忽略其他的查询子句:
{ "query": { "dis_max": { "queries": [ { "match": { "title": "Quick pets" }}, { "match": { "body": "Quick pets" }} ] } } }
{ "hits": [ { "_id": "1", "_score": 0.12713557, "_source": { "title": "Quick brown rabbits", "body": "Brown rabbits are commonly seen." } }, { "_id": "2", "_score": 0.12713557, "_source": { "title": "Keeping pets healthy", "body": "My quick brown fox eats rabbits on a regular basis." } } ] }
可以发现,两份文档的分值是一模一样的。
我们期望的是同时匹配了title
字段和body
字段的文档能够拥有更高的排名,但是结果并非如此。需要记住:dis_max
查询只是简单的使用最佳匹配查询子句得到的_score
。
但是,将其它匹配的查询子句考虑进来也是可能的。通过指定tie_breaker
参数:
{ "query": { "dis_max": { "queries": [ { "match": { "title": "Quick pets" }}, { "match": { "body": "Quick pets" }} ], "tie_breaker": 0.3 } } }
它会返回以下结果:
{ "hits": [ { "_id": "2", "_score": 0.14757764, "_source": { "title": "Keeping pets healthy", "body": "My quick brown fox eats rabbits on a regular basis." } }, { "_id": "1", "_score": 0.124275915, "_source": { "title": "Quick brown rabbits", "body": "Brown rabbits are commonly seen." } } ] }
现在文档2的分值比文档1稍高一些。
tie_breaker
参数会让dis_max
查询的行为更像是dis_max
和bool
的一种折中。它会通过下面的方式改变分值计算过程:
_score
。tie_breaker
。通过tie_breaker
参数,所有匹配的子句都会起作用,只不过最佳匹配子句的作用更大。