Spaces:
Running
Running
| 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 | |