bool 查询是什么
bool 查询是 Elasticsearch 组合查询的骨架:用 must、filter、should、must_not 把多个子查询拼成一个布尔表达式。关键区别在评分——must 与 should 参与相关性打分,filter 与 must_not 只做判定不评分,结果还能被过滤器缓存。因此状态、时间范围、权限这类纯筛选条件一律放 filter,只有真正影响排序的全文条件才放 must。
基本信息
| 适用版本 | Elasticsearch 7.x / 8.x,DSL 语法一致 |
|---|---|
| must | 必须匹配,参与评分 |
| filter | 必须匹配,不评分,可被过滤器缓存 |
| should | 应匹配;出现 must/filter 时默认不强制 |
| must_not | 必须不匹配,不评分 |
| 计划影响 | 子句书写顺序不影响执行计划,filter 会优先执行 |
典型使用场景
- 电商搜索:标题全文匹配(must)加价格区间与上架状态(filter)
- 日志检索:关键字匹配 + 时间范围 + 排除健康检查噪音(must_not)
- 多租户过滤:按 tenant_id 做 filter,避免干扰相关性排序
- 聚合前置筛选:在 search 里用 bool 缩小聚合扫描范围
- 可选项提权:多个 should 提升置顶或活动类文档的排名
- 权限可见性:把可见范围条件放进 filter 并复用查询缓存
示例
示例
GET /products/_search
{
"query": {
"bool": {
"must": [ { "match": { "title": "笔记本" } } ], # 全文相关性,参与评分
"filter": [ # 只筛不评分,可缓存
{ "term": { "status": "on_sale" } },
{ "range": { "price": { "gte": 3000, "lte": 8000 } } }
],
"should": [ { "term": { "tag": "促销" } } ], # 命中则加分
"must_not": [ { "term": { "flag": "deleted" } } ],
"minimum_should_match": 0 # 明确 should 不强制
}
}
}四个子句对照
| 子句 | 是否必须 | 是否评分 | 典型用途 |
|---|---|---|---|
| must | 是 | 是 | 全文相关性匹配 |
| filter | 是 | 否 | 状态、范围、权限过滤 |
| should | 有 must/filter 时否 | 是 | 提权、可选项 |
| must_not | 必须不匹配 | 否 | 排除垃圾与噪音数据 |
should 的强制程度由上下文决定:查询里没有 must 或 filter 时至少要命中一个 should;一旦有 must/filter,should 只用来加分,需要强制命中就写 minimum_should_match: 1。
filter 里的 term/range 条件能被 query cache 复用,把部署后不会变的过滤条件下沉到 filter,是成本最低的性能优化之一。
只用 must_not 的查询会先匹配全部文档再排除,海量索引上代价很高;先补一个 filter 或 term 限定范围,再加 must_not。
性能与调试要点
- 把不变条件放进 filter 而不是 must,可以省掉评分计算并复用过滤器缓存
- should 配合 boost 或字段权重做排序提权,比在应用层二次排序更省事
- 用 profile 或 _search 返回的 took 与总命中数观察代价,先看是否命中预期分片
- 条件较多时用 _validate/query 与 explain=true 观察查询被重写后的形态
- term 查 keyword 字段才是指精确匹配,text 字段会被拆词导致语义变化
- 嵌套 bool 时优先合并同层条件,层数越多查询解析开销越大
提权与嵌套示例
提权与嵌套示例
GET /products/_search
{
"query": {
"bool": {
"must": [ { "match": { "title": { "query": "笔记本", "boost": 2 } } } ],
"filter": [ { "term": { "status": "on_sale" } } ],
"should": [
{ "match": { "tag": { "query": "促销", "boost": 3 } } },
{ "term": { "brand": "某品牌" } }
]
}
}
}查询体里加 explain=true 或对 URI 追加 ?explain=true 可以看查询被改写后的结构,是确认 should 是否真的生效的最快办法。
常见组合范式
- 全文加过滤:match 放 must,状态与范围放 filter
- 排除型条件:用 must_not 排除已删除、测试账号与内部流量
- 可选项提权:should 配 boost 实现置顶与活动加权
- 多租户隔离:tenant_id 等值条件放 filter 以便复用缓存
- 精确与模糊分工:keyword 字段用 term,text 字段用 match,不要混用
- 先缩小集合再算分,比先算分再过滤更省资源
filter 里再嵌套 bool 时,内层 filter 依然不参与评分;但把可缓存条件分散在多层 bool 中会降低缓存命中率,状态与时间范围这类条件尽量集中写在同一个 filter 数组里。
bool 查询无命中时按顺序排查:先 GET _mapping 确认字段类型,再用 _analyze 看分词结果,最后核对 DSL 里 field 名与类型是否匹配,多数问题出在 text 字段被 term 查询。