Elasticsearch数据集对比求助:搜索过滤逻辑实现
我刚接触Elasticsearch的时候也对这类对比操作犯愁,毕竟和SQL里的EXCEPT或者NOT EXISTS思路不太一样!针对你要找两个数据集的差集(仅存在于数据集1或仅存在于数据集2的条目),这里有几种实用的方法,我一个个给你拆解:
注意:以下示例假设Item和periodDate的组合是条目的唯一标识,如果你的唯一标识是其他字段,替换成对应的字段即可
方法一:脚本查询(适合小规模数据集)
如果你的数据集不大,先从其中一个数据集导出所有唯一标识组合,再在另一个数据集里排除这些组合:
步骤1:获取目标数据集的唯一组合
先从数据集2中导出所有Item+periodDate的唯一组合,用聚合实现:
GET /dataset2/_search { "size": 0, "aggs": { "unique_entry_pairs": { "composite": { "sources": [ {"item": {"terms": {"field": "Item.keyword"}}}, {"date": {"terms": {"field": "periodDate"}}} ] } } } }
这个聚合会返回数据集2里所有不重复的条目组合。
步骤2:查询另一个数据集并排除匹配项
把步骤1得到的组合作为参数,传入数据集1的查询,排除那些在数据集2里存在的条目:
GET /dataset1/_search { "query": { "bool": { "must_not": [ { "script": { "script": { "source": "def currentPair = [doc['Item.keyword'].value, doc['periodDate'].value]; return params.targetPairs.contains(currentPair);", "params": { "targetPairs": [ ["blah5", "date2"], // 这里添加步骤1获取的所有组合 ] } } } } ] } } }
反过来,把查询索引换成dataset2,参数换成数据集1的组合,就能得到仅存在于数据集2的条目。
方法二:Enrich Policy(适合大规模数据集)
如果数据量很大,直接传参数到脚本里会受限,这时候可以用Elasticsearch的Enrich功能做关联查询:
步骤1:创建Enrich Policy
基于数据集2的唯一标识创建关联策略:
PUT /_enrich/policy/dataset2-reference-policy { "match": { "indices": "dataset2", "match_field": "Item.keyword", "enrich_fields": ["periodDate"] } }
步骤2:执行策略
让Elasticsearch生成关联所需的索引:
POST /_enrich/policy/dataset2-reference-policy/_execute
步骤3:创建Ingest管道
创建一个管道,用来在查询时关联数据集2的信息:
PUT /_ingest/pipeline/dataset2-enrich-pipeline { "processors": [ { "enrich": { "policy_name": "dataset2-reference-policy", "field": "Item.keyword", "target_field": "matched_dataset2", "max_matches": 1 } } ] }
步骤4:查询并过滤匹配项
查询数据集1时,通过管道关联数据集2的信息,然后排除那些periodDate也匹配的条目:
GET /dataset1/_search { "query": { "bool": { "must_not": [ { "bool": { "must": [ {"exists": {"field": "matched_dataset2.periodDate"}}, {"script": {"script": "doc['periodDate'].value == doc['matched_dataset2.periodDate'].value"}} ] } } ] } }, "pipeline": "dataset2-enrich-pipeline" }
同样,替换索引和策略就能查询仅存在于数据集2的条目。
方法三:Transform创建对比视图(适合定期对比)
如果需要定期执行这类对比,可以用Transform功能生成一个专门的差异索引:
步骤1:创建Transform任务
把两个数据集的条目按唯一标识分组,统计每个分组的来源索引:
PUT /_transform/dataset-diff-transform { "source": { "indices": ["dataset1", "dataset2"] }, "pivot": { "group_by": { "item": {"terms": {"field": "Item.keyword"}}, "date": {"terms": {"field": "periodDate"}} }, "aggregations": { "source_indices": {"terms": {"field": "_index"}} } }, "dest": { "index": "dataset-diff-results" } }
步骤2:启动Transform
让Elasticsearch生成差异索引:
POST /_transform/dataset-diff-transform/_start
步骤3:查询差异结果
在差异索引里,筛选出仅来自单个数据集的条目:
// 仅存在于数据集1的条目 GET /dataset-diff-results/_search { "query": { "bool": { "must": [ {"term": {"source_indices.doc_count": 1}}, {"term": {"source_indices.key": "dataset1"}} ] } } } // 仅存在于数据集2的条目 GET /dataset-diff-results/_search { "query": { "bool": { "must": [ {"term": {"source_indices.doc_count": 1}}, {"term": {"source_indices.key": "dataset2"}} ] } } }
内容的提问来源于stack exchange,提问作者H30

