testtest123's picture
Initial commit: Multimodal RAG Pipeline V3.0 with Fallback Logic
2ecc4a7
Raw
History Blame Contribute Delete
1.16 kB
from typing import List, Dict, Any
def reciprocal_rank_fusion(bm25_results: List[Dict[str, Any]], vector_results: List[Dict[str, Any]], k: int = 60) -> List[Dict[str, Any]]:
"""
Reciprocal Rank Fusion (RRF) to merge keyword and vector search results.
"""
scores = {}
# Process BM25
for rank, chunk in enumerate(bm25_results):
chunk_id = chunk.get("id") or chunk.get("chunk_id")
if not chunk_id: continue
scores[chunk_id] = scores.get(chunk_id, 0) + 1 / (rank + k)
# Process Vector
for rank, chunk in enumerate(vector_results):
chunk_id = chunk.get("id") or chunk.get("chunk_id")
if not chunk_id: continue
scores[chunk_id] = scores.get(chunk_id, 0) + 1 / (rank + k)
# Combine metadata
all_chunks = { (c.get("id") or c.get("chunk_id")): c for c in bm25_results + vector_results }
# Sort by fused score
fused_results = []
for chunk_id, score in sorted(scores.items(), key=lambda x: x[1], reverse=True):
chunk = all_chunks[chunk_id].copy()
chunk["fused_score"] = score
fused_results.append(chunk)
return fused_results