最佳字段查询的调优

如果用户(((“multifield search”, “best fields queries”, “tuning”)))(((“best fields queries”, “tuning”)))搜索的是”quick pets”,那么会发生什么呢?两份文档都包含了单词quick,但是只有文档2包含了单词pets。两份文档都没能在一个字段中同时包含搜索的两个单词。

一个像下面那样的简单dis_max查询会选择出拥有最佳匹配字段的查询子句,而忽略其他的查询子句:

  1. {
  2. "query": {
  3. "dis_max": {
  4. "queries": [
  5. { "match": { "title": "Quick pets" }},
  6. { "match": { "body": "Quick pets" }}
  7. ]
  8. }
  9. }
  10. }

// SENSE: 110_Multi_Field_Search/15_Best_fields.json

  1. {
  2. "hits": [
  3. {
  4. "_id": "1",
  5. "_score": 0.12713557, <1>
  6. "_source": {
  7. "title": "Quick brown rabbits",
  8. "body": "Brown rabbits are commonly seen."
  9. }
  10. },
  11. {
  12. "_id": "2",
  13. "_score": 0.12713557, <1>
  14. "_source": {
  15. "title": "Keeping pets healthy",
  16. "body": "My quick brown fox eats rabbits on a regular basis."
  17. }
  18. }
  19. ]
  20. }

<1> 可以发现,两份文档的分值是一模一样的。

我们期望的是同时匹配了title字段和body字段的文档能够拥有更高的排名,但是结果并非如此。需要记住:dis_max查询只是简单的使用最佳匹配查询子句得到的_score。

tie_breaker

但是,将其它匹配的查询子句考虑进来也是可能的。通过指定tie_breaker参数:

  1. {
  2. "query": {
  3. "dis_max": {
  4. "queries": [
  5. { "match": { "title": "Quick pets" }},
  6. { "match": { "body": "Quick pets" }}
  7. ],
  8. "tie_breaker": 0.3
  9. }
  10. }
  11. }

// SENSE: 110_Multi_Field_Search/15_Best_fields.json

它会返回以下结果:

  1. {
  2. "hits": [
  3. {
  4. "_id": "2",
  5. "_score": 0.14757764, <1>
  6. "_source": {
  7. "title": "Keeping pets healthy",
  8. "body": "My quick brown fox eats rabbits on a regular basis."
  9. }
  10. },
  11. {
  12. "_id": "1",
  13. "_score": 0.124275915, <1>
  14. "_source": {
  15. "title": "Quick brown rabbits",
  16. "body": "Brown rabbits are commonly seen."
  17. }
  18. }
  19. ]
  20. }

<1> 现在文档2的分值比文档1稍高一些。

tie_breaker参数会让dis_max查询的行为更像是dis_max和bool的一种折中。它会通过下面的方式改变分值计算过程:

  • 1.取得最佳匹配查询子句的_score。
  • 2.将其它每个匹配的子句的分值乘以tie_breaker。
  • 3.将以上得到的分值进行累加并规范化。

通过tie_breaker参数,所有匹配的子句都会起作用,只不过最佳匹配子句的作用更大。

提示:tie_breaker的取值范围是0到1之间的浮点数,取0时即为仅使用最佳匹配子句(译注:和不使用tie_breaker参数的dis_max查询效果相同),取1则会将所有匹配的子句一视同仁。它的确切值需要根据你的数据和查询进行调整,但是一个合理的值会靠近0,(比如,0.1 -0.4),来确保不会压倒dis_max查询具有的最佳匹配性质。