(क्यों) हमें कैश कॉल करने या RDD पर बने रहने की आवश्यकता है


171

जब एक लचीला वितरित डेटासेट (RDD) एक टेक्स्ट फ़ाइल या संग्रह (या किसी अन्य RDD) से बनाया जाता है, तो क्या हमें RDD डेटा को मेमोरी में स्टोर करने के लिए "कैश" या "लगातार" स्पष्ट रूप से कॉल करने की आवश्यकता है? या आरडीडी डेटा को डिफॉल्ट रूप से मेमोरी में वितरित तरीके से संग्रहीत किया जाता है?

val textFile = sc.textFile("/user/emp.txt")

मेरी समझ के अनुसार, उपरोक्त कदम के बाद, TextFile एक RDD है और नोड के सभी / कुछ मेमोरी में उपलब्ध है।

यदि हां, तो हमें TextFile RDD पर "कैश" या "जारी" रखने की आवश्यकता क्यों है?

जवाबों:


300

अधिकांश RDD ऑपरेशन आलसी हैं। संचालन की एक श्रृंखला के वर्णन के रूप में एक RDD के बारे में सोचो। एक RDD डेटा नहीं है। तो यह लाइन:

val textFile = sc.textFile("/user/emp.txt")

यह कुछ नहीं करता है। यह एक RDD बनाता है जो कहता है कि "हमें इस फ़ाइल को लोड करने की आवश्यकता होगी"। इस बिंदु पर फ़ाइल लोड नहीं है।

डेटा की सामग्री के अवलोकन की आवश्यकता वाले RDD संचालन को आलसी नहीं किया जा सकता है। (इन्हें क्रियाएं कहा जाता है ।) एक उदाहरण है RDD.count- आपको फ़ाइल में लाइनों की संख्या बताने के लिए, फ़ाइल को पढ़ने की आवश्यकता है। इसलिए यदि आप लिखते हैं textFile.count, तो इस बिंदु पर फ़ाइल को पढ़ा जाएगा, लाइनों को गिना जाएगा, और गिनती वापस आ जाएगी।

यदि आप textFile.countफिर से कॉल करते हैं तो क्या होगा ? एक ही बात: फ़ाइल को फिर से पढ़ा और गिना जाएगा। कुछ भी संग्रहीत नहीं है। एक RDD डेटा नहीं है।

तो क्या करता RDD.cacheहै? यदि आप textFile.cacheउपरोक्त कोड जोड़ते हैं :

val textFile = sc.textFile("/user/emp.txt")
textFile.cache

यह कुछ नहीं करता है। RDD.cacheएक आलसी ऑपरेशन भी है। फ़ाइल अभी भी नहीं पढ़ी गई है। लेकिन अब आरडीडी कहता है "इस फाइल को पढ़ें और फिर सामग्री को कैश करें"। यदि आप textFile.countपहली बार चलाते हैं , तो फ़ाइल लोड, कैश्ड और गिनी जाएगी। यदि आप textFile.countदूसरी बार कॉल करते हैं, तो ऑपरेशन कैश का उपयोग करेगा। यह सिर्फ कैश से डेटा लेगा और लाइनों की गणना करेगा।

उपलब्ध स्मृति पर कैश व्यवहार निर्भर करता है। यदि फ़ाइल स्मृति में फिट नहीं होती है, उदाहरण के लिए, तो textFile.countसामान्य व्यवहार में वापस आ जाएगी और फ़ाइल को फिर से पढ़ना होगा।


4
हाय डैनियल, - जब आप कैश कहते हैं, तो क्या इसका मतलब यह है कि RDD स्रोत से पुनः लोड नहीं किया गया है (उदाहरण के लिए पाठ फ़ाइल) - आप यह कैसे सुनिश्चित कर सकते हैं कि पाठ फ़ाइल से डेटा हाल ही में कैश किया गया है? (स्पार्क यह पता लगाता है या क्या यह एक मैनुअल ऑपरेशन है जो अनपेर्सिस्ट को दिया जाता है) (समय-समय पर स्रोत डेटा को वंशावली में बाद में पुन: प्राप्त करने के लिए सुनिश्चित करने के लिए?)
andrew.butkus

यह भी - यदि आपको समय-समय पर अप्रकाशक होना चाहिए, - यदि आपके पास एक आरडीडी है, जो एक और आरडीडी पर निर्भर है, जो कैश किया गया है, तो क्या आपको आरबीडी के पुन: विवादास्पद परिणामों को देखने के लिए दोनों को अप्रकाशित करना होगा?
andrew.butkus

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

10
हाँ। RDD अपरिवर्तनीय हैं, इसलिए प्रत्येक RDD मानती है कि उसकी निर्भरताएँ अपरिवर्तनीय हैं। स्पार्क स्ट्रीमिंग आपको ऐसे पेड़ लगाने की अनुमति देता है जो परिवर्तनों की एक धारा पर काम करते हैं। लेकिन एक और भी सरल समाधान एक फ़ंक्शन में पेड़ का निर्माण करना है जो एक फ़ाइल नाम को अपने पैरामीटर के रूप में लेता है। फिर बस नई फ़ाइल और पूफ के लिए फ़ंक्शन को कॉल करें, आपको नया संगणना ट्री मिला है।
डैनियल डारबोस

1
@ हूमयून: स्पार्क यूआई के स्टोरेज टैब पर आप देख सकते हैं कि प्रत्येक आरडीडी कितना कैश है। डेटा इतना बड़ा हो सकता है कि इसका केवल 40% आपके पास कैशिंग के लिए कुल मेमोरी में फिट बैठता है। इस मामले में एक विकल्प perisistएक भंडारण विकल्प का उपयोग करना और चुनना है जो कैश डेटा को डिस्क पर फैलाने की अनुमति देता है।
डैनियल डैराबोस

197

मुझे लगता है कि सवाल बेहतर होगा:

हमें कब कॉल करने या RDD पर बने रहने की आवश्यकता है?

स्पार्क प्रक्रियाएं आलसी हैं, अर्थात जब तक इसकी आवश्यकता नहीं होगी, तब तक कुछ भी नहीं होगा। प्रश्न का त्वरित उत्तर देने के लिए, val textFile = sc.textFile("/user/emp.txt")जारी किए जाने के बाद , डेटा के लिए कुछ भी नहीं होता है, केवल एक HadoopRDDनिर्माण होता है, फ़ाइल को स्रोत के रूप में उपयोग करते हुए।

मान लें कि हम उस डेटा को थोड़ा बदल देते हैं:

val wordsRDD = textFile.flatMap(line => line.split("\\W"))

फिर, डेटा के लिए कुछ भी नहीं होता है। अब एक नया आरडीडी wordsRDDहै जिसमें testFileजरूरत पड़ने पर एक संदर्भ और लागू करने के लिए एक फ़ंक्शन शामिल है।

केवल जब कोई कार्रवाई RDD पर कॉल की जाती है, जैसे wordsRDD.count, RDD श्रृंखला, जिसे वंश कहा जाता है, निष्पादित किया जाएगा। यही है, डेटा, विभाजन में टूट गया, स्पार्क क्लस्टर के निष्पादकों द्वारा लोड किया flatMapजाएगा , फ़ंक्शन लागू किया जाएगा और परिणाम की गणना की जाएगी।

एक रेखीय वंश पर, इस उदाहरण में एक की तरह, cache()जरूरत नहीं है। डेटा निष्पादकों को लोड किया जाएगा, सभी परिवर्तनों को लागू किया जाएगा और अंत में countगणना की जाएगी, सभी मेमोरी में - यदि डेटा मेमोरी में फिट बैठता है।

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

val positiveWordsCount = wordsRDD.filter(word => isPositive(word)).count()
val negativeWordsCount = wordsRDD.filter(word => isNegative(word)).count()

यहां, प्रत्येक शाखा डेटा का पुनः लोड जारी करती है। एक स्पष्ट cacheविवरण जोड़ना यह सुनिश्चित करेगा कि पहले किया गया प्रसंस्करण संरक्षित है और पुन: उपयोग किया जाता है। नौकरी इस तरह दिखाई देगी:

val textFile = sc.textFile("/user/emp.txt")
val wordsRDD = textFile.flatMap(line => line.split("\\W"))
wordsRDD.cache()
val positiveWordsCount = wordsRDD.filter(word => isPositive(word)).count()
val negativeWordsCount = wordsRDD.filter(word => isNegative(word)).count()

उस कारण से, cache'वंश को तोड़ने के लिए' कहा जाता है क्योंकि यह एक चौकी बनाता है जिसे आगे की प्रक्रिया के लिए पुन: उपयोग किया जा सकता है।

अंगूठे का नियम: cacheजब आपके RDD की वंशावली निकलती है या जब RDD का उपयोग लूप की तरह कई बार किया जाता है।


1
बहुत बढ़िया। धन्यवाद। एक और संबंधित प्रश्न। जब हम कैश करते हैं या जारी रखते हैं, तो डेटा निष्पादक की मेमोरी या कार्यकर्ता नोड की मेमोरी में संग्रहीत किया जाएगा। यदि यह निष्पादक की मेमोरी है, तो स्पार्क कैसे पहचानता है कि किस निष्पादक के पास डेटा है।
रमण

1
@RamanaUppala निष्पादक मेमोरी का उपयोग किया जाता है। कैशिंग के लिए उपयोग किए जाने वाले निष्पादक मेमोरी का अंश कॉन्फ़िगरेशन द्वारा नियंत्रित किया जाता है spark.storage.memoryFraction। किस निष्पादनकर्ता के पास कौन सा डेटा है, एक RDD अपने विभाजन का ध्यान रखेगा जो निष्पादकों पर वितरित किए जाते हैं।
मास्सग

5
@maasg मुझे सही अगर मैं गलत लेकिन न तो कर रहा हूँ cacheऔर न ही persist कर सकते हैं वंश को तोड़ने
शून्य 323

यदि उपरोक्त उदाहरण में .cache () स्टेटमेंट नहीं है, तो शब्दRDD कहाँ संग्रहीत किया जाएगा?
sun_dare

क्या होगा यदि दो गणनाओं से पहले, हम दो शाखाओं को एक-एक आरडीडी पर वापस जोड़ते हैं और गिनते हैं? क्या इस मामले में, कैश फायदेमंद है?
शियावी झांग

30

क्या हमें RDD डेटा को मेमोरी में स्टोर करने के लिए "कैश" या "जारी" रखने की आवश्यकता है?

हां, जरूरत है तो ही।

डिफ़ॉल्ट रूप से मेमोरी में वितरित तरीके से संग्रहीत RDD डेटा?

नहीं!

और ये कारण हैं:

  • स्पार्क दो प्रकार के साझा चर का समर्थन करता है: प्रसारण चर, जिसका उपयोग सभी नोड्स और संचयकों पर स्मृति में एक मूल्य को कैश करने के लिए किया जा सकता है, जो चर हैं जो केवल "जोड़े" हैं, जैसे काउंटर और रकम।

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

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

  • डिफ़ॉल्ट रूप से, प्रत्येक रूपांतरित RDD हर बार जब आप उस पर कोई क्रिया चलाते हैं, तो उसे फिर से जोड़ा जा सकता है। हालाँकि, आप ज़िद (या कैश) विधि का उपयोग करके मेमोरी में RDD भी जारी रख सकते हैं, उस स्थिति में जब स्पार्क अगली बार जब आप क्वेरी करते हैं, तो तत्व बहुत तेज़ी से एक्सेस करने के लिए क्लस्टर पर चारों ओर रखेंगे। डिस्क पर RDD को बनाए रखने के लिए समर्थन भी है, या कई नोड्स में दोहराया गया है।

अधिक जानकारी के लिए कृपया स्पार्क प्रोग्रामिंग गाइड देखें


1
मेरे सवाल का जवाब नहीं दिया।
रमण

इसका उत्तर क्या नहीं है?
इलियास

1
जब RDD का डेटा मेमोरी डिफॉल्ट में संग्रहीत होता है, तो हमें Cache या Persist को कॉल करने की आवश्यकता क्यों है?
रमण

RDD डिफ़ॉल्ट रूप से मेमोरी में संग्रहीत नहीं होते हैं, इसलिए RDD को जारी रखने से स्पार्क क्लस्टर पर तेजी से परिवर्तन कर सकता है
eliasah

2
यह एक अच्छा जवाब है, मुझे नहीं पता कि इसे क्यों हटाया गया। यह उच्च-स्तरीय उत्तर है, जिसमें बताया गया है कि उच्च-स्तरीय अवधारणाओं से RDD कैसे काम करते हैं। मैंने एक और उत्तर जोड़ा है जो नीचे से ऊपर जाता है: "यह पंक्ति क्या करती है" से शुरू होती है। हो सकता है कि स्पार्क से शुरू करने वाले किसी व्यक्ति के लिए अनुसरण करना आसान हो।
डैनियल डैराबोस

11

नीचे तीन स्थितियों में आपको अपने RDDs को कैश करना चाहिए:

कई बार RDD का उपयोग करना

एक ही RDD पर कई कार्य करना

(या बहुत महंगी) परिवर्तनों की लंबी श्रृंखला के लिए


7

जोड़ने का एक और कारण (या अस्थायी रूप से जोड़ने) cacheविधि कॉल।

डीबग स्मृति समस्याओं के लिए

cacheविधि के साथ , स्पार्क आरबीडी के आकार के बारे में डिबगिंग informations देगा। इसलिए स्पार्क एकीकृत यूआई में, आपको आरडीडी मेमोरी खपत की जानकारी मिलेगी। और यह स्मृति समस्याओं के निदान में बहुत मददगार साबित हुआ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.