La recherche lexicale BM25
Mis à jour le 30 juillet 2026
Notre pipeline RAG fonctionne — mais la recherche sémantique seule ne retourne pas toujours les meilleurs résultats. Elle excelle à retrouver des idées, des reformulations, des synonymes ; elle est étonnamment mauvaise sur un besoin pourtant trivial : la correspondance exacte de termes. La solution n’est pas de remplacer la recherche sémantique, mais de la compléter par une recherche lexicale via BM25 — l’algorithme classique des moteurs de recherche textuels.
Le problème de la recherche sémantique seule
Prenez une question d’utilisateur parfaitement légitime : « Que s’est-il passé avec l’incident INC-2023-Q4-011 ? ». Chercher un identifiant spécifique comme « INC-2023-Q4-011 » peut échouer avec la recherche sémantique — et la raison est structurelle. Les embeddings capturent le sens, et un identifiant technique n’a pas de sens : c’est une chaîne arbitraire, que le modèle d’embeddings n’a jamais vue et qu’il ne peut situer nulle part dans son espace sémantique. La requête sera rapprochée de segments qui « parlent d’incidents » en général — pas nécessairement de celui qui mentionne cet identifiant précis. Le même angle mort frappe les références de produits, les numéros de tickets, les noms de code internes : tout ce vocabulaire exact qui fait le quotidien des documents d’entreprise.
Stratégie de recherche hybride
D’où la stratégie hybride, qui fait travailler deux moteurs complémentaires :
- Recherche sémantique : embeddings et base vectorielle pour la correspondance de sens
- Recherche lexicale : recherche textuelle classique pour les correspondances exactes
- Fusion des résultats
Chaque moteur couvre l’angle mort de l’autre : le sémantique comprend « quels problèmes avons-nous eus au dernier trimestre ? » sans qu’aucun mot ne corresponde, le lexical retrouve « INC-2023-Q4-011 » au caractère près. La fusion des résultats — comment classer ce que deux moteurs aux scores incomparables retournent — est un sujet à part entière, traité dans la prochaine leçon.
Comment fonctionne BM25
BM25 ne comprend rien au sens ; il compte, et il compte intelligemment :
- Tokeniser la requête : décomposer la question en termes individuels
- Compter la fréquence : combien de fois chaque terme apparaît dans les documents
- Pondérer par rareté : les termes rares reçoivent des scores d’importance plus élevés
- Trouver les meilleures correspondances : retourner les segments contenant le plus de termes importants
La pondération par rareté est le cœur de l’algorithme : un terme présent dans tous les documents ne discrimine rien, un terme presque unique désigne son document. Le terme rare « INC-2023-Q4-011 » pèse ainsi infiniment plus que les mots courants comme « à » ou « le » — le segment qui le contient remonte en tête, exactement le comportement que la recherche sémantique ne pouvait pas offrir.
Implémentation
store = BM25Index()
for chunk in chunks:
store.add_document({"content": chunk})
results = store.search("Que s'est-il passe avec INC-2023-Q4-011 ?", 3)
Vous aurez remarqué l’essentiel : BM25Index et la recherche vectorielle partagent la même API — add_document() et search(). Cette interface commune est un choix de conception délibéré, et il paie dès la prochaine leçon : pour combiner les deux moteurs, il suffira de les traiter comme des index interchangeables derrière une façade unique. Notez aussi ce que BM25 n’exige pas : aucun embedding, aucun appel à un modèle — l’indexation est purement locale, instantanée et gratuite.
Points clés à retenir
- La recherche sémantique rate les correspondances exactes : identifiants, références, noms de code n’ont pas de « sens » vectorisable
- La stratégie hybride combine moteur sémantique (le sens) et moteur lexical BM25 (les termes exacts)
- BM25 pondère par rareté : un terme rare vaut beaucoup, un mot courant ne vaut presque rien
- Même API que l’index vectoriel (
add_document/search) — prête pour la fusion de la prochaine leçon - BM25 est local et gratuit : aucun embedding, aucun appel réseau à l’indexation