• ES本地分片逆文档频率评分策略(Shard Local IDF)导致的评分异常原理解析


    1、问题现象描述

    假设有shard_local_idf索引(索引数据见文章末尾)

    GET shard_local_idf/_search
    {
      "query": {
        "match": {
          "title": "xiaomi shouji"
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    召回结果如下:

    "hits" : [
          {
            "_index" : "shard_local_idf",
            "_type" : "_doc",
            "_id" : "11",
            "_score" : 1.9924302,
            "_routing" : "0",
            "_source" : {
              "title" : "xiaomi tv"
            }
          },
          {
            "_index" : "shard_local_idf",
            "_type" : "_doc",
            "_id" : "1",
            "_score" : 1.6282079,
            "_routing" : "1",
            "_source" : {
              "title" : "xiaomi shouji"
            }
          },
          {
            "_index" : "shard_local_idf",
            "_type" : "_doc",
            "_id" : "10",
            "_score" : 1.4816045,
            "_routing" : "1",
            "_source" : {
              "title" : "xiaomi tv"
            }
          }
          ...
        ]
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    2、原因分析

    注意

    如果对 相关性评分算法比较陌生,推荐先阅读以下文章:
    Elasticsearch相关度评分算法(三):BM25(Okapi BM25)

    2.1 词频得分(TF)相关性

    对于_doc1和_doc11,两个文档词频都是1,他们在同一个索引,所以反词频一定相同,所以单就TF得分而言,这两个词得分肯定相同。

    因此,对于上述问题,TF得分为常量,不是问题产生的主要原因。

    2.2 反词频得分(IDF)相关性

    假设对于搜索词“xiaomi”,两个文档的得分都是 x x x,对于_doc1 而言,由于假设 i d f idf idf 得分为 y y y 根据 i d f idf idf 计算函数可知 y y y > 0,而对于 _doc11 而言,tv 并未被命中,因此 i d f idf idf 得分为 0。

    那么由此可计算两个文档的最终得分为:_doc1: x + y x + y x+y > _doc11: x x x
    什么是逆文档频率评分(IDF)

    2.3 eplain 查看执行计划

    通过 explain 计算以下得分,如下

    GET shard_local_idf/_search
    {
      "explain": true, 
      "query": {
        "match": {
          "title": "xiaomi shouji"
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    对于 query:xiaomi shouji 查询结果如下:

    • _doc1:总分:1.4816045(term:xiaomi) + 0.14660348(term:shouji) = 1.6282079

      • xiaomi:2.2 * 1.4816046 * 0.45454544 = 1.4816045
        • boost:2.2( k 1 k_1 k1+1)
        • idf:1.4816046
          • n:2
          • N:10
        • tf:0.45454544
      • shouji:2.2 * 0.14660348 * 0.45454544 = 0.14660348
        • boost:2.2( k 1 k_1 k1+1)
        • idf:0.14660348
        • tf:0.45454544
    • _doc11:总分:1.9924302(term:xiaomi) = 1.9924302

      • xiaomi:2.2 * 1.9924302 * 0.45454544 = 1.9924302

        • boost:2.2( k 1 k_1 k1+1)
        • idf:1.9924302
          • n:1
          • N:10
        • tf:0.45454544
      • tv:0

    3、解决方案

    3.1 开发和灰度环境或数据量不大的情况

    search_type

    • dfs_query_then_fetch:使用从运行搜索的所有分片收集的信息,全局计算分布式词频。虽然此选项提高了评分的准确性,但它增加了每个分片的往返行程,这可能会导致搜索速度变慢。
    • query_then_fetch:(默认)为每个运行搜索的分片本地计算分布式词频。我们建议使用此选项进行更快的搜索,但评分可能不太准确。

    测试环境设置:search_type = dfs_query_then_fetch 即表示在计算 i d f idf idf 的分值的时候,对全局进行计算,而不是 local_shard 。会牺牲一部分性能,换取准确性。这种方式适合于本地开发环境或者测试环境,或者生产环境中数据不对的情况下。

    3.2 对于生产环境

    对于生产环境,一般分布式数据库数据都不会太少,既然设计了多个分片,必然要考虑海量数据的情况。一般来说用 query_then_fetch 不太合适,会影响检索速度,牺牲用户体验。

    生产环境真正的做法是避免分片不均衡,包括分片的大小、节点分片的分配数量、文档的均衡分配等。ES 本身通过 shard reblance 实现分片自动均衡策略,但是如果人工通过 routing 的方式分配数据,务必要保证数据按照某种机制,如分布式哈希表来控制数据的均衡分配,以避免这种情况的产生。

    总结:在不了解分布式文档路由原理的前提下,不要随意使用 routing 来指定文档的分配机制。以免挖坑。

    GET shard_local_idf/_search?search_type=dfs_query_then_fetch
    {
      "explain": true, 
      "query": {
        "match": {
          "title": "xiaomi shouji"
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4、测试数据

    PUT shard_local_idf
    {
      "settings": {
        "number_of_shards": 2,
        "number_of_replicas": 0
      }
    }
    PUT shard_local_idf/_bulk?routing=1&refresh=true
    {"index":{"_id":1,"_type":"_doc"}}
    {"title":"xiaomi shouji"}
    {"index":{"_id":2,"_type":"_doc"}}
    {"title":"huawei shouji"}
    {"index":{"_id":3,"_type":"_doc"}}
    {"title":"pingguo shouji"}
    {"index":{"_id":4,"_type":"_doc"}}
    {"title":"zhongxing shouji"}
    {"index":{"_id":5,"_type":"_doc"}}
    {"title":"sanxing shouji"}
    {"index":{"_id":6,"_type":"_doc"}}
    {"title":"bodao shouji"}
    {"index":{"_id":7,"_type":"_doc"}}
    {"title":"oppo shouji"}
    {"index":{"_id":8,"_type":"_doc"}}
    {"title":"lg shouji"}
    {"index":{"_id":9,"_type":"_doc"}}
    {"title":"vivo shouji"}
    {"index":{"_id":10,"_type":"_doc"}}
    {"title":"xiaomi tv"}
    PUT shard_local_idf/_bulk?routing=0&refresh=true
    {"index":{"_id":11,"_type":"_doc"}}
    {"title":"xiaomi tv"}
    {"index":{"_id":12,"_type":"_doc"}}
    {"title":"huawei 12"}
    {"index":{"_id":3,"_type":"_doc"}}
    {"title":"pingguo 13"}
    {"index":{"_id":14,"_type":"_doc"}}
    {"title":"zhongxing 14"}
    {"index":{"_id":15,"_type":"_doc"}}
    {"title":"sanxing 51"}
    {"index":{"_id":16,"_type":"_doc"}}
    {"title":"bodao 16"}
    {"index":{"_id":17,"_type":"_doc"}}
    {"title":"oppo 17"}
    {"index":{"_id":18,"_type":"_doc"}}
    {"title":"lg 18"}
    {"index":{"_id":19,"_type":"_doc"}}
    {"title":"vivo 19"}
    {"index":{"_id":20,"_type":"_doc"}}
    {"title":"meizu 20"}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
  • 相关阅读:
    C++基础——引用讲解1
    nuxt2框架知识总结
    【动态规划】—— 背包问题
    华为机试 - 判断一组不等式是否满足约束并输出最大差
    Android项目集成flutter模块
    MySQL数据库入门到精通
    MyBatis入门
    【C++】特殊类的设计
    记一次http接口自动重试现象的排查
    微服务实战 02 Sentinel 入门
  • 原文地址:https://blog.csdn.net/wlei0618/article/details/126584520