Skip to content
ES
搜索补全与 Suggesters

搜索补全与 Suggesters

两种搜索补全方案:(1)拼音分词器实现中文模糊补全;(2)Completion Suggester 实现毫秒级自动补全。


方案一:拼音分词器(中文场景)

应用场景

用户在搜索框输入:

  • 汉字 → “张三” 匹配含"张三"的文档
  • 全拼 → “zhangsan” 匹配含"张三"的文档
  • 拼音首字母 → “zs” 匹配含"张三"的文档

{5A8C84AC-D283-4696-8786-B4C69F0BBD00}

安装

# https://github.com/infinilabs/analysis-pinyin
./elasticsearch-plugin install https://github.com/infinilabs/analysis-pinyin/releases/download/v9.3.4/elasticsearch-analysis-pinyin-9.3.4.zip

核心策略:索引与搜索分析器分离

PUT /suggest
{
    "settings": {
        "analysis": {
            "analyzer": {
                "pinyin_analyzer": {
                    "tokenizer": "ik_max_word",
                    "filter": ["pinyin_filter"]
                }
            },
            "filter": {
                "pinyin_filter": {
                    "type": "pinyin",
                    "keep_full_pinyin": true,
                    "keep_joined_full_pinyin": true,
                    "keep_original": true,
                    "keep_first_letter": true,
                    "keep_separate_first_letter": true
                }
            }
        }
    },
    "mappings": {
        "properties": {
            "title": {
                "type": "text",
                "analyzer": "pinyin_analyzer",
                "search_analyzer": "ik_smart"
            }
        }
    }
}
参数 说明
analyzer 索引时使用:IK 分词 → 拼音转换 → 生成多路 term
search_analyzer 搜索时使用:仅用 IK 分词,不走拼音
keep_full_pinyin 保留全拼(zhang, san)
keep_joined_full_pinyin 保留连拼(zhangsan)
keep_first_letter 保留首字母(z, s)
keep_original 保留原文(张三)
keep_separate_first_letter 保留分开的首字母

image-20260610145600133

🔬 深入原理:索引时 “张三” → term 列表 ["张", "三", "zhang", "san", "zhangsan", "zs", "z", "s"]。搜索时用户输入 “张三” 用 IK 分词匹配 “张”/“三”,输入 “zhangsan” 也匹配到 “zhangsan” term。分离分析器防止搜索 “zhang” 时匹配到与拼音无关的文档。

效果演示

{0EE20F34-4811-4CCD-87C1-FB7468BD0312}

{1174A3AB-759E-42B7-A9E5-6F20B8F12705}


方案二:Completion Suggester(英文/关键词场景)

拼音方案基于反向索引(Term Dictionary),每次搜索遍历倒排表,延迟约 10-50ms。而 Completion Suggester 基于 FST(Finite State Transducer),在内存中构建有限状态机,延迟约 1-5ms,适合英文前缀补全和结构化关键词补全。

FST vs 倒排索引

维度 Completion Suggester (FST) 拼音分词 (倒排索引)
原理 内存中 FST,前缀树遍历 倒排索引 Term 匹配
延迟 1-5ms 10-50ms
中文支持 ❌ 不直接支持拼音 ✅ 原生支持
存储 内存,需谨慎控制规模 磁盘(OS 页缓存)
适用 英文、标签、用户名、品牌 中文商品名、人名、地址

基础用法

# Mapping
PUT /suggest_completion
{
    "mappings": {
        "properties": {
            "title": { "type": "text" },
            "suggest": {
                "type": "completion"
            }
        }
    }
}

# 写入数据
POST /suggest_completion/_doc/1
{
    "title": "Elasticsearch Guide",
    "suggest": {
        "input": ["Elasticsearch", "ES", "Search Engine"],
        "weight": 100
    }
}

# 查询
POST /suggest_completion/_search
{
    "_source": "title",
    "suggest": {
        "title-suggest": {
            "prefix": "elas",
            "completion": {
                "field": "suggest",
                "size": 10,
                "skip_duplicates": true
            }
        }
    }
}
参数 说明
input 输入词条(可多个同义词)
weight 权重,越高越靠前(可选)
skip_duplicates 跳过重复文本
fuzzy 启用模糊匹配(容忍拼写错误)

模糊匹配

POST /suggest_completion/_search
{
    "suggest": {
        "title-suggest": {
            "prefix": "elastc",
            "completion": {
                "field": "suggest",
                "fuzzy": {
                    "fuzziness": "AUTO",
                    "min_length": 3
                }
            }
        }
    }
}

方案三:Context Suggester — 带上下文的补全

根据上下文(如分类、地理位置)过滤补全建议。

# Mapping(按分类过滤)
PUT /places
{
    "mappings": {
        "properties": {
            "suggest": {
                "type": "completion",
                "contexts": [
                    {
                        "name": "category",
                        "type": "category"
                    }
                ]
            }
        }
    }
}

# 写入
POST /places/_doc/1
{
    "suggest": {
        "input": ["星巴克"],
        "contexts": { "category": ["咖啡", "餐饮"] }
    }
}

# 查询(只返回餐饮类)
POST /places/_search
{
    "suggest": {
        "place-suggest": {
            "prefix": "星",
            "completion": {
                "field": "suggest",
                "contexts": {
                    "category": ["餐饮"]
                }
            }
        }
    }
}

方案四:Edge N-Gram(灵活但占空间)

在索引时按字符前缀拆分,适合更灵活的补全场景。

PUT /autocomplete
{
    "settings": {
        "analysis": {
            "filter": {
                "edge_ngram_filter": {
                    "type": "edge_ngram",
                    "min_gram": 1,
                    "max_gram": 20
                }
            },
            "analyzer": {
                "edge_ngram_analyzer": {
                    "type": "custom",
                    "tokenizer": "standard",
                    "filter": ["lowercase", "edge_ngram_filter"]
                }
            }
        }
    },
    "mappings": {
        "properties": {
            "title": {
                "type": "text",
                "analyzer": "edge_ngram_analyzer",
                "search_analyzer": "standard"
            }
        }
    }
}
方案 适用场景 推荐度
拼音分词 中文搜索框(支持汉字+拼音+首字母) ⭐⭐⭐ 中文首选
Completion Suggester 英文/标签/用户名前缀补全 ⭐⭐⭐ 英文首选
Context Suggester 带分类/地域过滤的补全 ⭐⭐ 需要分类过滤时
Edge N-Gram 自定义匹配逻辑、需要中缀匹配 ⭐ 灵活但占空间

常见陷阱

陷阱 说明
🚨 搜索时也用拼音分词器 搜索 “zhang” 可能匹配到含 “张” 但与 Zhang 无关的文档
🚨 keep_original: false 纯汉字搜索无法命中,必须保留原文
🚨 IK 插件和拼音插件版本不匹配 两者版本必须与 ES 版本一致
🚨 Completion Suggester 不支持中文拼音 FST 不做分词,拼音场景应用方案一
🚨 Completion input 不允许重复 同一文档的 input 数组不允许有重复值
🚨 Edge N-Gram 索引膨胀 每个词生成 N 个 term,磁盘和内存消耗大