Elasticsearch bool 查询详解
bool 是 Boolean (布尔逻辑)的缩写,这个名字来源于数学和计算机科学中的布尔代数。
在 Elasticsearch 中,bool 查询的核心作用就是组合多个条件 ,实现逻辑上的 AND (与)、OR (或)、NOT(非)操作:
must→ AND(必须满足)should→ OR(至少满足一个,可配置)must_not→ NOT(必须不满足)filter→ AND(但不算分,性能更高)
方便理解,你可以认为他是WHERE。
一、bool 查询的结构
json
{
"query": {
"bool": {
"must": [ // 必须匹配,且贡献算分(类似 AND)
{ ... },
{ ... }
],
"filter": [ // 必须匹配,但不贡献算分(性能更高)
{ ... },
{ ... }
],
"should": [ // 选择性匹配,至少匹配一个(类似 OR),贡献算分
{ ... },
{ ... }
],
"must_not": [ // 必须不匹配,不贡献算分(类似 NOT)
{ ... },
{ ... }
],
"minimum_should_match": 1 // 可选:指定 should 至少需要匹配几个
}
}
}
二、各子句详解
| 子句 | 逻辑 | 是否贡献评分 | 是否缓存 | 典型用途 |
|---|---|---|---|---|
must |
AND | ✅ 是 | ❌ 否 | 用户输入的关键词搜索(需要相关性排序) |
filter |
AND | ❌ 否 | ✅ 是 | 结构化过滤(状态、分类、时间范围、精确ID) |
should |
OR(可配置) | ✅ 是(部分情况) | ❌ 否 | 可选条件,匹配越多得分越高(如标签匹配、多字段搜索) |
must_not |
NOT | ❌ 否 | ✅ 是 | 排除某些值(如删除标记、黑名单) |
重点理解 should 的评分行为:
- 如果查询只有
should子句(没有must/filter),则默认至少匹配一个should条件。 - 如果查询同时包含
must或filter,should中的条件变为可选,但匹配的越多,文档得分越高(可用于提升相关度)。
三、query vs filter 上下文
must/should在 query 上下文 中:会计算_score,结果不缓存。filter/must_not在 filter 上下文中:不计算分数,只判断是否匹配,结果可被缓存,性能极高。
最佳实践 :将无需影响排序 的条件(如 status="published", price > 100, category="dance")全部放入 filter 或 must_not,既能提升性能,又不干扰相关性评分。
四、示例:阿拉伯语舞蹈搜索场景
假设需要搜索舞蹈视频,要求:
- 标题或标签中包含阿拉伯语"رقص شرقي"(东方舞)
- 分类必须是
dance - 状态为
published - 时长大于 60 秒
- 可选:标签也包含"موسيقى"(音乐)的会加分
json
GET /videos/_search
{
"query": {
"bool": {
"must": [
{ "match": { "title": "رقص شرقي" } }
],
"filter": [
{ "term": { "category": "dance" } },
{ "term": { "status": "published" } },
{ "range": { "duration_sec": { "gt": 60 } } }
],
"should": [
{ "match": { "tags": "موسيقى" } }
]
}
}
}
执行逻辑:
- 先执行
filter快速过滤掉不满足条件的文档(可缓存)。 - 在剩余文档中,执行
must匹配标题中的"رقص شرقي"。 - 如果文档的
tags中还包含"موسيقى",则增加其_score。
五、minimum_should_match 的妙用
当有多个 should 条件时,可以指定至少需要匹配几个。
json
{
"query": {
"bool": {
"should": [
{ "match": { "title": "ballet" } },
{ "match": { "tags": "ballet" } },
{ "match": { "description": "ballet" } }
],
"minimum_should_match": 2
}
}
}
表示文档必须在标题、标签、描述中至少两个字段匹配 "ballet",提高精确度。
六、嵌套 bool 实现复杂逻辑
你可以将 bool 查询嵌套在另一个 bool 中,实现 (A AND B) OR (C AND D) 之类的逻辑。
json
{
"query": {
"bool": {
"should": [
{ "bool": { "must": [ { "term": { "type": "video" } }, { "range": { "likes": { "gte": 1000 } } } ] } },
{ "bool": { "must": [ { "term": { "type": "live" } }, { "range": { "viewers": { "gte": 500 } } } ] } }
]
}
}
}
匹配:
- 视频类型且点赞 ≥ 1000
- 或直播类型且观众 ≥ 500
七、性能优化要点
- 尽量多用
filter少用must:过滤条件不参与算分,且能被 ES 自动缓存(node query cache或request cache)。 - 将高频过滤字段设为
keyword类型 :如status,category,is_deleted。 - 避免在
must中放置大范围、低选择性的条件:它们会拖慢评分计算。 minimum_should_match谨慎设置:设置过高可能导致匹配结果过少。- 使用
_name参数调试 :为每个子句命名,方便在explain中查看哪个条件命中。
json
{
"bool": {
"must": [
{ "match": { "title": "dance", "_name": "title_match" } }
],
"filter": [
{ "term": { "status": "published", "_name": "status_filter" } }
]
}
}
八、常见误区
| 误区 | 正确做法 |
|---|---|
所有条件都塞进 must |
结构化条件放 filter,提升性能 |
should 不加 minimum_should_match |
在有 must 时 should 可选,容易漏掉预期逻辑 |
对 text 字段做 term 查询 |
term 不会分词,通常用 match 或 term 配合 keyword 子字段 |
在 filter 里用 match 查询 |
filter 不评分,用 term / terms / range 更合适 |
九、总结
bool 查询是 ES 查询的核心,掌握它就能构建 90% 的复杂搜索。记住口诀:
- 必须且要分 →
must - 必须但不要分 →
filter - 可选且要分 →
should - 必须排除 →
must_not
结合 minimum_should_match 和嵌套 bool,你就能实现任意逻辑的搜索。下次遇到多条件搜索,优先想到 bool!