04-03-03 — Hybrid search: vector + BM25
Por que keyword search ainda importa
Busca semântica via embeddings tem um ponto cego: termos exatos e raros.
Exemplos onde busca vetorial falha e keyword search acerta:
- "processo nº 0001234-56.2023.8.19.0001" → o embedding não distingue números de processo
- "LGPD art. 46" → acrônimos e referências legais específicas
- "CVE-2024-1234" → identificadores de vulnerabilidades
- "NF-e chave 43230214200166000139550010001234561234567890" → números de nota fiscal
- Nomes próprios incomuns
Para esses casos, BM25 é preciso e rápido. O problema é que BM25 falha quando o usuário pergunta "quais são as penalidades por quebra de contrato?" e o documento diz "multa rescisória" — as palavras não coincidem mas o significado sim. Daí a necessidade de combinar os dois.
BM25 — uma revisão rápida
BM25 (Best Matching 25) é o algoritmo de ranking de busca por keywords padrão da indústria. Ele pontua documentos baseado em:
- TF (Term Frequency): quantas vezes o termo aparece no documento
- IDF (Inverse Document Frequency): termos raros valem mais que termos comuns
- Saturação: repetição do mesmo termo tem retornos decrescentes
- Normalização de comprimento: documentos longos não têm vantagem injusta
Elasticsearch, Apache Solr, Azure AI Search — todos usam BM25 como base para busca textual.
Reciprocal Rank Fusion (RRF)
O desafio de combinar busca vetorial e BM25 é que os scores são incomparáveis: cosine similarity vai de 0 a 1, BM25 pode ser qualquer número positivo. Somar os scores diretamente não faz sentido.
RRF resolve isso usando apenas a posição no ranking, não o score absoluto:
RRF_score(d) = Σ 1 / (k + rank(d))
Onde k é uma constante (tipicamente 60) que suaviza a influência de rankings muito altos.
Implementação manual com RRF
def reciprocal_rank_fusion(rankings: list[list[str]], k: int = 60) -> list[tuple[str, float]]:
"""
rankings: lista de listas de IDs de documentos, cada lista é um ranking
retorna: lista de (doc_id, rrf_score) ordenada por score decrescente
"""
scores = {}
for ranking in rankings:
for position, doc_id in enumerate(ranking):
if doc_id not in scores:
scores[doc_id] = 0.0
scores[doc_id] += 1.0 / (k + position + 1)
return sorted(scores.items(), key=lambda x: x[1], reverse=True)
# Exemplo de uso
vector_results = ["chunk-A", "chunk-C", "chunk-B", "chunk-E"] # IDs por cosine
keyword_results = ["chunk-B", "chunk-A", "chunk-D", "chunk-C"] # IDs por BM25
fused = reciprocal_rank_fusion([vector_results, keyword_results])
top_5 = [doc_id for doc_id, score in fused[:5]]
Azure AI Search hybrid + semantic reranker
Azure AI Search implementa hybrid search + RRF nativamente. Adicionando o semantic ranker, você tem um pipeline de 3 níveis:
- Fase 1 — Candidate retrieval: BM25 busca top-50, vetorial busca top-50
- Fase 2 — RRF fusion: combina os dois rankings → top-50 unificado
- Fase 3 — Semantic reranker: modelo de linguagem reordena os 50 → retorna top-k
from azure.search.documents import SearchClient
from azure.search.documents.models import VectorizedQuery
results = search_client.search(
search_text=user_query, # ativa BM25
vector_queries=[VectorizedQuery(
vector=embed(user_query),
k_nearest_neighbors=50,
fields="content_vector" # ativa busca vetorial
)],
# RRF é automático quando ambos estão ativos
query_type="semantic", # ativa semantic reranker (3ª camada)
semantic_configuration_name="my-semantic-config",
top=5 # retorna top 5 após reranking
)
Microsoft publicou que em testes internos, hybrid search supera busca puramente vetorial em 10-15% de relevância (medida por NDCG@10). Com semantic reranker adicional, o ganho chega a 25-30% em benchmarks de QA sobre documentos corporativos. A combinação é o estado da arte para RAG enterprise.
O Azure AI Search implementa hybrid search com RRF sem configuração extra — basta incluir tanto search_text quanto vector_queries na mesma chamada. O parâmetro query_type="semantic" adiciona o semantic reranker como terceira camada. Custo do semantic ranker: veja tier e limite gratuito em 04-02-03.
Fontes
- Cormack, G., Clarke, C., Buettcher, S. (2009). Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods. SIGIR. dl.acm.org
- Microsoft. Hybrid search using vectors and full text in Azure AI Search. learn.microsoft.com
- Pinecone. Sparse-Dense Hybrid Search. pinecone.io/learn/hybrid-search-intro
- Robertson, S., Zaragoza, H. (2009). The Probabilistic Relevance Framework: BM25 and Beyond. nowpublishers.com