
3.3 Elasticsearch-同义词、拼写纠错、Suggesters(term/phrase/completion)
1. 同义词(Synonyms)
同义词功能让“土豆≈马铃薯≈potato”这类映射在检索层生效,避免用户因为用词差异而漏掉文档。Elasticsearch 支持两种生效位置:
- 索引时(index-time):在
analyzer里放synonymfilter,写入前就把原文替换成统一词形。优点是查询快、倒排里直接命中;缺点是索引体积膨胀、同义词表变更必须重建索引。 - 查询时(search-time):给查询串单独配一个
search_analyzer,只在查询阶段展开同义词。索引体积不变,词表可随时热更新;代价是每次查询都要做一遍展开,QPS 高时 CPU 压力明显。
官方推荐“查询时展开”+“同义词过滤器缓存”的组合:
PUT /product
{
"settings": {
"analysis": {
"filter": {
"my_synonym": {
"type": "synonym",
"synonyms_path": "analysis/synonym.txt",
"updateable": true // 7.3+ 支持热更新
}
},
"analyzer": {
"synonym_analyzer": {
"tokenizer": "ik_max_word",
"filter": ["lowercase", "my_synonym"]
}
}
}
},
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "synonym_analyzer"
}
}
}
}
synonym.txt 示例:
土豆,马铃薯,potato
注意
- 多词同义词必须放在同一行,用英文逗号分隔;如果写成两行,ES 会当成双向同义,导致“土豆”也展开成“马铃薯 potato”,可能误召回。
- 查询时展开会把同义词当 OR 处理,默认
bool should语义,可通过tie_breaker调整权重。 - 若使用 IK 分词,务必保证同义词过滤器在 IK 之后,否则“土豆”还没被切出来就替换,会失效。
2. 拼写纠错(Spell Check)
ES 没有独立的“spellcheck” API,而是借助 suggester 里的 term 模式完成纠错。核心思路:把用户输入的每个词与索引里实际出现的词做编辑距离(Levenshtein)比对,返回距离 ≤ max_edits(默认 2)且词频 ≥ min_doc_freq 的候选。
POST /product/_search
{
"suggest": {
"spell-check": {
"text": "马铃署",
"term": {
"field": "title",
"string_distance": "internal", // 可选 ngram、levenshtein、jarowinkler
"max_edits": 2,
"min_doc_freq": 2,
"sort": "frequency"
}
}
}
}
返回示例:
"suggest": {
"spell-check": [
{
"text": "马铃署",
"offset": 0,
"length": 3,
"options": [
{ "text": "马铃薯", "score": 0.89, "freq": 314 },
{ "text": "马铃鼠", "score": 0.71, "freq": 5 }
]
}
]
}
拿到候选后,前端可提示“您是不是要找:马铃薯”。
3. Suggesters 三兄弟
ES 把“建议”抽象成三种模式,各自有适用场景:
| 类型 | 工作级别 | 数据来源 | 实时性 | 典型场景 |
|---|---|---|---|---|
| term | 词粒 | 倒排索引 | 实时 | 拼写纠错 |
| phrase | 短语粒 | 倒排+Shingle | 实时 | 整句纠错(“elasticsearh”→“elasticsearch”) |
| completion | 前缀粒 | 独立的 in-memory FST | 实时 | 搜索框自动补全(“el”→“elasticsearch”) |
3.1 term suggester
已在上节演示。只纠错,不补全;返回单个词候选。
3.2 phrase suggester
在 term 基础上加 n-gram 语言模型,对整句打分,能纠正“空格打错”“词序颠倒”等跨词错误。
POST /product/_search
{
"suggest": {
"phrase-check": {
"text": "elasticsearh 同义词",
"phrase": {
"field": "title.trigram", // 需提前用 shingle filter 生成 trigram 字段
"max_errors": 0.8,
"confidence": 2.0,
"highlight": {
"pre_tag": "<em>",
"post_tag": "</em>"
}
}
}
}
}
返回:
"options": [
{
"text": "elasticsearch <em>同义词</em>",
"highlighted": "elasticsearch <em>同义词</em>",
"score": 0.92
}
]
注意
title.trigram需用shinglefilter 生成 2-3 词滑动窗口,否则语言模型无数据。confidence越高,候选越少;max_errors表示允许句子中最多有多大比例被纠错,默认 1.0(全句可改)。
3.3 completion suggester
专为“边输入边提示”设计,数据结构是内存里的 FST(Finite State Transducer),前缀查询复杂度 O(k)(k 为前缀长度),毫秒级返回。
PUT /product
{
"mappings": {
"properties": {
"title": {
"type": "completion", // 独立字段类型
"analyzer": "ik_max_word",
"preserve_separators": true,
"preserve_position_increments": true,
"max_input_length": 50
}
}
}
}
写入:
POST /product/_doc/1
{
"title": ["Elasticsearch 同义词", "ES 同义词设置"]
}
查询:
POST /product/_search
{
"suggest": {
"completion-sug": {
"prefix": "es 同",
"completion": {
"field": "title",
"size": 5,
"fuzzy": {
"fuzziness": 1 // 允许前缀也模糊
}
}
}
}
}
返回:
"options": [
{ "text": "ES 同义词设置", "_score": 1.0 },
{ "text": "Elasticsearch 同义词", "_score": 0.8 }
]
进阶玩法
- 用
context做分类过滤,比如只提示“手机”类目下的品牌。 - 结合
payload回传商品 ID、价格,前端直接渲染,无需二次查询。 - 7.x 之后支持 可搜索快照 里的
completion,FST 可以落盘到快照,集群重启不再重建,冷启动时间从分钟级降到秒级。
4. 运维与性能
- 同义词热更新:7.3+ 的
updateable=true只对search-time生效,文件变更后调用_reload_search_analyzers即可,无需滚动重启。 - completion 内存占用:FST 大小 ≈ 索引唯一词项数 × 平均长度 × 1.5 byte,1000 万中文词约 2 GB。若数据量过大,可拆分成多索引 + alias,或改用
search-as-you-type字段(内部是 shingle + prefix query,内存友好但 latency 稍高)。 - phrase suggester 的 shard 级局部模型:默认只在协调节点合并候选,跨 shard 时可能打分不准。可设置
?preference=_local让查询落到同一 shard,提升一致性。
5. 小结
- 同义词:优先“查询时展开”,词表走文件 +
reload_search_analyzers热更新。 - 拼写纠错:term suggester 做单词,phrase suggester 做整句,均需提前构造 shingle 字段。
- 自动补全:completion suggester 基于内存 FST,最快;数据量大时考虑
search-as-you-type或分层索引。 - 三者可以组合成“输入-纠错-补全-同义展开”的完整链路,让用户“打错也能搜到,打一半就能提示,提示的还是同义词扩展后的结果”。
更多技术文章见公众号: 大城市小农民
696

被折叠的 条评论
为什么被折叠?



