深入学习 ElasticSearch 的搜索(六):搜索语法总结
前面几篇分别整理了:
- Query DSL
matchmatch_phrasetermbool
这一篇做一次总结,把这些查询放到同一张图里理解。
ElasticSearch 搜索最容易混淆的点,通常不是语法本身,而是没有分清:
- 字段是
text还是keyword - 查询是否会走 analyzer
- 条件是用于评分还是用于过滤
- 查询目标是全文检索还是精确匹配
一、先按字段类型判断
ElasticSearch 搜索之前,先看字段类型。
Mapping 可以理解为索引的字段结构说明书。它决定字段应该如何被索引、如何被搜索。
也就是说,搜索设计的第一步不是写 DSL,而是先判断字段身份:
- 自然语言内容:通常用
text - 结构化精确值:通常用
keyword、数字、日期、布尔等类型
字段身份错了,后面的查询再复杂也很难自然。
1. text 字段
text 字段会分词。
适合:
- 标题
- 正文
- 摘要
- 评论
- 描述信息
常用查询:
matchmatch_phrase
例如:
json
POST article_search/_search
{
"query": {
"match": {
"content": "ElasticSearch 倒排索引"
}
}
}
2. keyword 字段
keyword 字段通常不分词。
适合:
- 分类
- 状态
- 标签
- 用户 ID
- 订单号
- 枚举值
常用查询:
termtermsbool.filter
例如:
json
POST article_search/_search
{
"query": {
"term": {
"category": "elasticsearch"
}
}
}
3. multi-fields
实际项目中,同一个字段经常既需要全文检索,又需要精确匹配。
这时可以使用 multi-fields:
json
PUT article_search_v2
{
"mappings": {
"properties": {
"nickname": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
}
}
}
}
这样:
nickname:用于match、match_phrasenickname.keyword:用于term、排序、聚合
这也是很多搜索系统里最常见的字段建模方式。
二、match、match_phrase、term 的区别
可以用下面这张表理解。
| 查询 | 是否分析查询文本 | 适合字段 | 典型用途 |
|---|---|---|---|
match |
是 | text |
全文关键词搜索 |
match_phrase |
是 | text |
连续短语搜索 |
term |
否 | keyword |
精确值匹配 |
一句话记忆:
text
match 查词,match_phrase 查短语,term 查精确值。
三、match 怎么用
match 是全文检索入口。
json
POST article_search/_search
{
"query": {
"match": {
"content": "ElasticSearch 搜索"
}
}
}
适合:
- 用户输入关键词
- 搜文章正文
- 搜标题
- 搜自然语言文本
关键点:
- 查询文本会被 analyzer 分析
- 命中结果会计算
_score - 默认比较宽松
- 可以用
operator或minimum_should_match控制严格程度
四、match_phrase 怎么用
match_phrase 用于短语查询。
json
POST article_search/_search
{
"query": {
"match_phrase": {
"content": "倒排索引"
}
}
}
适合:
- 搜固定表达
- 搜连续标题
- 搜日志片段
- 提高结果精确度
关键点:
- 查询文本也会被 analyzer 分析
- 不只看 term 是否出现,还看 position
- 可以用
slop放宽距离
五、term 怎么用
term 用于精确词项查询。
json
POST article_search/_search
{
"query": {
"term": {
"status": "published"
}
}
}
适合:
- 查状态
- 查分类
- 查用户 ID
- 查枚举值
- 查精确标签
关键点:
- 不要用它做普通全文搜索
- 对
text字段使用时要特别小心 - 最常搭配
keyword字段
六、bool 怎么用
bool 用来组合多个条件。
json
POST article_search/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"content": "ElasticSearch"
}
}
],
"filter": [
{
"term": {
"status": "published"
}
}
],
"should": [
{
"match": {
"title": "ElasticSearch"
}
}
],
"must_not": [
{
"term": {
"author": "ops"
}
}
]
}
}
}
四个子句的含义:
must:必须匹配,并参与评分filter:必须匹配,不参与评分should:最好匹配,通常用于加分must_not:必须不匹配
七、一套常用业务搜索模板
很多后台搜索都可以从这个模板开始:
json
POST article_search/_search
{
"from": 0,
"size": 10,
"query": {
"bool": {
"must": [
{
"match": {
"content": "ElasticSearch"
}
}
],
"filter": [
{
"term": {
"status": "published"
}
},
{
"term": {
"category": "elasticsearch"
}
},
{
"range": {
"created_at": {
"gte": "2026-04-01",
"lte": "2026-04-30"
}
}
}
]
}
},
"sort": [
{
"created_at": {
"order": "desc"
}
}
]
}
这个模板里:
from/size控制分页match做全文检索term做精确过滤range做范围过滤sort做排序
八、高亮和返回字段控制
业务搜索通常还需要控制返回字段和高亮。
例如只返回标题、分类、创建时间,并对正文命中的关键词做高亮:
json
POST article_search/_search
{
"_source": ["title", "category", "created_at"],
"query": {
"match": {
"content": "ElasticSearch"
}
},
"highlight": {
"fields": {
"content": {}
}
}
}
其中:
_source控制返回哪些原始字段highlight控制命中片段高亮
如果文档很大,合理控制 _source 可以减少网络传输和客户端处理成本。
九、分页要注意什么
普通分页可以使用 from 和 size。
json
POST article_search/_search
{
"from": 20,
"size": 10,
"query": {
"match_all": {}
}
}
它适合浅分页。
如果页数很深,例如翻到几千页,from + size 的成本会明显升高。
深分页场景通常要考虑:
search_after- PIT
- 避免无限制跳页
普通后台列表可以先用 from + size,但要限制最大翻页深度。
十、前缀、通配和联想搜索
搜索框输入时,通常有两种模式:
- 搜索结果页:用户输入完整关键词后搜索
- 联想建议:用户边输入边出结果
正式搜索结果页更重视排序质量,通常使用:
text
multi_match + bool + phrase + boost
联想建议更重视响应速度和前缀匹配,可以考虑:
match_bool_prefixsearch_as_you_typecompletion suggesteredge_ngram
通配符查询如 wildcard 虽然直观,但不要轻易当主查询。
json
POST article_search/_search
{
"query": {
"wildcard": {
"author": "*adm*"
}
}
}
这类查询在大数据量下可能比较重,而且排序语义也不如全文查询自然。真要大量使用通配搜索,最好从 mapping 层专门设计。
十一、小说分块搜索的字段建模例子
如果是小说分块或内容 chunk 搜索,字段可以按用途拆开。
示例文档:
json
{
"book_id": "book_001",
"chapter_index": 12,
"chapter_title": "武当山上",
"chunk_text": "饭后,张三丰看着郭靖,没有说话。",
"entity_names": ["张三丰", "郭靖"],
"start_line": 120,
"word_count": 86
}
建议的搜索语义:
chunk_text:正文全文搜索,用match/match_phrasechunk_text.keyword:整段完全相等时才用termentity_names:人名实体精确检索,用term/termsbook_id:书籍过滤,用termchapter_index、start_line、word_count:范围过滤,用range
一个完整查询可以这样写:
json
POST article_search/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"chunk_text": "武当"
}
}
],
"filter": [
{
"term": {
"book_id": "book_001"
}
},
{
"terms": {
"entity_names": ["张三丰", "郭靖"]
}
},
{
"range": {
"chapter_index": {
"gte": 1,
"lte": 20
}
}
}
],
"must_not": [
{
"term": {
"entity_names": "郭襄"
}
}
],
"should": [
{
"match_phrase": {
"chunk_text": {
"query": "张三丰",
"boost": 3
}
}
}
]
}
}
}
这里的重点不是字段名,而是建模思路:
正文走全文,实体走精确,范围走 filter,排序靠 should 和 boost。
十二、排查搜索不准的顺序
如果搜索结果不符合预期,建议按下面顺序排查。
1. 看 mapping
先确认字段类型。
json
GET article_search/_mapping
重点看:
- 字段是不是
text - 字段是不是
keyword - 字段用了哪个 analyzer
- 是否配置了
search_analyzer
2. 看 analyzer
用 _analyze 看文本会被拆成什么。
json
POST article_search/_analyze
{
"field": "content",
"text": "ElasticSearch 倒排索引"
}
如果分词不符合预期,先解决 analyzer。
3. 看查询类型
确认是不是用错了查询:
- 全文搜索却用了
term - 精确过滤却用了
match - 短语搜索却用了普通
match - 多条件查询没有用
bool
4. 看 filter 和 score
如果某些过滤条件影响了排序,检查是否把本该放 filter 的条件放进了 must。
如果结果太多,考虑:
operator: "and"minimum_should_matchmatch_phrase- 增加
filter
十三、排查评分:explain 和 profile
如果想知道某篇文档为什么命中、为什么评分高,可以用 _explain。
json
GET article_search/_explain/1
{
"query": {
"match": {
"content": "ElasticSearch"
}
}
}
如果想分析查询执行过程和耗时,可以在搜索请求中开启 profile。
json
POST article_search/_search
{
"profile": true,
"query": {
"match": {
"content": "ElasticSearch"
}
}
}
这两个工具适合排查问题,不建议在普通业务请求中长期打开。
十四、为什么排序有时看起来不合理
ElasticSearch 默认会根据相关性模型计算 _score,常见默认模型是 BM25。
搜索结果看起来"不合理",通常不是单个 DSL 语法错了,而是这些因素叠加:
- 字段类型设计错了
- 应该精确查的字段走了全文搜索
- 字段权重没有配置
- 短语优先没有做
- 过滤条件写进了
must,污染了评分 fuzzy、wildcard被当成主查询
常见优化方式:
- 给重要字段更高 boost
- 用
.keyword做精确命中加权 - 用
match_phrase给完整短语加分 - 结构化条件放入
filter
十五、最常用的判断口诀
可以按下面方式选择查询:
text
搜正文标题:match
搜连续短语:match_phrase
搜分类状态:term
多个条件组合:bool
结构化过滤:bool.filter
排除数据:bool.must_not
提升相关性:bool.should
再结合字段类型:
text
text -> match / match_phrase
keyword -> term / terms
number/date -> range / term
十六、一句话总结
ElasticSearch 搜索语法的核心不是背 API,而是先分清查询意图。
最终可以这样理解:
用户输入的自然语言,用 match;需要连续短语,用 match_phrase;结构化精确值,用 term;多个条件组合,用 bool。
只要把字段类型、分词结果、查询类型这三件事对齐,大部分搜索问题都会变得容易排查。
参考链接
-
Query DSL
https://www.elastic.co/docs/query-languages/query-dsl -
Match query
https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-match-query -
Term query
https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-term-query -
Boolean query
https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-bool-query -
Highlighting
https://www.elastic.co/docs/reference/elasticsearch/rest-apis/highlighting -
Paginate search results
https://www.elastic.co/docs/reference/elasticsearch/rest-apis/paginate-search-results
