目录
-
- [一、`keyword` 字段的 `prefix` 查询:最直接的结构化前缀匹配](#一、
keyword字段的prefix查询:最直接的结构化前缀匹配) - 二、`match_phrase_prefix`:查询时短语前缀匹配
- 三、`bool_prefix`:多字段前缀组合查询
- 四、`edge_ngram`:经典但笨重的预处理方案
- 五、`search_as_you_type`:官方推荐的均衡方案
- [六、`Completion Suggester`:极致性能的专用工具](#六、
Completion Suggester:极致性能的专用工具) - 七、总结与选型矩阵
- [一、`keyword` 字段的 `prefix` 查询:最直接的结构化前缀匹配](#一、
在实际开发中,搜索框的"输入即搜索"(Search-as-you-type)功能几乎成了标配。Elasticsearch 提供了多种实现前缀匹配的技术,包括面向 text 字段的 match_phrase_prefix、 bool_prefix、 edge_ngram、 search_as_you_type,面向极致性能的 completion suggester,以及面向 keyword 字段的 prefix 查询。很多开发者容易混淆它们之间的差别和适用场景。本文将带你从原理到实战,逐一剖析这六种方案,并给出可直接运行的索引和查询示例。
一、keyword 字段的 prefix 查询:最直接的结构化前缀匹配
1)原理简述
prefix 查询用于 keyword 类型(不分词)的字段。它在查询时扫描倒排索引中所有以指定前缀开头的词项。由于 keyword 字段存储完整的词项(如 "user_12345"),prefix 查询可以快速定位到以 "user_" 开头的所有文档。但如果前缀太短(如单个字母),性能会急剧下降。
2)索引建立
推荐同时开启 index_prefixes 参数,让 ES 额外建立前缀索引以加速查询。
json
PUT /users
{
"mappings": {
"properties": {
"uid": {
"type": "keyword",
"index_prefixes": {
"min_chars": 2,
"max_chars": 10
}
}
}
}
}
3)查询示例
查询所有 uid 以 "user_12" 开头的文档:
json
GET /users/_search
{
"query": {
"prefix": {
"uid": "user_12"
}
}
}
如果字段是动态映射的 text 类型下的 .keyword 子字段,写法为 "uid.keyword": "user_12"。
4)优缺点
- ✅ 简单直接,无需自定义分析器。
- ✅ 支持大小写不敏感(
case_insensitive参数)。 - ❌ 短前缀性能差,需要配合
index_prefixes优化。 - ❌ 只能用于
keyword字段,无法处理分词后的文本自动补全。
二、match_phrase_prefix:查询时短语前缀匹配
1)原理简述
match_phrase_prefix 是一种查询类型,它在查询时动态工作。它将用户输入的文本视为一个短语,最后一个词作为前缀,去倒排索引中查找所有以此前缀开头的词条,并保持短语中前面词的顺序。由于要动态扫描多个词条,性能较差,通常需要配合 max_expansions 限制扩展数量。
2)索引建立
无需特殊分析器,普通 text 字段即可。
json
PUT /blog_articles
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "standard"
}
}
}
}
3)查询示例
假设用户输入 "elastic sea",希望匹配 "elasticsearch" 开头的文档。
json
GET /blog_articles/_search
{
"query": {
"match_phrase_prefix": {
"title": {
"query": "elastic sea",
"max_expansions": 10
}
}
}
}
4)优缺点
- ✅ 无需特殊索引,开箱即用。
- ❌ 性能最差,长尾前缀或高并发时容易超时。
- ❌
max_expansions限制可能导致结果被截断。
建议 :仅用于快速原型验证,禁止在生产环境作为主搜索建议方案。
三、bool_prefix:多字段前缀组合查询
1)原理简述
bool_prefix 是 multi_match 查询的一种 type。它会将查询字符串分词后,最后一个词作为前缀查询(prefix 查询),其余词作为普通的词项查询(term 查询),然后将它们用 AND 逻辑组合。这非常适合在多个字段上同时进行前缀匹配。
2)索引建立
依然使用普通 text 字段即可。
json
PUT /products
{
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "standard"
},
"brand": {
"type": "text",
"analyzer": "standard"
}
}
}
}
3)查询示例
用户在搜索框输入 "apple i",期望在 name 或 brand 字段中找到以 "i" 开头的词(如 "iPhone")。
json
GET /products/_search
{
"query": {
"multi_match": {
"query": "apple i",
"type": "bool_prefix",
"fields": ["name", "brand"]
}
}
}
4)优缺点
- ✅ 支持多字段,使用简单。
- ✅ 与
match_phrase_prefix相比,能保持更好的精度(非最后一个词强制为 term)。 - ❌ 仍然属于查询时动态计算,性能不如索引时预处理方案。
建议:适合对性能要求不高的多字段前缀搜索场景。
四、edge_ngram:经典但笨重的预处理方案
1)原理简述
edge_ngram 是一个 tokenizer 或 filter,它在索引时 将每个词从首字母开始切分成多个前缀片段(如 elastic → e, el, ela, elas, elast, elasti, elastic)。搜索时用户输入的前缀可以直接匹配这些片段,查询极快。但代价是索引体积显著膨胀。
2)索引建立
需要自定义分析器,并应用到目标字段。
json
PUT /books
{
"settings": {
"analysis": {
"analyzer": {
"edge_ngram_analyzer": {
"tokenizer": "standard",
"filter": ["lowercase", "edge_ngram_filter"]
}
},
"filter": {
"edge_ngram_filter": {
"type": "edge_ngram",
"min_gram": 2,
"max_gram": 10
}
}
}
},
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "edge_ngram_analyzer",
"search_analyzer": "standard" // 查询时用标准分词
}
}
}
}
3)查询示例
用户输入 "ela" 即可匹配包含 "elastic" 或 "elasticsearch" 的文档。
json
GET /books/_search
{
"query": {
"match": {
"title": "ela"
}
}
}
4)优缺点
- ✅ 查询速度快,完全避免了查询时的前缀扩展。
- ❌ 索引体积可增大 10~30 倍,写入性能下降。
- ❌ 对短语顺序匹配支持弱(需要额外配置
match_phrase)。 - ❌ 配置较复杂。
建议:仅在读多写少、对存储不敏感且需要极致查询性能的场景下使用。
五、search_as_you_type:官方推荐的均衡方案
1)原理简述
从 ES 7.2 开始引入的专用字段类型。它在索引时自动创建多个子字段:
_2gram、_3gram:存储 2 个词和 3 个词的连续序列(shingles)。_index_prefix:基于 3-gram 字段再应用edge_ngram生成前缀索引。
搜索时使用 multi_match 的 bool_prefix 类型,可以同时匹配单词前缀和短语前缀,实现了性能和功能的良好平衡。
2)索引建立
直接将字段类型定义为 search_as_you_type,可选配置 max_shingle_size(默认 3)。
json
PUT /movies
{
"mappings": {
"properties": {
"title": {
"type": "search_as_you_type",
"max_shingle_size": 3
}
}
}
}
3)查询示例
用户输入 "the dark k",期望匹配短语 "the dark knight"。
json
GET /movies/_search
{
"query": {
"multi_match": {
"query": "the dark k",
"type": "bool_prefix",
"fields": [
"title",
"title._2gram",
"title._3gram"
]
}
}
}
4)优缺点
- ✅ 开箱即用,无需自定义分析器。
- ✅ 支持单词前缀和短词组前缀,匹配准确。
- ✅ 性能优于
match_phrase_prefix,存储开销小于纯edge_ngram。 - ❌ 对非常长的短语(超过
max_shingle_size)支持有限。
建议 :首选方案,覆盖绝大多数搜索建议场景。
六、Completion Suggester:极致性能的专用工具
1)原理简述
completion 字段类型在索引时构建有限状态转换器(FST) ,全部加载到内存中。查询时通过 FST 进行前缀查找,响应时间通常在微秒级,且支持模糊匹配、上下文过滤和自定义权重。它不是为了全文检索设计,而是专门为快速补全服务的。
2)索引建立
字段类型为 completion,可配置 analyzer、contexts 等。
json
PUT /cities
{
"mappings": {
"properties": {
"name": {
"type": "completion",
"analyzer": "simple",
"contexts": [
{
"name": "country",
"type": "category"
}
]
}
}
}
}
索引文档时,可以指定 input 和 weight。
json
POST /cities/_doc
{
"name": {
"input": ["New York", "NYC"],
"weight": 100
},
"country": "USA"
}
3)查询示例
搜索 "ne" 并过滤国家为 "USA"。
json
GET /cities/_search
{
"suggest": {
"city_suggestion": {
"prefix": "ne",
"completion": {
"field": "name",
"size": 5,
"contexts": {
"country": ["USA"]
},
"fuzzy": {
"fuzziness": 1
}
}
}
}
}
4)优缺点
- ✅ 查询速度极快(毫秒级甚至微秒级)。
- ✅ 原生支持模糊匹配、上下文过滤和权重排序。
- ❌ 内存消耗大(FST 常驻内存)。
- ❌ 不支持短语顺序(只能匹配前缀,不能保证中间词的顺序)。
- ❌ 查询语法不同于普通查询(通过
suggest端点)。
建议:适合对速度要求极致、数据量可控且内存充裕的自动补全场景(如电商搜索框、导航栏)。
七、总结与选型矩阵
| 方案 | 适用字段类型 | 查询性能 | 存储/内存 | 短语支持 | 配置复杂度 | 推荐指数 |
|---|---|---|---|---|---|---|
prefix (keyword) |
keyword |
中等(需优化) | 低 | 不支持 | 低 | ⭐⭐⭐ |
match_phrase_prefix |
text |
差 | 低 | 支持 | 低 | ⭐ |
bool_prefix |
text |
中等 | 低 | 支持 | 低 | ⭐⭐ |
edge_ngram |
text |
高 | 高(磁盘) | 弱 | 高 | ⭐⭐⭐ |
search_as_you_type |
text |
高 | 中等 | 强 | 低 | ⭐⭐⭐⭐⭐ |
Completion Suggester |
completion |
极高 | 高(内存) | 不支持 | 中等 | ⭐⭐⭐⭐ |
选型建议
- 结构化字段(ID、路径、标签)的前缀过滤 → 使用
prefix查询 +index_prefixes优化。 - 新项目,无历史包袱,需要文本自动补全 → 直接使用
search_as_you_type。 - 需要极速补全 + 内存充裕 →
Completion Suggester。 - 需要中缀匹配(如搜索中间的字) → 选择
edge_ngram(并开启max_gram足够大)。 - 只是临时测试或数据量极小 →
match_phrase_prefix或bool_prefix。
希望这篇博客能帮助你彻底理清 Elasticsearch 中各种前缀匹配技术的原理和适用场景。如果你在实际选型中遇到特定场景的困惑,欢迎留言交流!