前缀 n 元词元生成器

前缀 n 元词元生成器 #

前缀 n 元词元生成器会从每个单词的开头生成部分单词词元,也就是 n 元组。它会根据指定的字符分割文本,并在定义的最小和最大长度范围内生成词元。这种词元生成器在实现即输即搜(search-as-you-type)功能时特别有用。

前缀 n 元组非常适合用于自动补全搜索,在这种搜索中单词的顺序可能会有所不同,例如在搜索产品名称或地址时。有关更多信息,请参阅 “自动补全” 相关内容。不过,对于像电影或歌曲标题这种顺序固定的文本,完成建议器(completion suggester)可能会更准确。

默认情况下,前缀 n 元词元生成器生成的词元最小长度为 1,最大长度为 2。例如,当分析文本 Easysearch 时,默认配置会生成 “E” 和 “Ea” 这两个 n 元组。这些短的 n 元组常常会匹配到太多不相关的词条,所以调整 n 元组的长度,对词元生成器进行优化是很有必要的。

参考样例 #

以下示例请求创建了一个名为 my_index 的新索引,并配置了一个使用前缀 n 元词元生成器的分词器。该词元生成器生成长度为 3 到 6 个字符的词元,且将字母和符号都视为有效的词元字符。

PUT /edge_n_gram_index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_custom_analyzer": {
          "tokenizer": "my_custom_tokenizer"
        }
      },
      "tokenizer": {
        "my_custom_tokenizer": {
          "type": "edge_ngram",
          "min_gram": 3,
          "max_gram": 6,
          "token_chars": [
            "letter"          ]
        }
      }
    }
  }
}

产生的词元 #

使用以下请求来检查使用该分词器生成的词元:

POST /edge_n_gram_index/_analyze
{
  "analyzer": "my_custom_analyzer",
  "text": "Code 42 rocks!"
}

返回内容包含产生的词元

{
  "tokens": [
    {
      "token": "Cod",
      "start_offset": 0,
      "end_offset": 3,
      "type": "word",
      "position": 0
    },
    {
      "token": "Code",
      "start_offset": 0,
      "end_offset": 4,
      "type": "word",
      "position": 1
    },
    {
      "token": "roc",
      "start_offset": 8,
      "end_offset": 11,
      "type": "word",
      "position": 2
    },
    {
      "token": "rock",
      "start_offset": 8,
      "end_offset": 12,
      "type": "word",
      "position": 3
    },
    {
      "token": "rocks",
      "start_offset": 8,
      "end_offset": 13,
      "type": "word",
      "position": 4
    }
  ]
}

参数说明 #

参数必填/选填数据类型描述
min_gram选填整数词元的最小长度。默认值为 1。
max_gram选填整数词元的最大长度。默认值为 2。
custom_token_chars选填字符串被视为词元一部分的自定义字符(例如,+-_)。
token_chars选填字符串数组定义要包含在词元中的字符类。词元会字符类规则进行拆分。默认是所有字符。可用的字符类包括:
- letter:字母字符(例如,a、ç 或 “京”)
- digit:数字字符(例如,3 或 7)
- punctuation:标点符号(例如,! 或 ?)
- symbol:其他符号(例如,$ 或 √)
- whitespace:空格或换行符
- custom:允许您在 custom_token_chars 设置中指定自定义字符。

最大词元长度(max_gram)参数的限制 #

最大词元长度(max_gram)参数设置了生成的词元的最大长度。当一个查询词项的长度超过这个设定时,它可能无法匹配索引中的任何词条。

例如,如果将 max_gram 设置为 4,那么在索引过程中,查询词 explore 会被分词为 expl。这样一来,当搜索完整的词条 explore 时,就无法匹配到已索引的词元 expl 了。

为了解决这个限制问题,你可以应用一个截断(truncate)词元过滤器,将搜索词缩短到最大词元长度。不过,这种方法也存在权衡取舍。将 explore 截断为 expl 可能会导致与一些不相关的词条匹配,比如 explosionexplicit,从而降低搜索精度。

我们建议仔细权衡 max_gram 的值,以确保在进行高效分词的同时,尽量减少不相关的匹配。如果搜索精度至关重要,可考虑其他策略,比如调整查询分词器或微调过滤器。

最佳实践 #

我们建议仅在索引创建阶段使用前缀 n 元词元生成器,以确保部分单词词元得以存储。在执行搜索时,应使用基础分词器来匹配所有的查询词条。

配置“即输即搜”功能 #

要实现即输即搜(search-as-you-type)功能,可在索引创建时使用前缀 n 元词元生成器,在搜索时使用一个执行最少处理操作的分词器。以下示例展示了这种实现方法。

使用前缀 n 元词元生成器创建一个索引:

PUT /my-autocomplete-index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "autocomplete": {
          "tokenizer": "autocomplete",
          "filter": [
            "lowercase"
          ]
        },
        "autocomplete_search": {
          "tokenizer": "lowercase"
        }
      },
      "tokenizer": {
        "autocomplete": {
          "type": "edge_ngram",
          "min_gram": 2,
          "max_gram": 10,
          "token_chars": [
            "letter"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "autocomplete",
        "search_analyzer": "autocomplete_search"
      }
    }
  }
}

索引一个包含 product 字段的文档,并刷新该索引:

PUT my-autocomplete-index/_doc/1?refresh
{
  "title": "Laptop Pro"
}

这种配置确保了前缀 n 元词元生成器会将诸如 “Laptop” 这样的词条拆分成 “La”、“Lap” 和 “Lapt” 等词元,从而在搜索时能够实现部分匹配。在搜索阶段,standard词元生成器会简化查询操作,并且由于有小写字母过滤器的存在,还能确保匹配操作不区分大小写。

现在,当搜索 “laptop Pr” 或 “lap pr” 时,就会基于部分匹配检索到相关的文档:

GET my-autocomplete-index/_search
{
  "query": {
    "match": {
      "title": {
        "query": "lap pr",
        "operator": "and"
      }
    }
  }
}

了解更多信息,请参阅 Search as you type 相关内容。