如何在同结构Elasticsearch索引demo-cm与demo-v2中识别缺失文档ID
问题描述
我有两个文档结构相同的Elasticsearch索引:demo-v2和demo-cm。
demo-v2的文档数据:
[{ "_index": "demo-v2", "_type": "v2", "_id": "1", "_source": { "user": "kimchy", "message": "trying out Elastic Search" } },{ "_index": "demo-v2", "_type": "v2", "_id": "2", "_source": { "user": "kimchy", "message": "trying out Elastic Search" } },{ "_index": "demo-v2", "_type": "v2", "_id": "3", "_source": { "user": "kimchy", "message": "trying out Elastic Search" } }]
demo-cm的文档数据:
[{ "_index": "demo-cm", "_type": "cm", "_id": "1", "_source": { "user": "kimchy", "message": "trying out Elastic Search" } }]
我需要找出demo-v2中存在但demo-cm中缺失的文档ID列表,期望结果是:
ids = ["2", "3"]
我尝试用Painless脚本编写了如下聚合查询,但没能得到准确结果,希望得到解决方案或示例:
{ "size": 0, "aggs": { "missing_ids": { "scripted_metric": { "init_script": "state.docs = []", "map_script": "state.docs.add(doc._id.value)", "combine_script": "return state.docs", "reduce_script": "def unique_ids = []; def uniques = []; for (docs in states) { unique_ids.addAll(docs); } return unique_ids;" } } }, "query": { "bool": { "must": [ { "match_all": {} } ] } } }
解决方案1:分步查询(简单易实现)
步骤1:获取demo-cm的所有文档ID
先查询demo-cm索引,用terms聚合提取所有ID:
{ "size": 0, "aggs": { "cm_ids": { "terms": { "field": "_id", "size": 10000 // 根据实际数据量调整最大值 } } } }
执行后会得到demo-cm的所有ID列表(比如示例中的["1"])。
步骤2:筛选demo-v2中缺失的ID
把步骤1得到的ID放入bool查询的must_not条件,再聚合提取结果:
{ "size": 0, "aggs": { "missing_ids": { "terms": { "field": "_id", "size": 10000 } } }, "query": { "bool": { "must_not": [ { "terms": { "_id": ["1"] // 替换为步骤1得到的ID列表 } } ] } } }
missing_ids聚合的buckets字段就是最终缺失的ID列表。
解决方案2:单查询脚本化聚合(一次性完成)
通过scripted_metric聚合同时查询两个索引,在脚本中完成ID对比:
{ "size": 0, "indices": ["demo-v2", "demo-cm"], "aggs": { "missing_ids": { "scripted_metric": { "init_script": "state.v2_ids = new HashSet(); state.cm_ids = new HashSet();", "map_script": """ if (doc['_index'].value == 'demo-v2') { state.v2_ids.add(doc['_id'].value); } else if (doc['_index'].value == 'demo-cm') { state.cm_ids.add(doc['_id'].value); } """, "combine_script": """ def missing = new ArrayList(); for (id in state.v2_ids) { if (!state.cm_ids.contains(id)) { missing.add(id); } } return missing; """, "reduce_script": """ def all_missing = new HashSet(); for (result in states) { all_missing.addAll(result); } return new ArrayList(all_missing); """ } } } }
脚本逻辑说明
init_script:初始化两个HashSet,分别存储两个索引的IDmap_script:根据文档所属索引,将ID添加到对应集合combine_script:在分片层面对比集合,筛选出demo-v2独有的IDreduce_script:合并所有分片的结果,返回最终缺失ID列表
原查询失效原因
你的脚本仅收集了所有查询到的ID,没有区分索引来源,也未做对比逻辑,最终返回的是两个索引的ID合集,无法得到缺失的ID。调整后的脚本增加了索引判断和集合对比逻辑,才能输出正确结果。
内容的提问来源于stack exchange,提问作者alpha demo
相关产品推荐
相关产品推荐

