"""Pure search utility functions: text search, vector search, and RRF fusion.
Lives at the project root so that both rag_usage.py (production) and
evaluation/evaluation.py (evaluation) can import from here without
creating a circular dependency.
"""
def text_search(query, index, num_results=10):
boost_dict = {
"question": 0.5,
"answer": 1.0,
}
return index.search(query, num_results=num_results, boost_dict=boost_dict)
def vector_search(query, embedder, index, num_results=10):
q_vector = embedder.encode(query)
return index.search(q_vector, num_results=num_results)
def rrf(result_lists, k=60, num_results=5):
"""Reciprocal Rank Fusion over multiple ranked result lists."""
scores = {}
docs = {}
for results in result_lists:
for rank, doc in enumerate(results):
key = doc["id"]
scores[key] = scores.get(key, 0) + 1 / (k + rank)
docs[key] = doc
ranked = sorted(scores, key=scores.get, reverse=True)
return [docs[key] for key in ranked[:num_results]]