Szybki sposób wyszukiwania duplikatów na indeksowanych kolumnach w mongodb

Mam kolekcję md5 w mongodb. Chciałbym znaleźć wszystkie duplikaty. Kolumna md5 jest indeksowana. Czy znasz jakiś szybki sposób, aby to zrobić za pomocą Map reduce. A może powinienem po prostu powtórzyć wszystkie rekordy i sprawdzić duplikaty ręcznie?

Moje obecne podejście przy użyciu map reduce iterates nad zbiorem prawie dwukrotnie (zakładając, że jest bardzo mała ilość duplikatów):

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)
});
Author: Piotr Czapla, 2010-11-19

3 answers

Najprostszym sposobem zrobienia tego w jednym przejściu jest sortowanie według md5, a następnie odpowiednie przetwarzanie.

Coś w stylu:

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;

});

Ten mały skrypt sortuje wpisy md5 i zapętla je w kolejności. Jeśli md5 zostanie powtórzone, będą one "back-to-back" po sortowaniu. Trzymamy więc wskaźnik previous_md5 i porównujemy current.md5. Jeśli znajdziemy duplikat, wrzucę go do kolekcji duplicates (i użyję $inc do policzenia liczby duplikatów).

Ten skrypt oznacza, że ty wystarczy tylko raz zapętlić podstawowy zestaw danych. Następnie możesz przejrzeć kolekcję duplicates i wykonać czyszczenie.

 30
Author: Gates VP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-19 15:44:50

Osobiście stwierdziłem, że w dużych bazach danych (1TB i więcej) akceptowana odpowiedź jest strasznie powolna. Agregacja jest znacznie szybsza. Przykład znajduje się poniżej:

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

Wyszukuje dokumenty, których extra_info.id jest używane dwa lub więcej razy, sortuje wyniki w porządku malejącym podanego pola i wypisuje pierwsze 5 jego wartości.

 63
Author: expert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-12 02:00:29

Możesz zrobić grupę przez to pole, a następnie zapytanie, aby uzyskać duplikat (o count > 1). http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Group

Chociaż najszybszą rzeczą może być wykonanie zapytania, które zwraca tylko to pole, a następnie wykonanie agregacji w kliencie. Grupa / Mapa-ograniczenie konieczności zapewnienia dostępu do całego dokumentu, co jest o wiele bardziej kosztowne niż tylko udostępnienie danych z indeksu (który jest obecnie objęty 1.7.3+).

Jeśli jest to ogólny problem, który musisz uruchamiać okresowo, możesz chcieć zachować kolekcję, która jest po prostu {md5: value, count:value}, więc możesz pominąć agregację, a to będzie bardzo szybkie, gdy będziesz musiał usunąć duplikaty.

 5
Author: Scott Hernandez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-19 15:24:38