首页/数据/NoSQL 速查/bool 布尔组合查询
Elasticsearch89 条

bool 布尔组合查询

bool 用 must、should、must_not、filter 组合子查询:filter 不参与评分且可被缓存,适合状态、时间范围这类纯筛选条件。

NoSQL 速查数据更新于 2026-10-13

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 查询。

易错点

  • 把纯筛选条件写在 must 里会白算评分:过滤条件越多越复杂,浪费的 CPU 越明显
  • should 在有 must 或 filter 时默认不强制命中,做严格筛选却只写 should 会返回大量不相关结果
  • must_not 单独使用时先匹配全集,大数据量下应先加范围条件缩小候选集
  • bool 嵌套层数过多会让查询解析与计划开销上升,能合并到同一层的条件不要逐层嵌套
  • filter 里的条件不会提高 _score,若希望某字段也影响排序,需要放到 must 或 should 而不是 filter

数据来源与参考

  • Elasticsearch Guide: Boolean query
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌