2011-12-06 10 views
5

मेरे पास MongoDB पर एक बहुत बड़ा संग्रह है और मैं उस संग्रह से डुप्लिकेट रिकॉर्ड को हटाना चाहता हूं। पहला विचार मेरे दिमाग में आता है कि इंडेक्स को छोड़ना और ड्रॉपड्यूप्स के साथ इंडेक्स का पुनर्निर्माण करना है। हालांकि, डुप्लिकेट डेटा मोंगोडीबी द्वारा संभाला जाने वाला बहुत अधिक है।MapReduce द्वारा MongoDB में डुप्लिकेट रिकॉर्ड को कैसे निकालें?

तो मैं मदद के लिए MapReduce में बदल जाता हूं। मेरी वर्तमान प्रगति यहाँ है।

m = function() { 
    emit(this.myid, 1); 
} 

r = function (k, vals) { 
    return Array.sum(vals); 
} 

res = db.userList.mapReduce(m,r, { out : "myoutput" }); 

और सभी डुप्लिकेट रिकॉर्ड के "myid" को "myoutput" संग्रह में संग्रहीत किया जाता है। हालांकि, मुझे नहीं पता कि myoutput.myid का संदर्भ देकर उपयोगकर्ता सूची से रिकॉर्ड को कैसे हटाया जाए।

db.myoutput.find({value: {$gt: 1}}).forEach(
    function(obj) { 
     db.userList.remove(xxxxxxxxx) // I don't know how to do so 
}) 

Btw, foreach का उपयोग कर समझदार MyID साथ सभी रिकॉर्ड को हटा देगा लगता है: यह कुछ इस तरह होना करने के लिए supposes। लेकिन मैं सिर्फ डुप्लिकेट रिकॉर्ड को हटाना चाहता हूं। पूर्व:

{ "_id" : ObjectId("4edc6773e206a55d1c0000d8"), "myid" : 0 } 
{ "_id" : ObjectId("4edc6780e206a55e6100011a"), "myid" : 0 } 

{ "_id" : ObjectId("4edc6784e206a55ed30000c1"), "myid" : 0 } 

अंतिम परिणाम केवल एक रिकॉर्ड को संरक्षित रखना चाहिए। क्या कोई मुझे इस पर कुछ मदद दे सकता है?

धन्यवाद। :)

उत्तर

8

साफ शायद एक क्लाइंट-साइड स्क्रिप्ट रिकॉर्ड को हटा देता है लिखना है:

db.myoutput.find({value: {$gt: 1}}).forEach(
    function(obj) { 
    var cur = db.userList.find({ myid: obj._id }, {_id: 1}); 
    var first = true; 
    while (cur.hasNext()) { 
     var doc = cur.next(); 
     if (first) {first = false; continue;} 
     db.userList.remove({ _id: doc._id }); 
    } 
}) 

मैं इस कोड इसलिए हमेशा दोहरी जांच अगर prod डेटा के खिलाफ चल परीक्षण नहीं किया ..

+3

धन्यवाद। यह काम करता हैं। हालांकि, myoutput संग्रह में 3 एम रिकॉर्ड होगा। निष्पादन गति बहुत धीमी है। क्या इसे तेज करना संभव है? –

1

जबकि उपर्युक्त उत्तर काफी प्रभावी है, यदि आपके डेटाबेस/संग्रह में 900K या 3M रिकॉर्ड हैं तो यह वास्तव में बहुत धीमा है।

तो डेटा की बड़ी मात्रा के साथ काम कर, मैं लंबी सड़क सलाह देते हैं:

  • चुनें अनुरूप द्वारा एक ग्रुप का उपयोग कर आइटम - db.collection.group()
  • स्टोर इस डेटा समारोह को कम का उपयोग कर एक सरणी में
  • निर्यात किए गए डेटा को JSON
  • के रूप में सहेजें, इसे एक साफ डेटाबेस में mongoimport का उपयोग करके फिर से आयात करें।

900K प्रविष्टियों के लिए, इसमें लगभग 35s (समूह क्वेरी) लिया गया। PHP में

कार्यान्वयन:

$mongo_client = new MongoClient(); 
$collection = $mongo_client->selectCollection("main", "settings"); 

//Group by the field "code" 
$keys = array("code" => 1); 
//You must create objects for every field you wish to transfer (except the one grouped by - that gets auto-transferred) 
$initial = array("location" => "", "name" => "", "score" => 0, "type" => ""); 
//The reduce function will set the grouped properties 
$reduce = "function (obj, prev) { prev.location = obj.location; prev.name = obj.name; prev.score = obj.score; prev.type = obj.type; }"; 

$fh = fopen("Export.json", "w"); 
$unique_set = $collection->group($keys, $initial, $reduce); 
fwrite($fh, json_encode($unique_set['retval'])); 
fclose($fh); 

आप बहुत कुछ डुप्लिकेट हैं, पीएचपी पर इसे चलाने तो सबसे अच्छा विकल्प नहीं हो सकता है, लेकिन मेरे सेट डुप्लिकेट की एक बड़ी संख्या थी, इसलिए अंतिम डाटासेट करने के लिए आसान था संभाल। शायद किसी को यह गति के लिए उपयोगी लगेगा। (और मोंगो खोल को स्थानांतरित करना काफी आसान होना चाहिए।)

याद रखें, हालांकि, आपको अंतिम फ़ाइल को फिर से प्रारूपित करना होगा ताकि इसे प्रति पंक्ति 1 दस्तावेज़ रखने के लिए mongoimport के साथ काम किया जा सके। (सभी खोजें/प्रतिस्थापित करें यहां ठीक होना चाहिए।)

0
/* 
* This map reduce will output a new collection: "duplicateinvoices" 
* { "_id" : "12345", "value" : 2 } 
* { "_id" : "23456", "value" : 2 } 
* ... 
**/ 
m = function() { 
    emit(this.MlsId, 1); 
} 

r = function (k, vals) { 
    return Array.sum(vals); 
} 

res = db.invoices.mapReduce(m,r, { out : "duplicateinvoices" }); 

/* 
* We have two approaches (we should test wich is faster/reliable, i didn't 
**/ 

/* OPTION 1 */ 
// We iterate over duplicateinvoices and get the media-hash 
// of the ones with value > 1 the duplicates 
db.duplicateinvoices.find({value: {$gt: 1}}).forEach(
    function(invoice) { 
     // temporary save one of this objects into a variable 
     var obj = db.invoices.findOne({ media_hash: invoice._id }); 
     // remove all media-hash matched invoices from invoice collection 
     db.invoices.remove({media_hash: invoice._id}) 
     // insert again the previously saved object into collection 
     db.invoices.insert(obj) 
    } 
) 

/* OPTION 2 */ 
// We iterate over duplicateinvoices and get the media-hash 
// of the ones with value > 1 the duplicates 
db.duplicateinvoices.find({value: {$gt: 1}}).forEach(
    function(invoice) { 
     // Invoices cursor with all the media_hash matched documents 
     var cur = db.invoices.find({ media_hash: invoice._id }); 
     var first = true; 
     while (cur.hasNext()) { 
      var doc = cur.next(); 
      // Skip the first one 
      if (first) {first = false; continue;} 
      // Delete the others matched documents 
      db.userList.remove({ _id: doc._id }); 
     } 
    } 
) 

सूत्रों का कहना है:

How to remove duplicate record in MongoDB by MapReduce? http://openmymind.net/2011/1/20/Understanding-Map-Reduce/ http://docs.mongodb.org/manual/tutorial/map-reduce-examples/

1

वास्तव में वहाँ mapreduce यहाँ की कोई आवश्यकता नहीं है। इसके बारे में क्या:? मोंगो खोल में पेस्ट कोड:

function removeDupls (collectionName, keyField, reportEvery) { 
    if (reportEvery === undefined) {reportEvery=10;} 
    sort = {}; 
    sort[keyField] = 1; 
    var myidLast; 
    var res = {docsCnt:0,docsRemoved:0} 
    db[collectionName].find().sort(sort).clone().forEach(
     function(doc) { 
       res['docsCnt'] += 1; 
       if (doc.myid == myidLast) {db[collectionName].remove({_id:doc._id}); res['docsRemoved'] +=1;} 
       else {myidLast = doc.myid;} 
       if (res['docsCnt'] % reportEvery === 0) {print (JSON.stringify(res))} 
      } 
    ); 
    return res; 
} 

तो यह कहते हैं:

removeDupls('users','myid',1000) 

इस काम करेंगे और शायद यह किसी भी mapreduce तुलना में तेजी से हो जाएगा> कार्य निकालने (डुप्लिकेट किए गए दस्तावेजों के अपने मात्रा पर निर्भर करता है) यदि आप इसे वास्तव में तेज़ी से बनाना चाहते हैं तो आपको अस्थायी सरणी में निकाले जाने वाले दस्तावेज़ों के _ids को स्टोर करना चाहिए, फिर बैच निकालें का उपयोग करें।

संबंधित मुद्दे