快速查找mongodb中索引列的重复项

时间:2010-11-19 12:05:06

标签: mongodb mapreduce

我在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)
});

3 个答案:

答案 0 :(得分:64)

我个人发现在大型数据库(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个值。

答案 1 :(得分:30)

一次通过最简单的方法是按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集合并执行清理。

答案 2 :(得分:5)

您可以按该字段执行分组,然后进行查询以获取重复的内容(计数> 1)。 http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Group

尽管如此,最快的事情可能就是只进行一个只返回该字段然后在客户端进行聚合的查询。 Group / Map-Reduce需要提供对整个文档的访问权限,这比仅提供索引中的数据(现在已在1.7.3 +中介绍)要昂贵得多。

如果这是一个普遍的问题,你需要定期运行,你可能想保留一个只有{md5:value,count:value}的集合,这样你就可以跳过聚合,当你需要时它会非常快剔除重复。