प्रतिनिधि इंटरव्यू विषय

कोडिंग इंटरव्यू: एक Bloom Filter लागू करें

कोडिंगकठिन
Offer.cc संपादकीय टीमप्रकाशित अपडेट किया गया

प्रश्न

add(value) और mightContain(value) के साथ एक Bloom filter लागू करें। अपेक्षित कार्डिनैलिटी n और लक्षित फ़ॉल्स-पॉज़िटिव दर p से बिट-ऐरे की लंबाई m और हैश काउंट k चुनने का तरीका समझाएं, और डिलीशन, रिसाइज़िंग, कन्करेंसी और टेस्ट्स पर चर्चा करें।

प्रॉम्प्ट और संदर्भ

add(value) और mightContain(value) के साथ एक Bloom filter लागू करें। यह एक महंगे लुकअप से पहले का प्रीफ़िल्टर है: false का अर्थ है कि वैल्यू निश्चित रूप से अनुपस्थित है, जबकि true का अर्थ है कि आधिकारिक (authoritative) स्टोर की अभी भी जांच की जानी चाहिए। n, p, m, k, डिलीशन, रिसाइज़िंग, कन्करेंसी और टेस्ट्स को कवर करें।

इंटरव्यूअर क्या जांच रहा है

सदस्यता के सही सिमेंटिक्स (Correct membership semantics)

एक मानक Bloom filter फ़ॉल्स पॉज़िटिव्स की अनुमति देता है लेकिन फ़ॉल्स नेगेटिव्स की नहीं। mightContain नाम कॉलर्स को true को सदस्यता के प्रमाण के रूप में मानने से रोकना चाहिए।

समझाने योग्य साइज़िंग (Explainable sizing)

बिट-ऐरे की लंबाई m और हैश काउंट k मेमोरी, स्पीड और त्रुटि दर को नियंत्रित करते हैं। पैरामीटर चुनने से पहले अपेक्षित कार्डिनैलिटी और स्वीकार्य p के बारे में पूछें।

पूर्ण सीमाएँ (Complete boundaries)

एक मजबूत उत्तर बताता है कि मानक संरचना किसी एक वैल्यू को सुरक्षित रूप से डिलीट नहीं कर सकती है, संतृप्ति (saturation) फ़ॉल्स-पॉज़िटिव दर को बढ़ाती है, और विकास के लिए पुनर्निर्माण (rebuild) या स्केलेबल लेयर्ड डिज़ाइन की आवश्यकता होती है।

पहले स्पष्ट करने योग्य प्रश्न

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

30 सेकंड का उत्तर

“मैं एक m-बिट ऐरे और k पर्याप्त रूप से स्वतंत्र पोज़िशन्स का उपयोग करूँगा। add उन k बिट्स को सेट करता है; क्वेरी के दौरान एक शून्य बिट अनुपस्थिति को साबित करता है, जबकि सभी वन्स (ones) का अर्थ संभावित उपस्थिति है। अपेक्षित n और लक्षित p के लिए, m=-n ln(p)/(ln2)^2 और k=(m/n)ln2 का उपयोग करें। एक मानक फ़िल्टर सुरक्षित रूप से डिलीट नहीं कर सकता, इसलिए डिलीशन के लिए काउंटिंग बकेट्स की आवश्यकता होती है; क्षमता परिवर्तन के लिए रीबिल्ड या लेयर्स की आवश्यकता होती है। मैं कोई फ़ॉल्स नेगेटिव न होने, सैंपल्ड फ़ॉल्स-पॉज़िटिव दर, संतृप्ति और कन्करेंसी गारंटियों का परीक्षण करूँगा।”

चरण-दर-चरण गहन उत्तर

इनवेरिएंट और API को स्पष्ट करें

सभी बिट्स शून्य से शुरू होते हैं। स्थिर हैश फ़ंक्शंस प्रत्येक वैल्यू के लिए k इंडेक्स उत्पन्न करते हैं; इंसर्शन केवल बिट्स को शून्य से एक में बदलता है। यदि कोई क्वेरी किसी भी आवश्यक इंडेक्स पर शून्य देखती है, तो वह वैल्यू पोज़िशन्स के इस सटीक सेट को इन्सर्ट नहीं कर सकती थी।

m और k की गणना करें

अपेक्षित n आइटम्स और लक्षित फ़ॉल्स-पॉज़िटिव दर p के लिए, m = -n * ln(p) / (ln(2)^2) और k = (m/n) * ln(2) का उपयोग करें। n=1,000,000 और p=1% के साथ, m लगभग 9.6M बिट्स (लगभग 1.14 MiB) है, और k लगभग 7 है।

हैश और बिट ऑपरेशंस चुनें

डबल हैशिंग k पूर्ण हैश कार्यान्वयनों से बचते हुए, h_i(x) = h1(x) + i*h2(x) मॉड्यूलो m के रूप में पोज़िशन्स प्राप्त कर सकती है। बाइट एन्कोडिंग, एंडियननेस और सीड्स को स्थिर रखें; उन्हें बदलने से पर्सिस्टेड फ़िल्टर असंगत हो जाते हैं।

डिलीशन और रिसाइज़िंग को समझाएं

कई वैल्यूज़ एक बिट साझा कर सकती हैं, इसलिए एक डिलीशन के लिए इसे साफ़ करने से फ़ॉल्स नेगेटिव बन सकता है। इसलिए एक मानक Bloom filter में कोई सुरक्षित डिलीट ऑपरेशन नहीं होता है। Counting Bloom filters मेमोरी लागत पर प्रति-बकेट काउंटर्स जोड़ते हैं। जब अपेक्षित क्षमता बदलती है, तो एक बड़ा फ़िल्टर फिर से बनाएं या कई क्षमता-बद्ध लेयर्स का उपयोग करें।

कन्करेंसी और लाइफ़साइकिल को संभालें

कन्करेंट रीड्स आमतौर पर सीधे होते हैं। कन्करेंट राइट्स में बिट-सेटिंग ऑपरेशंस नहीं खोने चाहिए; एटॉमिक OR, शार्डेड बिट ऐरे, या राइट लॉक संभावित विकल्प हैं। क्षमता, m, k, हैश एल्गोरिदम, सीड्स और फ़ॉर्मेट वर्ज़न को एक साथ पर्सिस्ट करें।

स्यूडोकोड

~~~text add(x): for i in 0..k-1: bits[index(hash1(x), hash2(x), i)] = 1

mightContain(x): for i in 0..k-1: if bits[index(hash1(x), hash2(x), i)] == 0: return false return true ~~~

जटिलता और सत्यापन

प्रत्येक ऑपरेशन k पोज़िशन्स की जाँच या सेट करता है, इसलिए समय O(k) है और अतिरिक्त स्पेस O(m) है। परीक्षण करें कि प्रत्येक इन्सर्ट की गई वैल्यू true लौटाती है, यादृच्छिक अनुपस्थित नमूनों से फ़ॉल्स पॉज़िटिव्स का अनुमान लगाएं, क्षमता के निकट संतृप्ति का निरीक्षण करें, और रिक्त, डुप्लिकेट, सीड/वर्ज़न और कन्करेंट-राइट मामलों को कवर करें।

ऑपरेशनअनुबंध (Contract)जटिलता
add(x)बिट्स सेट करता है और सदस्यता के साक्ष्य को कभी नहीं हटाता हैO(k)
mightContain(x)false निश्चित अनुपस्थिति है; true संभावित उपस्थिति हैO(k)
Resizeपुनर्निर्माण करें या क्षमता-बद्ध लेयर जोड़ेंआइटम काउंट और m पर निर्भर करता है

मॉडल उत्तर

“Bloom filter एक संभाव्य सदस्यता प्रीफ़िल्टर है। मैं एक m-बिट ऐरे और k पोज़िशन फ़ंक्शंस बनाए रखूँगा। इंसर्शन k बिट्स सेट करता है; कोई भी शून्य मिलने पर क्वेरी false लौटाती है, जबकि सभी वन्स मिलने पर true लौटाती है लेकिन केवल 'संभावित रूप से मौजूद' के रूप में, ताकि बैकिंग स्टोर इसकी पुष्टि कर सके। n और p से m और k की गणना करें; 1% फ़ॉल्स पॉज़िटिव्स पर दस लाख आइटम्स के लिए लगभग 9.6M बिट्स और सात पोज़िशन्स की आवश्यकता होती है। मानक संरचना डिलीट नहीं कर सकती क्योंकि बिट्स साझा किए जाते हैं; डिलीशन के लिए काउंटिंग वेरिएंट का उपयोग करें और क्षमता बढ़ने पर फ़िल्टर को रीबिल्ड या लेयर करें। मैं एन्कोडिंग और सीड्स को स्थिर रखूँगा, फिर कोई फ़ॉल्स नेगेटिव न होने का परीक्षण करूँगा और अनुपस्थित नमूनों पर फ़ॉल्स पॉज़िटिव्स को मापूँगा।”

सामान्य गलतियाँ

true को प्रमाण मानना

सभी आवश्यक बिट्स का एक होना अन्य वैल्यूज़ के कारण भी हो सकता है। कॉलर को अभी भी एक आधिकारिक लुकअप की आवश्यकता है।

एक हैश का उपयोग करना

एकल हैश बिट वितरण और डिज़ाइन की गई त्रुटि दर को विकृत कर सकता है। डबल हैशिंग का उपयोग करें या एकाधिक पोज़िशन्स के पीछे स्वतंत्रता मान्यताओं की व्याख्या करें।

डिलीशन के लिए बिट्स साफ़ करना

साझा बिट को साफ़ करने से अन्य इन्सर्ट की गई वैल्यू false लौटा सकती है। इसके बजाय काउंटिंग बकेट्स का उपयोग करें या रीबिल्ड करें।

संतृप्ति को नज़रअंदाज़ करना

जैसे-जैसे अधिक बिट्स एक होते जाते हैं, फ़ॉल्स पॉज़िटिव्स बढ़ते जाते हैं। अनुमानित कार्डिनैलिटी और सेट-बिट अनुपात को ट्रैक करें, और बजट समाप्त होने से पहले पुनर्निर्माण करें।

केवल हिट्स का परीक्षण करना

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

फॉलो-अप प्रश्न और उत्तर

फ़ॉल्स पॉज़िटिव शून्य क्यों नहीं हो सकते?

विभिन्न वैल्यूज़ बिट्स के समान सीमित सेट में मैप हो सकती हैं। अधिक मेमोरी और एक उपयुक्त k दर को कम करते हैं लेकिन टकराव (collisions) को समाप्त नहीं करते हैं।

आप Cuckoo filter कब चुनेंगे?

जब डिलीशन, फ़िंगरप्रिंट स्टोरेज या लुकअप व्यवहार मायने रखता है, तब इसकी तुलना करें। केवल नाम से चुनने के बजाय मेमोरी, राइट्स और डिलीट्स को बेंचमार्क करें।

आप इसे कैसे पर्सिस्ट करेंगे?

बिट ऐरे को m, k, हैश एल्गोरिदम, सीड्स, एन्कोडिंग वर्ज़न और क्षमता अनुमान के साथ स्टोर करें। लोड करते समय वर्ज़न को मान्य करें।

आप गुणवत्ता की निगरानी कैसे करेंगे?

बैकएंड-पुष्ट फ़ॉल्स पॉज़िटिव्स, सेट-बिट अनुपात, अनुमानित कार्डिनैलिटी, लुकअप लेटेंसी और रीबिल्ड काउंट को मापें। एक परिभाषित सीमा पर रीबिल्ड या एक नई लेयर को ट्रिगर करें।

फॉर्मूले के पीछे क्या धारणाएं हैं?

यह लगभग एकसमान हैशिंग, n के करीब इंसर्शन वॉल्यूम और पोज़िशन्स के बीच पर्याप्त स्वतंत्रता मानता है। वास्तविक डेटा के नमूनों के साथ कैलिब्रेट करें।

आप छूटे हुए कन्करेंट राइट्स से कैसे बचते हैं?

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

सार्वजनिक स्रोत

संबंधित प्रश्न

संबंधित इंटरव्यू टूल

कोडिंग प्रॉम्प्ट के लिए स्क्रीनशॉट का उपयोग करें

समस्या को कैप्चर करें, फिर क्रम से प्रतिबंधों (constraints), समाधान, कोड, एज केस और जटिलता पर काम करें।

टूल देखें