المستوى المطلوب: متوسط — يفترض إنك بتشتغل على PostgreSQL أو MySQL، عندك خبرة Python أساسية، وفاهم يعني إيه hash function ولو على المستوى السطحي. لو لسه مبتدئ، فيه قسم في النص بيشرح الفكرة بمثال بوّاب الفندق قبل ما ندخل في الرياضيات.
Bloom Filters: ازاي توفّر 99% من استعلامات قاعدة بياناتك بـ 16 كيلوبايت ذاكرة بس
لو الـ login endpoint بتاعك بيستقبل 4,500 محاولة دخول في الدقيقة، و 3,800 منهم بأسماء مستخدمين مش موجودة أصلاً، انت بتضيع 84% من طاقة قاعدة البيانات على بحث بيرجع صفر. Bloom Filter في 50 سطر Python بيرفض المحاولات دي قبل ما توصل لـ DB، باستهلاك 119 كيلوبايت ذاكرة لـ 100 ألف مستخدم.
المشكلة باختصار
قاعدة البيانات بتشتغل بكفاءة لما السؤال له إجابة. الكارثة بتبدأ لما السؤال إجابته "غير موجود". في الحالة دي، حتى مع index كويس، الـ planner لازم يفتح صفحات الـ B-tree ويتأكد، ويرجّعلك صفر. لو ده بيحصل آلاف المرات في الثانية، الـ DB بتشتغل 100% CPU في حاجة عديمة الفائدة، والمستخدم اللي عنده اسم صحيح بيدفع التمن في زمن استجابة عالي.
المفهوم بمثال بسيط جداً
تخيّل بوّاب فندق عنده دفتر فيه أسماء النزلاء. كل ما حد ييجي الباب يقوله اسمه. لو الاسم مش في الدفتر، البوّاب لازم يقفل الكتاب ويفتح صفحة صفحة عشان يتأكد. ده بياخد وقت.
دلوقتي خلّي البوّاب عنده ورقة صغيرة فيها 1000 خانة فاضية. كل ما يدخل نزيل جديد، البوّاب بياخد اسمه ويحطّ علامة في 3 خانات محسوبة من الاسم — مش الاسم نفسه، بصمة منه. لما حد ييجي يدّعي إنه نزيل، البوّاب بيشوف الـ 3 خانات بتاعت اسمه. لو خانة واحدة فيهم فاضية، يبقى أكيد مش نزيل، ومش محتاج يفتح الدفتر أصلاً. لو الـ 3 ممتلين، يبقى يمكن نزيل، يفتح الدفتر يتأكد. الورقة الصغيرة دي اسمها Bloom Filter.
التعريف العلمي بالظبط
Bloom Filter هو bit array بطول m بت مع k دوال hash مستقلة. لما تضيف عنصر، بتمرّر العنصر على الـ k دوال، وبتشغّل الـ k bits اللي بترجعهم (set to 1). لما تستعلم عن وجود عنصر، بتعيد نفس العملية؛ لو أي bit منهم = 0، يبقى العنصر مش موجود قطعاً. لو كلهم = 1، يبقى غالباً موجود مع احتمال false positive.
الورقة الأصلية كتبها Burton Howard Bloom سنة 1970 في Communications of the ACM. النتيجة الرياضية الأهم: عشان تضمن نسبة false positive قدرها p على n عنصر، محتاج m = -n · ln(p) / (ln 2)² بت، وعدد دوال hash المثالي k = (m/n) · ln 2. للقيم الشائعة 1% FPR و 100K عنصر تطلع تقريباً 958,506 بت ≈ 117 كيلوبايت، و 7 hash functions. الرقم 16KB في العنوان بيناسب 10K عنصر بنفس النسبة.
كود Python شغّال
هتحتاج pybloom-live لو الـ filter محلي داخل الـ application، أو redis 7+ مع وحدة RedisBloom لو عايز كل الـ instances تستفيد من نفس الـ filter: