ElasticSearch查询需求:构建匹配全部指定值才返回结果的查询
Elasticsearch 实现「必须匹配所有指定值」的查询方案
嘿,针对你需要的「仅当所有指定值都匹配时才返回文档」的需求,我分两种常见场景给出具体的查询方案,对应不同的文档结构:
场景1:单个文档的数组字段需包含全部指定值
如果你的文档里有类似数组类型的字段(比如某个设备的传感器事件列表),要确保这个数组包含所有你指定的值(比如["open", "close"])才返回该文档,推荐这两种方式:
方式一:用terms_set查询(ES 6.1+ 支持)
terms_set可以指定必须匹配的最小数量,把这个数量设为你指定值的总数,就能实现全匹配:
{ "query": { "terms_set": { "nome": { "terms": ["open", "close"], "minimum_should_match_script": { "source": "params.num_terms" } } } } }
方式二:用bool的must子句兼容旧版本
如果你的ES版本低于6.1,直接用多个term查询嵌套在must里,强制所有条件都满足:
{ "query": { "bool": { "must": [ {"term": {"nome": "open"}}, {"term": {"nome": "close"}} ] } } }
场景2:跨文档匹配同一主体的全量值
从你给出的示例文档来看,每个文档是单个传感器的独立记录(比如veiculo_id=1有两条记录,分别对应nome=open和nome=close)。这种场景下,你需要的是:仅当某个veiculo_id同时存在所有指定nome的记录时,才返回该veiculo_id的所有相关文档,否则返回空结果。
方案:聚合筛选+二次查询
这种场景需要分两步走,先找出符合条件的主体ID,再查询对应文档:
第一步:聚合筛选出满足全匹配的veiculo_id
{ "size": 0, // 只返回聚合结果,不返回原始文档 "query": { "terms": {"nome": ["open", "close"]} // 先筛选出包含指定值的文档 }, "aggs": { "group_by_veiculo": { "terms": { "field": "veiculo_id", "size": 1000 // 根据你的数据量调整大小 }, "aggs": { "count_nome_types": { "terms": { "field": "nome", "size": 1000 } }, "has_all_required_nomes": { "bucket_selector": { "buckets_path": { "uniqueNomeCount": "count_nome_types._bucket_count" }, "script": "params.uniqueNomeCount == 2" // 2是你指定值的总数,比如这里是open和close两个 } } } } } }
这个查询会返回所有同时拥有open和close两种记录的veiculo_id。
第二步:根据聚合结果查询完整文档
拿到第一步得到的veiculo_id列表后,用terms查询返回对应的所有文档:
{ "query": { "terms": {"veiculo_id": ["1"]} // 替换成第一步得到的有效ID列表 } }
小提示:数据量小时的一步到位方案
如果你的数据量不大,也可以用脚本过滤实现一次性查询,但性能不如分两步:
{ "query": { "bool": { "filter": [ {"terms": {"nome": ["open", "close"]}}, { "script": { "source": "doc['veiculo_id'].value in params.valid_veiculos", "params": { "valid_veiculos": ["1"] // 这里提前注入第一步得到的有效ID } } } ] } } }
针对你示例文档的测试
假设你的索引中veiculo_id和nome都是keyword类型,用第一步的聚合查询会得到veiculo_id=1的结果,第二步就能返回对应的两条文档;如果某个veiculo_id只有open没有close,则不会被纳入结果。
内容的提问来源于stack exchange,提问作者valter Gomes
相关产品推荐
相关产品推荐

