真实对比bool查询里must和filter子句对相关性得分的不同影响,用_explain拆开打分明细证明filter条件被整体跳过打分求和,并验证must_not与单独使用should的真实行为边界。
代码3篇文档: doc1{title:"quick quick brown fox",status:active,price:50} doc2{title:"quick fox",status:active,price:100} doc3{title:"lazy dog",status:inactive,price:30} POST /bool_test/_search {"query":{"bool":{"must":[ {"match":{"title":"quick"}},{"term":{"status":"active"}} ]}}} POST /bool_test/_search {"query":{"bool":{ "must":[{"match":{"title":"quick"}}], "filter":[{"term":{"status":"active"}}] }}}
status放must里,两个条件都参与打分: → doc1 score=1.0365833 → doc2 score=0.99355197 status放filter里,只有title:quick参与打分: → doc1 score=0.5665797 ← 真实明显更低 → doc2 score=0.52354836 ← 真实明显更低
这组真实得分对比直接说明了must和filter最核心的区别:两者在"要求文档必须满足条件"这一点上完全一样(都是真实的AND逻辑,少了任何一个条件文档都不会出现在结果里),但must里的每一个子查询真实都会参与最终的相关性打分,而filter里的子查询真实只负责筛选,完全不影响最终得分。本次实测里把status:active这个条件从must挪到filter之后,两篇文档的得分真实都几乎腰斩,因为原本term查询贡献的那部分分数真实被完全拿掉了。
代码POST /bool_test/_explain/1 {"query":{"bool":{ "must":[{"match":{"title":"quick"}}], "filter":[{"term":{"status":"active"}}] }}}
explain输出(doc1,score=0.5665797):
→ "description": "sum of:"
→ "details": [
{ "value": 0.5665797, "description": "weight(title:quick in 0) ..." }
]
← sum of 后面真实只有title:quick这一项,status:active这个词项查询
← 真实根本没有出现在这个求和明细里,连一个值为0的条目都没有代码POST /bool_test/_search {"query":{"bool":{"must_not":[{"term":{"status":"inactive"}}]}}} POST /bool_test/_search {"query":{"bool":{"should":[ {"term":{"status":"inactive"}},{"range":{"price":{"gt":80}}} ]}}}
must_not排除status=inactive: hits=2 ["1","2"] ← doc3真实被排除
单独should(不配合must):
→ hits=2 [("2", score=1.0), ("3", score=0.9808291)]
← doc2因为price=100>80命中,doc3因为status=inactive命中
← 两个should条件真实任一满足就够,不要求同时满足这组真实结果补全了bool查询四种子句各自的角色:must_not真实是硬性排除条件,不参与打分(跟filter一样底层走constant_score),命中must_not里条件的文档会被真实直接踢出结果集;should在有must或filter同时存在时,真实只是"加分项"(命中与否不影响文档是否出现,只影响得分高低),但本次实测验证了当bool查询里真实只有should、没有任何must或filter条件时,它的行为真实会切换成"至少命中一个should条件才能出现在结果里",等效于一次OR查询——这正是很多人以为的"should永远只是加分不影响是否出现"这个误解的真实反例。
每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。
bool 查询与 _explain API