ElasticSearch的ngram分词器

young 415 2024-05-09

项目中使用 ElasticSearch 作为全文检索的工具对文档等数据进行检索,客户反馈了部分问题
1.数字信息无法进行模糊查询
2.查询的匹配度排序与预期不符

针对第一个问题的排查,分词器确实不会对数字进行拆分
分词查询数字
分词查询数字结果

针对第二个问题,在不增加词库的情况下,即使是 standard 分词器,通过 match、match_phrase、match_phrase_prefix 也无法解决。

经查询资料,可以使用ngram分词器来自定义分词操作。

在 Elasticsearch 中,ngram 分词器是一种基于 n-gram 算法的分词器,用于将文本转换为一组 n-gram 词项。与其他一些分词器(如 standard 分词器)不同,ngram 分词器可以生成部分单词,并且不需要完整的词汇表。

ngram 分词器的工作原理是将输入文本切分成一个个较小的子字符串,然后将这些子字符串作为词项添加到索引中。

分词器接收以下参数:

  1. min_gram: 以gram为单位的最小字符长度,默认值为 1
  2. max_gram:以gram为单位的最大字符长度,默认值为 2
  3. token_chars:令牌(分词结果)中包含的字符类型,默认是全部类型。字符类型可以是以下几种类型:
    • letter —保留字母类型,如a,b,c, 京
    • digit —保留数字类型,如1,2
    • whitespace —保留空格类型,如 " " or “\n”
    • punctuation —保留标点类型,如 ! or "
    • symbol —保留符号类型,如 $ or √
    • custom —保留自定义类型,使用custom_token_chars设置自定义的字符
  4. custom_token_chars:自定义的字符将视为令牌的一部分

注意:将 min_gram 和 max_gram 设置为相同的值通常是有意义的。
min_gram值越小,匹配的文档就越多,但匹配出来的文档相关性质量就越低。
max_gram值越长, 匹配的文档就越少,但匹配出来的文档相关性质量就越高。
通常:min_gram 长度为 3是一个很好的起点
索引级别max_ngram_diff参数控制最大允许的差异,max_gram的值不能超过。

创建索引的时候,先在 setting 中创建自定义的analyzer,然后在创建 mapping时指定创建的analyzer即可

PUT attachment-test
{
  "settings": {
    "index.max_ngram_diff":"10",
    "analysis": {
      "analyzer": {
        "ngram_analyzer":{
          "tokenizer":"ngram_tokenizer"
        }
      },
      "tokenizer": {
        "ngram_tokenizer":{
          "type":"ngram",
          "min_gram":1,
          "max_gram":10,
          "token_chars":[
            "letter","digit"
          ]
        }
      }
    }
  },
  "mappings": {
    "_meta":{
      "dataId":"主数据Id",
      "dataGlobalId":"主数据全局Id",
      "fileId":"文件Id",
      "fileName":"文件名称",
      "title":"标题",
      "type":"所属类型"
    },
    "properties": {
      "dataId":{
        "type": "long"
      },
      "dataGlobalId":{
        "type": "keyword"
      },
      "fileId": {
        "type": "keyword"
      },
      "fileName": {
        "type": "text",
        "analyzer": "ik_max_word",
        "fields": {
          "keyword":{
            "type":"keyword"
          },
          "standard":{
            "type":"text",
            "analyzer": "ngram_analyzer"
          }
        }
      },
      "title": {
        "type": "text",
        "analyzer": "ik_max_word",
        "fields": {
          "keyword":{
            "type":"keyword"
          },
          "standard":{
            "type":"text",
            "analyzer": "ngram_analyzer"
          }
        }
      },
      "type": {
        "type": "keyword"
      },
      "document": {
        "properties": {
          "content": {
            "type": "text",
            "analyzer": "ik_max_word",
            "fields": {
              "standard":{
                "type":"text",
                "analyzer": "ngram_analyzer"
              }
            }
          }
        }
      }
    }
  }
}