私はmongodbにmd5のコレクションを持っています。すべての重複を見つけたいのですが。 md5列にインデックスが付けられます。 mapreduceを使用してそれを行うための高速な方法を知っていますか。または、すべてのレコードを繰り返し処理して、重複を手動でチェックする必要がありますか?
Map reduceを使用する現在のアプローチでは、コレクションをほぼ2回繰り返します(重複が非常に少ないと仮定)。
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)
});
1回のパスでそれを行う最も簡単な方法は、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を使用して重複の数をカウントします)。
このスクリプトは、プライマリデータセットを1回だけループする必要があることを意味します。次に、duplicates
コレクションをループして、クリーンアップを実行できます。
私は個人的に、大きなデータベース(1TB以上)では受け入れられた答えがひどく遅いことに気づきました。集約ははるかに高速です。例を以下に示します。
db.places.aggregate(
{ $group : {_id : "$extra_info.id", total : { $sum : 1 } } },
{ $match : { total : { $gte : 2 } } },
{ $sort : {total : -1} },
{ $limit : 5 }
);
extra_info.id
が2回以上使用されているドキュメントを検索し、指定されたフィールドの降順で結果を並べ替えて、最初の5つの値を出力します。
そのフィールドでグループ化してから、クエリを実行して複製を取得できます(カウントが1より大きい)。 http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Group
ただし、最速の方法は、そのフィールドのみを返すクエリを実行してから、クライアントで集計を実行することです。 Group/Map-Reduceは、ドキュメント全体へのアクセスを提供する必要があります。これは、インデックスからデータを提供するよりもはるかにコストがかかります(現在、1.7.3以降で説明されています)。
これが定期的に実行する必要がある一般的な問題である場合は、{md5:value、count:value}だけのコレクションを保持して、集計をスキップできるようにすることをお勧めします。重複をカリングする必要がある場合は、非常に高速になります。 。