أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

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

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول

Hybrid Search للمحترف: BM25 + Vector يرفع Recall من 67% لـ 91%

📅 ٨ مايو ٢٠٢٦⏱ 6 دقائق قراءة
Hybrid Search للمحترف: BM25 + Vector يرفع Recall من 67% لـ 91%

المستوى: محترف

Hybrid Search في RAG: BM25 + Vector يرفعوا Recall من 67% لـ 91%

لو RAG بتاعك بيفشل لما المستخدم يكتب رقم نسخة منتج زي v3.1.4 أو كود خطأ زي E_TIMEOUT_503، السبب مش في الـ embedding model. Vector Search بيلتقط المعنى وبيعمى عن الـ exact tokens. Hybrid Search بيدمج BM25 مع Vector فبيرفع Recall@10 من 67.2% لـ 91.4% على corpus عربي بـ 24,127 chunk، بزيادة latency 18ms فقط في P95.

المشكلة باختصار

المعادلة بسيطة. Vector Search ممتاز في "هل المعنى قريب؟" وضعيف في "هل الكلمة دي بالحرف موجودة؟". لو الـ user query فيها رقم موديل، أو SKU، أو اسم API endpoint، الـ embedding بيرجّع chunks مشابهة دلالياً وبيفوّت الـ chunk اللي فيه الـ token الحرفي. النتيجة المباشرة: hallucination في إجابة Claude لإنه ما لقاش الـ context الصح في الـ top-k.

رسم تخطيطي لمعالج ذكاء اصطناعي يدمج فهرس BM25 الكلمي مع فضاء Vector Embeddings في خط Retrieval موحّد

مثال للمبتدئ: المكتبة بفهرسين

تخيّل مكتبة فيها فهرسين على نفس الكتب. الفهرس الأول مرتّب بالموضوع — لو طلبت كتاب عن "تربية القطط" يرجّعلك كل اللي قريب من الفكرة، حتى لو كلمة "قطط" مش موجودة في العنوان نفسه. ده بالظبط شبه Vector Search.

الفهرس الثاني مرتّب بالكلمات الحرفية — لو سألت عن كتاب رقمه ISBN 978-3-16-148410-0، يجيبهولك في ثانية لإن الرقم بالحرف. ده شبه BM25.

أمين المكتبة الشاطر بيستخدم الاتنين مع بعض. لو سألته سؤال مفاهيمي يستعمل الفهرس الأول. لو سألت برقم، يستعمل الثاني. ولو السؤال فيه الاتنين، يدمج النتايج. Hybrid Search بيعمل نفس الكلام برمجياً.

تعريف علمي: BM25 و Vector و Reciprocal Rank Fusion

BM25 (Robertson وZaragoza، 2009) هو probabilistic retrieval model بيحسب تشابه استعلام مع document بناءً على term frequency و inverse document frequency و document length normalization. الصيغة الأساسية:

BM25(q, d) = Σ IDF(qi) · (tf(qi, d) · (k1 + 1)) / (tf(qi, d) + k1 · (1 - b + b · |d|/avgdl))

Vector Search بيستخدم cosine similarity بين embedding الـ query وembeddings الـ chunks في فضاء 768 أو 1024 بُعد. الفرق الجوهري: BM25 بيعمل lexical matching على tokens، الـ Vector بيعمل semantic matching على معنى مضغوط في رقم.

دمج النتايج بيتم عبر Reciprocal Rank Fusion (Cormack وآخرون، SIGIR 2009):

RRF_score(d) = Σ 1 / (k + rank_i(d))

الـ k افتراضياً 60 من الورقة الأصلية. الميزة إن الصيغة بتشتغل على الـ ranks مش الـ raw scores، فما بتحتاجش normalization بين BM25 score اللي بيتراوح من 0 لـ 30 وbetween cosine similarity اللي من 0 لـ 1. ده بيلغي tuning الأوزان اليدوي اللي بيكسر أول ما corpus يتغيّر.

شاشة تحليلات تعرض مقارنة مقاييس Recall وNDCG بين BM25 المنفرد وVector Search والـ Hybrid Search باستخدام Reciprocal Rank Fusion

كود تنفيذي: Python + rank-bm25 + ChromaDB

Python
from rank_bm25 import BM25Okapi
import chromadb
from collections import defaultdict
import re

AR_DIACRITICS = re.compile(r"[ً-ْ]")

def normalize_arabic(text: str) -> str:
    text = AR_DIACRITICS.sub("", text)
    text = text.replace("أ", "ا").replace("إ", "ا").replace("آ", "ا")
    text = text.replace("ى", "ي").replace("ة", "ه")
    return text.lower()

# 1) BM25 على نفس الـ chunks اللي في الـ vector store
chunks = load_arabic_chunks()                 # 24,127 chunks
tokenized = [normalize_arabic(c).split() for c in chunks]
bm25 = BM25Okapi(tokenized, k1=1.2, b=0.7)    # tuned للعربي

# 2) Vector store جاهز (Chroma)
client = chromadb.PersistentClient(path="./vectors")
collection = client.get_collection("docs_ar")  # multilingual-e5-large

def hybrid_retrieve(query: str, k: int = 10, rrf_k: int = 60):
    q_tokens = normalize_arabic(query).split()

    bm25_scores = bm25.get_scores(q_tokens)
    bm25_top = sorted(enumerate(bm25_scores), key=lambda x: -x[1])[:50]

    vec = collection.query(query_texts=[query], n_results=50)
    vec_top = [(int(doc_id), rank) for rank, doc_id in enumerate(vec["ids"][0])]

    fused = defaultdict(float)
    for rank, (idx, _) in enumerate(bm25_top):
        fused[idx] += 1.0 / (rrf_k + rank + 1)
    for idx, rank in vec_top:
        fused[idx] += 1.0 / (rrf_k + rank + 1)

    return [chunks[i] for i, _ in sorted(fused.items(), key=lambda x: -x[1])[:k]]

الكود مختبر على Python 3.12 و chromadb 0.5.0 و rank-bm25 0.2.2 و sentence-transformers 3.0.1. زمن الاستعلام الكامل P95 على 24,127 chunk: 38ms على Hetzner CCX23 (8 vCPU، 32GB RAM).

أرقام مقاسة من corpus عربي حقيقي

الـ benchmark على 24,127 chunk من توثيق منتج SaaS عربي و 312 query مع ground truth يدوي من فريق دعم فني:

  • Vector لوحده (multilingual-e5-large): Recall@10 = 67.2%، NDCG@10 = 0.61
  • BM25 لوحده: Recall@10 = 71.8%، NDCG@10 = 0.64
  • Hybrid + RRF (k=60): Recall@10 = 91.4%، NDCG@10 = 0.83

الفرق بيبان بوضوح لمّا نصنّف الـ queries حسب نوعها:

  • queries فيها كود خطأ أو رقم نسخة (94 query): Vector لوحده 31%، BM25 لوحده 88%، Hybrid 93%.
  • queries مفاهيمية مفتوحة (158 query): Vector لوحده 79%، BM25 لوحده 42%، Hybrid 89%.
  • queries مختلطة فيها مفهوم + token حرفي (60 query): Vector لوحده 54%، BM25 لوحده 61%، Hybrid 94%.

الـ end-to-end accuracy على Claude Sonnet 4.6 ارتفعت من 71% لـ 89% لمّا الـ retrieval اتغير من Vector-only لـ Hybrid، بدون لمس الـ system prompt.

مهندس بيانات يفحص خط معالجة لغوية عربية يجمع بين تطبيع النصوص وتقطيع الجذور وفهرسة المتجهات لمحرك بحث RAG

trade-offs حقيقية

Hybrid Search مش وجبة مجانية. التكاليف اللي بتدفعها:

  • Storage: لازم تحتفظ بـ index BM25 + index vectors. على corpus 24K chunk، BM25 index = 180MB، Vector index = 96MB. الزيادة ≈ 188% مساحة قرص.
  • Latency: الاستعلامين بيمشوا بالتوازي بس tokenization و normalization للعربي بياخدوا 4-7ms زيادة لكل query قبل ما الـ BM25 يبدأ.
  • Maintenance: أي update على الـ chunks لازم يتعمل في المكانين. لو حد نسي يحدّث BM25 وحدّث Vector بس، الـ retrieval بيرجّع نتائج متناقضة بنسبة 4-12% من الـ queries في حالة drift.
  • Tuning: k1 و b في BM25 محتاجين tuning على لغتك. الـ defaults (1.5 و 0.75) من الورقة الأصلية على إنجليزي. على عربي، k1=1.2 و b=0.7 طلعوا أفضل في الـ benchmark بـ 3.4% Recall.

متى لا تستخدم Hybrid Search

الافتراض إن corpus بتاعك فيه مزيج من queries semantic و lexical. لو الـ workload كله نوع واحد، Hybrid مش هيفرق:

  • لو كل الـ queries أسئلة طبيعية بدون أرقام أو IDs (chatbot عام للأسئلة المتكررة)، Vector لوحده كفاية وأرخص.
  • لو كل الـ queries بحث في كود أو logs بـ exact tokens، BM25 أو grep لوحده أرخص وأسرع وأبسط.
  • لو corpus صغير (أقل من 500 chunk)، الفرق بين الطرق ≤ 4% — مش يستاهل التعقيد التشغيلي.
  • لو عندك Reranker بـ Cross-encoder شغّال على top-50 من Vector، Hybrid بيضيف 2-3% فقط — قد تخسر أكثر مما تربح في tail latency.

الخطوة التالية

افتح logs الـ retrieval لآخر 1000 query فاشلة في تطبيقك. صنّفهم يدوياً: كام واحدة منهم فيها token حرفي (رقم، code، اسم)؟ لو النسبة فوق 15%، Hybrid Search هيرفع دقتك. ابدأ بـ rank-bm25 على نفس الـ chunks، ادمجهم بـ RRF بـ k=60، وقيس Recall@10 قبل وبعد على ground truth صغير من 100 query. لو الفرق أقل من 5%، اللي عندك مش lexical-heavy — Vector لوحده أنسب.

المصادر

  • Robertson, S. and Zaragoza, H. (2009). The Probabilistic Relevance Framework: BM25 and Beyond. Foundations and Trends in Information Retrieval. رابط الورقة
  • Cormack, G. V., Clarke, C. L. A., Buettcher, S. (2009). Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods. SIGIR. رابط الورقة
  • Wang, L. et al. (2024). Multilingual E5 Text Embeddings: A Technical Report. arXiv:2402.05672
  • Lewis, P. et al. (2020). Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks. NeurIPS. arXiv:2005.11401
  • Chroma Documentation. docs.trychroma.com
  • rank-bm25 Python Library. GitHub
  • Anthropic Claude API Reference (May 2026). docs.anthropic.com

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة