يا جماعة الخير، السلام عليكم ورحمة الله. معكم أخوكم أبو عمر.
قبل كم سنة، كنت أشتغل على مشروع لشركة كبيرة عندها بوابة دعم فني ضخمة. آلاف المقالات والأدلة والأسئلة الشائعة. المشكلة كانت كارثية، يا زلمة! فريق خدمة العملاء والمستخدمين كانوا “بطموا” من كثر ما البحث سيء. المستخدم يكتب “كيف أسترجع كلمة السر؟”، والنظام ما يطلعله إشي. ليش؟ لأنه المقال الرسمي عنوانه “إجراءات إعادة تعيين كلمة المرور”. إذا ما كتبت الكلمة “بالحرف”، كأنك بتبحث في الهوا.
قعدت مع مدير المشروع، رجل أعمال همه الأرقام، وقال لي: “أبو عمر، شو هالحكي؟ دافعين دم قلبنا على هالنظام والناس مش ملاقية اللي بدها إياه! حلها”. وقتها، الحلول التقليدية كانت مجرد ترقيعات: نضيف كلمات مفتاحية يدوياً لكل مقال، نعمل قوائم مرادفات… شغل يدوي ممل وما بيخلص. كنا عايشين في “جحيم البحث الحرفي”. كل يوم يمر كان يزيد إحباطنا وإحباط المستخدمين. إلى أن لمعت في بالي فكرة كانت وقتها تعتبر حديثة نسبياً: البحث الدلالي باستخدام المتجهات. ومن هنا بدأت رحلتنا اللي بدي أحكيلكم عنها اليوم.
جحيم البحث الحرفي: لما الكلمات تفقد معناها
خلينا نكون صريحين، معظم أنظمة البحث اللي تعودنا عليها كانت “غبية”. هي لا تفهم المعنى، بل تطابق الحروف. لو عندك قاعدة بيانات SQL، فالبحث فيها يتم عادة باستخدام جملة مثل:
SELECT * FROM articles WHERE title LIKE '%كلمة السر%';
هذا السطر يبحث عن المقالات التي تحتوي “حرفياً” على عبارة “كلمة السر”. لكن ماذا لو كتب المستخدم:
- “نسيت الباسورد”
- “مش قادر أفوت على حسابي”
- “كيف أغير الرمز السري؟”
النظام التقليدي سيرد ببرود: “لا توجد نتائج”. هنا تكمن المشكلة. البحث الحرفي يعتمد على تطابق الكلمات، بينما البشر يتعاملون بالمعاني والمفاهيم. هذا هو الفرق بين البحث المعجمي (Lexical Search) والبحث الدلالي (Semantic Search).
الضوء في آخر النفق: الـ Embeddings وقواعد البيانات المتجهية
الحل لهذه المعضلة يكمن في تحويل الكلمات والجمل إلى شيء تفهمه الآلة بشكل أعمق: الأرقام. وهنا يأتي دور مفهوم “التضمينات” أو كما نسميها في عالم الذكاء الاصطناعي، Embeddings.
ببساطة شديدة، الـ Embedding هو تحويل أي قطعة نص (كلمة، جملة، فقرة) إلى قائمة من الأرقام تسمى “متجه” (Vector). هذا المتجه ليس عشوائياً، بل هو تمثيل رياضي لمعنى النص في فضاء متعدد الأبعاد.
تخيلها كخريطة ضخمة للمعاني. الكلمات والجمل ذات المعاني المتقاربة تكون نقاطاً قريبة من بعضها على هذه الخريطة. فمثلاً، ستجد أن متجه “تفاحة” ومتجه “برتقالة” أقرب إلى بعضهما من متجه “سيارة”.
كيف تعمل هذه “المتجهات” السحرية؟
يتم إنشاء هذه المتجهات باستخدام نماذج لغوية ضخمة (LLMs) مدربة على كميات هائلة من النصوص. هذه النماذج (مثل BERT أو نماذج OpenAI) تتعلم العلاقات الدقيقة بين الكلمات وسياقاتها. أشهر مثال يوضح قوة هذه المتجهات هو المعادلة الرياضية الشهيرة:
متجه(“ملك”) – متجه(“رجل”) + متجه(“امرأة”) ≈ متجه(“ملكة”)
هذا يثبت أن المتجهات لا تحفظ الكلمات فقط، بل تفهم العلاقات الكامنة بينها. فعندما نطرح “مفهوم الرجل” من “الملك” ونضيف “مفهوم المرأة”، نحصل على شيء قريب جداً من “مفهوم الملكة”. هذا هو السحر بعينه!
قواعد البيانات المتجهية: المكتبة الجديدة لمعلوماتنا
حسناً يا أبو عمر، فهمنا فكرة المتجهات. الآن لدينا آلاف أو ملايين المتجهات التي تمثل مقالات الدعم الفني. أين نخزنها؟ وكيف نبحث فيها؟
هل يمكن استخدام قاعدة بيانات تقليدية مثل MySQL أو PostgreSQL؟ الجواب هو: نعم، ولكن… سيكون الأداء كارثياً. البحث عن “أقرب متجه” لمتجه البحث في قاعدة بيانات تقليدية يتطلب مقارنة متجه البحث مع كل المتجهات المخزنة، واحدة تلو الأخرى. هذا الأمر بطيء جداً وغير عملي على الإطلاق مع نمو البيانات.
من هنا ولدت الحاجة إلى نوع جديد ومخصص من قواعد البيانات: قواعد البيانات المتجهية (Vector Databases).
ما الذي يميزها عن قواعد البيانات التقليدية؟
هذه القواعد مصممة لغرض واحد أساسي: تخزين والبحث في كميات ضخمة من المتجهات عالية الأبعاد بسرعة فائقة. هي لا تبحث عن تطابق تام، بل عن “الجيران الأقرب” (Nearest Neighbors). وتستخدم خوارزميات فهرسة ذكية جداً للقيام بذلك، مثل:
- HNSW (Hierarchical Navigable Small World): تبني ما يشبه شبكة طرق سريعة بين المتجهات، مما يسمح لها بالقفز بسرعة إلى المنطقة الصحيحة في فضاء المعاني بدلاً من البحث في كل شارع صغير.
- IVF (Inverted File): تقسم الفضاء إلى مجموعات (clusters) وتبحث فقط داخل المجموعات ذات الصلة.
هذه الخوارزميات تقدم ما يسمى “البحث التقريبي عن الجيران الأقرب” (Approximate Nearest Neighbor – ANN). أي أنها قد لا تضمن النتيجة الصحيحة 100% طوال الوقت، لكنها تقدم نتائج دقيقة بنسبة 99%+ بسرعة أكبر بآلاف المرات. وهذه مقايضة ممتازة في معظم التطبيقات.
أشهر اللاعبين في الساحة
هناك العديد من قواعد البيانات المتجهية اليوم، ولكل منها نقاط قوة:
- Pinecone: خدمة مُدارة (managed service)، سهلة الاستخدام وقوية جداً، لكنها ليست مجانية للمشاريع الكبيرة.
- Weaviate: مفتوحة المصدر، قوية جداً وتدعم البحث الهجين (متجهي + تقليدي).
- Milvus: حل مفتوح المصدر وقابل للتوسع بشكل هائل، مناسب للشركات الكبيرة.
- ChromaDB: مفتوحة المصدر وسهلة جداً للبدء، ممتازة للمشاريع الصغيرة والمتوسطة والتعلم. وهي التي سنستخدمها في مثالنا.
يلا نطبق: بناء نظام بحث دلالي بسيط
يكفي كلام نظري، خلينا “نشمر عن إيدينا” ونبني مثالاً عملياً باستخدام Python. سنقوم ببناء نظام بحث بسيط للأسئلة الشائعة.
الخطوة الأولى: تحويل النص إلى متجهات (Embeddings)
سنستخدم مكتبة sentence-transformers الرائعة والمجانية لإنشاء المتجهات. أولاً، قم بتثبيت المكتبات اللازمة:
pip install sentence-transformers chromadb
الآن، لنكتب الكود الذي يحول النص إلى متجهات:
# نستدعي المكتبات اللازمة
from sentence_transformers import SentenceTransformer
import chromadb
# تحميل نموذج لغوي قادر على فهم اللغة العربية
# 'paraphrase-multilingual-MiniLM-L12-v2' نموذج جيد متعدد اللغات
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
# قائمة بالوثائق (الأسئلة الشائعة في مثالنا)
documents = [
"كيف يمكنني تغيير كلمة المرور الخاصة بي؟",
"ما هي طرق الدفع المقبولة؟",
"كم من الوقت يستغرق شحن الطلب؟",
"هل يمكنني إرجاع المنتج بعد شرائه؟",
"لقد نسيت اسم المستخدم الخاص بي."
]
# إنشاء المتجهات لكل وثيقة
document_embeddings = model.encode(documents)
# طباعة أبعاد المتجه الأول للتأكد
print("شكل متجه الوثيقة الأولى:", document_embeddings[0].shape)
# سيطبع شيئاً مثل (384,) مما يعني أنه متجه من 384 رقم
الخطوة الثانية: تخزين المتجهات والبحث عنها باستخدام ChromaDB
الآن بعد أن أصبح لدينا المتجهات، سنقوم بتخزينها في قاعدة بيانات ChromaDB والبحث فيها.
# إعداد قاعدة بيانات Chroma (في الذاكرة لسهولة المثال)
client = chromadb.Client()
# إنشاء "مجموعة" (collection) لتخزين وثائقنا
# يمكن تخيلها كجدول في قاعدة البيانات التقليدية
collection = client.create_collection("faq_collection")
# إضافة الوثائق والمتجهات إلى المجموعة
# من المهم إعطاء كل وثيقة ID فريد
collection.add(
embeddings=document_embeddings,
documents=documents,
ids=[f"id_{i}" for i in range(len(documents))]
)
# --- الآن مرحلة البحث ---
query = "ما هي المدة اللازمة لوصول طلبيتي؟"
# 1. تحويل سؤال المستخدم إلى متجه
query_embedding = model.encode([query])
# 2. البحث في المجموعة عن أقرب 2 وثائق لمتجه السؤال
results = collection.query(
query_embeddings=query_embedding,
n_results=2
)
# 3. طباعة النتائج
print("nسؤال المستخدم:", query)
print("أفضل النتائج التي تم العثور عليها:")
for doc in results['documents'][0]:
print(f"- {doc}")
# مثال بحث آخر
query_2 = "فقدت كلمة السر"
query_embedding_2 = model.encode([query_2])
results_2 = collection.query(query_embeddings=query_embedding_2, n_results=2)
print("nسؤال المستخدم:", query_2)
print("أفضل النتائج التي تم العثور عليها:")
for doc in results_2['documents'][0]:
print(f"- {doc}")
إذا قمت بتشغيل هذا الكود، ستلاحظ أن البحث الأول عن “ما هي المدة اللازمة لوصول طلبيتي؟” سيعيد “كم من الوقت يستغرق شحن الطلب؟” كنتيجة أولى. والبحث الثاني عن “فقدت كلمة السر” سيعيد “كيف يمكنني تغيير كلمة المرور الخاصة بي؟” و “لقد نسيت اسم المستخدم الخاص بي.”. هذا هو سحر البحث الدلالي! النظام فهم المعنى ولم يطابق الكلمات حرفياً.
نصائح من “الختيار”: خلاصة تجاربي مع المتجهات
بعد سنوات من العمل في هذا المجال، تعلمت بعض الدروس التي أحب أن أشاركها معكم:
- اختر النموذج المناسب (Choose the right model): ليست كل نماذج الـ Embedding متشابهة. نموذج مدرب على التغريدات لن يكون جيداً في تحليل المستندات القانونية. ابحث دائماً عن نماذج تم تدريبها على بيانات قريبة من مجالك، وتأكد من أنها تدعم اللغات التي تحتاجها.
- “التقطيع” فن (Chunking is an art): عندما تتعامل مع مستندات طويلة، طريقة تقسيمها إلى أجزاء أصغر (chunks) قبل تحويلها لمتجهات هي أمر حاسم. هل تقسم حسب الفقرات؟ أم حسب عدد كلمات معين؟ التجربة هي سيد الموقف هنا. القاعدة العامة هي أن يكون كل جزء مكتفياً ذاتياً بالمعنى قدر الإمكان.
- لا تنسَ البيانات الوصفية (Metadata is your friend): قواعد البيانات المتجهية تسمح لك بتخزين بيانات وصفية (metadata) بجانب كل متجه. هذه ميزة خارقة! يمكنك البحث دلالياً ثم تصفية النتائج. مثلاً: ابحث عن “مقالات عن الذكاء الاصطناعي” ثم قم بالتصفية بحيث تكون `category = ‘tutorials’` و `year > 2023`.
- البحث التقريبي ليس سيئاً: لا تخف من كلمة “تقريبي” (Approximate). في عالم البحث الدلالي، الحصول على نتيجة “جيدة جداً” بسرعة فائقة أفضل بكثير من الحصول على نتيجة “مثالية” بعد انتظار طويل. الدقة مقابل السرعة هي مقايضة ستتعامل معها دائماً.
الخلاصة: من البحث “الأعمى” إلى البحث “الذكي”
يا جماعة، الانتقال من البحث الحرفي إلى البحث الدلالي ليس مجرد تحسين تقني، بل هو نقلة نوعية في كيفية تفاعلنا مع البيانات. لقد انتقلنا من أنظمة “عمياء” لا ترى إلا الحروف، إلى أنظمة “ذكية” تفهم المعنى والسياق والقصد من وراء كلماتنا.
هذه التقنية هي العمود الفقري لكثير من تطبيقات الذكاء الاصطناعي الحديثة التي نسمع عنها اليوم، مثل أنظمة الإجابة على الأسئلة المتقدمة (RAG)، ومحركات التوصية الشخصية، واكتشاف المحتوى المكرر وغيرها الكثير.
الرحلة قد تبدو معقدة في البداية، لكن كما رأيتم في مثالنا، الأدوات أصبحت اليوم أبسط وأقوى من أي وقت مضى. لم يعد الأمر مقتصراً على عمالقة التكنولوجيا، بل أصبح في متناول أي مطور لديه الفضول والرغبة في التعلم.
أتمنى أن تكون هذه المقالة قد أنارت لكم الطريق. الآن الكرة في ملعبكم. يلا شدوا حيلكم وابدأوا رحلتكم في بناء أنظمة أكثر ذكاءً وفهماً. 💪