Elasticsearch搜索之best_fields分析

     顾名思义,best_field就是获取最佳匹配的field,另个可以通过tie_breaker来控制其他field的得分,boost可以设置权重(默认都为1)。

     下面从宏观上来讲的简单公式:

     score=best_field.score*boost+other_fields*boost.score*tie_breaker。     

     实际计算远比这个公式复杂得多,还要考虑分片因素、出现位置、文档长短等。 

     评分算法请参考:http://m.blog.csdn.net/article/details?id=50623948

     假如有二个文档

     doc1: 

          “title”: "我爱北京天安门,城上挂的是毛爷爷"
          "body": "北京西路有美女,哪位男神去采呢?"

     doc2:
           "title" : "我的家在东北,松花江上唉"
            "body" : "北京东路99号益丰近天安门城楼"

     查询如下:
            "bool" : { "should" : [ {"match" : {"title" : "北京东路" }}, { "match" : { "body" : "北京东路"}}]}

 
      es返回的结果应该是什么呢?哪一个doc的得分更高一些?是不是跟预期一致?
      我们预期是希望doc2得分更高,因为相关性更强一些。
      其实不然,es的返回结果是doc1得分更高。why?
      看看es是如何计算score的吧。

    (1)执行should中的两个match
    (2)叠加score
    (3)乘以match到的clause数目(召回文档)
    (4)除以所有clause数目(所有文档)

      doc1中title和body中含有词干“北京”,因此两个match都成功
      doc2中显然只有一个match能成功

      第三步中差距出来了,doc1是2,doc2则是1.因此doc1得分比doc2要高。
      其实这不是我们想要的结果。

      这个例子中title和body是相互竞争的字段,我们想要的是最佳匹配,哪一个字段match的结果更好,就选用哪一个字段的score作为最终的score。
      所以我们采用dis_max-query:

      意义是:返回match到任何一个子查询的doc,哪一个doc的match结果做好,作为最后的score。
      “query” : { "dis_max" : { "queries" : [ {"match" : {"title" : "北京东路"}}, {"match" : {"body" : "北京东路"}} ]}
      现在,查询结果是我们想要的了,虽然doc1匹配数为2,但doc2中匹配度更高,有“北京东路”完整内容匹配,真所谓狭路相逢,勇者胜。

      新情况有出现了:如果我们沿用dis_max查询“天安门美女”呢?
      结果显示为doc1跟doc2是一样的score。原因在于:dis_max之选用单个最好匹配的score作为最后的score,二个文档中都包括了“天安门”。
      doc1虽然title匹配了“天安门”,doby匹配了“美女”,但取最佳匹配也只能得1分,跟doc2相同。

      显然这也不是我们想要的结果,我们觉得doc2得分应该高一些?如何调节?

     我们需要综合考虑所有能match到的查询,同时还得考虑到最佳match的查询,因此tie_breaker参数出现了。

      配合tie_breaker参数,score的计算过程是专业的

    (1)获取最佳匹配的score

    (2)获取其他匹配的score,乘以tie_breaker

    (3)两者相加,规范化,作为score值

      tie_breaker的参数值要同时考虑到最佳match和所有match,推荐0.1---0.4,如果是0的话,就只考虑最佳match了

      multi_match query提供了上边的机制,通过制定type实现相同的效果:best_fields, most_fields,cross_fields.默认是best_field。

      如下dis_max的query:
       

{ "dis_max" : { "queries" : [ { "match" : { "titile" : { "query" : "天安门美女", "minimun_should_match" : "50%" } } }, { "match" : { "body" : { "query" : "天安门美女", "minimun_should_match" : "30%" } } } ], "tie_breaker" : 0.3 } }


    可以用下面的multi_match query代替:

{
   "multi_match" : {
      "query" : "天安门美女",
      "type" : "best_fields",
      "tie_breaker" : 0.3,
      "fields" : [ "title", "body" ],
      "minimun_should_match" : "30%"
   }
}

fields字段支持通配符和单个字段提升boost(^),下面举个例子更清晰点,假如搜索关键字为“美女城楼”,首先会提取词干为“美女”,“城楼”

doc1与doc2分别是body与title各匹配一个,分值相同,若我们在title上加个权重,则会打破这分值,虽然匹配值一样,但加上权重,则doc2分值更高。

{
   "multi_match" : {
      "query" : "美女城楼",
      "type" : "best_fields",
      "tie_breaker" : 0.3,
      "fields" : [ "title^1.5", "body" ],
      "minimun_should_match" : "30%"
   }
}

 

 

     

posted on 2017-04-06 18:40  虾米&老黄牛  阅读(9717)  评论(0编辑  收藏  举报

导航