如何在Elasticsearch中按嵌套数据的多条件过滤文档?
Elasticsearch 嵌套类型数据查询需求与解决方案
数据结构
数据包含嵌套类型的predictions字段,示例如下:
{"number":1234, "predictions": [ {"variant":"blue", "startDate": "2023-02-22"}, {"variant":"red", "startDate": "2023-03-01"} ]}, ...
predictions字段用于标记从指定日期起可用的产品变体。
查询需求
需要构建查询筛选满足以下条件的产品:
- 匹配给定日期之前最近的一条预测记录
- 该预测记录的
variant与指定变体一致
此前尝试的查询
我曾用嵌套查询结合范围条件获取最近一周的预测(每周生成一条),语句如下:
"query": { "bool": { "must": [ {"nested": { "path":"predictions", "query": { "bool": { "must": [ {"range": { "predictions.startDate": { "lte": "2023-03-02", "gte": "2023-02-23", } }}, { "match": {"predictions.variant": "blue"} } ] } } } } ] } }
但该查询无法精准匹配「给定日期之前最近的预测记录」,需要调整。
预期输入与结果
variant: "blue", startDate: 2023-02-28 => 1234 在结果中 variant: "blue", startDate: 2023-03-02 => 1234 不在结果中 variant: "red", startDate: 2023-04-20 => 1234 在结果中
解决方案
要实现需求,需确保匹配的嵌套文档是该产品中startDate小于等于给定日期的最大值,同时variant匹配指定值。可通过嵌套查询结合must_not子句实现:
{ "query": { "bool": { "must": [ { "nested": { "path": "predictions", "query": { "bool": { "must": [ { "match": { "predictions.variant": "blue" } }, { "range": { "predictions.startDate": { "lte": "2023-02-28" } } } ], "must_not": [ { "script": { "source": """ doc['predictions.startDate'].stream() .filter(date -> date.lte(params.targetDate)) .anyMatch(date -> date.gt(doc['predictions.startDate'].value)) """, "params": { "targetDate": "2023-02-28" } } } ] } } } } ] } } }
逻辑说明
must子句先筛选出variant匹配且startDate小于等于目标日期的嵌套记录must_not子句排除存在其他startDate更晚(但仍小于等于目标日期)的嵌套记录的情况,确保当前匹配的是最近的那条
若需要先聚合获取每个产品的最新预测再过滤,也可使用top_hits聚合实现,但上述查询更适合直接筛选目标文档。
内容的提问来源于stack exchange,提问作者Hung Nguyen
相关产品推荐
相关产品推荐

