2012-03-14 20 views
18

में दो संग्रह विलय करना मैं मोंगो डीबी में मैपरेडस का उपयोग करने की कोशिश कर रहा हूं जो मुझे लगता है कि एक साधारण प्रक्रिया है। मुझे नहीं पता कि यह सही दृष्टिकोण है, अगर मुझे MapReduce का उपयोग करना चाहिए। मैंने जो खोजशब्दों के बारे में सोचा और उन दस्तावेज़ों को मारने की कोशिश की जहां मैंने सोचा कि मुझे सबसे ज्यादा सफलता मिलेगी - लेकिन कुछ भी नहीं। शायद मैं इस बारे में बहुत मुश्किल सोच रहा हूँ? details और gpasमोंगोडीबी

details दस्तावेजों की एक पूरी गुच्छा (3+ मिलियन) से बना है:

मैं दो संग्रह है। studentid तत्व दो बार, हर year के लिए एक दोहराया जा सकता है, निम्नलिखित की तरह:

{ "_id" : ObjectId("4d49b7yah5b6d8372v640100"), "classes" : [1,17,19,21], "studentid" : "12345a", "year" : 1} 
{ "_id" : ObjectId("4d76b7oij7s2d8372v640100"), "classes" : [2,12,19,22], "studentid" : "98765a", "year" : 1} 
{ "_id" : ObjectId("4d49b7oij7s2d8372v640100"), "classes" : [32,91,101,217], "studentid" : "12345a", "year" : 2} 
{ "_id" : ObjectId("4d76b7rty7s2d8372v640100"), "classes" : [1,11,18,22], "studentid" : "24680a", "year" : 1} 
{ "_id" : ObjectId("4d49b7oij7s2d8856v640100"), "classes" : [32,99,110,215], "studentid" : "98765a", "year" : 2} 
... 

gpasdetails से एक ही studentid के साथ तत्व है। studentid में केवल एक प्रविष्टि, इस तरह:

{ "_id" : ObjectId("4d49b7yah5b6d8372v640111"), "studentid" : "12345a", "overall" : 97, "subscore": 1} 
{ "_id" : ObjectId("4f76b7oij7s2d8372v640213"), "studentid" : "98765a", "overall" : 85, "subscore": 5} 
{ "_id" : ObjectId("4j49b7oij7s2d8372v640871"), "studentid" : "24680a", "overall" : 76, "subscore": 2} 
... 

अंत मैं इस प्रारूप में प्रत्येक छात्र के लिए एक पंक्ति के साथ एक संग्रह है करना चाहते हैं:

{ "_id" : ObjectId("4d49b7yah5b6d8372v640111"), "studentid" : "12345a", "classes_1": [1,17,19,21], "classes_2": [32,91,101,217], "overall" : 97, "subscore": 1} 
{ "_id" : ObjectId("4f76b7oij7s2d8372v640213"), "studentid" : "98765a", "classes_1": [2,12,19,22], "classes_2": [32,99,110,215], "overall" : 85, "subscore": 5} 
{ "_id" : ObjectId("4j49b7oij7s2d8372v640871"), "studentid" : "24680a", "classes_1": [1,11,18,22], "classes_2": [], "overall" : 76, "subscore": 2} 
... 

तरह से मैं यह करने के लिए जा रहा था इस तरह MapReduce चलाकर था:

var mapDetails = function() { 
    emit(this.studentid, {studentid: this.studentid, classes: this.classes, year: this.year, overall: 0, subscore: 0}); 
}; 

var mapGpas = function() { 
    emit(this.studentid, {studentid: this.studentid, classes: [], year: 0, overall: this.overall, subscore: this.subscore}); 
}; 

var reduce = function(key, values) { 
    var outs = { studentid: "0", classes_1: [], classes_2: [], overall: 0, subscore: 0}; 

    values.forEach(function(value) { 
     if (value.year == 0) { 
      outs.overall = value.overall; 
      outs.subscore = value.subscore; 
     } 
     else { 
      if (value.year == 1) { 
       outs.classes_1 = value.classes; 
      } 
      if (value.year == 2) { 
       outs.classes_2 = value.classes; 
      } 

      outs.studentid = value.studentid; 
     } 
    }); 

    return outs; 

}; 

res = db.details.mapReduce(mapDetails, reduce, {out: {reduce: 'joined'}}) 
res = db.gpas.mapReduce(mapGpas, reduce, {out: {reduce: 'joined'}}) 

लेकिन जब मैं इसे चलाने, यह मेरा है, जिसके परिणामस्वरूप संग्रह है:

{ "_id" : "12345a", "value" : { "studentid" : "12345a", "classes_1" : [ ], "classes_2" : [ ], "overall" : 97, "subscore" : 1 } } 
{ "_id" : "98765a", "value" : { "studentid" : "98765a", "classes_1" : [ ], "classes_2" : [ ], "overall" : 85, "subscore" : 5 } } 
{ "_id" : "24680a", "value" : { "studentid" : "24680a", "classes_1" : [ ], "classes_2" : [ ], "overall" : 76, "subscore" : 2 } } 

मुझे कक्षाओं के सरणी गायब हैं।

इसके अलावा, एक तरफ के रूप में, मैं MapReduce value तत्व के परिणामस्वरूप तत्वों का उपयोग कैसे करूं? क्या MapReduce हमेशा value पर आउटपुट करता है या जो कुछ भी आप इसे नाम देते हैं?

उत्तर

41

यह मोंगोडीबी-उपयोगकर्ता Google समूह पर एक प्रश्न के समान है।
https://groups.google.com/group/mongodb-user/browse_thread/thread/60a8b683e2626ada?pli=1

जवाब का संदर्भ एक ऑन लाइन ट्यूटोरियल जो अपने उदाहरण की तरह दिखता है:, साथ ही http://www.mongodb.org/display/DOCS/MapReduce

वहाँ: http://tebros.com/2011/07/using-mongodb-mapreduce-to-join-2-collections/

MongoDB में MapReduce के बारे में अधिक जानकारी के लिए कृपया दस्तावेज़ देखें मोंडडब्लूबी कूकबुक आलेख के "अतिरिक्त" खंड में "मैड्रिडस ऑपरेशन" वर्जन किए गए दस्तावेज़ों के साथ अधिकतम और न्यूनतम मान ढूंढने के तरीके के बारे में एक उपयोगी कदम-दर-चरण चलना है: http://cookbook.mongodb.org/patterns/finding_max_and_min/

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

में मैपरेडस का उपयोग करने के लिए नया हो सकता है यह महत्वपूर्ण है कि मानचित्र कार्यों में 'उत्सर्ज' बयान से आउटपुट कम करने के कार्य के आउटपुट से मेल खाते हैं । यदि मानचित्र फ़ंक्शन द्वारा केवल एक दस्तावेज़ आउटपुट होता है, तो कम से कम फ़ंक्शन शायद नहीं चलाया जा सकता है, और फिर आपके आउटपुट संग्रह में मेल नहीं खाते होंगे।

मैंने दो अलग "कक्षाओं" सरणी के साथ, आपके वांछित आउटपुट के प्रारूप में दस्तावेज़ों को उत्सर्जित करने के लिए अपने मानचित्र विवरणों को थोड़ा सा संशोधित किया है।
मैंने कक्षाओं और कक्षाओं के सरणी में नए वर्ग जोड़ने के लिए अपने कम विवरण का भी पुन: कार्य किया है, केवल तभी जब वे पहले से मौजूद नहीं हैं।

var mapDetails = function(){ 
    var output = {studentid: this.studentid, classes_1: [], classes_2: [], year: this.year, overall: 0, subscore: 0} 
    if (this.year == 1) { 
     output.classes_1 = this.classes; 
    } 
    if (this.year == 2) { 
     output.classes_2 = this.classes; 
    } 
    emit(this.studentid, output); 
}; 

var mapGpas = function() { 
    emit(this.studentid, {studentid: this.studentid, classes_1: [], classes_2: [], year: 0, overall: this.overall, subscore: this.subscore}); 
}; 

var r = function(key, values) { 
    var outs = { studentid: "0", classes_1: [], classes_2: [], overall: 0, subscore: 0}; 

    values.forEach(function(v){ 
     outs.studentid = v.studentid; 
     v.classes_1.forEach(function(class){if(outs.classes_1.indexOf(class)==-1){outs.classes_1.push(class)}}) 
     v.classes_2.forEach(function(class){if(outs.classes_2.indexOf(class)==-1){outs.classes_2.push(class)}}) 

     if (v.year == 0) { 
      outs.overall = v.overall; 
      outs.subscore = v.subscore; 
     } 
    }); 
    return outs; 
}; 

res = db.details.mapReduce(mapDetails, r, {out: {reduce: 'joined'}}) 
res = db.gpas.mapReduce(mapGpas, r, {out: {reduce: 'joined'}}) 

निम्नलिखित संग्रह है, जो अपने वांछित प्रारूप से मेल खाता में दो MapReduce संचालन परिणाम चल रहा है:

> db.joined.find() 
{ "_id" : "12345a", "value" : { "studentid" : "12345a", "classes_1" : [ 1, 17, 19, 21 ], "classes_2" : [ 32, 91, 101, 217 ], "overall" : 97, "subscore" : 1 } } 
{ "_id" : "24680a", "value" : { "studentid" : "24680a", "classes_1" : [ 1, 11, 18, 22 ], "classes_2" : [ ], "overall" : 76, "subscore" : 2 } } 
{ "_id" : "98765a", "value" : { "studentid" : "98765a", "classes_1" : [ 2, 12, 19, 22 ], "classes_2" : [ 32, 99, 110, 215 ], "overall" : 85, "subscore" : 5 } } 
> 

MapReduce हमेशा {_ id के रूप में दस्तावेजों आउटपुट: "आईडी", मूल्य: "मूल्य http://www.mongodb.org/display/DOCS/Dot+Notation+%28Reaching+into+Objects%29

आप MapReduce टी के उत्पादन में करना चाहते हैं: डॉट संकेतन (वस्तुओं में पहुँचना) ""} वहाँ और अधिक जानकारी उपलब्ध दस्तावेज़ शीर्षक, उप दस्तावेजों के साथ काम करने पर है " o एक अलग प्रारूप में दिखाई देते हैं, आपको अपने आवेदन में प्रोग्रामेटिक रूप से करना होगा।

उम्मीद है कि यह MapReduce की आपकी समझ में सुधार करेगा, और आपको वांछित आउटपुट संग्रह के उत्पादन के लिए एक कदम आगे ले जाएगा। शुभ लाभ!

+0

इससे बहुत मदद मिली। मैं इस पोस्ट में हर बार सराहना करता हूं। एक बार फिर धन्यवाद! – TFX

+0

मेरी खुशी! मुझे खुशी है कि मैं मदद करने में सक्षम था! ईमानदारी से, मार्क – Marc

2

आप इसके लिए एम/आर का उपयोग नहीं कर सकते क्योंकि यह केवल एक संग्रह पर लागू करने के लिए डिज़ाइन किया गया है। एक से अधिक संग्रह से पढ़ना शेडिंग संगतता को तोड़ देगा और इसलिए इसकी अनुमति नहीं है। आप जो भी चाहते हैं वह नए समेकन ढांचे (2.1+) के साथ कर सकते हैं या इसे अपने आवेदन के अंदर कर सकते हैं।