以下是对您提供的博文内容进行深度润色与结构重构后的技术文章。整体遵循“去AI化、强人设、重实战、有节奏”的编辑原则,彻底打破模板式写作惯性,以一位十年 Elasticsearch 架构师 + 开源社区布道者的真实口吻重写全文。语言更凝练、逻辑更自然、案例更贴近一线开发痛点,并强化了「为什么这么用」背后的工程权衡思考,同时删除所有机械标题、总结段与空洞结语,让技术分享像一次深夜的技术对谈。
当你的搜索开始“讲逻辑”:一个老Elasticsearch工程师的布尔查询手记
上周五晚上十一点,我收到一条钉钉消息:“线上商品搜索突然变慢,QPS掉了一半,用户投诉搜不到新款AirPods……”
我连上Kibana看了眼慢查询日志——问题出在一个看似无害的DSL上:
{ "query": { "bool": { "must": [ { "match": { "title": "airpods" } }, { "range": { "price": { "gte": 150 } } } ], "must_not": [ { "match": { "description": "refurbished" } } ] } } }没错,就是它。must_not里那个match,在千万级商品索引中触发了全段扫描,Lucene直接放弃缓存优化路径,每个分片都扛着正则级开销跑全文倒排。而真正该被排除的,不过是几个固定字符串:“refurbished”、“used”、“open-box”。
这不是语法错误,是语义误判——把“过滤”当成了“打分”,把“确定性排除”交给了“概率匹配”。
这件事让我决定写下这篇文字。不讲定义,不列文档,只说我们每天在API网关后、在日志告警里、在A/B测试报表中,真正踩过的坑、调过的参、改过的DSL。
must不是“必须”,而是“参与排序的必须”
很多人第一次写bool,会下意识把所有条件塞进must:品牌、价格、状态、分类……觉得“都得满足,当然放must”。
错。
must的本质,是Lucene BooleanQuery 中的 MUST 子句,但它带一个隐藏属性:每个子句都会喂给TF-IDF或BM25打分器。哪怕你只加了一个term: { "status": "published" },ES也会为这个字段计算词频、逆文档频率、字段长度归一化——而这些计算,对一个只有两个值( <