Yii2 Elasticsearch6中混合使用andFilterWhere与query的问题
这个问题本质是Yii2 elasticsearch扩展从2.0升级到2.1后,查询构建逻辑发生了核心变化,再加上ES6与ES2.x的语法差异共同导致的。我给你梳理下具体的解决思路:
1. 先搞懂新版本的查询构建逻辑
在旧版2.0的扩展中,$query->query()是直接设置Elasticsearch请求的query节点,而andFilterWhere是往filtered查询的filter部分追加条件,两者可以和平共存。但升级到2.1后,扩展全面适配ES5+的bool查询结构:andFilterWhere会直接操作bool查询的filter数组——如果此时你用$query->query()直接替换整个查询体,后续调用andFilterWhere会把整个查询重构为bool结构,覆盖你之前设置的query内容;反过来先调用andFilterWhere再设置query,也会把之前的filter条件直接覆盖。
2. 重构查询代码,统一用bool查询的组合方式
放弃直接使用$query->query(),改用扩展提供的bool查询相关方法来组合条件,这样就能让查询条件和过滤条件共存:
方案一:用andWhere替代直接设置query
把原来通过$query->query()设置的查询条件,改用andWhere来添加(对应bool查询的must部分),然后用andFilterWhere添加过滤条件(对应bool的filter部分):
// 原来的冲突写法 // $query->query(['match' => ['title' => $this->title]]); // $query->andFilterWhere(['term' => ['status' => 1]]); // 升级后的兼容写法 $query->andWhere(['match' => ['title' => $this->title]]); $query->andFilterWhere(['term' => ['status' => 1]]);
这样生成的ES查询会是一个包含must和filter的标准bool查询,两者互不干扰。
方案二:手动构建完整的bool查询
如果需要更复杂的查询结构(比如包含should、must_not等逻辑),可以直接调用bool()方法构建完整查询,同时用andFilterWhere追加过滤条件:
$query->bool([ 'must' => [ ['match' => ['title' => $this->title]], ['range' => ['created_at' => ['gte' => $this->start_time]]] ], 'should' => [ ['term' => ['tag' => 'hot']] ] ]); // 追加的过滤条件会自动加入bool的filter数组 $query->andFilterWhere(['term' => ['status' => 1]]);
3. 调试生成的查询语句定位问题
如果还是遇到异常,可以打印出扩展生成的原始ES查询,对比新旧版本的结构差异:
var_dump($query->createCommand()->getRawQuery()); exit;
通过对比就能直观看到条件被覆盖的具体原因,再针对性调整代码。
4. 适配ES6的语法细节
ES6和ES2.2.1在查询语法上有不少差异,比如:
- 彻底移除了
filtered查询,统一用bool查询的filter部分实现过滤 - text字段不能直接用
term查询,需要改用match或者term.keyword - 部分查询参数的写法和默认值有变化
这些细节也可能导致查询失效,需要结合ES6的官方文档调整条件写法。
内容的提问来源于stack exchange,提问作者Tibor Nagy

