这是《Elasticsearch 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 中文搜索效果往往取决于分词。同一个查询“轻薄高性能笔记本”,不同的 Analyzer 可能产生完全不同的词项,进而影响召回和排序。
本章讲解 Analyzer 组成、内置分词器、自定义分词、中文分词、多字段分词、搜索与写入分词差异,以及分词排查方法。
7.1 什么是 Analyzer
Analyzer 是文本分析流程,负责把原始字符串转换为倒排索引用的词项。
Character Filters -> Tokenizer -> Token Filters
| 组件 | 作用 | 示例 |
|---|---|---|
| Character Filter | 处理原始字符 | 去 HTML 标签 |
| Tokenizer | 切分词元 | 按空格、英文单词、中文词 |
| Token Filter | 处理词元 | 小写、停用词、同义词、词干 |
输入:
Elasticsearch 搜索引擎实战
可能输出:
elasticsearch
搜索
搜索引擎
实战
7.2 _analyze API
这是排查分词最重要的工具。
POST /_analyze
{
"analyzer": "standard",
"text": "Elasticsearch 搜索引擎实战"
}
返回:
{
"tokens": [
{
"token": "elasticsearch",
"start_offset": 0,
"end_offset": 13,
"type": "<ALPHANUM>",
"position": 0
}
]
}
指定字段 Analyzer:
POST /products/_analyze
{
"field": "title",
"text": "轻薄高性能笔记本电脑"
}
自定义测试:
POST /_analyze
{
"tokenizer": "standard",
"filter": ["lowercase"],
"text": "Elasticsearch SEARCH Engine"
}
7.3 内置 Analyzer
| Analyzer | 特点 |
|---|---|
standard |
默认,英文效果好,中文常按单字切 |
simple |
按非字母切分并转小写 |
whitespace |
按空白切分,不转小写 |
stop |
类似 simple,并移除停用词 |
keyword |
不分词 |
pattern |
按正则切分 |
fingerprint |
排序并拼接词项,适合去重 |
standard 测试:
POST /_analyze
{
"analyzer": "standard",
"text": "高性能笔记本电脑"
}
常见输出:
高
性
能
笔
记
本
电
脑
它对英文处理较好,但中文搜索会产生大量单字词项,通常需要中文分词器。
7.4 Tokenizer
| Tokenizer | 说明 |
|---|---|
standard |
Unicode 文本分词 |
whitespace |
按空白切分 |
letter |
按字母切分 |
lowercase |
等价 letter + lowercase |
keyword |
不分词 |
pattern |
正则切分 |
path_hierarchy |
路径分词 |
edge_ngram |
前缀切分 |
路径分词:
POST /_analyze
{
"tokenizer": "path_hierarchy",
"text": "/usr/local/elasticsearch"
}
输出:
/usr
/usr/local
/usr/local/elasticsearch
适合类目路径、部门路径、文件路径。
7.5 Token Filter
| Filter | 作用 |
|---|---|
lowercase |
小写 |
uppercase |
大写 |
stop |
停用词 |
stemmer |
英文词干 |
asciifolding |
音符字符转换 |
trim |
去首尾空白 |
synonym |
同义词 |
ngram |
N-gram |
edge_ngram |
前缀 N-gram |
word_delimiter |
拆分复合词 |
unique |
词项去重 |
示例:
POST /_analyze
{
"tokenizer": "standard",
"filter": ["lowercase", "stop"],
"text": "The Quick Brown Fox"
}
输出:
quick
brown
fox
7.6 自定义 Analyzer
在索引设置中定义:
PUT /articles
{
"settings": {
"analysis": {
"filter": {
"my_stopwords": {
"type": "stop",
"stopwords": ["的", "了", "和"]
}
},
"analyzer": {
"custom_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": ["lowercase", "my_stopwords"]
}
}
}
},
"mappings": {
"properties": {
"content": {
"type": "text",
"analyzer": "custom_analyzer"
}
}
}
}
也可以加入 Character Filter,例如移除 HTML 标签:
"analyzer": {
"html_analyzer": {
"type": "custom",
"char_filter": ["html_strip"],
"tokenizer": "standard",
"filter": ["lowercase"]
}
}
注意:Analyzer 属于索引设置,修改已索引字段的 Analyzer 通常需要 Reindex。
7.7 中文分词:IK
常用模式:
| Analyzer | 特点 |
|---|---|
ik_max_word |
尽可能多切分,召回更全 |
ik_smart |
尽量少切分,词项更粗 |
写入测试:
POST /_analyze
{
"analyzer": "ik_max_word",
"text": "轻薄高性能笔记本电脑"
}
可能输出:
轻薄
高性能
笔记本
电脑
搜索测试:
POST /_analyze
{
"analyzer": "ik_smart",
"text": "轻薄笔记本电脑"
}
常见组合:
{
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
}
}
思路是索引时多切分提升召回,搜索时少切分减少无关组合。具体效果必须按业务查询评估。
7.8 IK 自定义词典
安装目录下通常有配置文件:
config/analysis-ik/
+-- IKAnalyzer.cfg.xml
+-- main.dic
+-- stopword.dic
+-- custom/
添加自定义词:
程序员
云原生
高刷新率
轻薄本
添加停用词:
请问
一下
怎么样
修改后需要重启或调用插件提供的 reload API,具体能力取决于插件版本。
词表治理示例:
| 类型 | 示例 | 目的 |
|---|---|---|
| 业务词 | 轻薄本、高刷新率 | 避免拆错 |
| 品牌词 | Elasticsearch、云原生 | 保持专有名词 |
| 停用词 | 请问、一下、怎么样 | 降低噪声 |
| 同义词 | 笔记本=笔记本电脑 | 扩展召回 |
| 屏蔽词 | 违规词 | 合规控制 |
7.9 同义词
搜索时同义词:
PUT /products
{
"settings": {
"analysis": {
"filter": {
"search_synonym": {
"type": "synonym_graph",
"synonyms": [
"笔记本,笔记本电脑",
"手机,智能手机"
]
}
},
"analyzer": {
"search_synonym_analyzer": {
"tokenizer": "ik_max_word",
"filter": ["search_synonym"]
}
}
}
}
}
Mapping:
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "search_synonym_analyzer"
}
}
}
}
写入时同义词会增加索引体积;搜索时同义词灵活但增加查询成本。业务词表频繁变化时,通常优先使用搜索时同义词。
7.10 搜索补全
edge_ngram
适合输入前缀补全:
PUT /suggests
{
"settings": {
"analysis": {
"filter": {
"edge_ngram_filter": {
"type": "edge_ngram",
"min_gram": 1,
"max_gram": 20
}
},
"analyzer": {
"edge_ngram_analyzer": {
"tokenizer": "standard",
"filter": ["lowercase", "edge_ngram_filter"]
}
}
}
},
"mappings": {
"properties": {
"keyword": {
"type": "text",
"analyzer": "edge_ngram_analyzer",
"search_analyzer": "standard"
}
}
}
}
写入 elasticsearch 后索引:
e
el
ela
elas
...
completion suggester
PUT /suggests-completion
{
"mappings": {
"properties": {
"suggest": {
"type": "completion"
}
}
}
}
写入:
PUT /suggests-completion/_doc/1
{
"suggest": {
"input": ["Elasticsearch 教程", "ES 入门"],
"weight": 10
}
}
查询:
GET /suggests-completion/_search
{
"suggest": {
"product-suggest": {
"prefix": "elastic",
"completion": {
"field": "suggest"
}
}
}
}
7.11 多字段分词策略
同一文本可以用不同 Analyzer 建多个子字段:
{
"title": {
"type": "text",
"analyzer": "ik_max_word",
"fields": {
"smart": {
"type": "text",
"analyzer": "ik_smart"
},
"english": {
"type": "text",
"analyzer": "english"
},
"keyword": {
"type": "keyword",
"ignore_above": 128
}
}
}
}
查询:
{
"multi_match": {
"query": "elasticsearch search",
"fields": ["title", "title.smart", "title.english"],
"type": "most_fields"
}
}
适合中英混合、品牌词、缩写、拼音等场景。
7.12 拼音搜索
可使用拼音分词插件。常见三层召回:
中文原词 -> 拼音全拼 -> 拼音缩写
示例:
用户输入:bjb
候选结果:笔记本
拼音搜索要重点治理:
- 多音字;
- 拼音切分歧义;
- 英文品牌词;
- 缩写误召回;
- 词表更新流程。
7.13 写入分词与搜索分词
搜索前,查询文本也会被分析。
GET /products/_search
{
"query": {
"match": {
"title": {
"query": "高性能笔记本",
"analyzer": "ik_smart"
}
}
}
}
常见问题:
| 问题 | 原因 |
|---|---|
| 文档搜不到 | 写入与搜索词项不同 |
| 召回太多 | 分词过细 |
| 召回太少 | 分词过粗或词表缺失 |
| 大小写不匹配 | 未 lowercase |
| 同义词无效 | Analyzer 未生效或未重建 |
| 前缀搜不到 | 未使用 edge_ngram/completion |
排查步骤:
1. _analyze 写入 Analyzer
2. _analyze 搜索 Analyzer
3. 对比词项
4. 查看 Mapping
5. 用 term query 验证词项
6. 检查词库和同义词
7.14 分词与相关性
分词结果直接影响 BM25:
- 词项越多,单字段匹配概率越高;
- 罕见词通常权重更高;
- 字段长度影响归一化;
- 多字段重复内容会提高匹配度;
- 停用词和同义词会改变召回。
不要只追求“能搜到”,还要观察无关结果是否变多、长标题是否被过度惩罚、品牌词是否被拆错、缩写是否有专门字段、热门词是否需要业务加权。
7.15 本章小结
- Analyzer 由 Character Filter、Tokenizer、Token Filter 组成;
_analyze是排查分词问题的第一工具;- 中文通常使用 IK 等分词器,并按业务维护词表;
- 索引分词和搜索分词可以不同;
- 多字段分词可以兼顾中文、英文、拼音、精确匹配和补全;
- 同义词、edge_ngram、completion 是搜索体验常用能力;
- 分词质量直接决定召回、排序和用户体验。
7.16 思考题
ik_max_word和ik_smart应如何组合使用?- 为什么修改索引 Analyzer 通常需要重建索引?
- 写入时同义词和搜索时同义词各有什么优缺点?
- 用户输入“ysb”想搜“笔记本”,如何设计拼音搜索?
- 如果某个查询无结果,你会按什么顺序排查分词?