must 和 should 混用时只返回 must 匹配结果,因 should 默认不参与过滤仅影响评分;需设 minimum_should_match 才能使其参与筛选。

must 和 should 混用时为什么只返回 must 匹配的结果
因为 should 在有 must 或 filter 存在时,默认不强制匹配——它只负责打分,不影响是否命中。文档只要满足 must 条件就会被返回,should 匹配越多,_score 越高,但没匹配也不会被过滤掉。
常见错误是以为 must + should 是“且+或”的交并组合,实际是“必须满足 + 可选加分”。想让 should 也参与筛选,必须显式设 minimum_should_match。
- 不设
minimum_should_match:should 完全不控制结果集,只调排序 - 设
"minimum_should_match": 1:至少一个 should 必须命中,否则不返回该文档 - 设
"minimum_should_match": "75%":需满足 75% 的 should 子句(按数量向下取整)
什么时候该用 must,什么时候该用 filter
must 用于影响相关性评分的条件,比如全文检索字段;filter 用于确定性、无评分需求的条件,比如上架状态、类目 ID、价格区间。Elasticsearch 9.x 强制要求显式区分二者,混用会导致 query 解析失败或性能下降。
-
must里放:multi_match(带权重如"title^3")、query_string(适合用户输入关键词) -
filter里放:term(["sale" => true])、range(["price" => ["gte" => 10, "lte" => 500]])、exists(排除软删除:["must_not" => [["exists" => ["field" => "deleted_at"]]]]) -
filter子句可被缓存,must不会,高频变动条件(如时间范围)放filter更省资源
should 一定要配 minimum_should_match 吗
不是“一定”,而是“取决于你要不要它参与筛选”。如果只是想让某些字段(比如品牌、标签)匹配了就排前面,不配也行;但一旦你写上了 should 却发现结果没按预期缩小范围,八成就是漏了这个参数。
- 只用
should(无must/filter):默认行为是 OR,至少匹配一个即可,此时minimum_should_match默认为1 - 和
must一起用:默认minimum_should_match是0,即“可有可无”,必须手动覆盖 - Laravel 中用原生客户端构造时,别依赖 Scout 的自动转换——它可能把
should错转进must,导致评分异常或漏数据
软删除模型在 bool 查询里怎么安全过滤
不能只靠数据库层软删,ES 里必须同步加 must_not + exists,否则刚删完还能搜到。Laravel Scout 默认不处理这个,得手动补。
- 同步阶段:重写模型的
shouldBeSearchable(),返回!$this->trashed() - 查询阶段:在 bool 的顶层
must_not里加["exists" => ["field" => "deleted_at"]] - 注意顺序:这个
must_not要和must/filter并列,别嵌套错层级,否则逻辑失效 - 测试要点:删一条记录 → 等 Scout 队列执行完 → 查 ES 的
_searchAPI 返回结果里hits.total.value是否实时减 1
should 的语义容易被直觉误导,它既不是“或”,也不是“可选条件”那么简单——它的作用开关完全由 minimum_should_match 和周围子句类型决定。调试时最有效的方式是直接打 log 输出最终 DSL,而不是靠 PHP 层逻辑猜。


















