手工控制搜索结果精度

通常不加operator,表示的是or

  1. GET student/_search{
  2. "query":{
  3. "match":{
  4. "remark":{
  5. "query": "java developer",
  6. "operator": "and"
  7. }
  8. }
  9. }
  10. }

operator也可以用 “minimum_should_match” : 2

boost权重控制

人为的控制搜索条件在进行相关度分数计算时的权重大小。
比如搜索document中content字段内包含first的数据,如果content包含java或C++,则优先显示包含它们的数据,并且java的权重是C++的三倍。
boost权重控制一般用于搜索时搭配相关度排序使用。比如: 电商平台对商品进行综合排序。将一个商品的销量、广告费、评价值、库存、单价等信息进行比较并综合排序。排序时,库存的权重最低,广告费的权重最高。

  1. GET /test_sort/_search
  2. {
  3. "query": {
  4. "bool": {
  5. "must": [
  6. {
  7. "match": {
  8. "content": "first"
  9. }
  10. }
  11. ],
  12. "should": [
  13. {
  14. "match": {
  15. "content": {
  16. "query": "java",
  17. "boost": 3
  18. }
  19. }
  20. },
  21. {
  22. "match": {
  23. "content": {
  24. "query": "C++",
  25. "boost": 1
  26. }
  27. }
  28. }
  29. ]
  30. }
  31. }
  32. }

最佳字段 dismax

  1. PUT /my_index/my_type/1
  2. {
  3. "title": "Quick brown rabbits",
  4. "body": "Brown rabbits are commonly seen."
  5. }
  6. PUT /my_index/my_type/2
  7. {
  8. "title": "Keeping pets healthy",
  9. "body": "My quick brown fox eats rabbits on a regular basis."
  10. }

用户输入词组 “Brown fox” 然后点击搜索按钮。事先,我们并不知道用户的搜索项是会在 title 还是在 body 字段中被找到,但是,用户很有可能是想搜索相关的词组。用肉眼判断,文档 2 的匹配度更高,因为它同时包括要查找的两个词:
现在运行以下 bool 查询:

  1. {
  2. "query": {
  3. "bool": {
  4. "should": [
  5. { "match": { "title": "Brown fox" }},
  6. { "match": { "body": "Brown fox" }}
  7. ]
  8. }
  9. }
  10. }

但是我们发现查询的结果是文档 1 的评分更高:

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

为了理解导致这样的原因,需要回想一下 bool 是如何计算评分的:

  1. 它会执行 should 语句中的两个查询。
  2. 加和两个查询的评分。
  3. 乘以匹配语句的总数。
  4. 除以所有语句总数(这里为:2)。

文档 1 的两个字段都包含 brown 这个词,所以两个 match 语句都能成功匹配并且有一个评分。文档 2 的 body 字段同时包含 brown 和 fox 这两个词,但 title 字段没有包含任何词。这样, body 查询结果中的高分,加上 title 查询中的 0 分,然后乘以二分之一,就得到比文档 1 更低的整体评分。
在本例中, title 和 body 字段是相互竞争的关系,所以就需要找到单个 最佳匹配 的字段。
如果不是简单将每个字段的评分结果加在一起,而是将 最佳匹配 字段的评分作为查询的整体评分,结果会怎样?这样返回的结果可能是: 同时 包含 brown 和 fox 的单个字段比反复出现相同词语的多个不同字段有更高的相关度。

这里就出现了dis_max查询 (Disjunction Max Query)

分离最大化查询

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

得到我们想要的结果为:

  1. {
  2. "hits": [
  3. {
  4. "_id": "2",
  5. "_score": 0.21509302,
  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.12713557,
  14. "_source": {
  15. "title": "Quick brown rabbits",
  16. "body": "Brown rabbits are commonly seen."
  17. }
  18. }
  19. ]
  20. }

最佳字段优化tie_breaker

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

注意两个评分是完全相同的。


我们可能期望同时匹配 title 和 body 字段的文档比只与一个字段匹配的文档的相关度更高,但事实并非如此,因为 dismax 查询只会简单地使用 单个_ 最佳匹配语句的评分 _score 作为整体评分。
可以通过指定 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. }

结果如下:

  1. {
  2. "hits": [
  3. {
  4. "_id": "2",
  5. "_score": 0.14757764,
  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,
  14. "_source": {
  15. "title": "Quick brown rabbits",
  16. "body": "Brown rabbits are commonly seen."
  17. }
  18. }
  19. ]
  20. }

tie_breaker 参数提供了一种 dis_max 和 bool 之间的折中选择,它的评分方式如下:

  1. 获得最佳匹配语句的评分 _score 。
  2. 将其他匹配语句的评分结果与 tie_breaker 相乘。
  3. 对以上评分求和并规范化。

有了 tie_breaker ,会考虑所有匹配语句,但最佳匹配语句依然占最终结果里的很大一部分。

tie_breaker 可以是 0 到 1 之间的浮点数,其中 0 代表使用 dis_max 最佳匹配语句的普通逻辑, 1 表示所有匹配语句同等重要。最佳的精确值需要根据数据与查询调试得出,但是合理值应该与零接近(处于 0.1 - 0.4 之间),这样就不会颠覆 dis_max 最佳匹配性质的根本。