Dataflow के दर्शन PTransform
अमूर्त और composability, जैसे कि, किसी भी आत्म निहित डाटा प्रोसेसिंग काम के लिए एक PTransform
के रूप में समझाया जाना चाहिए की मुख्य इकाई है। इसमें किसी तृतीय-पक्ष स्टोरेज सिस्टम से कनेक्ट करने का कार्य शामिल है: कहीं से डेटा डालना या इसे कहीं भी निर्यात करना।
उदाहरण के लिए, Google क्लाउड डेटास्टोर लें। कोड स्निपेट में:
PCollection<Entity> entities =
p.apply(DatastoreIO.readFrom(dataset, query));
...
p.apply(some processing)
.apply(DatastoreIO.writeTo(dataset));
DatastoreIO.readFrom(dataset, query)
की वापसी प्रकार PTransform<PBegin, PCollection<Entity>>
का एक उपवर्ग है, और DatastoreIO.writeTo(dataset)
के प्रकार PTransform<PCollection<Entity>, PDone>
का एक उपवर्ग है।
यह सच है कि इन कार्यों हुड के नीचे हैं Source
और Sink
वर्गों का उपयोग लागू किया है, लेकिन जो सिर्फ पढ़ने के लिए या डेटास्टोर के लिए कुछ लिखने के लिए चाहता है एक उपयोगकर्ता के लिए, कि एक कार्यान्वयन विस्तार है कि आमतौर पर कोई फर्क नहीं करना चाहिए (हालांकि, Source
या Sink
कक्षा को उजागर करने के बारे में इस उत्तर के अंत में नोट देखें)। कोई भी कनेक्टर, या उस मामले के लिए, कोई अन्य डेटा प्रोसेसिंग कार्य PTransform
है।
ध्यान दें: वर्तमान कनेक्टर्स है कि कहीं से पढ़ा PTransform<PBegin, PCollection<T>>
हो जाते हैं, और कनेक्टर्स है कि कहीं पर लिख PTransform<PCollection<T>, PDone>
हो जाते हैं, लेकिन हम यह आसान और अधिक लचीला मायनों में कनेक्टर्स (उदाहरण के लिए उपयोग करने के लिए बनाने के लिए विकल्पों पर विचार कर रहे हैं, पढ़ने फ़ाइल नामों के PCollection
से)।
हालांकि, यह विवरण किसी ऐसे व्यक्ति से मायने रखता है जो एक नया कनेक्टर लागू करना चाहता है। विशेष रूप से, आप पूछ सकते हैं:
प्रश्न: मुझे Source
और Sink
कक्षाओं की आवश्यकता क्यों है, अगर मैं अपने कनेक्टर को PTRansform के रूप में लागू कर सकता हूं?
एक: तुम बस में निर्मित रूपांतरण का उपयोग करके अपने कनेक्टर को लागू कर सकते हैं (जैसे ParDo
, GroupByKey
आदि), यह एक कनेक्टर विकसित करने के लिए एक बिल्कुल वैध तरीका है। हालांकि, Source
और Sink
कक्षाएं कुछ निम्न-स्तरीय क्षमताओं को प्रदान करती हैं, यदि आपको उनकी आवश्यकता हो, तो खुद को विकसित करने के लिए बोझिल या असंभव होगा। है, जबकि इन हुक वर्तमान में मनमाने ढंग से DoFn
रों के लिए उजागर नहीं कर रहे हैं -
उदाहरण के लिए, BoundedSource
और UnboundedSource
हुक को नियंत्रित कैसे बनता है क्या होता है (BoundedSource.splitIntoBundles
, BoundedReader.splitAtFraction
शुरूआती और गतिशील काम पुनर्संतुलन) के लिए प्रदान करते हैं।
आप तकनीकी रूप से एक DoFn<FilePath, SomeRecord>
कि इनपुट के रूप में फ़ाइल नाम लेता है, फ़ाइल पढ़ता है और SomeRecord
उत्सर्जन करता है, लिख कर एक फ़ाइल स्वरूप के लिए एक पार्सर को लागू कर सकता है, लेकिन इस DoFn
गतिशील कई कार्यकर्ताओं पर फ़ाइल के पढ़ने भागों parallelize करने में सक्षम नहीं होगा यदि फ़ाइल रनटाइम पर बहुत बड़ी हो गई है। दूसरी तरफ, FileBasedSource
में यह क्षमता अंतर्निहित है, साथ ही ग्लोब फ़ाइलपटलों और इस तरह के हैंडलिंग भी है।
इसी तरह, आप एक DoFn
कि इनपुट के रूप में एक डमी तत्व लेता है, एक कनेक्शन स्थापित और ProcessingContext.output()
में सभी तत्वों धाराओं को लागू करने से एक स्ट्रीमिंग प्रणाली के लिए एक कनेक्टर को लागू करने की कोशिश कर सकते हैं, लेकिन DoFn
s वर्तमान की असीम मात्रा में लेखन का समर्थन नहीं करते एक बंडल से आउटपुट, और न ही वे मजबूत स्थिरता गारंटी के लिए आवश्यक चेकपॉइंटिंग और deduplication मशीनरी का स्पष्ट रूप से समर्थन करते हैं डेटाफ्लो स्ट्रीमिंग पाइपलाइनों को देता है। दूसरी ओर, UnboundedSource
, यह सब का समर्थन करता है। सिर्फ एक समग्र बदलना आप अपने आप को लिख सकता है कि अगर आप (Dataflow धावक या बैकएंड में यानी यह कोई हार्ड-कोडेड है समर्थन) करना चाहता था है यह, लेकिन:
Sink
(अधिक सटीक, Write.to()
PTransform
) भी दिलचस्प है इसे सामान्य वितरित गलती सहनशीलता के मुद्दों पर विचार करने के साथ विकसित किया गया था जो समानांतर में स्टोरेज सिस्टम में डेटा लिखते समय उत्पन्न होता है, और यह उन हुक प्रदान करता है जो आपको उन मुद्दों को ध्यान में रखने के लिए मजबूर करते हैं: उदाहरण के लिए, क्योंकि डेटा के बंडल समानांतर में लिखे जाते हैं, और कुछ बंडलों को गलती सहनशीलता के लिए पुनः प्रयास या डुप्लीकेट किया जा सकता है, सफलतापूर्वक पूर्ण बंडलों (WriteOperation.finalize
) के परिणामों को "प्रतिबद्ध" करने के लिए एक हुक है।
संक्षेप में:Source
या Sink
API का उपयोग करके एक कनेक्टर आपकी मदद करता है एक तरीका है कि एक वितरित प्रसंस्करण की स्थापना में अच्छी तरह से काम करेगा में अपने कोड संरचना विकसित करने के लिए, और स्रोत API आपको ढांचे के उन्नत क्षमताओं के लिए पहुँच दे। लेकिन अगर आपका कनेक्टर एक बहुत ही सरल है जिसे न तो चाहिए, तो आप अपने कनेक्टर को अन्य अंतर्निर्मित ट्रांसफॉर्म से इकट्ठा करने के लिए स्वतंत्र हैं।
प्रश्न: मान लीजिए कि मैं Source
और Sink
का उपयोग करने का निर्णय लेता हूं। फिर मैं अपने कनेक्टर को पुस्तकालय के रूप में कैसे पैकेज करूं: क्या मुझे केवल Source
या Sink
कक्षा प्रदान करनी चाहिए, या क्या मुझे इसे PTransform
में लपेटना चाहिए?
एक: आपका कनेक्टर अंत में, एक PTransform
के रूप में पैक किया जाना चाहिए ताकि उपयोगकर्ता कर सकते हैं बस p.apply()
यह उनकी पाइप लाइन में। हालांकि, हुड के तहत आपका परिवर्तन Source
और Sink
कक्षाओं का उपयोग कर सकता है।
एक आम पैटर्न के रूप में अच्छी तरह से Source
और Sink
कक्षाओं का पर्दाफाश करने, सुविज्ञ बिल्डर पैटर्न का इस्तेमाल कर रही है, और दे उपयोगकर्ता उन्हें एक Read.from()
या Write.to()
खुद को बदलने में लपेट है, लेकिन इस एक सख्त आवश्यकता नहीं है।
महान सवाल! हम अब एक पूर्ण जवाब लिख रहे हैं। –