美文网首页ElasticSearch实战笔记
22、基于boost的权重控制以及基于dis_max实现best

22、基于boost的权重控制以及基于dis_max实现best

作者: 众神开挂 | 来源:发表于2020-04-06 02:03 被阅读0次

    主要内容:基于boost的权重控制以及基于dis_max实现best fields策略进行多字段搜索

    1、基于boost的细粒度搜索条件权重控制

    需求:搜索标题中包含java的帖子,同时呢,如果标题中包含hadoop或elasticsearch就优先搜索出来,同时呢,如果一个帖子包含java hadoop,一个帖子包含java elasticsearch,包含hadoop的帖子要比elasticsearch优先搜索出来

    知识点,搜索条件的权重,boost,可以将某个搜索条件的权重加大,此时当匹配这个搜索条件和匹配另一个搜索条件的document,计算relevance score时,匹配权重更大的搜索条件的document,relevance score会更高,当然也就会优先被返回来

    默认情况下,搜索条件的权重都是一样的,都是1

    GET /forum/_search
    {
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "title": "blog"
              }
            }
          ],
          "should": [
            {
              "match": {
                "title": {
                  "query": "spark",
                  "boost": 5  ##提升spark的权重
                }
              }
            }
          ]
        }
      }
    }
    

    2、多shard场景下relevance score不准确问题

    如果你的一个index有多个shard的话,可能搜索结果会不准确

    不准确的原因就是因为ES默认只在Shard local本地计算IDF,所以有的shard上document包含的关键字多,有的关键字少,进而导致结果不准确。

    2、如何解决该问题?

    (1)生产环境下,数据量大,尽可能实现均匀分配

    数据量很大的话,其实一般情况下,在概率学的背景下,es都是在多个shard中均匀路由数据的,路由的时候根据_id,负载均衡
    比如说有10个document,title都包含java,一共有5个shard,那么在概率学的背景下,如果负载均衡的话,其实每个shard都应该有2个doc,title包含java
    如果说数据分布均匀的话,其实就没有刚才说的那个问题了

    (2)测试环境下,将索引的primary shard设置为1个,number_of_shards=1,index settings

    如果说只有一个shard,那么当然,所有的document都在这个shard里面,就没有这个问题了

    (3)测试环境下,搜索附带search_type=dfs_query_then_fetch参数,会将local IDF取出来计算global IDF

    计算一个doc的相关度分数的时候,就会将所有shard对的local IDF计算一下,获取出来,在本地进行global IDF分数的计算,会将所有shard的doc作为上下文来进行计算,也能确保准确性。但是production生产环境下,不推荐这个参数,因为性能很差。

    3、基于dis_max实现best fields策略进行多字段搜索

    3.1、添加数据

    为帖子数据增加content字段

    POST /forum/_bulk
    { "update": { "_id": "1"} }
    { "doc" : {"content" : "i like to write best elasticsearch article"} }
    { "update": { "_id": "2"} }
    { "doc" : {"content" : "i think java is the best programming language"} }
    { "update": { "_id": "3"} }
    { "doc" : {"content" : "i am only an elasticsearch beginner"} }
    { "update": { "_id": "4"} }
    { "doc" : {"content" : "elasticsearch and hadoop are all very good solution, i am a beginner"} }
    { "update": { "_id": "5"} }
    { "doc" : {"content" : "spark is best big data solution based on scala ,an programming language similar to java"} }
    
    3.2、搜索title或content中包含java或solution的帖子

    下面这个就是multi-field搜索,多字段搜索

    GET /forum/_search
    {
      "query": {
        "bool": {
          "should": [
            {
              "match": {
                "title": "java solution"
              }
            },
            {
              "match": {
                "content": "java solution"
              }
            }
          ]
        }
      }
    }
    
    3.3、结果分析

    期望的是doc5,结果是doc2,doc4排在了前面

    计算每个document的relevance score:每个query的分数,乘以matched query数量,除以总query数量

    doc2:

    { "match": { "title": "java solution" }},有分数
    { "match": { "content": "java solution" }},有分数

    doc5:

    { "match": { "title": "java solution" }},没有分数
    { "match": { "content": "java solution" }},有分数

    doc5匹配的match query数量要少,但是总的query数量是相同的,所以doc5的分数< doc2的分数

    3.4、best fields策略,dis_max

    best fields策略,就是说,搜索到的结果,应该是某一个field中匹配到了尽可能多的关键词,被排在前面;而不是尽可能多的field匹配到了少数的关键词,排在了前面

    dis_max语法,直接取多个query中,分数最高的那一个query的分数即可

    { "match": { "title": "java solution" }},针对doc4,是有一个分数的,1.1
    { "match": { "content": "java solution" }},针对doc4,也是有一个分数的,1.2
    取最大分数,1.2

    { "match": { "title": "java solution" }},针对doc5,是没有分数的
    { "match": { "content": "java solution" }},针对doc5,是有一个分数的,2.3
    取最大分数,2.3

    然后doc4的分数 = 1.2 < doc5的分数 = 2.3,所以doc5就可以排在更前面的地方,符合我们的需要

    GET /forum/_search
    {
      "query": {
        "dis_max": {            
          "queries": [         
            {
              "match": {
                "title": "java solution"
              }
            },
            {
              "match": {
                "content": "java solution"
              }
            }
          ]
        }
      }
    }
    

    使用tie_breaker参数优化dis_max搜索

    1、dis_max只取某一个query最大的分数,完全不考虑其他query的分数

    2、使用tie_breaker将其他query的分数也考虑进去

    3、tie_breaker的值,在0~1之间,是个小数

    实战示例:

    GET /forum/_search
    {
      "query": {
        "dis_max": {
          "queries": [
            {
              "match": {
                "title": "java beginner"
              }
            },
            {
              "match": {
                "content": "java beginner"
              }
            }
          ],
          "tie_breaker": 0.3
        }
      }
    }
    

    相关文章

      网友评论

        本文标题:22、基于boost的权重控制以及基于dis_max实现best

        本文链接:https://www.haomeiwen.com/subject/cyokuhtx.html