MongoDB द्वारा समर्थित एकत्रीकरण कार्यों में मैप-रिड्यूस शायद सबसे बहुमुखी है।
मैप-रिड्यूस एक लोकप्रिय प्रोग्रामिंग मॉडल है जो Google में समानांतर में बड़ी मात्रा में डेटा को संसाधित करने और एकत्र करने के लिए उत्पन्न हुआ है। मैप-रिड्यूस पर एक विस्तृत चर्चा इस लेख के दायरे से बाहर है, लेकिन अनिवार्य रूप से यह एक बहु-चरणीय एकत्रीकरण प्रक्रिया है। सबसे महत्वपूर्ण दो चरण हैं मानचित्र चरण (प्रत्येक दस्तावेज़ को संसाधित करें और परिणाम उत्सर्जित करें) और कम करें चरण (मानचित्र चरण के दौरान उत्सर्जित परिणामों का मिलान करें)।
MongoDB तीन तरह के एग्रीगेशन ऑपरेशन को सपोर्ट करता है:मैप-रिड्यूस, एग्रीगेशन पाइपलाइन और सिंगल पर्पस एग्रीगेशन कमांड। आप इस MongoDB तुलना दस्तावेज़ का उपयोग यह देखने के लिए कर सकते हैं कि आपकी आवश्यकताओं के अनुरूप कौन सा है।https://scalegrid.io/blog/mongodb-performance-running-mongodb-map-reduce-operations-on-secondaries/
मेरी पिछली पोस्ट में, हमने उदाहरणों के साथ देखा कि सेकेंडरी पर एग्रीगेशन पाइपलाइन कैसे चलाएं। इस पोस्ट में, हम MongoDB सेकेंडरी रेप्लिका पर मैप-रिड्यूस जॉब्स चलाएंगे।
MongoDB मैप-रिड्यूस
MongoDB डेटाबेस सर्वर पर मैप-रिड्यूस जॉब चलाने का समर्थन करता है। यह जटिल एकत्रीकरण कार्यों को लिखने की सुविधा प्रदान करता है जो एकत्रीकरण पाइपलाइनों के माध्यम से आसानी से नहीं किए जाते हैं। MongoDB आपको जावास्क्रिप्ट में कस्टम मैप लिखने और फ़ंक्शन को कम करने देता है जिसे Mongo शेल या किसी अन्य क्लाइंट के माध्यम से डेटाबेस में पास किया जा सकता है। बड़े और लगातार बढ़ते डेटा सेट पर, हर बार पुराने डेटा को संसाधित करने से बचने के लिए वृद्धिशील मैप-रिड्यूस जॉब चलाने पर भी विचार किया जा सकता है।
ऐतिहासिक रूप से, मानचित्र और कम करने के तरीकों को एकल-थ्रेडेड संदर्भ में निष्पादित किया जाता था। हालांकि, संस्करण 2.4 में उस सीमा को हटा दिया गया था।
माप-रिड्यूस जॉब को सेकेंडरी पर क्यों चलाएं?
अन्य एकत्रीकरण नौकरियों की तरह, मैप-रिड्यूस भी एक संसाधन गहन 'बैच' कार्य है, इसलिए यह केवल-पढ़ने के लिए प्रतिकृतियों पर चलने के लिए उपयुक्त है। ऐसा करने में चेतावनी हैं:
1) थोड़े पुराने डेटा का उपयोग करना ठीक होना चाहिए। या आप यह सुनिश्चित करने के लिए लेखन चिंता को बदल सकते हैं कि प्रतिकृतियां हमेशा प्राथमिक के साथ समन्वयित हों। यह दूसरा विकल्प मानता है कि लेखन के प्रदर्शन पर चोट लगना स्वीकार्य है।
2) मैप-रिड्यूस जॉब का आउटपुट डेटाबेस के भीतर किसी अन्य संग्रह में नहीं लिखा जाना चाहिए, बल्कि एप्लिकेशन को वापस किया जाना चाहिए (यानी डेटाबेस को कोई लिखता नहीं है)।
आइए देखें कि इसे मोंगो शेल और जावा ड्राइवर दोनों से उदाहरणों के माध्यम से कैसे किया जाए।
नक्शा-प्रतिकृति सेट पर कम करें
डेटा सेट
उदाहरण के लिए, हम एक साधारण डेटा सेट का उपयोग करेंगे:एक खुदरा विक्रेता से दैनिक लेनदेन रिकॉर्ड डंप। एक नमूना प्रविष्टि इस तरह दिखती है:
RS-replica-0:PRIMARY> use test switched to db test RS-replica-0:PRIMARY> show tables txns RS-replica-0:PRIMARY> db.txns.findOne() { "_id" : ObjectId("584a3b71cdc1cb061957289b"), "custid" : "cust_66", "txnval" : 100, "items" : [{"sku": sku1", "qty": 1, "pr": 100}, ...], ... }
हमारे उदाहरणों में, हम उस दिन किसी दिए गए ग्राहक के कुल व्यय की गणना करेंगे। इस प्रकार, हमारे स्कीमा को देखते हुए, नक्शा और कम करने के तरीके इस तरह दिखेंगे:
var mapFunction = function() { emit(this.custid, this.txnval); } // Emit the custid and txn value from each record var reduceFunction = function(key, values) { return Array.sum(values); } // Sum all the txn values for a given custid
हमारे स्कीमा के स्थापित होने के साथ, आइए मैप-रिड्यूस इन एक्शन को देखें।
MongoDB शेल
यह सुनिश्चित करने के लिए कि मैप-रिड्यूस जॉब सेकेंडरी पर निष्पादित हो, पठन वरीयता को सेकेंडरी पर सेट किया जाना चाहिए . जैसा कि हमने ऊपर कहा, मैप-रिड्यूस को सेकेंडरी पर चलाने के लिए, परिणाम का आउटपुट इनलाइन होना चाहिए (वास्तव में, यह सेकेंडरी पर अनुमत एकमात्र आउट वैल्यू है)। आइए देखें कि यह कैसे काम करता है।
$ mongo -u admin -p pwd --authenticationDatabase admin --host RS-replica-0/server-1.servers.example.com:27017,server-2.servers.example.com:27017 MongoDB shell version: 3.2.10 connecting to: RS-replica-0/server-1.servers.example.com:27017,server-2.servers.example.com:27017/test 2016-12-09T08:15:19.347+0000 I NETWORK [thread1] Starting new replica set monitor for server-1.servers.example.com:27017,server-2.servers.example.com:27017 2016-12-09T08:15:19.349+0000 I NETWORK [ReplicaSetMonitorWatcher] starting RS-replica-0:PRIMARY> db.setSlaveOk() RS-replica-0:PRIMARY> db.getMongo().setReadPref('secondary') RS-replica-0:PRIMARY> db.getMongo().getReadPrefMode() secondary RS-replica-0:PRIMARY> var mapFunc = function() { emit(this.custid, this.txnval); } RS-replica-0:PRIMARY> var reduceFunc = function(key, values) { return Array.sum(values); } RS-replica-0:PRIMARY> db.txns.mapReduce(mapFunc, reduceFunc, {out: { inline: 1 }}) { "results" : [ { "_id" : "cust_0", "value" : 72734 }, { "_id" : "cust_1", "value" : 67737 }, ... ] "timeMillis" : 215, "counts" : { "input" : 10000, "emit" : 10000, "reduce" : 909, "output" : 101 }, "ok" : 1 }
सेकेंडरी पर लॉग्स पर एक नज़र इस बात की पुष्टि करती है कि जॉब वास्तव में सेकेंडरी पर चल रही थी।
... 2016-12-09T08:17:24.842+0000 D COMMAND [conn344] mr ns: test.txns 2016-12-09T08:17:24.843+0000 I COMMAND [conn344] command test.$cmd command: listCollections { listCollections: 1, filter: { name: "txns" }, cursor: {} } keyUpdates:0 writeConflicts:0 numYields:0 reslen:150 locks:{ Global: { acquireCount: { r: 4 } }, Database: { acquireCount: { r: 1, R: 1 } }, Collection: { acquireCount: { r: 1 } } } protocol:op_query 0ms 2016-12-09T08:17:24.865+0000 I COMMAND [conn344] query test.system.js planSummary: EOF ntoreturn:0 ntoskip:0 keysExamined:0 docsExamined:0 cursorExhausted:1 keyUpdates:0 writeConflicts:0 numYields:0 nreturned:0 reslen:20 locks:{ Global: { acquireCount: { r: 6 } }, Database: { acquireCount: { r: 2, R: 1 } }, Collection: { acquireCount: { r: 2 } } } 0ms 2016-12-09T08:17:25.063+0000 I COMMAND [conn344] command test.txns command: mapReduce { mapreduce: "txns", map: function () { emit(this.custid, this.txnval); }, reduce: function (key, values) { return Array.sum(values); }, out: { inline: 1.0 } } planSummary: COUNT keyUpdates:0 writeConflicts:0 numYields:78 reslen:4233 locks:{ Global: { acquireCount: { r: 366 } }, Database: { acquireCount: { r: 3, R: 180 } }, Collection: { acquireCount: { r: 3 } } } protocol:op_command 220ms ...
जावा
अब जावा एप्लिकेशन से रीड रेप्लिका पर मैप-रिड्यूस जॉब चलाने की कोशिश करते हैं। मोंगोडीबी जावा ड्राइवर पर, पठन वरीयता सेट करना चाल है। आउटपुट डिफ़ॉल्ट रूप से इनलाइन है इसलिए कोई अतिरिक्त पैरामीटर पारित करने की आवश्यकता नहीं है। यहां ड्राइवर संस्करण 3.2.2 का उपयोग करते हुए एक उदाहरण दिया गया है:
public class MapReduceExample { private static final String MONGO_END_POINT = "mongodb://admin:[email protected]:27017,server-2.servers.example.com:27017/admin?replicaSet=RS-replica-0"; private static final String COL_NAME = "txns"; private static final String DEF_DB = "test"; public MapReduceExample() { } public static void main(String[] args) { MapReduceExample writer = new MapReduceExample(); writer.mapReduce(); } public static final String mapfunction = "function() { emit(this.custid, this.txnval); }"; public static final String reducefunction = "function(key, values) { return Array.sum(values); }"; private void mapReduce() { printer("Initializing..."); Builder options = MongoClientOptions.builder().readPreference(ReadPreference.secondary()); MongoClientURI uri = new MongoClientURI(MONGO_END_POINT, options); MongoClient client = new MongoClient(uri); MongoDatabase database = client.getDatabase(DEF_DB); MongoCollection collection = database.getCollection(COL_NAME); MapReduceIterable iterable = collection.mapReduce(mapfunction, reducefunction); // inline by default MongoCursor cursor = iterable.iterator(); while (cursor.hasNext()) { Document result = cursor.next(); printer("Customer: " + result.getString("_id") + ", Total Txn value: " + result.getDouble("value")); } printer("Done..."); } ... }
जैसा कि लॉग से स्पष्ट है, कार्य माध्यमिक पर चला:
... 2016-12-09T08:32:31.419+0000 D COMMAND [conn371] mr ns: test.txns 2016-12-09T08:32:31.420+0000 I COMMAND [conn371] command test.$cmd command: listCollections { listCollections: 1, filter: { name: "txns" }, cursor: {} } keyUpdates:0 writeConflicts:0 numYields:0 reslen:150 locks:{ Global: { acquireCount: { r: 4 } }, Database: { acquireCount: { r: 1, R: 1 } }, Collection: { acquireCount: { r: 1 } } } protocol:op_query 0ms 2016-12-09T08:32:31.444+0000 I COMMAND [conn371] query test.system.js planSummary: EOF ntoreturn:0 ntoskip:0 keysExamined:0 docsExamined:0 cursorExhausted:1 keyUpdates:0 writeConflicts:0 numYields:0 nreturned:0 reslen:20 locks:{ Global: { acquireCount: { r: 6 } }, Database: { acquireCount: { r: 2, R: 1 } }, Collection: { acquireCount: { r: 2 } } } 0ms 2016-12-09T08:32:31.890+0000 I COMMAND [conn371] command test.txns command: mapReduce { mapreduce: "txns", map: function() { emit(this.custid, this.txnval); }, reduce: function(key, values) { return Array.sum(values); }, out: { inline: 1 }, query: null, sort: null, finalize: null, scope: null, verbose: true } planSummary: COUNT keyUpdates:0 writeConflicts:0 numYields:156 reslen:4331 locks:{ Global: { acquireCount: { r: 722 } }, Database: { acquireCount: { r: 3, R: 358 } }, Collection: { acquireCount: { r: 3 } } } protocol:op_query 470ms ...
MongoDB मैप-साझा क्लस्टर पर कम करें
MongoDB शार्प किए गए क्लस्टर पर मैप-रिड्यूस का समर्थन करता है, दोनों जब एक शार्प कलेक्शन इनपुट होता है और जब यह मैप-रिड्यूस जॉब का आउटपुट होता है। हालाँकि, MongoDB वर्तमान में शार्प किए गए क्लस्टर के सेकेंडरी पर मैप-रिड्यूस जॉब चलाने का समर्थन नहीं करता है। तो भले ही आउट विकल्प इनलाइन . पर सेट है , मैप-रिड्यूस जॉब हमेशा शार्प्ड क्लस्टर के प्राइमरी पर चलेगा। इस JIRA बग के माध्यम से इस समस्या को ट्रैक किया जा रहा है।
शार्प किए गए क्लस्टर पर मैप-रिड्यूस जॉब को निष्पादित करने का सिंटैक्स प्रतिकृति सेट के समान है। तो उपरोक्त खंड में दिए गए उदाहरण पकड़ में आते हैं। यदि उपरोक्त जावा उदाहरण एक शार्प्ड क्लस्टर पर चलाया जाता है, तो प्राइमरी पर लॉग संदेश दिखाई देते हैं जो दर्शाता है कि कमांड वहां चल रहा है।
... 2016-11-24T08:46:30.828+0000 I COMMAND [conn357] command test.$cmd command: mapreduce.shardedfinish { mapreduce.shardedfinish: { mapreduce: "txns", map: function() { emit(this.custid, this.txnval); }, reduce: function(key, values) { return Array.sum(values); }, out: { in line: 1 }, query: null, sort: null, finalize: null, scope: null, verbose: true, $queryOptions: { $readPreference: { mode: "secondary" } } }, inputDB: "test", shardedOutputCollection: "tmp.mrs.txns_1479977190_0", shards: { Shard-0/primary.shard0.example.com:27017,secondary.shard0.example.com:27017: { result: "tmp.mrs.txns_1479977190_0", timeMillis: 123, timing: { mapTime: 51, emitLoop: 116, reduceTime: 9, mode: "mixed", total: 123 }, counts: { input: 9474, emit: 9474, reduce: 909, output: 101 }, ok: 1.0, $gleS tats: { lastOpTime: Timestamp 1479977190000|103, electionId: ObjectId('7fffffff0000000000000001') } }, Shard-1/primary.shard1.example.com:27017,secondary.shard1.example.com:27017: { result: "tmp.mrs.txns_1479977190_0", timeMillis: 71, timing: { mapTime: 8, emitLoop: 63, reduceTime: 4, mode: "mixed", total: 71 }, counts: { input: 1526, emit: 1526, reduce: 197, output: 101 }, ok: 1.0, $gleStats: { lastOpTime: Timestamp 1479977190000|103, electionId: ObjectId('7fffffff0000000000000001') } } }, shardCounts: { Sha rd-0/primary.shard0.example.com:27017,secondary.shard0.example.com:27017: { input: 9474, emit: 9474, reduce: 909, output: 101 }, Shard-1/primary.shard1.example.com:27017,secondary.shard1.example.com:27017: { inpu t: 1526, emit: 1526, reduce: 197, output: 101 } }, counts: { emit: 11000, input: 11000, output: 202, reduce: 1106 } } keyUpdates:0 writeConflicts:0 numYields:0 reslen:4368 locks:{ Global: { acquireCount: { r: 2 } }, Database: { acquireCount: { r: 1 } }, Collection: { acqu ireCount: { r: 1 } } } protocol:op_command 115ms 2016-11-24T08:46:30.830+0000 I COMMAND [conn46] CMD: drop test.tmp.mrs.txns_1479977190_0 ...
हमारी विस्तृत सुविधाओं की सूची के बारे में जानने के लिए कृपया हमारे MongoDB उत्पाद पृष्ठ पर जाएं।