暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

如何提高 ES 检索准确率和召回率?

ZUTNLP 2021-07-05
5209

大家在使用 ES 作全文检索,经常会遇到库里有数据,但是无法检索出来,以至于遗漏掉部分重要信息。这里我们将场聚焦于使用 IK 分词器,同时使用 ik_smart 分词模式,那么常见的一种方案是进行词库的远程更新,对新数据生效。在舆情监测场景下,客户需要对已有的品牌词、主体词进行监测,丢数据是一种比较尴尬的存在。下面主要介绍在追求极高检索召回率目标下的一些尝试和总结。

        分词器

有些同学可能认为,我没有指明分词器,但是也能进行正常索引和检索。下面就简单介绍一些常见的分词器:

    a) standard - 标准分词器

    该分词器是 ES 默认分词器,具有极好的普适性。英文的处理能力同于StopAnalyzer. 支持中文采用的方法为单字切分。他会将词汇单元转换成小写形式,并去除用词和标点符号。

    b) Whitespace 分词器

    仅仅是去除空格,对字符没有lowcase化,不支持中文;并且不对生成的词汇单元进行其他的规范化处理。

    c) IK Analyzer

    IK 分为 ik_max_word 和 ik_smart 两种分词策略。根据 IK 的文档,二者区别如下:

  1.  ik_max_word:会将文本做最细粒度的拆分,例如「中华人民共和国国歌」会被拆分为「中华人民共和国中华人民中华华人人民共和国人民共和国共和国国国歌」,会穷尽各种可能的组合;         

  2. ik_smart:会将文本做最粗粒度的拆分,例如「中华人民共和国国歌」会被拆分为「中华人民共和国国歌」;

基本可以满足常见的中文分词场景。


检索误差分析


我们以 ik_smart 举例:

    index_v1/_analyze/ POST
    {
    "analyzer": "ik_smart",
    "text": "微贷网费用有哪些"
    }
    分词结果: ["微""贷""网费""用""有""哪""些"]
    分 析: 如果此时检索 "微贷网" 就无法命中该条数据。(Phrase查询,且slop=0) ) 此时的优化方案为扩充词库 "微贷网",此时便可以正确分词。此类问题,我们归咎于是因为分词不精准导致的。


    此时一个直观的解决思路是 按字分词,我们将 IK 对应的默认词库拿掉,就达到按字分词的目的。

      index_v1/_analyze/ POST
      {
      "analyzer": "ik_smart",
      "text": "微贷网费用有哪些"
      }
      分词结果:
      {
      "tokens":[
      {
      "token":"微",
      "start_offset":0,
      "end_offset":1,
      "type":"CN_CHAR",
      "position":0
      },
      {
      "token":"贷",
      "start_offset":1,
      "end_offset":2,
      "type":"CN_CHAR",
      "position":1
      },
      {
      "token":"网",
      "start_offset":2,
      "end_offset":3,
      "type":"CN_CHAR",
      "position":2
      },
      {
      "token":"费",
      "start_offset":3,
      "end_offset":4,
      "type":"CN_CHAR",
      "position":3
      },
      {
      "token":"用",
      "start_offset":4,
      "end_offset":5,
      "type":"CN_CHAR",
      "position":4
      },
      {
      "token":"有",
      "start_offset":5,
      "end_offset":6,
      "type":"CN_CHAR",
      "position":5
      },
      {
      "token":"哪",
      "start_offset":6,
      "end_offset":7,
      "type":"CN_CHAR",
      "position":6
      },
      {
      "token":"些",
      "start_offset":7,
      "end_offset":8,
      "type":"CN_CHAR",
      "position":7
      }
      ]
      }
      分 析: 此时 phrase 查询 "微贷网",便可以精准查询。

      如果仅仅到这里,使用标准分词器也是可以的。按字分词 + Phrase 查询可以保证较高的检索召回率。但是我们不要忘记还有停用词的概念,也会影响检索的精准度。我们考虑 Phrase 查询:"苏宁" 

        index_v1/_analyze/ POST
        {
        "analyzer": "standard",
        "text": "江苏、宁夏"
        }
        分词结果:
        {
        "tokens":[
        {
        "token":"江",
        "start_offset":0,
        "end_offset":1,
        "type":"<IDEOGRAPHIC>",
        "position":0
        },
        {
        "token":"苏",
        "start_offset":1,
        "end_offset":2,
        "type":"<IDEOGRAPHIC>",
        "position":1
        },
        {
        "token":"宁",
        "start_offset":3,
        "end_offset":4,
        "type":"<IDEOGRAPHIC>",
        "position":2
        },
        {
        "token":"夏",
        "start_offset":4,
        "end_offset":5,
        "type":"<IDEOGRAPHIC>",
        "position":3
        }
        ]
        }
        分 析:可以看到标点符号的确被过滤掉,不会建索引。所以该文档会检索到。但是不符合自然语义。

        此时如果基于 standard 分词器去改造,就需要重新编译 ES源码。而对IK进行改造,就显容易些。

          {
          "analyzer": "ik_smart",
          "text": "江苏、宁夏"
          }
          分词结果:




          {
          "tokens": [
          {
          "token": "江",
          "start_offset": 0,
          "end_offset": 1,
          "type": "CN_CHAR",
          "position": 0
          }
          ,
          {
          "token": "苏",
          "start_offset": 1,
          "end_offset": 2,
          "type": "CN_CHAR",
          "position": 1
          }
          ,
          {
          "token": "、",
          "start_offset": 2,
          "end_offset": 3,
          "type": "OTHER_CJK",
          "position": 2
          }
          ,
          {
          "token": "宁",
          "start_offset": 3,
          "end_offset": 4,
          "type": "CN_CHAR",
          "position": 3
          }
          ,
          {
          "token": "夏",
          "start_offset": 4,
          "end_offset": 5,
          "type": "CN_CHAR",
          "position": 4
          }
          ]
          }
          分析:可以看到 "、" 被保留,此时 Phrase 查询,就不会被检索出来。

          通过对 IK 进行改造,保留部分用词,提高检索准确率。

          收益

          在进行按字分词且保留特殊字符模式下,召回和准确率直线提升,也减轻了词典的运维和维护工作,从而能将注意力集中在系统开发和维护中。

          总结

          这种模式在一定场景下能解决检索遇到的问题。但是会产生以下问题:

            1. 检索效率降低

              phrase 查询要比Terms查询效率低10倍,而又是基于字的分词,效率自然会更低。而随后的基于 bigram 查询优化具有一定的性能提升。

            2. 噪音数据变得多

            3. 即便是基于词典的分词模式,也是有一定先验知识存在。按字分词,只能机械的按照规则进行拆分。可想而知,在某些场景下检索出的数据是不符合预期的。搜索 "更美"(更美APP简称),"今天变的更美丽"这样的文档都会检索出来。当然这个还涉及实体识别、相关度等一系列NLP相关任务。

          希望能对大家产生一些帮助!!!


          文章转载自ZUTNLP,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

          评论