Elasticsearch 分词
分词决定文本如何被拆成 token,并最终写入倒排索引。搜索结果不准确时,很多问题都和分词有关。
零基础可以先记住一句话:
ES 搜索不是直接拿整句话匹配整句话,而是先把文本拆成词,再根据词去倒排索引里找文档。
为什么分词重要
以商品名为例:
Apple iPhone 15 Pro Max 256G 官方旗舰用户可能搜索:
苹果手机 15pro 256如果分词器不能处理大小写、品牌词、型号词、同义词和中英文混合,可能出现:
- 搜“苹果手机”搜不到 iPhone。
- 搜“15pro”搜不到
15 Pro。 - 搜“蓝牙耳机”命中很多无关音箱。
- 商品标题里有词,但因为被切错导致排序很差。
所以商业搜索里,分词不是锦上添花,而是决定搜索质量的基础。
分词流程
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 查看分词
排查分词问题时,第一步不是猜,而是看实际切分结果。
GET /_analyze
{
"analyzer": "standard",
"text": "Apple iPhone 15 Pro Max 256G 官方旗舰"
}如果安装了 IK:
GET /_analyze
{
"analyzer": "ik_max_word",
"text": "无线蓝牙降噪耳机 Pro"
}看到 token 后再判断:哪些词被切出来,哪些词没切出来,哪些词太碎,哪些词需要加入自定义词典。
中文分词为什么特殊
英文天然有空格:
wireless bluetooth headset中文没有天然空格:
无线蓝牙降噪耳机如果简单按单字切,会得到:
无, 线, 蓝, 牙, 降, 噪, 耳, 机这种结果召回很泛,排序也差。更合理的是识别出:
无线, 蓝牙, 降噪, 耳机, 蓝牙耳机, 降噪耳机商业搜索经常要处理:
- 品牌词:Apple、苹果、华为。
- 型号词:iPhone 15 Pro、Mate 60、RTX 4090。
- 类目词:蓝牙耳机、跑步鞋、机械键盘。
- 规格词:256G、1TB、XL、42码。
- 同义词:无线耳机、蓝牙耳机。
- 错别字和大小写:airpods、AirPods、air pods。
text 和 keyword
分词通常发生在 text 字段上。
| 类型 | 是否分词 | 适合 |
|---|---|---|
text | 是 | 商品名、卖点、描述、工单内容、日志 message |
keyword | 否 | 品牌、状态、订单号、标签、精确匹配字段 |
商品名可以这样设计:
{
"productName": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}这样既能全文搜索,也能在必要时做完整名称精确匹配。
索引分词和查询分词
ES 有两个阶段:
- 写入文档时分词,叫索引分词。
- 用户搜索时分词,叫查询分词。
flowchart TD
A["写入商品名"] --> B["索引分词 analyzer"]
B --> C["倒排索引"]
D["用户搜索词"] --> E["查询分词 search_analyzer"]
E --> F["匹配倒排索引"]
F --> G["返回商品"]常见策略是:索引时切得更细,查询时切得更稳。
以 IK 为例:
| 分词器 | 特点 | 常见用途 |
|---|---|---|
ik_max_word | 尽量切出更多词 | 索引阶段,提高召回 |
ik_smart | 切得更粗更稳定 | 查询阶段,减少噪音 |
如果索引分词和查询分词完全不匹配,就会出现“写进去了但搜不到”的问题。
自定义 Analyzer Demo
下面是一个学习用示例,演示小写、同义词和自定义分词配置的基本结构。
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"
}
}
}
}测试分词:
GET /product_analyzer_demo/_analyze
{
"analyzer": "product_search_analyzer",
"text": "AirPods 主动降噪"
}生产环境的同义词通常不会直接写在 Mapping 里,而是通过同义词文件、可热更新机制或搜索服务侧词库治理。否则每次改同义词都可能需要重建索引。
同义词怎么用才合理
用户可能搜索不同叫法:
iPhone, 苹果手机
AirPods, 蓝牙耳机, 无线耳机
运动鞋, 跑步鞋
笔记本, 电脑, laptop同义词可以提升召回,但一定要克制。
| 做法 | 后果 |
|---|---|
| 同义词太少 | 用户换个说法搜不到 |
| 同义词太多 | 搜出来很多无关结果 |
| 双向同义词乱配 | “苹果”可能同时命中水果和手机 |
| 不区分类目 | “鼠标”在电脑配件和宠物语境完全不同 |
更稳的做法:
- 按业务类目维护同义词。
- 高频词先灰度验证。
- 配合搜索日志观察点击率和转化率。
- 对品牌词、型号词做人工维护。
停用词和低价值词
停用词是对搜索意义不大的词,例如:
的, 了, 和, 正品, 新款但商业搜索不能盲目删除所有看似低价值词。例如“新款手机”和“二手手机”里,“新款”“二手”可能就很重要。
停用词要结合业务判断:
| 词 | 是否适合停用 | 原因 |
|---|---|---|
| 的 | 通常可以 | 搜索意义弱 |
| 官方旗舰 | 不建议简单停用 | 可能影响转化和排序 |
| 二手 | 不应停用 | 直接影响商品属性 |
| 免息 | 不应随便停用 | 可能是营销筛选条件 |
前缀搜索和输入提示
搜索建议不能简单用 wildcard "*蓝牙*" 扛。数据大了会慢。
更常见的方案:
search_as_you_typecompletion suggesteredge_ngram- 独立热词表加 ES 或 Redis
search_as_you_type Demo:
PUT /suggest_demo
{
"mappings": {
"properties": {
"suggestText": { "type": "search_as_you_type" },
"hotScore": { "type": "long" }
}
}
}POST /suggest_demo/_doc/1
{
"suggestText": "蓝牙耳机",
"hotScore": 9800
}GET /suggest_demo/_search
{
"query": {
"multi_match": {
"query": "蓝牙",
"type": "bool_prefix",
"fields": [
"suggestText",
"suggestText._2gram",
"suggestText._3gram"
]
}
},
"sort": [
{ "hotScore": "desc" }
]
}分词调整后为什么要重建索引
分词结果是在写入时生成的。已经写入的文档,其倒排索引不会因为你修改了 analyzer 自动变化。
flowchart TD
A["旧 analyzer 写入文档"] --> B["生成旧倒排索引"]
C["修改 analyzer"] --> D["只影响之后新写入的数据"]
B --> E["旧数据仍然按旧分词搜索"]
D --> F["新旧分词结果不一致"]
F --> G["需要重建索引"]如果不重建,会出现同一类商品有的能搜到、有的搜不到,排查非常困难。
搜索不准排查流程
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。
修改分词器为什么不生效
已经写入的文档分词结果不会自动变化,通常需要重建索引。
为什么加同义词后结果变差
同义词扩大了召回范围,但也可能引入无关文档。要通过点击率、转化率、人工评测集验证,不要凭感觉大量添加。
为什么商品型号搜索很难
型号经常包含字母、数字、空格、连字符和大小写,例如 iPhone15Pro、iPhone 15 Pro、15pro。需要自定义词典、大小写归一、同义词或搜索服务侧归一化一起处理。
本章小结
分词是 ES 搜索质量的基础。遇到搜索不准,先用 _analyze 看文本到底被切成了什么,再检查字段类型、查询方式、同义词、停用词和自定义词典。
真正能做好的商业搜索,不是只会写 match,而是能持续治理词库、评估搜索效果,并知道每次分词调整对索引重建和线上结果有什么影响。
