zoukankan      html  css  js  c++  java
  • ElasticSearch 之 dis_max tie_break的应用

    1. 插入数据

    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."
    }

    2. 搜索

    {
        "query": {
            "bool": {
                "should": [
                    { "match": { "title": "Brown fox" }},
                    { "match": { "body":  "Brown fox" }}
                ]
            }
        }
    }

    3. 结果

    {
      "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."
            }
         }
      ]
    }

      理论上 2 的文档其实是我们需要的,但是搜索的结果不是。要理解原因,需要知道 bool 查询时如何计算得到其分值的:

    1. 运行should子句中的两个查询
    2. 相加查询返回的分值
    3. 将相加得到的分值乘以匹配的查询子句的数量
    4. 除以总的查询子句的数量

      文档1 在两个字段中都包含了 brown,因此两个 match 查询都匹配成功并拥有了一个分值。文档2 在 body 字段中包含了 brown 以及 fox,但是在 title 字段中没有出现任何搜索的单词。因此对 body 字段查询得到的高分加上对 title字段查询得到的零分,然后再乘以匹配的查询子句数量1,最后除以总的查询子句数量2,导致整体分值比文档1 的低。具体计算过程如下:

    score_1 = (1 + 1) * 2 / 2 = 2
    score_2 = (0 + 2) * 1 / 2 = 1

      在这个例子中,title 和 body 字段是互相竞争的。我们想要找到一个最佳匹配(Best-matching)的字段。

      如果我们不是合并来自每个字段的分值,而是使用最佳匹配字段的分值作为整个查询的整体分值呢?这就会让包含有我们寻找的两个单词的字段有更高的权重,而不是在不同的字段中重复出现的相同单词。

    4. dis_max 查询

      相比使用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."
            }
         }
      ]
    }

    5. 最佳字段查询调优

      如果用户搜索的是"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

    6. tie_breaker

    但是,将其它匹配的查询子句考虑进来也是可能的。通过指定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的一种折中。它会通过下面的方式改变分值计算过程:

      1. 取得最佳匹配查询子句的_score。

      2. 将其它每个匹配的子句的分值乘以tie_breaker。

      3. 将以上得到的分值进行累加并规范化。

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

  • 相关阅读:
    keypress事件
    input输入框(blur,change,focus)
    click点击以后添加新class,删除其余同名class
    强制数组并且匹配Array
    模拟鼠标事件
    简单的form操作
    鼠标滚轮事件(mousewheel、DOMMouseScroll)
    事件委托技术
    从程序员到项目经理:项目经理必须懂一点“章法”
    JavaScript项目优化总结
  • 原文地址:https://www.cnblogs.com/liang1101/p/10330611.html
Copyright © 2011-2022 走看看