إنتقل إلى المحتوى الرئيسي

الفصل 2: البحث الهجين

لماذا البحث الهجين؟​

نوع البحثالقوةالضعف
كلمات مفتاحية (BM25)تطابقات دقيقة، مصطلحات نادرةيفوّت المرادفات
دلاليفهم المعنىقد يفوّت المصطلحات الدقيقة
هجينأفضل ما في الاثنينأكثر تعقيدًا

نظرة عامة على BM25​

BM25 خوارزمية ترتيب قائمة على الكلمات المفتاحية:

from rank_bm25 import BM25Okapi

# Tokenize documents
tokenized_corpus = [doc.split() for doc in documents]
bm25 = BM25Okapi(tokenized_corpus)

# Search
query_tokens = query.split()
scores = bm25.get_scores(query_tokens)

تنفيذ البحث الهجين​

مع LangChain​

from langchain.retrievers import EnsembleRetriever
from langchain.retrievers import BM25Retriever

# BM25 retriever
bm25_retriever = BM25Retriever.from_documents(documents)
bm25_retriever.k = 5

# Vector retriever
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 5})

# Combine
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, vector_retriever],
weights=[0.4, 0.6] # BM25 weight, Vector weight
)

# Search
results = ensemble_retriever.get_relevant_documents(query)

Reciprocal Rank Fusion (RRF)​

ادمج الترتيبات من عدة مسترجعات:

def reciprocal_rank_fusion(rankings, k=60):
"""
Combine multiple rankings using RRF.
k: constant to prevent high ranks from dominating
"""
fused_scores = {}

for ranking in rankings:
for rank, doc in enumerate(ranking):
doc_id = doc.metadata.get('id', hash(doc.page_content))
if doc_id not in fused_scores:
fused_scores[doc_id] = {'doc': doc, 'score': 0}
fused_scores[doc_id]['score'] += 1 / (k + rank + 1)

# Sort by fused score
sorted_docs = sorted(
fused_scores.values(),
key=lambda x: x['score'],
reverse=True
)

return [item['doc'] for item in sorted_docs]

متى تستخدم البحث الهجين​

✅ استخدم الهجين عندما:

  • تتضمّن الاستعلامات مصطلحات أو أسماء محددة
  • للمجال مفردات متخصّصة
  • يتوقع المستخدمون تطابقات دقيقة

❌ التزم بالدلالي عندما:

  • استعلامات بلغة طبيعية
  • بحث قائم على المفاهيم
  • محتوى متعدد اللغات

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

تابع إلى الفصل 3: إعادة الترتيب.