FOSElasticaBundle GeoBoundingBox添加时间过滤报错的正确实现
问题根因
你现在的报错本质是错误使用了查询对象的参数附加逻辑:
GeoBoundingBox是专门用于生成Elasticsearch地理边界框查询的类,它的addParam()方法只能用来添加这个查询本身官方支持的专属配置,不能用来插入其他独立的筛选条件。- 你之前给地理查询对象调用
addParam('lastActivityAt', ...)的操作,会直接把时间筛选字段塞到geo_bbox查询的结构根节点下,Elasticsearch解析到这个不属于地理查询的额外字段时,自然会抛出unexpected field [gte]的解析错误。
正确实现方式
地理边界筛选、最近10分钟活跃的时间筛选是两个相互独立的查询规则,需要通过布尔查询的逻辑把两个条件组合成“同时满足两项要求”的搜索逻辑,不能把所有参数堆叠在同一个地理查询对象上。
具体改造步骤:
- 保留原本的
GeoBoundingBox地理查询逻辑,删除之前给它追加时间参数的代码 - 单独用
Range查询类构造时间范围筛选规则 - 用
BoolQuery布尔查询把两个独立条件绑定为组合查询
改造后的示例代码如下:
// 引入需要的查询类 use Elastica\Query\BoolQuery; use Elastica\Query\GeoBoundingBox; use Elastica\Query\Range; // 构造地理边界框查询 $geoQuery = new GeoBoundingBox( 'location', [ // top_left坐标 ['lat' => $data['north'], 'lon' => $data['west']], // bottom_right坐标 ['lat' => $data['south'], 'lon' => $data['east']] ] ); // 构造最近10分钟活跃的时间范围查询 $earlier = new \DateTime('10 minutes ago'); $timeQuery = new Range('lastActivityAt', ['gte' => $earlier]); // 组合两个查询条件 $boolQuery = new BoolQuery(); // 小优化:如果时间筛选不需要参与搜索结果的相关度评分,可以把addMust()替换为addFilter(),这部分筛选会走Elasticsearch的缓存,查询响应速度会更快 $boolQuery->addMust($geoQuery); $boolQuery->addMust($timeQuery); // 执行搜索 $result = $this->get('fos_elastica.finder.app.user')->find($boolQuery);
关于
addParam()的正确使用场景 这个方法仅适用于给当前查询对象本身支持的原生配置项赋值,例如给GeoBoundingBox添加自身支持的ignore_unmapped参数,合法用法示例:
// 合法用法:给geo_bbox查询添加自身支持的配置 $geoQuery->addParam('ignore_unmapped', true);
除此之外,其他独立字段的筛选条件都应该构造独立的查询对象,通过布尔查询的逻辑组合到最终搜索请求中。
内容的提问来源于stack exchange,提问作者Mayor of the Plattenbaus
相关产品推荐
相关产品推荐

