ব্লুম ফিল্টার (Bloom Filter)
ধরুন একটি অনুষ্ঠানের দারোয়ান, যিনি একটি তালিকা দেখে অতিথিদের প্রবেশ করাচ্ছেন — কিন্তু তালিকাটি অদৃশ্য কালিতে লেখা, এবং মাঝে মাঝে কালি ছড়িয়ে গিয়ে এমন নামও দাগিয়ে দেয় যা সেখানে কখনোই ছিল না। দারোয়ান হয়তো কোনো নিরীহ ব্যক্তিকে ফিরিয়ে দিতে পারেন (ফলস পজিটিভ), কিন্তু তিনি কখনোই নিষিদ্ধ তালিকার কাউকে ঢুকতে দেবেন না (কোনো ফলস নেগেটিভ নেই)।
এটাই হলো ব্লুম ফিল্টার (Bloom Filter): মেমরি-সাশ্রয়ী ও অত্যন্ত দ্রুত একটি উপায় যা দিয়ে আপনি জানতে পারেন "এই জিনিসটি কি আমার সেটে আছে?" এটি হয়তো বলবে "সম্ভবত হ্যাঁ" যখন উত্তরটি আসলে না হতে পারে — কিন্তু এটি যদি বলে "নিশ্চিতভাবে না," তবে আপনি তা চোখ বন্ধ করে বিশ্বাস করতে পারেন।
এটি কীভাবে কাজ করে
ব্লুম ফিল্টার মূলত m বিটের একটি বিট অ্যারে (bit array) (শুরুতে সবগুলো শূন্য থাকে) যার সাথে k সংখ্যক স্বাধীন হ্যাশ ফাংশন যুক্ত থাকে। প্রতিটি হ্যাশ ফাংশন যেকোনো ইনপুটকে ওই অ্যারের একটি অবস্থানে ম্যাপ করে।
ইনসার্ট করার জন্য, একটি উপাদানকে সবকটি k হ্যাশ ফাংশনের মধ্য দিয়ে চালান এবং সেই বিট অবস্থানগুলোকে 1 করে দিন। ব্যাস, এটুকুই।
কোয়েরি করার জন্য, একই k হ্যাশ চালান। যদি সেই অবস্থানগুলোর প্রতিটি বিট 1 হয় → "সম্ভবত সেটের মধ্যে আছে।" যদি যেকোনো একটি বিট 0 হয় → "নিশ্চিতভাবে সেটের মধ্যে নেই।" একটি 0 তখনই থাকতে পারে যদি সেই অবস্থানটি কখনোই পাল্টানো না হয় — এর মানে এই উপাদানটি কখনোই ইনসার্ট করা হয়নি।
কেন ফলস পজিটিভ ঘটে — কিন্তু ফলস নেগেটিভ অসম্ভব
সময়ের সাথে সাথে অন্যান্য উপাদানগুলো অ্যারের বিভিন্ন বিট পরিবর্তন করতে থাকে। কাকতালীয়ভাবে, আপনার কোয়েরির জন্য যে নির্দিষ্ট অবস্থানগুলো দরকার, সেগুলো আগে থেকেই 1 হয়ে থাকতে পারে — যেগুলো অন্যান্য উপাদানগুলোর দ্বারা সেট হয়েছিল। এটিই হলো ফলস পজিটিভ। কিন্তু একবার কোনো বিট 1 হয়ে গেলে, সেটি চিরকাল 1-ই থাকে। সুতরাং যদি আপনি কোনো কিছু ইনসার্ট করে থাকেন, এর বিটগুলো সবসময় চালু থাকার গ্যারান্টি রয়েছে — যার মানে ফলস নেগেটিভ গঠনগতভাবেই অসম্ভব।
ফলস পজিটিভ রেট টিউন করা
প্রত্যাশিত ইনসারশন সংখ্যা n এবং লক্ষ্যকৃত ফলস পজিটিভ রেট p হলে, সর্বোত্তম প্যারামিটারগুলো হলো:
• বিট অ্যারের সাইজ: m = -n·ln(p) / (ln 2)²
• হ্যাশ ফাংশনের সংখ্যা: k = (m/n)·ln 2 ≈ 0.693·m/n
১% ফলস পজিটিভ রেটের জন্য, আপনার প্রতিটি উপাদানের জন্য প্রায় ৯.৬ বিট প্রয়োজন। ৬৪-বিট কী সংরক্ষণ করা একটি সাধারণ হ্যাশ সেটে প্রতিটি উপাদানের জন্য কমপক্ষে ৬৪ বিট লাগে — অর্থাৎ প্রায় ৭ গুণ বেশি স্পেস প্রয়োজন।
ডিলিশন বা মুছে ফেলা কেন সম্ভব নয়?
যদি আপনি কোনো উপাদান "মুছে ফেলার" জন্য একটি বিট পরিষ্কার (0) করেন, তবে আপনি হয়তো অন্যান্য উপাদানের প্রমাণও মুছে ফেলতে পারেন যারা ওই একই বিট অবস্থান ব্যবহার করছিল। এর ফলে আপনি ফলস নেগেটিভ তৈরি করবেন — যা ব্লুম ফিল্টারকে অকেজো করে দেবে। কাউন্টিং ব্লুম ফিল্টার (Counting Bloom Filters) এর মতো এক্সটেনশনগুলো বিটের বদলে ছোট কাউন্টার ব্যবহার করে ডিলিশন করতে সক্ষম, তবে এর জন্য বেশি মেমরি লাগে।
বাস্তব উদাহরণ
গুগল ক্রোমের সেফ ব্রাউজিং ক্ষতিকারক ইউআরএলগুলোর একটি লোকাল ব্লুম ফিল্টার ব্যবহার করে। একটি ফলস পজিটিভ হলে শুধুমাত্র সার্ভারে গিয়ে আবার চেক করতে হয় — যার খরচ খুব সামান্য। কিন্তু একটি ফলস নেগেটিভ (প্রকৃত বিপদ এড়িয়ে যাওয়া) হলে তা বিপর্যয়কর হতে পারে, এবং ফিল্টারটি তা অসম্ভব করে তোলে।
ডেটাবেসগুলো (ক্যাসান্দ্রা, রক্সডিবি, এইচবেস) ডিস্কে হাত দেওয়ার আগে ব্লুম ফিল্টার ব্যবহার করে: "এই কী (key) কি এই SSTable-এ আছে?" একটি ফলস পজিটিভ হলে শুধুমাত্র একটি ডিস্ক রিড নষ্ট হয়। একটি ফলস নেগেটিভ হলে ভুল ডেটা ফেরত আসতো। ফিল্টারটি ফলস নেগেটিভ সম্পূর্ণ দূর করে এবং বেশিরভাগ অপ্রয়োজনীয় ডিস্ক আই/ও কমিয়ে দেয়।