4. Analyzer与分词:内置分词器介绍、自定义分词器、中文分词选型(IK, pinyin),分词对搜索的影响。

聊到 Elasticsearch,有个东西你绕不开——分词器(Analyzer)

说白了,分词器就是决定「用户搜什么能命中」的关键。我见过不少团队,索引建得挺漂亮,查询语法也熟练,但搜索效果就是差。一查,问题全出在分词上。

嗯,这节课我们就把它彻底讲透。

4.1 内置分词器:开箱即用的那些家伙

Elasticsearch 自带了好几个分词器,大部分场景下够用。我个人习惯先拿它们快速验证,不够再定制。

分词器名称 工作原理 典型场景
Standard 按单词边界切分,小写化,去除标点 英文全文搜索(默认)
Simple 按非字母字符切分,小写化 纯英文、无数字干扰的场景
Whitespace 仅按空格切分,不做小写化 精确匹配、代码片段搜索
Keyword 不切分,整个字段作为一个词条 ID、标签、枚举值
Pattern 按正则表达式切分 自定义分隔符需求
Stop 类似 Simple,但会移除停用词 对噪音词敏感的场景
小提示:Standard 分词器对英文友好,但对中文就是一字一词。你想想看,搜「苹果」它给你拆成「苹」「果」,这能搜到啥?

4.2 自定义分词器:自己动手,丰衣足食

内置的不够用?那就自己搭。自定义分词器其实就三个组件:Character Filters(字符过滤)、Tokenizer(分词器)、Token Filters(词条过滤)。

我举个例子。假设你要处理用户输入的手机号,希望去掉中间的横杠和空格,再转成小写。可以这样配:

PUT /my_index
{
  "settings": {
    "analysis": {
      "char_filter": {
        "my_char_filter": {
          "type": "mapping",
          "mappings": ["-=>", " =>"]
        }
      },
      "tokenizer": {
        "my_tokenizer": {
          "type": "keyword"
        }
      },
      "filter": {
        "my_filter": {
          "type": "lowercase"
        }
      },
      "analyzer": {
        "my_analyzer": {
          "type": "custom",
          "char_filter": ["my_char_filter"],
          "tokenizer": "my_tokenizer",
          "filter": ["my_filter"]
        }
      }
    }
  }
}

你看,整个过程就像搭积木。先过滤字符,再切分,最后处理词条。我在项目中经常用这个套路处理脏数据,效果立竿见影。

注意:自定义分词器必须在创建索引时定义,不能事后修改。我曾经因为没规划好,重建索引花了整整一个周末……嗯,血的教训。

4.3 中文分词选型:IK 与 pinyin

中文分词是搜索的「灵魂」。你想想看,中文没有空格,词与词之间全靠猜。选错分词器,搜索体验直接崩盘。

4.3.1 IK 分词器:中文搜索的标配

IK 是目前最流行的中文分词器,支持两种模式:

  • ik_smart:最粗粒度切分,速度最快。适合搜索场景。
  • ik_max_word:最细粒度切分,会穷举所有可能组合。适合索引阶段,召回率高。

举个例子,对「中华人民共和国国歌」:

  • ik_smart 输出:中华人民共和国、国歌
  • ik_max_word 输出:中华人民共和国、中华人民、中华、华人、人民共和国、人民、共和国、共和、国歌

我个人习惯:索引用 ik_max_word,搜索用 ik_smart。这样既保证召回率,又避免搜索时产生太多噪音。

避坑指南:我曾经在电商项目中只用 ik_smart 做索引,结果用户搜「手机壳」时,因为「手机壳」被拆成「手机」「壳」,而商品标题是「iPhone 手机保护壳」,导致匹配不上。后来改成 ik_max_word 索引,问题解决。

4.3.2 pinyin 分词器:拼音搜索的利器

你有没有遇到过用户搜「zhongguo」想找「中国」?或者搜「lj」想找「李健」?这就是拼音分词器的用武之地。

pinyin 分词器可以把汉字转成拼音,支持全拼、首字母、混合模式。配置示例:

PUT /my_index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "pinyin_analyzer": {
          "tokenizer": "ik_max_word",
          "filter": ["pinyin_filter"]
        }
      },
      "filter": {
        "pinyin_filter": {
          "type": "pinyin",
          "keep_full_pinyin": true,
          "keep_joined_full_pinyin": true,
          "keep_original": true,
          "limit_first_letter_length": 16,
          "remove_duplicated_term": true
        }
      }
    }
  }
}

这里有个关键参数 keep_original,设为 true 表示保留原始汉字。否则你搜「中国」可能只匹配到拼音,汉字反而搜不到,那就尴尬了。

经验之谈:pinyin 分词器适合做「辅助搜索」,不建议作为唯一分词器。我一般把它放在 search_as_you_type 字段里,配合 IK 一起用,效果最好。

4.4 分词对搜索的影响:成也分词,败也分词

分词选得好不好,直接决定搜索的「准」和「全」。我总结了几条核心影响:

  • 召回率:分词越细,能匹配到的文档越多。但噪音也越大。
  • 精准度:分词越粗,匹配越精确。但可能漏掉相关文档。
  • 性能:分词越细,索引越大,查询越慢。需要权衡。
  • 排序:分词结果影响 TF/IDF 和 BM25 评分。词条越多,评分越分散。

举个例子。假设你有一个商品标题「华为 Mate 40 Pro 5G 手机」:

  • 用 Standard 分词器:华为、Mate、40、Pro、5G、手机
  • 用 IK 分词器:华为、Mate、40、Pro、5G、手机
  • 用 IK + pinyin:华为、huawei、Mate、40、Pro、5G、手机、shouji

你看,同样的内容,不同分词器产生不同的词条。用户搜「华为手机」时,Standard 和 IK 都能命中,但搜「huawei」时,只有加了 pinyin 的才能命中。

核心原则:分词策略必须与用户搜索习惯对齐。如果用户习惯打拼音,你就得配 pinyin;如果用户习惯搜全称,IK 就够了。没有银弹,只有适配。

4.5 实战建议:如何选择分词器

说了这么多,到底怎么选?我给出一个通用策略:

  1. 英文为主:直接用 Standard,省心。
  2. 中文为主:IK(ik_max_word 索引 + ik_smart 搜索)。
  3. 需要拼音搜索:IK + pinyin 组合,pinyin 放在搜索字段的 fields 子字段中。
  4. 精确匹配:用 Keyword 分词器,或者设置 index: false 的字段。
  5. 混合语言:自定义分词器,组合多种 filter。

嗯,最后提醒一句:分词器选型一定要在项目初期确定。等数据量上来了再改,那代价……你懂的。

测试小技巧:GET /_analyze API 快速验证分词效果,不用建索引就能看结果。我每次调分词器都先用它跑一遍,省时省力。

好了,这节课就到这里。下一节我们聊聊 Mapping 设计,那又是一个大坑……