Skip to content

Elasticsearch 分词

分词决定文本如何被拆成 token,并最终写入倒排索引。搜索结果不准确时,很多问题都和分词有关。

零基础可以先记住一句话:

ES 搜索不是直接拿整句话匹配整句话,而是先把文本拆成词,再根据词去倒排索引里找文档。

为什么分词重要

以商品名为例:

text
Apple iPhone 15 Pro Max 256G 官方旗舰

用户可能搜索:

text
苹果手机 15pro 256

如果分词器不能处理大小写、品牌词、型号词、同义词和中英文混合,可能出现:

  1. 搜“苹果手机”搜不到 iPhone。
  2. 搜“15pro”搜不到 15 Pro
  3. 搜“蓝牙耳机”命中很多无关音箱。
  4. 商品标题里有词,但因为被切错导致排序很差。

所以商业搜索里,分词不是锦上添花,而是决定搜索质量的基础。

分词流程

mermaid
flowchart TD
    A["原始文本"] --> B["Character Filter 字符预处理"]
    B --> C["Tokenizer 切词"]
    C --> D["Token Filter 词元过滤"]
    D --> E["Token 列表"]
    E --> F["写入倒排索引"]

Analyzer = Character Filter + Tokenizer + Token Filter。

组件作用商业示例
Character Filter分词前清洗字符去 HTML、把 & 替换成 and
Tokenizer把文本切成词standard、ik_max_word、edge_ngram
Token Filter对词做后处理小写、同义词、停用词、拼音

使用 _analyze 查看分词

排查分词问题时,第一步不是猜,而是看实际切分结果。

json
GET /_analyze
{
  "analyzer": "standard",
  "text": "Apple iPhone 15 Pro Max 256G 官方旗舰"
}

如果安装了 IK:

json
GET /_analyze
{
  "analyzer": "ik_max_word",
  "text": "无线蓝牙降噪耳机 Pro"
}

看到 token 后再判断:哪些词被切出来,哪些词没切出来,哪些词太碎,哪些词需要加入自定义词典。

中文分词为什么特殊

英文天然有空格:

text
wireless bluetooth headset

中文没有天然空格:

text
无线蓝牙降噪耳机

如果简单按单字切,会得到:

text
无, 线, 蓝, 牙, 降, 噪, 耳, 机

这种结果召回很泛,排序也差。更合理的是识别出:

text
无线, 蓝牙, 降噪, 耳机, 蓝牙耳机, 降噪耳机

商业搜索经常要处理:

  1. 品牌词:Apple、苹果、华为。
  2. 型号词:iPhone 15 Pro、Mate 60、RTX 4090。
  3. 类目词:蓝牙耳机、跑步鞋、机械键盘。
  4. 规格词:256G、1TB、XL、42码。
  5. 同义词:无线耳机、蓝牙耳机。
  6. 错别字和大小写:airpods、AirPods、air pods。

textkeyword

分词通常发生在 text 字段上。

类型是否分词适合
text商品名、卖点、描述、工单内容、日志 message
keyword品牌、状态、订单号、标签、精确匹配字段

商品名可以这样设计:

json
{
  "productName": {
    "type": "text",
    "analyzer": "ik_max_word",
    "search_analyzer": "ik_smart",
    "fields": {
      "keyword": {
        "type": "keyword",
        "ignore_above": 256
      }
    }
  }
}

这样既能全文搜索,也能在必要时做完整名称精确匹配。

索引分词和查询分词

ES 有两个阶段:

  1. 写入文档时分词,叫索引分词。
  2. 用户搜索时分词,叫查询分词。
mermaid
flowchart TD
    A["写入商品名"] --> B["索引分词 analyzer"]
    B --> C["倒排索引"]
    D["用户搜索词"] --> E["查询分词 search_analyzer"]
    E --> F["匹配倒排索引"]
    F --> G["返回商品"]

常见策略是:索引时切得更细,查询时切得更稳。

以 IK 为例:

分词器特点常见用途
ik_max_word尽量切出更多词索引阶段,提高召回
ik_smart切得更粗更稳定查询阶段,减少噪音

如果索引分词和查询分词完全不匹配,就会出现“写进去了但搜不到”的问题。

自定义 Analyzer Demo

下面是一个学习用示例,演示小写、同义词和自定义分词配置的基本结构。

json
PUT /product_analyzer_demo
{
  "settings": {
    "analysis": {
      "filter": {
        "product_synonym_filter": {
          "type": "synonym",
          "synonyms": [
            "iphone, 苹果手机",
            "airpods, 蓝牙耳机, 无线耳机",
            "降噪, 主动降噪"
          ]
        }
      },
      "analyzer": {
        "product_search_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "product_synonym_filter"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "productName": {
        "type": "text",
        "analyzer": "product_search_analyzer"
      }
    }
  }
}

测试分词:

json
GET /product_analyzer_demo/_analyze
{
  "analyzer": "product_search_analyzer",
  "text": "AirPods 主动降噪"
}

生产环境的同义词通常不会直接写在 Mapping 里,而是通过同义词文件、可热更新机制或搜索服务侧词库治理。否则每次改同义词都可能需要重建索引。

同义词怎么用才合理

用户可能搜索不同叫法:

text
iPhone, 苹果手机
AirPods, 蓝牙耳机, 无线耳机
运动鞋, 跑步鞋
笔记本, 电脑, laptop

同义词可以提升召回,但一定要克制。

做法后果
同义词太少用户换个说法搜不到
同义词太多搜出来很多无关结果
双向同义词乱配“苹果”可能同时命中水果和手机
不区分类目“鼠标”在电脑配件和宠物语境完全不同

更稳的做法:

  1. 按业务类目维护同义词。
  2. 高频词先灰度验证。
  3. 配合搜索日志观察点击率和转化率。
  4. 对品牌词、型号词做人工维护。

停用词和低价值词

停用词是对搜索意义不大的词,例如:

text
的, 了, 和, 正品, 新款

但商业搜索不能盲目删除所有看似低价值词。例如“新款手机”和“二手手机”里,“新款”“二手”可能就很重要。

停用词要结合业务判断:

是否适合停用原因
通常可以搜索意义弱
官方旗舰不建议简单停用可能影响转化和排序
二手不应停用直接影响商品属性
免息不应随便停用可能是营销筛选条件

前缀搜索和输入提示

搜索建议不能简单用 wildcard "*蓝牙*" 扛。数据大了会慢。

更常见的方案:

  1. search_as_you_type
  2. completion suggester
  3. edge_ngram
  4. 独立热词表加 ES 或 Redis

search_as_you_type Demo:

json
PUT /suggest_demo
{
  "mappings": {
    "properties": {
      "suggestText": { "type": "search_as_you_type" },
      "hotScore": { "type": "long" }
    }
  }
}
json
POST /suggest_demo/_doc/1
{
  "suggestText": "蓝牙耳机",
  "hotScore": 9800
}
json
GET /suggest_demo/_search
{
  "query": {
    "multi_match": {
      "query": "蓝牙",
      "type": "bool_prefix",
      "fields": [
        "suggestText",
        "suggestText._2gram",
        "suggestText._3gram"
      ]
    }
  },
  "sort": [
    { "hotScore": "desc" }
  ]
}

分词调整后为什么要重建索引

分词结果是在写入时生成的。已经写入的文档,其倒排索引不会因为你修改了 analyzer 自动变化。

mermaid
flowchart TD
    A["旧 analyzer 写入文档"] --> B["生成旧倒排索引"]
    C["修改 analyzer"] --> D["只影响之后新写入的数据"]
    B --> E["旧数据仍然按旧分词搜索"]
    D --> F["新旧分词结果不一致"]
    F --> G["需要重建索引"]

如果不重建,会出现同一类商品有的能搜到、有的搜不到,排查非常困难。

搜索不准排查流程

mermaid
flowchart TD
    A["搜索结果不准"] --> B["确认数据是否同步到 ES"]
    B --> C["用 _analyze 查看索引分词"]
    C --> D["用 _analyze 查看查询分词"]
    D --> E["检查字段类型 text/keyword"]
    E --> F["检查 match/term 是否用错"]
    F --> G["检查同义词、停用词、自定义词典"]
    G --> H["检查字段权重和排序规则"]
    H --> I["调整 Mapping、词典或查询"]

常见问题

为什么 term 查不到 text 字段

term 不分析查询词,适合精确值。text 字段已经分词,通常应该用 match 查询。

为什么 keyword 搜索不支持自然语言模糊

keyword 不分词,适合精确匹配、过滤、聚合。如果要全文搜索,用 text

修改分词器为什么不生效

已经写入的文档分词结果不会自动变化,通常需要重建索引。

为什么加同义词后结果变差

同义词扩大了召回范围,但也可能引入无关文档。要通过点击率、转化率、人工评测集验证,不要凭感觉大量添加。

为什么商品型号搜索很难

型号经常包含字母、数字、空格、连字符和大小写,例如 iPhone15ProiPhone 15 Pro15pro。需要自定义词典、大小写归一、同义词或搜索服务侧归一化一起处理。

本章小结

分词是 ES 搜索质量的基础。遇到搜索不准,先用 _analyze 看文本到底被切成了什么,再检查字段类型、查询方式、同义词、停用词和自定义词典。

真正能做好的商业搜索,不是只会写 match,而是能持续治理词库、评估搜索效果,并知道每次分词调整对索引重建和线上结果有什么影响。