वर्तमान संसाधन mapReduce है
यदि आपको सर्वर पर इसे निष्पादित करने और शीर्ष परिणामों को क्रमबद्ध करने और शीर्ष 100 रखने की आवश्यकता है, तो आप इसके लिए mapReduce का उपयोग कर सकते हैं:
db.test.mapReduce(
function() {
var input = [0.1,0.3,0.4];
var value = Array.sum(this.vals.map(function(el,idx) {
return Math.abs( el - input[idx] )
}));
emit(null,{ "output": [{ "_id": this._id, "value": value }]});
},
function(key,values) {
var output = [];
values.forEach(function(value) {
value.output.forEach(function(item) {
output.push(item);
});
});
output.sort(function(a,b) {
return a.value < b.value;
});
return { "output": output.slice(0,100) };
},
{ "out": { "inline": 1 } }
)
तो मैपर फ़ंक्शन एक ही कुंजी के तहत गणना और आउटपुट का सब कुछ करता है, इसलिए सभी परिणाम रेड्यूसर को भेजे जाते हैं। अंतिम आउटपुट एक एकल आउटपुट दस्तावेज़ में एक सरणी में समाहित होने जा रहा है, इसलिए यह महत्वपूर्ण है कि सभी परिणाम समान कुंजी मान के साथ उत्सर्जित हों और प्रत्येक उत्सर्जन का आउटपुट स्वयं एक सरणी है इसलिए mapReduce ठीक से काम कर सकता है।पी>
छँटाई और कमी रेड्यूसर में ही की जाती है, क्योंकि प्रत्येक उत्सर्जित दस्तावेज़ का निरीक्षण किया जाता है, तत्वों को एक अस्थायी सरणी में रखा जाता है, क्रमबद्ध किया जाता है, और शीर्ष परिणाम वापस कर दिए जाते हैं।
यह महत्वपूर्ण है, और यही कारण है कि एमिटर इसे एक सरणी के रूप में उत्पन्न करता है, भले ही पहले एक तत्व हो। MapReduce परिणामों को "खंड" में संसाधित करके काम करता है, इसलिए भले ही सभी उत्सर्जित दस्तावेज़ों में एक ही कुंजी हो, वे सभी एक बार में संसाधित नहीं होते हैं। बल्कि रेड्यूसर अपने परिणामों को वापस उत्सर्जित परिणामों की कतार में डाल देता है, जब तक कि उस विशेष कुंजी के लिए केवल एक ही दस्तावेज़ शेष न हो।
मैं लिस्टिंग की संक्षिप्तता के लिए यहां "स्लाइस" आउटपुट को 10 तक सीमित कर रहा हूं, और आंकड़ों को एक बिंदु बनाने के लिए, क्योंकि इस 10000 नमूने पर 100 कम चक्रों को देखा जा सकता है:
{
"results" : [
{
"_id" : null,
"value" : {
"output" : [
{
"_id" : ObjectId("56558d93138303848b496cd4"),
"value" : 2.2
},
{
"_id" : ObjectId("56558d96138303848b49906e"),
"value" : 2.2
},
{
"_id" : ObjectId("56558d93138303848b496d9a"),
"value" : 2.1
},
{
"_id" : ObjectId("56558d93138303848b496ef2"),
"value" : 2.1
},
{
"_id" : ObjectId("56558d94138303848b497861"),
"value" : 2.1
},
{
"_id" : ObjectId("56558d94138303848b497b58"),
"value" : 2.1
},
{
"_id" : ObjectId("56558d94138303848b497ba5"),
"value" : 2.1
},
{
"_id" : ObjectId("56558d94138303848b497c43"),
"value" : 2.1
},
{
"_id" : ObjectId("56558d95138303848b49842b"),
"value" : 2.1
},
{
"_id" : ObjectId("56558d96138303848b498db4"),
"value" : 2.1
}
]
}
}
],
"timeMillis" : 1758,
"counts" : {
"input" : 10000,
"emit" : 10000,
"reduce" : 100,
"output" : 1
},
"ok" : 1
}
तो यह एक एकल दस्तावेज़ आउटपुट है, विशिष्ट mapReduce प्रारूप में, जहां "मान" में एक तत्व होता है जो क्रमबद्ध और सीमित परिणाम की एक सरणी है।
भविष्य की प्रोसेसिंग समग्र है
लेखन के समय, MongoDB की वर्तमान नवीनतम स्थिर रिलीज़ 3.0 है, और इसमें आपके संचालन को संभव बनाने के लिए कार्यक्षमता का अभाव है। लेकिन आगामी 3.2 रिलीज नए ऑपरेटरों को पेश करता है जो इसे संभव बनाते हैं:
db.test.aggregate([
{ "$unwind": { "path": "$vals", "includeArrayIndex": "index" }},
{ "$group": {
"_id": "$_id",
"result": {
"$sum": {
"$abs": {
"$subtract": [
"$vals",
{ "$arrayElemAt": [ { "$literal": [0.1,0.3,0.4] }, "$index" ] }
]
}
}
}
}},
{ "$sort": { "result": -1 } },
{ "$limit": 100 }
])
साथ ही संक्षिप्तता के लिए समान 10 परिणामों को सीमित करते हुए, आपको इस तरह का आउटपुट मिलता है:
{ "_id" : ObjectId("56558d96138303848b49906e"), "result" : 2.2 }
{ "_id" : ObjectId("56558d93138303848b496cd4"), "result" : 2.2 }
{ "_id" : ObjectId("56558d96138303848b498e31"), "result" : 2.1 }
{ "_id" : ObjectId("56558d94138303848b497c43"), "result" : 2.1 }
{ "_id" : ObjectId("56558d94138303848b497861"), "result" : 2.1 }
{ "_id" : ObjectId("56558d96138303848b499037"), "result" : 2.1 }
{ "_id" : ObjectId("56558d96138303848b498db4"), "result" : 2.1 }
{ "_id" : ObjectId("56558d93138303848b496ef2"), "result" : 2.1 }
{ "_id" : ObjectId("56558d93138303848b496d9a"), "result" : 2.1 }
{ "_id" : ObjectId("56558d96138303848b499182"), "result" : 2.1 }
यह काफी हद तक $unwind
के कारण संभव हुआ है।
परिणामों में एक फ़ील्ड प्रोजेक्ट करने के लिए संशोधित किया जा रहा है जिसमें सरणी अनुक्रमणिका है, और $arrayElemAt
जो एक नया ऑपरेटर है जो किसी दिए गए इंडेक्स से एक सरणी तत्व को एकवचन मान के रूप में निकाल सकता है।
यह प्रत्येक तत्व पर गणित को लागू करने के लिए आपके इनपुट सरणी से सूचकांक स्थिति द्वारा मूल्यों के "लुक-अप" की अनुमति देता है। इनपुट सरणी को मौजूदा $literal
ऑपरेटर तो $arrayElemAt
शिकायत नहीं करता है और इसे एक सरणी के रूप में पुन:व्यवस्थित करता है, (वर्तमान में एक छोटा बग प्रतीत होता है, क्योंकि अन्य सरणी कार्यों में प्रत्यक्ष इनपुट के साथ समस्या नहीं है) और द्वारा उत्पादित "इंडेक्स" फ़ील्ड का उपयोग करके उचित मिलान सूचकांक मान प्राप्त करता है $अनविंड
तुलना के लिए।
गणित $subtract
द्वारा किया जाता है
और निश्चित रूप से $abs
में एक और नया ऑपरेटर
अपनी कार्यक्षमता को पूरा करने के लिए। इसके अलावा, चूंकि पहली बार में सरणी को खोलना आवश्यक था, यह सब एक $group
प्रति दस्तावेज़ सभी सरणी सदस्यों को जमा करने और <के माध्यम से प्रविष्टियों को जोड़ने का चरण कोड>$योग
संचायक।
अंत में सभी परिणाम दस्तावेज़ों को $sort
के साथ संसाधित किया जाता है
और फिर $limit
केवल शीर्ष परिणाम लौटाने के लिए लागू किया जाता है।
सारांश
MongoDB के लिए एकत्रीकरण ढांचे के लिए उपलब्ध होने वाली नई कार्यक्षमता के साथ भी यह बहस का विषय है कि कौन सा दृष्टिकोण वास्तव में परिणामों के लिए अधिक कुशल है। इसका मुख्य कारण अभी भी $अनविंड
. की आवश्यकता है सरणी सामग्री, जो प्रभावी रूप से संसाधित होने के लिए पाइपलाइन में प्रति सरणी सदस्य प्रत्येक दस्तावेज़ की एक प्रति उत्पन्न करती है, और जो आम तौर पर एक ओवरहेड का कारण बनती है।
इसलिए जबकि mapReduce एक नई रिलीज़ तक ऐसा करने का एकमात्र वर्तमान तरीका है, यह वास्तव में संसाधित किए जाने वाले डेटा की मात्रा के आधार पर एकत्रीकरण कथन से बेहतर प्रदर्शन कर सकता है, और इस तथ्य के बावजूद कि एकत्रीकरण ढांचा अनुवादित जावास्क्रिप्ट के बजाय देशी कोडित ऑपरेटरों पर काम करता है। संचालन।
सभी चीजों की तरह, यह देखने के लिए हमेशा परीक्षण की सिफारिश की जाती है कि कौन सा मामला आपके उद्देश्यों के लिए बेहतर है और कौन सा आपके अपेक्षित प्रसंस्करण के लिए सबसे अच्छा प्रदर्शन देता है।
नमूना
बेशक प्रश्न में दिए गए नमूना दस्तावेज़ के लिए अपेक्षित परिणाम 0.9
. है गणित द्वारा लागू। लेकिन सिर्फ मेरे परीक्षण उद्देश्यों के लिए, यहां कुछ नमूना डेटा उत्पन्न करने के लिए उपयोग की जाने वाली एक छोटी सूची है जिसे मैं कम से कम सत्यापित करना चाहता था कि नक्शा रेड्यूस कोड काम कर रहा था:
var bulk = db.test.initializeUnorderedBulkOp();
var x = 10000;
while ( x-- ) {
var vals = [0,0,0];
vals = vals.map(function(val) {
return Math.round((Math.random()*10),1)/10;
});
bulk.insert({ "vals": vals });
if ( x % 1000 == 0) {
bulk.execute();
bulk = db.test.initializeUnorderedBulkOp();
}
}
सरणियाँ पूरी तरह से यादृच्छिक एकल दशमलव बिंदु मान हैं, इसलिए मेरे द्वारा नमूना आउटपुट के रूप में दिए गए सूचीबद्ध परिणामों में बहुत अधिक वितरण नहीं है।