MongoDb और MapReduce का उपयोग करके उत्पाद फ़िल्टर के निर्माण के लिए एक सरल तकनीक

जब मैंने पहली बार MapReduce का सामना किया था, तो लंबे समय से मैं वास्तविक दुनिया के एप्लिकेशन उदाहरणों की तलाश में था। MapReduce के बारे में हर दूसरे लेख में पाए जाने वाले पाठ में शब्दों की कुख्यात खोज को एक वांछित उदाहरण नहीं माना जाएगा। अंत में कौरसेरा में बिग डेटा पर दो पाठ्यक्रमों में, मुझे न केवल जीवित उदाहरण मिले, बल्कि जो हो रहा है उसकी गहरी समझ के लिए एक सैद्धांतिक पृष्ठभूमि। अर्जित ज्ञान को लागू करने का अवसर आने में लंबा नहीं था।

इस लघु लेख में मैं पर्यटन पोर्टल के लिए मापदंड के अनुसार अधिकांश ऑनलाइन स्टोर उत्पाद फ़िल्टरिंग प्रणाली के लिए एक क्लासिक को लागू करने के अनुभव को साझा करना चाहता हूं, जहां हजारों होटलों के डेटाबेस द्वारा खोज और फ़िल्टर करने का कार्य दिखाई दिया, जिनमें से प्रत्येक को कई मापदंडों और कई दसियों सेवाओं की उपस्थिति द्वारा वर्णित किया गया है। सैकड़ों संभव से बाहर।


समस्या का बयान


कई दसियों वस्तुओं के लिए होटल का एक डेटाबेस है। प्रत्येक होटल द्वारा वर्णित किया गया है:
  1. प्रत्येक के लिए संभव विकल्पों की एक छोटी संख्या के साथ मापदंडों के पास। उदाहरण के लिए, किसी होटल की स्टार रेटिंग: 1 से 5. या किसी होटल में भोजन के प्रकार: उनमें से कई भी नहीं हैं। और इसी तरह। यहां कठिनाई केवल यह है कि प्रत्येक होटल के लिए कुछ मापदंडों के लिए केवल एक ही मूल्य हो सकता है, और संभव के किसी भी सेट के लिए। लेकिन संभव विकल्पों की एक छोटी संख्या के अधीन, यह अभी तक एक समस्या नहीं है।
  2. मूल्य। कार्य को सरल बनाते हुए, कल आने वाले कल के साथ एक डबल प्रति दिन के लिए न्यूनतम मूल्य आधार मूल्य के लिए लिया जाता है। और यह कीमत 0 (ओह, अगर ...) से लेकर हजारों तक हो सकती है। फ़िल्टरिंग में चुनने के लिए कई मूल्य श्रेणियां हैं। तदनुसार, उन होटलों की तलाश करना आवश्यक है जिनकी कीमत एक निश्चित अवधि के भीतर आती है।
  3. क्षेत्रीय संबद्धता। स्थिति पैराग्राफ 1 के समान है, सिवाय इसके कि मानदंड "देश" के लिए संभावित विकल्पों की संख्या दो सौ अनुमानित है, और "शहर" के लिए - पहले से ही हजारों में। कार्य इस तथ्य से सुगम है कि प्रत्येक होटल का देश और शहर के मापदंडों के लिए एक अद्वितीय महत्व है।
  4. और अंत में, सबसे दिलचस्प: होटल द्वारा प्रदान की गई सेवाओं की एक सूची। इस समस्या को हल करने के लिए शुरू, सेवाओं की सूची 700 से अधिक आइटम थी। मैनुअल "सभी अनावश्यक" और समूहों को बाहर निकालने की मदद से, सेवाओं की संख्या 300 तक कम हो गई, जो कि छोटी भी नहीं है। यह आगे क्या करने की धमकी देता है।


अब, वास्तव में, कार्य: संभव पैरामीटर मूल्यों के किसी भी संयोजन के एक मनमाने ढंग से सेट को फ़िल्टर करने के लिए जो होटल का वर्णन करता है और फ़िल्टर की सूची प्रदर्शित करते समय, प्रत्येक फ़िल्टर के विपरीत होटल की संख्या प्रदर्शित करता है। फ़िल्टर के प्रत्येक संयोजन में एक स्पष्ट URL होना चाहिए और होटलों के पुनरुत्पादित चयन को प्रतिबिंबित करना चाहिए।

हजारों की संख्या में वस्तुओं की संख्या के साथ मानदंड द्वारा होटल खोजना और सापेक्ष स्थैतिक जानकारी की स्थिति कम या ज्यादा दर्द रहित रूप से कार्यान्वित की जाती है जो कि प्रत्येक अनुरोध और बिल्डिंग इंडेक्स के विश्लेषण या अनुकूलन के लिए दो दर्जन तालिकाओं को सामान्यीकृत डेटाबेस के मामले में, या एक विस्तृत तालिका द्वारा पथ चुना जाता है। विकृतीकरण के माध्यम से समस्या को हल करना।

लेकिन यहां 1000 के करीब आने वाले इन मानों की संख्या के साथ खोज मापदंडों के संभावित मूल्यों में से प्रत्येक के लिए नमूने में गिरने वाले होटलों की संख्या की गिनती के रूप में एक छोटा "प्रेटीनेस" शुरू में एक छोटे से स्तूप का कारण बना।

थोड़े से कॉम्बिनेटरिक्स


सुदूर अतीत में मूल्य एग्रीगेटर के लिए एक समान कार्य सिर पर हल किया गया था और बहुत सारे प्रतिबंधों के साथ: डेटाबेस में प्रत्येक संयोजन के लिए फिल्टर और माल की मात्रा की पूर्व-गणना संयोजनों के साथ एक विशाल तालिका संग्रहीत की गई थी। तालिका को हर रात पूरी तरह से पुनर्गठित किया गया और लंबे समय तक इस ऑपरेशन को अंजाम दिया।

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

इस उद्देश्य के लिए, एक्सेल में एक अद्भुत फ़ंक्शन "NUMBER COMB" है, जो दिए गए तत्वों की एक चयनित संख्या के लिए कई तत्वों के संयोजन की संख्या देता है। स्पष्टता के लिए, हम 10 तत्वों को लेते हैं और चयनित 1, 2, 3 और इसी तरह के तत्वों के लिए संभावित संयोजनों की संख्या पर विचार करते हैं। हमें टेबल मिलती है:

110
245
3120
4210
5252
6210
7120
845
910
101


कुल में: 1023 विकल्प। इस प्रकार, 10 संभावित फिल्टर के लिए, हमें 1023 फ़िल्टर संयोजनों के साथ एक तालिका बनानी चाहिए, जिसमें से प्रत्येक के लिए हमें उन होटलों की संख्या की गणना करनी चाहिए जो प्रत्येक फ़िल्टर संयोजनों के अंतर्गत आते हैं। सबकुछ ठीक होगा, लेकिन फ़िल्टर की संख्या में वृद्धि के साथ, विकल्पों की संख्या एक आंकड़े तक बढ़ जाती है जिसने मुझे व्यक्तिगत रूप से झटका दिया।

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

MongoDB का उपयोग करना


जब 1+ बिलियन होटल की कीमतों को स्टोर करने के लिए एक पर्यटक पोर्टल के लिए एक डेटाबेस का चयन किया गया था, तो MongoDB का सबसे आगे परीक्षण किया गया था, क्योंकि उस समय, मैंने पूर्वोक्त आधार पर पाठ्यक्रम पूरा कर लिया था और सब कुछ इंद्रधनुष के रंगों में लग रहा था: शार्पनिंग, प्रतिकृति, एक दस्तावेज-उन्मुख डेटाबेस, उच्च प्रदर्शन ... लेकिन सब कुछ तुरंत हकीकत में दुर्घटनाग्रस्त हो गया: संग्रह स्तर पर ताले के लिए एक टिकट लंबे समय तक 10gen ( अधिक) पर लटका रहा। टिकट और एक अन्य टिकट ) और बड़ी संख्या में समग्र सूचकांकों के साथ दस्तावेजों की बेहद धीमी प्रतिस्पर्धात्मक प्रविष्टि ने उनका गंदा काम किया: कई प्रयोगों के बाद, डेटाबेस को ज़ोर से मैटयुकी के साथ स्क्रैप पर भेजा गया। यह हमेशा के लिए प्रतीत होगा। लेकिन जैसा कि अक्सर जीवन में होता है: प्रत्येक कार्य के लिए - अपना स्वयं का उपकरण। और मानगोवेद ने पंखों में इंतजार किया।

क्यों MongoDB?


हाथ में कार्य के लिए, यह अपने स्कीमा-कम और दस्तावेज़-उन्मुख के साथ मोंगा था जो बेहतर नहीं हो सकता: हम प्रत्येक होटल को एक दस्तावेज के रूप में विशेषताओं के एक मनमाने सेट के साथ प्रतिनिधित्व करते हैं और (महत्वपूर्ण!) प्रत्येक विशेषताओं के लिए मूल्यों के सरणियों को संग्रहीत करने की क्षमता के साथ। इसका मतलब है कि हम सेवाओं और अन्य मापदंडों की सूची संग्रहीत कर सकते हैं जो एक ही समय में कई मान ले सकते हैं, दस्तावेज़ के अंदर सरणियों में, उन्हें अनुक्रमित करते हैं और दस्तावेजों के संग्रह के माध्यम से मनमानी खोज करते हैं। बेशक, MongoDB के अलावा, अन्य NoSQL डेटाबेस के विकल्पों पर विचार किया गया था, लेकिन यह मोंगा था जिसने अपनी सादगी और दस्तावेजों के भीतर संग्रह पर अनुक्रमित खोजों को संग्रहीत करने और प्रदर्शन करने की क्षमता के साथ विजय प्राप्त की।

मैं होटल का वर्णन करने वाले दस्तावेज़ की फसली (हैलो, एनडीए) संरचना लाता हूँ:
"_id" : ObjectId(), "hotel_id" : int, "country_id" : int, "city_id" : int, "category_id" : int, "services" : [int, int, int...] 


मुकुट के अनुसार, इस संग्रह को मुख्य डेटाबेस से मोंगोव्स्की अपटेरर का उपयोग करके जानकारी के आधार पर अपडेट किया गया है।

और इस संग्रह से फिल्टर के एक मनमाने सेट के साथ होटलों की सूची प्राप्त करने में कोई समस्या नहीं है। उदाहरण के लिए:
  1. {country_id: 1, सेवाएं: {$ all: [10, 20]}} - देश के सभी होटल 1 जिसमें एक ही समय में सेवा 10 और 20 है।
  2. {category_id: 5, सेवाएं: {$ in: [20, 30]}} - सभी श्रेणी के 5 होटल जिनमें 10 या 20 सेवा है।

बिल्कुल उसी तरह के फिल्टर न केवल सेवाओं के लिए बनते हैं, बल्कि होटल का वर्णन करने वाले अन्य सभी मापदंडों के लिए भी हैं। इस प्रकार, हम मुख्य डेटाबेस में दस-कहानी एसक्यूएल प्रश्नों को लिखने की आवश्यकता से बचते हैं। इसी समय, उत्पादकता बहुत उच्च स्तर पर बनी हुई है, क्योंकि हजारों या दसियों दस्तावेजों के अपेक्षाकृत स्थिर संग्रह के साथ, उचित समग्र अनुक्रमित और पर्याप्त रैम के साथ, MongoDB एक महान काम करता है।

बहुत बढ़िया! MapReduce का इससे क्या लेना-देना है?


इसलिए, फ़िल्टर के साथ GET अनुरोध के मापदंडों को पार्स करने के बाद, हम होटल की एक सूची प्राप्त करने के लिए MongoDb में अनुरोध कर सकते हैं। यहां फ़िल्टर की एक सूची बनाने और प्रत्येक फ़िल्टर के तहत आने वाले होटलों की संख्या प्राप्त करने की बारी है। उपकरण लेख के शीर्षक से स्पष्ट है: MongoDB और MapReduce

मैं लंबे समय तक MapReduce के सिद्धांत को चित्रित नहीं करूंगा। मुझे सिर्फ यह याद रखना चाहिए कि डेटा प्रोसेसिंग के इस दृष्टिकोण में दो चरण होते हैं: मैपिंग और कनवल्शन। इसके अलावा, प्रत्येक चरण कई कोर / प्रोसेसर / सर्वर / क्लस्टर पर समानांतर में हो सकता है और एकल डेटा सरणी पर काम कर सकता है। चूंकि डेटा मैपिंग ऑपरेशन द्वारा, साझा-मेमोरी (हमारे मामले में मोंगा के साथ) के माध्यम से तैयार किया जाता है, यह डेटा ढह जाता है, जहां यह अंतिम प्रसंस्करण और वांछित सरणी में परिवर्तन से गुजरता है।
इस सिद्धांत को समझना, व्यवहार में सब कुछ आश्चर्यजनक रूप से सरल हो जाता है। मैं मानचित्र का स्रोत कोड देता हूं और विधियों को कम करता हूं:

 var map = function() { emit({"category": this.category_id}, 1); if (this.services) this.services.forEach(function(value) { emit({"service": value}, 1); }); if (this.types) this.types.forEach(function(value) { emit({"type": value}, 1); }); // …................................. // And a large number of other filters }; var reduce = function(key, values) { return Array.sum(values); }; 


यह कैसे काम करता है?


बहुत आसान है!

MongoDb डेटाबेस में संग्रहीत प्रत्येक होटल मैपिंग फ़ंक्शन में शामिल हो जाता है, और प्रत्येक सेवा / प्रकार के भोजन / होटल के स्थान (और सूची में इत्यादि) के लिए, emit () फ़ंक्शन को कहा जाता है, जो प्रत्येक "के लिए नंबर 1" के साथ स्मृति में सहयोगी सरणी में जोड़ा जाता है। सेवाएं।
सीमा तक दीक्षांत समारोह सरल है: मानचित्रण चरण में प्राप्त साहचर्य सरणी के प्रत्येक तत्व के लिए मात्रा के अंकों को योग करें।

वह सब है!

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

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

क्या इसका अनुकूलन संभव है?

हाँ आप कर सकते हैं। तथ्य यह है कि जब बड़ी संख्या में होटल (कहते हैं, 100 हज़ार) प्रसंस्करण और बशर्ते कि प्रत्येक होटल में कुल 100 पैरामीटर मान हों, तो 10 मिलियन कॉल () का उत्सर्जन होगा, जो बिना देखे भी प्रदर्शन को प्रभावित कर सकता है समानांतरकरण के लिए। और समाधान पाया गया था:

 var map = function() { var obj = { "categories": {}, "services": {} // Other params }; if (this.category_id > 0) obj.categories[this.category_id] = 1; var attrs = ["services", "types"]; for (var i = 0; i < 2; i++) { var attrKey = attrs[i]; var attrsArray = this[attrKey]; for (var key in attrsArray) { obj[attrKey][attrsArray[key]] = 1; } } emit("attrs", obj); }; var reduce = function(key, values) { var obj = { "categories": {}, "services": {} // Other params }; var attrs = ["categories", "services"]; for (var j = 0; j<2; j++) { attrObjArray = []; for (var i = 0; i < values.length; i++) { attrValuesArray = values[i][attrs[j]]; for (var attrKey in attrValuesArray) { var val = parseInt(attrValuesArray[attrKey]); if (!attrObjArray[attrKey]) { attrObjArray[attrKey] = val; } else { attrObjArray[attrKey] += val; } } } finalAttrObj = {}; for (i = 0; i < attrObjArray.length; i++) { var val = attrObjArray[i]; if (val) { finalAttrObj[i] = val; } } obj[attrs[j]] = finalAttrObj; } return obj; }; 


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

आगे क्या है?


बेशक, यह लेख केवल होटलों के एक नमूने को प्राप्त करने और एक फ़िल्टरिंग प्रणाली के निर्माण के मूल सिद्धांतों को रेखांकित करता है, जिसे शुरू में इस धारणा के माध्यम से बहुत सरल किया गया था कि होटल की कीमत MongoDB में भी संग्रहीत है। वास्तव में, सब कुछ कुछ अधिक जटिल है और वास्तविक जादू तब शुरू होता है जब उपयोगकर्ता मूल्य द्वारा एक फिल्टर का चयन करता है और सभी होटलों को ढूंढना आवश्यक हो जाता है जो किसी दिए गए अंतराल से एक निश्चित संख्या में लोगों / रातों / तिथियों के लिए सर्विस फिल्टर के तहत आते हैं। विशेष रूप से यह देखते हुए कि होटल की कीमतें एक REST सेवा के अनुरोध का उपयोग करके ली जाती हैं । मल्टी-मिलियन डेटाबेस के साथ काम करने का यह जादू और ठंडे कैश पर 100ms की अधिकतम प्रतिक्रिया समय और सबसे कठिन प्रश्नों को कैसे प्राप्त किया जाए, मैं भी धीरे-धीरे निम्नलिखित लेखों में खुलासा करने की योजना बना रहा हूं।

कुल मिलाकर


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

Source: https://habr.com/ru/post/In186572/


All Articles