كنا نرهق قاعدة البيانات بسؤال ‘هل هذا موجود؟’: كيف أنقذنا ‘فلتر بلوم’ من جحيم الاستعلامات غير الضرورية؟

يا أهلاً وسهلاً فيكم يا جماعة. اسمحولي اليوم أحكيلكم قصة صارت معي ومع فريقي قبل كم سنة، قصة علّمتنا درس مهم في عالم البرمجة، درس عن كيف إن الحلول أحياناً بتكون بسيطة وعبقرية، بس إحنا اللي بنكون معقّدينها على حالنا.

كنا وقتها شغالين على نظام كبير فيه تسجيل مستخدمين بمعدل عالي جداً. وكان “إشي” طبيعي إنه المستخدم الجديد لما يجي يسجل، يجرّب كذا اسم مستخدم قبل ما يلاقي واحد متاح. المشكلة إنه مع كل محاولة كتابة حرف واحد في خانة اسم المستخدم، كان نظامنا يركض زي المجنون على قاعدة البيانات ويسألها: “يا ست قاعدة البيانات، بالله تشوفيلي هالإسم موجود عندك ولا لأ؟”.

في البداية، الأمور كانت ماشية. بس مع ازدياد عدد المستخدمين، قاعدة البيانات المسكينة صارت تصرخ وتولول. صار عنا بطء ملحوظ، والمستخدمين صاروا يشتكوا من تعليق صفحة التسجيل. مدير قواعد البيانات (DBA) كان كل يوم يبعتلي إيميل عنوانه “URGENT” ويحكيلي: “يا أبو عمر، استعلامات الـ SELECT COUNT(*) من جدول المستخدمين رح تجلطنا! لازم تلاقيلنا حل!”.

جلسنا نفكر ونحلل، وقلنا يا جماعة، 95% من الأسماء اللي المستخدمين بجربوها هي أصلاً مش موجودة. إحنا قاعدين بنرهق أغلى وأثمن مورد عنا (قاعدة البيانات) عشان يجاوب على سؤال، في معظم الأحيان، إجابته “لأ، مش موجود”. وهنا، زي ما بنحكي “إجا الفرج”، تذكرت هيكل بيانات كنت قرأت عنه أيام الجامعة، هيكل بيانات احتمالي (Probabilistic) اسمه “فلتر بلوم” (Bloom Filter). كان هو طوق النجاة اللي طلعنا من هالجحيم.

ما هو “فلتر بلوم”؟ وليش هو الحل السحري؟

بكل بساطة، فلتر بلوم هو هيكل بيانات ذكي جداً وموفّر للمساحة، مصمم ليجيب على سؤال واحد فقط وبسرعة فائقة: “هل هذا العنصر محتمل أن يكون عضواً في مجموعة؟”.

لاحظوا إني شدّدت على كلمة “محتمل”. وهنا تكمن عبقريته وسرّه. فلتر بلوم له خاصيتين أساسيتين:

  • إذا قال الفلتر “هذا العنصر غير موجود بالتأكيد”، فهو صادق 100%. لا مجال للخطأ هنا. (No False Negatives)
  • إذا قال الفلتر “هذا العنصر قد يكون موجوداً“، فهناك احتمال بسيط أنه مخطئ. هذا ما نسميه “الإيجابية الكاذبة” (False Positive).

تخيل فلتر بلوم كأنه حارس أمن على باب بناية ضخمة. معه قائمة بأسماء السكان. إذا سألته عن اسم “أبو عمر” وقال لك “أكيد مش ساكن عنا”، فهو صادق تماماً. لكن إذا سألته عن اسم “محمد علي” وقال لك “أه، يمكن ساكن”، فممكن يكون صادق، وممكن يكون الاسم تشابه مع اسم شخص آخر في القائمة بسبب طريقة تسجيله المبسطة. في هذه الحالة فقط، تحتاج أن تدخل البناية وتتأكد بنفسك من الاستعلامات.

هذا بالضبط ما كنا نحتاجه! كنا نحتاج طريقة سريعة ورخيصة جداً لتصفية الـ 95% من الاستعلامات اللي إجابتها “لأ” قبل أن تصل لقاعدة البيانات الغالية علينا.

كيف يعمل هذا السحر؟ شرح مبسط

بدون الدخول في تعقيدات رياضية، الفكرة بسيطة. فلتر بلوم يتكون من شيئين:

  1. مصفوفة بتات (Bit Array): تخيلها كشريط طويل جداً من الأصفار، مثلاً مليون صفر.
  2. عدة دوال هاش (Hash Functions): مثلاً 3 دوال هاش مختلفة. وظيفة دالة الهاش هي أن تأخذ أي مدخل (مثل اسم المستخدم) وتعطيك رقماً فريداً مقابله.

عملية الإضافة (لما نسجل مستخدم جديد)

عندما يتم تسجيل اسم مستخدم جديد بنجاح، مثلاً “abu_omar”، نقوم بالآتي:

  1. نمرر اسم “abu_omar” على دوال الهاش الثلاثة.
  2. كل دالة ستعطينا رقم (مؤشر) مختلف. مثلاً:
    • الدالة الأولى أعطت: 2501
    • الدالة الثانية أعطت: 105890
    • الدالة الثالثة أعطت: 788321
  3. نذهب إلى مصفوفة البتات، وفي المواقع (Indices) التي حصلنا عليها، نحوّل القيمة من 0 إلى 1.

هيك بنكون “علّمنا” الأماكن الخاصة بهذا الاسم في الفلتر.

عملية التحقق (لما مستخدم جديد يجرّب اسم)

الآن، يأتي مستخدم جديد ويحاول تجربة اسم، مثلاً “palestine_dev”.

  1. نمرر الاسم “palestine_dev” على نفس دوال الهاش الثلاثة.
  2. نحصل على 3 مواقع جديدة. مثلاً: 550, 9871, 450000.
  3. نذهب ونفحص القيم في هذه المواقع في مصفوفة البتات.
  4. إذا وجدنا أن واحداً على الأقل من هذه المواقع قيمته لا تزال 0، فهذا يعني 100% أن هذا الاسم لم يمر من هنا من قبل. إذن، الاسم متاح! (وهذا هو المكسب الكبير، لا داعي لسؤال قاعدة البيانات).
  5. أما إذا وجدنا أن كل المواقع الثلاثة قيمتها 1، فهنا نقول أن الاسم “محتمل” أن يكون محجوزاً. لماذا محتمل؟ لأنه قد يكون هناك تضارب (Collision) حيث أن أسماء مستخدمين مختلفين، بعد مرورهم على دوال الهاش، قاموا بتعليم نفس مجموعة البتات بالصدفة. في هذه الحالة فقط، نسمح للاستعلام بالمرور إلى قاعدة البيانات للتأكد بشكل قاطع.

دعونا نكتب بعض الكود: مثال عملي بلغة Python

الكلام النظري جميل، لكن “الشغل بزبط الشغل”. خلينا نشوف مثال عملي باستخدام لغة Python ومكتبة مشهورة اسمها pybloom_live. (يمكنك تثبيتها بـ pip install pybloom-live)


from pybloom_live import BloomFilter

# 1. إنشاء فلتر بلوم
# سنقوم بإنشاء فلتر يتسع لـ 100,000 عنصر تقريباً
# مع نسبة خطأ (false positive rate) تبلغ 0.1%
# المكتبة ستقوم بحساب حجم المصفوفة وعدد دوال الهاش المناسبة تلقائياً
capacity = 100000
error_rate = 0.001
username_filter = BloomFilter(capacity=capacity, error_rate=error_rate)

# 2. إضافة بعض أسماء المستخدمين الموجودة فعلاً في قاعدة البيانات
existing_users = ["abu_omar", "ahmad_22", "falasteen", "dev_master"]
for user in existing_users:
    username_filter.add(user)
    print(f"تمت إضافة المستخدم '{user}' إلى الفلتر.")

print("n--- بدأ التحقق ---n")

# 3. التحقق من أسماء مستخدمين
# الحالة الأولى: التحقق من اسم موجود بالفعل
test_user_1 = "abu_omar"
if test_user_1 in username_filter:
    print(f"الفلتر يقول: '{test_user_1}' قد يكون موجوداً. (صحيح)")
else:
    print(f"الفلتر يقول: '{test_user_1}' غير موجود بالتأكيد.")


# الحالة الثانية: التحقق من اسم غير موجود بالتأكيد
test_user_2 = "new_user_123"
if test_user_2 in username_filter:
    print(f"الفلتر يقول: '{test_user_2}' قد يكون موجوداً. (هذه إيجابية كاذبة إن حدثت)")
else:
    # هذه هي الحالة الأكثر شيوعاً والتي توفر علينا عبء قاعدة البيانات
    print(f"الفلتر يقول: '{test_user_2}' غير موجود بالتأكيد. (صحيح وهو المطلوب!)")

# الحالة الثالثة: إمكانية حدوث إيجابية كاذبة
# هذا مثال توضيحي، من الصعب جداً هندسة مثال يسبب إيجابية كاذبة يدوياً
# لكن لنتخيل أن 'random_user' بالصدفة أعطى نفس مؤشرات بتات لعناصر أخرى
test_user_3 = "random_user_that_might_collide"
if test_user_3 in username_filter:
    print(f"الفلتر يقول: '{test_user_3}' قد يكون موجوداً. الآن فقط، نذهب لقاعدة البيانات لنتأكد!")
else:
    print(f"الفلتر يقول: '{test_user_3}' غير موجود بالتأكيد.")

كما ترون، الكود بسيط جداً. المنطق الذي طبقناه في نظامنا كان كالتالي:


function isUsernameAvailable(username):
    # الخطوة 1: اسأل فلتر بلوم أولاً (سريع جداً ورخيص)
    if username not in bloom_filter:
        # إذا قال الفلتر "لأ"، فالإجابة "نعم، متاح" مؤكدة
        return True
    
    # الخطوة 2: فقط إذا قال الفلتر "نعم"، اسأل قاعدة البيانات (بطيء ومكلف)
    # هذا سيحدث في نسبة قليلة جداً من الحالات
    return database.doesUserExist(username) == False

النتيجة كانت مذهلة. خففنا الضغط على قاعدة البيانات بنسبة تتجاوز 90%، وزمن الاستجابة في صفحة التسجيل أصبح شبه فوري. مدير قواعد البيانات رجع يبتسم وصار يعزمنا على القهوة.

نصائح أبو عمر من الخوابي 🏺

بعد ما اشتغلنا على هاي الشغلة وغيرها، جمعتلكم شوية نصائح عملية:

  • اختيار الحجم ومعدل الخطأ: أهم قرارين هما حجم الفلتر (capacity) ومعدل الخطأ (error rate). كلما أردت معدل خطأ أقل، احتجت لمصفوفة بتات أكبر. هناك معادلات رياضية لحسابها، لكن معظم المكتبات الجاهزة تطلب منك فقط السعة ومعدل الخطأ وهي تحسب الباقي. كن واقعياً، معدل خطأ 1% أو 0.1% غالباً ما يكون كافياً وممتازاً.
  • لا يمكن الحذف: فلتر بلوم التقليدي لا يدعم حذف العناصر. بمجرد أن يصبح البت 1، لا يمكن إعادته إلى 0، لأن ذلك قد يؤثر على عناصر أخرى تشترك في نفس البت. إذا كنت تحتاج للحذف، هناك أنواع متقدمة مثل (Counting Bloom Filter) لكنها تستهلك ذاكرة أكبر.
  • إعادة بناء الفلتر: بما أنك لا تستطيع الحذف، في بعض الأنظمة قد تحتاج إلى إعادة بناء الفلتر بشكل دوري (مثلاً، كل ليلة) من البيانات الحالية في قاعدة البيانات لضمان أنه يعكس أحدث حالة.
  • استخدامات أخرى: هذه التقنية ليست فقط لأسماء المستخدمين. فكر فيها لأي سيناريو “هل هذا موجود؟” يكون مكلفاً:
    • منع المستخدمين من رؤية نفس المقالات أو المنتجات التي شاهدوها من قبل في قسم “مقترح لك”.
    • أنظمة كشف الاحتيال للتحقق بسرعة مما إذا كانت معاملة (بـ IP أو بريد إلكتروني معين) قد شوهدت في قائمة سوداء.
    • قواعد بيانات مثل Google BigTable و Apache Cassandra تستخدم فلاتر بلوم لتجنب البحث في الأقراص عن بيانات غير موجودة.
    • التحقق من وجود URL في قائمة المواقع الضارة قبل زيارتها.

الخلاصة يا جماعة الخير 🏁

فلتر بلوم هو مثال رائع على كيف يمكن لفكرة بسيطة من علوم الحاسوب أن تحل مشاكل ضخمة في العالم الحقيقي. هو ليس حلاً لكل شيء، ولكنه أداة قوية جداً في جعبة أي مطور برمجيات يهتم بالأداء.

الدرس الأهم الذي تعلمته من تلك التجربة هو: لا ترهق الخبير (قاعدة البيانات) بأسئلة يمكن لمتدرب سريع (فلتر بلوم) أن يجيب على معظمها بـ “لا”.

أتمنى أن تكون هذه القصة والتقنية مفيدة لكم في مشاريعكم. استمروا في التعلم والبحث عن هذه الجواهر الخفية في عالم الخوارزميات وهياكل البيانات. دمتم مبدعين! 👋

أبو عمر

سجل دخولك لعمل نقاش تفاعلي

كافة المحادثات خاصة ولا يتم عرضها على الموقع نهائياً

آراء من النقاشات

لا توجد آراء منشورة بعد. كن أول من يشارك رأيه!

آخر المدونات

ذكاء اصطناعي

كنا نغرق في بحر البيانات: كيف أنقذنا ‘الإشراف الضعيف’ (Weak Supervision) من جحيم التسمية اليدوية؟

مقالة تستعرض تقنية الإشراف الضعيف (Weak Supervision) كحل عملي لمشكلة تسمية البيانات الهائلة في مشاريع الذكاء الاصطناعي. من قصة واقعية إلى دليل تطبيقي، نكتشف كيف...

21 مايو، 2026 قراءة المزيد
تسويق رقمي

كانت تحويلاتنا ضحية لحاصرات الإعلانات: كيف أنقذتنا واجهة برمجة تطبيقات التحويلات (CAPI) من جحيم التتبع المفقود؟

في هذه المقالة، أشارككم قصة حقيقية من قلب الميدان عن كيفية انهيار تتبع حملاتنا الإعلانية بسبب حاصرات الإعلانات، وكيف كانت واجهة برمجة تطبيقات التحويلات (CAPI)...

21 مايو، 2026 قراءة المزيد
تجربة المستخدم والابداع البصري

من الشاشات البيضاء إلى الحوار: فن تصميم حالات الواجهة (Loading, Empty, Error)

في هذا المقال، يأخذكم أبو عمر في رحلة من تجربته كمطور فلسطيني، ليكشف أسرار تصميم حالات الواجهة (التحميل، الفراغ، والخطأ). تعلم كيف تحول الشاشات الصامتة...

21 مايو، 2026 قراءة المزيد
الحوسبة السحابية

كنا ندفع ثمن الخوادم الخاملة: كيف أنقذتنا ‘الحوسبة بلا خوادم’ (Serverless) من جحيم التكاليف المهدرة؟

في هذه المقالة، أشارككم قصة حقيقية من تجربتي كمطور برمجيات عن كيفية انتقالنا من الخوادم التقليدية باهظة الثمن إلى معمارية الحوسبة بلا خوادم (Serverless). سنغوص...

21 مايو، 2026 قراءة المزيد
التوسع والأداء العالي والأحمال

كانت طلباتنا تتعثر في أوقات الذروة: كيف أنقذتنا ‘طوابير الرسائل’ (Message Queues) من جحيم الاختناقات؟

أشارككم قصة حقيقية من قلب المعركة البرمجية، كيف كاد تطبيقنا أن ينهار تحت ضغط المستخدمين في يوم إطلاق مهم، وكيف كانت "طوابير الرسائل" (Message Queues)...

21 مايو، 2026 قراءة المزيد
التكنلوجيا المالية Fintech

كانت بياناتنا المالية سجينة البنوك: كيف حررتها واجهات ‘الصيرفة المفتوحة’ (Open Banking)؟

من واقع تجربتي كمبرمج، كانت بياناتنا المالية حبيسة جدران البنوك الرقمية. في هذه المقالة، أسرد لكم كيف حولت واجهات برمجة التطبيقات للصيرفة المفتوحة (Open Banking)...

21 مايو، 2026 قراءة المزيد
البودكاست