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

يا جماعة الخير، السلام عليكم ورحمة الله وبركاته. معكم أخوكم أبو عمر.

خلوني أحكيلكم هالسالفة اللي صارت معي قبل فترة، قصة بتلخص المعاناة اللي كتير من المبرمجين عاشوها. كنا شغالين على مشروع متجر إلكتروني كبير، وكل شي كان ماشي زي الحلاوة، التصميم بجنن، والأداء سريع، والعميل مبسوط. لحد ما وصلنا لمرحلة “محرك البحث” تبع الموقع.

بكل ثقة، بنينا نظام بحث تقليدي بيعتمد على الكلمات المفتاحية. يعني المستخدم بيكتب “لابتوب”، النظام بروح بدور على كلمة “لابتوب” في قاعدة البيانات وبرجعله النتائج. بسيط، صح؟ هاد اللي فكرناه.

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

جحيم البحث بالكلمات المفتاحية (Keyword Search)

المشكلة اللي واجهناها هي مشكلة متأصلة في البحث التقليدي القائم على الكلمات. هاي الأنظمة، سواء كانت جملة LIKE '%...%' بسيطة في SQL أو حتى محركات بحث متقدمة مثل Elasticsearch في إعداداتها الأساسية، بتتعامل مع النص كـ”حروف” مش كـ”معنى”.

وهنا تكمن الكارثة:

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

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

الحل السحري: البحث الدلالي (Semantic Search)

بعد ليالي من البحث والتجربة، وجدنا ضالتنا في مفهوم اسمه “البحث الدلالي”. الفكرة بسيطة في مفهومها، ثورية في تطبيقها: بدلاً من البحث عن تطابق الكلمات، دعنا نبحث عن تقارب “المعنى”.

يعني لما المستخدم يبحث عن “أحذية مريحة للمشي لمسافات طويلة”، النظام لازم يفهم إنه قصده “comfort”, “walking”, “long-distance” ويبحث عن المنتجات اللي بتحمل هاي “المفاهيم”، حتى لو الكلمات نفسها مش مكتوبة بالحرف في الوصف.

طيب، كلام جميل، بس كيف بدنا نترجم “المعنى” هاد لأشي الكمبيوتر يفهمه؟ هنا يأتي دور بطل القصة الحقيقي.

السر يكمن في “التضمينات” (Embeddings)

إذا كان البحث الدلالي هو الوجهة، فالتضمينات أو الـ Embeddings هي السيارة اللي رح توصلنا لهناك. فكّر فيها بهاي الطريقة البسيطة:

ما هي الـ Embeddings؟

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

فمثلاً، النقاط اللي بتمثل “ملك” و “ملكة” و “أمير” بتكون قريبة من بعضها في منطقة معينة من هذا الفضاء. والنقطة اللي بتمثل “تفاحة” بتكون قريبة من “برتقالة” أكتر بكتير من قربها من “سيارة”.

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

كيف نصنع هذه المتجهات؟

هنا يأتي دور نماذج الذكاء الاصطناعي الضخمة (LLMs) المدربة مسبقاً، مثل نماذج BERT ورفاقه. هاي النماذج قرأت مليارات النصوص من الإنترنت وتعلمت العلاقات الدقيقة بين الكلمات. لما نعطيها جملة، هي بتعطينا مقابلها “المتجه” الرقمي اللي بيمثل معناها.

ولحسن حظنا، الموضوع صار أسهل من شرب المي بفضل مكتبات زي sentence-transformers في بايثون.


# تثبيت المكتبات اللازمة
# pip install sentence-transformers

from sentence_transformers import SentenceTransformer

# اختر نموذجاً يدعم اللغة العربية، هذا النموذج متعدد اللغات وممتاز
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')

sentences = [
    "أفضل هاتف ذكي للتصوير",
    "جوال بكاميرا ممتازة",
    "وصفة لعمل الكنافة النابلسية"
]

# تحويل الجمل إلى متجهات (Embeddings)
embeddings = model.encode(sentences)

# embeddings الآن هي مصفوفة من المتجهات الرقمية
print(embeddings)
print("Shape:", embeddings.shape) 
# سيطبع شيئاً مثل (3, 384)، يعني 3 جمل، كل جملة ممثلة بـ 384 رقم

ممتاز! الآن صار عنا طريقة لتحويل أي نص إلى أرقام تفهمها الآلة. بس ظهرت مشكلة جديدة… وكبيرة.

المشكلة الجديدة: كيف نبحث في ملايين المتجهات؟

في مشروعنا، كان عنا آلاف المنتجات. يعني آلاف المتجهات الرقمية. لما يجي المستخدم ويبحث، لازم نعمل التالي:

  1. نحوّل جملة البحث تبعته لمتجه.
  2. نقارن هذا المتجه مع كل متجهات المنتجات الموجودة عنا في قاعدة البيانات (عادة باستخدام مقياس اسمه Cosine Similarity).
  3. نرتب النتائج حسب الأكثر قرباً (تشابهاً).

هذا الحل بيشتغل بشكل رائع على 100 منتج. بس على 100 ألف منتج؟ أو مليون؟ العملية بتصير بطيئة بشكل قاتل. بدك قوة معالجة هائلة وسيرفرات قد بلد عشان ترجع نتيجة بحث وحدة بوقت معقول. كنا زي اللي طلع من حفرة ليوقع ببئر.

المنقذ: قواعد بيانات المتجهات (Vector Databases)

وهنا، وكأنها فارس على حصان أبيض، ظهرت “قواعد بيانات المتجهات”.

ما هي قواعد بيانات المتجهات؟

ببساطة، هي قواعد بيانات متخصصة ومُحسّنة لغرض واحد فقط لا غير: تخزين والبحث عن المتجهات عالية الأبعاد (High-dimensional vectors) بسرعة فائقة.

كيف تعمل (السحر الحقيقي)؟

هي لا تقوم بالبحث الخطي الغبي (مقارنة متجه البحث مع كل المتجهات الأخرى). بدلاً من ذلك، هي تستخدم خوارزميات ذكية جداً تُعرف باسم (Approximate Nearest Neighbor – ANN).

تخيل معي هالمثال: بدك تلاقي أقرب مطعم إيطالي لموقعك في مدينة ضخمة. الطريقة الغبية هي إنك تمسك خريطة المدينة وتزور كل مبنى فيها وتشوف إذا هو مطعم إيطالي أو لأ. أما الطريقة الذكية (طريقة Vector DB) هي إنك تفتح الخريطة اللي مقسمة مسبقاً لأحياء، وتروح مباشرة على “الحي الإيطالي” أو الأحياء المعروفة بالمطاعم، وتبحث هناك فقط. صح ممكن ما تلاقي أقرب مطعم بنسبة 100% (يمكن في مطعم أقرب بـ 10 أمتار في حي تاني)، بس رح تلاقي نتيجة ممتازة بنسبة 99.9% وبجزء صغير جداً من الوقت والجهد. هذا هو جوهر خوارزميات ANN مثل HNSW.

أشهر اللاعبين في الساحة

هناك العديد من الخيارات المتاحة اليوم، منها ما هو خدمة سحابية مُدارة (Managed) ومنها ما هو مكتبة مفتوحة المصدر يمكنك تشغيلها بنفسك:

  • مكتبات (Self-hosted): مثل FAISS (من ميتا/فيسبوك)، و ChromaDB (سهل جداً للبدء والتجربة)، و Milvus.
  • خدمات سحابية (Managed): مثل Pinecone, Weaviate.

مثال عملي: لنبني محرك بحث بسيط جداً

دعنا نستخدم chromadb لسهولته الشديدة في بناء مثال حي يوضح الفكرة.


# تثبيت المكتبات
# pip install chromadb sentence-transformers

import chromadb
from sentence_transformers import SentenceTransformer

# 1. إعداد النموذج وقاعدة البيانات
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
client = chromadb.Client() # يمكنك استخدام نسخة تعمل في الذاكرة للتجربة

# إنشاء "مجموعة" لتخزين بياناتنا
# ChromaDB يمكنه استخدام نموذج التضمين تلقائياً، هذا يسهل الأمور أكثر
collection = client.get_or_create_collection(
    name="products_ar",
    metadata={"hnsw:space": "cosine"} # تحديد مقياس التشابه
)

# 2. إضافة البيانات (المنتجات)
# في الواقع، هذه البيانات تأتي من قاعدة بياناتك الأساسية
products_data = {
    "ids": ["item1", "item2", "item3", "item4"],
    "documents": [
        "معطف شتوي ثقيل مصنوع من الصوف الخالص، يوفر دفئاً لا مثيل له في البرد القارص.",
        "حذاء رياضي خفيف الوزن مصمم خصيصاً للجري والماراثون، يوفر تهوية ممتازة للقدم.",
        "ساعة ذكية مقاومة للماء مع مستشعر لقياس نبضات القلب وتتبع جودة النوم.",
        "قميص قطني ناعم بألوان صيفية زاهية، مثالي للنزهات اليومية."
    ]
}

collection.add(
    documents=products_data["documents"],
    ids=products_data["ids"]
)

# 3. الآن وقت البحث! 
query = "ملابس دافئة للشتاء"

# 4. البحث عن أقرب منتجين للمعنى
results = collection.query(
    query_texts=[query],
    n_results=2
)

# 5. عرض النتائج
print(results['documents'])

# النتيجة المتوقعة ستكون شيئاً كهذا:
# [['معطف شتوي ثقيل مصنوع من الصوف الخالص...', 'قميص قطني ناعم...']]
# لاحظ كيف فهم أن "ملابس دافئة للشتاء" أقرب للمعطف الشتوي!

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

نصائح من خبرة أبو عمر

بعد ما خضنا هذه التجربة، اسمحولي أقدم لكم كم نصيحة على طبق من ذهب:

  • ابدأ صغيراً ومحلياً: لا تركض وراء الخدمات السحابية الكبيرة من اليوم الأول. ابدأ بمكتبة مثل ChromaDB أو FAISS على جهازك، افهم المبدأ، وعندما يكبر مشروعك، فكر بالانتقال.
  • نموذج التضمين هو كل شيء: جودة بحثك تعتمد 90% على جودة نموذج التضمين (Embedding Model). اختر نموذجاً مناسباً للغات وبياناتك. النماذج متعددة اللغات كنز حقيقي للمحتوى العربي.
  • البيانات هي الملك: “الزبالة مدخلات، زبالة مخرجات” (Garbage in, garbage out). نظّف بياناتك النصية قبل تحويلها لمتجهات. كلما كان النص المصدر أوضح وأغنى، كانت النتائج أفضل.
  • لا ترمِ القديم كله: أفضل الأنظمة اليوم تستخدم “البحث الهجين” (Hybrid Search). هي تجمع بين قوة البحث الدلالي (للمعنى) ودقة البحث بالكلمات المفتاحية (للمصطلحات الدقيقة مثل أسماء الماركات أو أرقام الموديلات SKU).

الخلاصة: المستقبل للمعنى، وليس للكلمة 🚀

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

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

يلا يا جماعة، شدّوا الهمة، وابدأوا ابنوا الجيل الجديد من التطبيقات الذكية. العالم محتاج حلولكم. الله يوفقكم جميعاً.

أبو عمر

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

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

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

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

آخر المدونات

خوارزميات

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

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

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

كانت واجهاتنا خليطاً عشوائياً: كيف أنقذنا ‘نظام التصميم’ (Design System) من جحيم الفوضى البصرية؟

أسرد لكم قصتي كـ "أبو عمر"، مطور برمجيات فلسطيني، وكيف واجهنا فوضى بصرية عارمة في مشاريعنا. اكتشفوا معنا كيف كان "نظام التصميم" (Design System) هو...

14 مايو، 2026 قراءة المزيد
برمجة وقواعد بيانات

كانت بياناتنا تتلف في سباق محموم: كيف أنقذتنا ‘مستويات عزل المعاملات’ من جحيم القراءات الشبحية؟

أروي لكم يا جماعة قصة حقيقية من قلب المعركة البرمجية، يوم كادت القراءات الشبحية (Phantom Reads) أن تدمر مشروعنا. في هذه المقالة، أغوص معكم في...

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

كانت قاعدة بياناتنا تحتضر: كيف أنقذنا ‘التخزين المؤقت’ (Caching) من جحيم الاستعلامات المتكررة؟

أشارككم قصة حقيقية من قلب المعركة التقنية، عندما كادت قاعدة بياناتنا أن تنهار تحت ضغط الاستعلامات المتكررة. سأشرح لكم كيف كان "التخزين المؤقت" (Caching) هو...

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