Быстрый способ найти дубликаты по проиндексированному столбцу в mongodb - PullRequest
19 голосов
/ 19 ноября 2010

У меня есть коллекция md5 в mongodb.Я хотел бы найти все дубликаты.Столбец md5 индексируется.Знаете ли вы какой-нибудь быстрый способ сделать это с помощью карты уменьшить.Или я должен просто перебрать все записи и вручную проверить наличие дубликатов?

Мой нынешний подход с использованием карты уменьшает количество итераций по коллекции почти вдвое (при условии, что дубликатов очень мало):

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 ]

65 голосов
/ 12 августа 2013

Я лично обнаружил, что на больших базах данных (1 ТБ и более) принятый ответ ужасно медленный. Агрегация намного быстрее. Пример ниже:

db.places.aggregate(
    { $group : {_id : "$extra_info.id", total : { $sum : 1 } } },
    { $match : { total : { $gte : 2 } } },
    { $sort : {total : -1} },
    { $limit : 5 }
    );

Выполняет поиск документов, чей extra_info.id используется дважды или более раз, сортирует результаты по убыванию данного поля и печатает первые 5 его значений.

30 голосов
/ 19 ноября 2010

Самый простой способ сделать это за один проход - отсортировать по 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 и выполнить очистку.

5 голосов
/ 19 ноября 2010

Вы можете создать группу по этому полю и затем запросить, чтобы получить дубликат (с количеством> 1).http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Group

Хотя самой быстрой вещью может быть просто выполнить запрос, который возвращает только это поле, а затем выполнить агрегацию на клиенте.Group / Map-Reduce необходимо предоставить доступ ко всему документу, что намного дороже, чем просто предоставление данных из индекса (который теперь рассматривается в 1.7.3 +).

Если это общая проблемавам нужно периодически запускать, вы можете сохранить коллекцию, которая просто {md5: value, count: value}, чтобы вы могли пропустить агрегацию, и это будет очень быстро, когда вам нужно отбирать дубликаты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...