Elasticsearch 的 analyzer、tokenizer 和 token filter 有什么区别?
简化版
analyzer 是完整分析链,通常由 character filter、tokenizer 和 token filter 组成。tokenizer 负责把文本切成 token,token filter 负责对 token 做小写、停用词、同义词、词干等处理;索引时和搜索时 analyzer 不一致,可能导致查不到或召回异常。
详细版
Elasticsearch 的全文检索不是直接拿原字符串匹配,而是先分析文本。典型链路是:character filter 先清洗原文,tokenizer 切词,token filter 再规范化 token。
"The Quick Foxes!"
-> tokenizer
-> ["The", "Quick", "Foxes"]
-> lowercase/stemmer
-> ["the", "quick", "fox"]
面试回答要强调:analyzer 是总装配,tokenizer 是切词器,token filter 是 token 后处理。text 字段会走 analyzer,keyword 字段通常保持整体值。中文、英文、日志、商品名的 analyzer 设计不同,要用 _analyze API 验证实际 token。
完整版教学
一、为什么搜索前要做文本分析
全文检索面对的是自然语言,不是简单等值匹配。用户搜 quick fox,文档里可能写 The Quick Foxes;如果按原字符串精确比较,就很难召回。
文本分析的目标是把“人类语言”转成“可检索 token”。大小写、标点、复数、同义词、中文切词都会影响召回和相关性。
原文: The Quick Foxes!
期望: quick / fox 这些词能被搜索命中
记忆钩子:Analyzer 是流水线,tokenizer 负责切开,token filter 负责打磨。
二、Analyzer 是完整流水线
一个 analyzer 通常包含 3 层。
| 组件 | 输入 | 输出 | 例子 |
|---|---|---|---|
| character filter | 原始字符串 | 清洗后的字符串 | 去 HTML、字符映射 |
| tokenizer | 字符串 | token 列表 | standard、keyword、ngram |
| token filter | token 列表 | 新 token 列表 | lowercase、stop、synonym |
流程可以画成:
raw text
-> char_filter
-> tokenizer
-> token_filter
-> indexed tokens
如果只记 tokenizer,就会漏掉很多线上问题。例如 HTML 标签没清洗、大小写没统一、同义词放错位置,都可能导致搜索体验异常。
三、Tokenizer 决定怎么切词
Tokenizer 是分析链里最核心的一步,它决定文本如何被切成 token。
常见 tokenizer:
| tokenizer | 行为 | 适合场景 |
|---|---|---|
standard | 按 Unicode 文本规则切分 | 通用英文、混合文本 |
keyword | 整个输入当一个 token | 标签、枚举、编号 |
ngram | 按 N 个字符切片 | 模糊匹配、部分匹配 |
edge_ngram | 从开头生成前缀 | 搜索建议、前缀补全 |
比如 keyword tokenizer 处理 Beijing China 会得到 1 个 token;standard 可能得到 2 个 token。这个差异会直接决定查询能否命中。
四、Token filter 改变 token 的形态
Token filter 在切词之后工作,常见动作是小写化、去停用词、同义词扩展、词干还原。
["The", "Quick", "Foxes"]
lowercase -> ["the", "quick", "foxes"]
stop -> ["quick", "foxes"]
stemmer -> ["quick", "fox"]
顺序很重要。同义词、词干、大小写如果顺序不合理,生成 token 会不同。比如先做同义词还是先做词干,可能影响同义词规则能否匹配。
面试里可以补一句:不要凭想象判断分词结果,用 _analyze API 看真实 token。
五、索引 analyzer 和搜索 analyzer 可以不同
字段可以设置索引时 analyzer,也可以设置搜索时 analyzer。索引 analyzer 决定写入倒排索引的 token,搜索 analyzer 决定查询文本被拆成什么 token。
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
}
}
}
}
常见策略是索引时切得细一点,提高召回;搜索时切得粗一点,提高精度。但这不是固定公式,商品搜索、文章搜索、日志搜索的目标不同。
六、用 _analyze API 做验证
分析器配置必须测试。一个简单 _analyze 请求能让你看到最终 token。
POST /_analyze
{
"analyzer": "standard",
"text": "The Quick Foxes!"
}
如果返回 token 是 the、quick、foxes,你就能判断停用词和词干有没有生效。线上搜索问题常常不是查询 DSL 错,而是 analyzer 产生的 token 与预期不同。
验证时至少测 3 类样本:正常词、边界词、业务特殊词。比如中文品牌名、英文缩写、带连字符型号、同义词词典里的词。
七、常见误区与追问
- 误区:Analyzer 和 tokenizer 是一回事。 Analyzer 是完整流水线,tokenizer 只是其中负责切词的一环。
- 误区:分词越细召回越好就一定越好。 分词太细会引入噪声,相关性下降,商品名尤其容易误召回。
- 误区:索引 analyzer 和搜索 analyzer 必须一样。 可以不同,但要明确召回和精度取舍,并用样本验证。
- 追问:为什么 keyword 字段不适合全文搜索? keyword 通常整体作为一个 token,更适合精确过滤、排序和聚合。
- 追问:中文搜索为什么常要自定义 analyzer? 中文没有天然空格分隔,默认分析器很难满足业务词边界。
- 追问:怎么排查搜不到? 用
_analyze看索引和查询 token,再看 mapping、字段类型和查询 DSL。
八、加强记忆
Elasticsearch 分词题记成“清洗、切词、打磨、验证”。Analyzer 是总流水线,character filter 清洗原文,tokenizer 切出 token,token filter 做小写、停用词、同义词等后处理。索引和搜索 analyzer 可能不同,但必须用 _analyze 验证真实 token;搜索查不到时,先别急着改 DSL,先看字段类型和分析结果。