?
GuideintermédiaireVérifié le 2025-05

Hybrid search : BM25 + sémantique

Combiner recherche lexicale et sémantique pour un retrieval plus robuste.

Limites de la recherche purement sémantique

La recherche vectorielle excelle pour trouver des concepts similaires mais échoue sur les correspondances exactes (noms propres, codes, identifiants). La recherche lexicale (BM25) fait l'inverse. La combinaison des deux est appelée recherche hybride.

Comment fonctionne BM25

BM25 (Best Matching 25) est un algorithme de ranking basé sur la fréquence des termes. Il excelle pour :

  • Mots-clés exacts et termes techniques
  • Noms propres et identifiants
  • Requêtes courtes et précises

Architecture hybride

Query → [BM25 retrieval] → résultats lexicaux
      → [Vector search]  → résultats sémantiques
      → [Fusion (RRF)]   → résultats combinés → LLM

Reciprocal Rank Fusion (RRF)

L'algorithme RRF combine les rankings de plusieurs sources :

def reciprocal_rank_fusion(rankings, k=60):
    scores = {}
    for ranking in rankings:
        for rank, doc in enumerate(ranking):
            if doc not in scores:
                scores[doc] = 0
            scores[doc] += 1 / (rank + k)
    return sorted(scores.items(), key=lambda x: x[1], reverse=True)

Implémentation avec Weaviate

Weaviate supporte nativement la recherche hybride :

result = client.query.get("Document", ["content"]) \
    .with_hybrid(query="machine learning optimization", alpha=0.5) \
    .with_limit(10) \
    .do()

Le paramètre alpha contrôle la balance : 0 = full BM25, 1 = full vector.

Implémentation avec pgvector + tsvector

PostgreSQL permet les deux approches nativement :

-- Index full-text
ALTER TABLE documents ADD COLUMN tsv tsvector
  GENERATED ALWAYS AS (to_tsvector('french', content)) STORED;
CREATE INDEX ON documents USING gin(tsv);

-- Requête hybride
SELECT *,
  (ts_rank(tsv, plainto_tsquery('french', $1))) * 0.5 +
  (1 - (embedding <=> $2)) * 0.5 AS hybrid_score
FROM documents
ORDER BY hybrid_score DESC
LIMIT 10;

Pinecone Hybrid Search

Pinecone supporte les sparse-dense vectors pour l'hybride :

index.query(
    vector=dense_embedding,
    sparse_vector=sparse_embedding,  # BM25/SPLADE
    top_k=10,
    alpha=0.5
)

Quand utiliser l'hybride

  • Documents techniques avec beaucoup de jargon
  • Corpus multilingue où les embeddings peuvent être moins fiables
  • Cas où les utilisateurs recherchent des termes exacts ET des concepts
  • Production : l'hybride est rarement pire que l'un ou l'autre seul

Sources

RAGhybridrecherche