我在mongodb中有一个md5的集合.我想找到所有重复的内容.md5列已编制索引.你知道使用map reduce做任何快速的方法吗?或者我应该迭代所有记录并手动检查重复项?
我目前使用map reduce的方法几乎两次迭代集合(假设重复数量非常少):
res = db.files.mapReduce( function () { emit(this.md5, 1); }, function (key, vals) { return Array.sum(vals); } ) db[res.result].find({value: {$gte:1}}).forEach( function (obj) { out.duplicates.insert(obj) });
expert.. 66
我个人发现在大型数据库(1TB以上)上接受的答案非常慢.聚合更快.示例如下:
db.places.aggregate( { $group : {_id : "$extra_info.id", total : { $sum : 1 } } }, { $match : { total : { $gte : 2 } } }, { $sort : {total : -1} }, { $limit : 5 } );
它搜索extra_info.id
使用两次或更多次的文档,按给定字段的降序对结果进行排序,并打印前5个值.
我个人发现在大型数据库(1TB以上)上接受的答案非常慢.聚合更快.示例如下:
db.places.aggregate( { $group : {_id : "$extra_info.id", total : { $sum : 1 } } }, { $match : { total : { $gte : 2 } } }, { $sort : {total : -1} }, { $limit : 5 } );
它搜索extra_info.id
使用两次或更多次的文档,按给定字段的降序对结果进行排序,并打印前5个值.
在一次通过中执行此操作的最简单方法是按md5排序,然后进行适当处理.
就像是:
var previous_md5; db.files.find( {"md5" : {$exists:true} }, {"md5" : 1} ).sort( { "md5" : 1} ).forEach( function(current) { if(current.md5 == previous_md5){ db.duplicates.update( {"_id" : current.md5}, { "$inc" : {count:1} }, true); } previous_md5 = current.md5; });
那个小脚本按顺序对md5条目进行排序并循环遍历它们.如果重复md5,那么它们将在排序后"背靠背".所以我们只保留一个指针previous_md5
并进行比较current.md5
.如果我们发现重复,我将它放入duplicates
集合中(并使用$ inc来计算重复数).
此脚本意味着您只需要遍历主数据集一次.然后,您可以遍历duplicates
集合并执行清理.
您可以按该字段执行分组,然后进行查询以获取重复(计数> 1).http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Group
虽然,最快的事情可能是只执行一个只返回该字段然后在客户端进行聚合的查询.Group/Map-Reduce需要提供对整个文档的访问权限,这比仅提供索引中的数据(现在已在1.7.3+中介绍)要昂贵得多.
如果这是一个普遍的问题,你需要定期运行,你可能想保留一个只有{md5:value,count:value}的集合,这样你就可以跳过聚合,当你需要剔除重复时它会非常快.