La recherche hybride : pgvector + FTS + trigram + RRF
Le problĂšme : « BOUL. INOX 50MM x100 » â quel produit ?
Une ligne de commande arrive salie : abrĂ©viations, fautes, rĂ©fĂ©rences partielles. Le retrouver dans un catalogue de dizaines de milliers de variants est un problĂšme de recherche, pas de classification. Aucune technique seule ne suffit â le projet en fusionne quatre, toutes dans PostgreSQL :
| Source | Outil PG | Attrape |
|---|---|---|
| SKU exact | ILIKE + heuristique « ça ressemble à une réf » | les références précises |
| Full-text | colonne générée TSVECTOR + websearch_to_tsquery('french'), score ts_rank_cd | les mots exacts, pluriels/conjugaisons |
| Trigram | extension pg_trgm, similarity() + index GIN | les fautes de frappe (« boulon »â« bulon ») |
| Vecteur | pgvector : search_vec <=> :emb (cosine), index HNSW | le sens (« vis » â « boulon ») |
Les embeddings : Cohere embed-multilingual (1024 dim), une colonne vector(1024) par variant, avec le bon input_type (search_document Ă l'indexation, search_query Ă la requĂȘte â l'asymĂ©trie compte).
La fusion : Reciprocal Rank Fusion
Comment combiner quatre listes aux scores incomparables (un ts_rank_cd et un cosinus ne se comparent pas) ? RRF ne regarde que les rangs :
score(candidat) = ÎŁ sur chaque source : 1 / (60 + rang_dans_la_source)
Un candidat bien classĂ© dans plusieurs sources monte â robuste, sans normalisation de scores, sans rĂ©glage. C'est la mĂȘme fusion que tu as croisĂ©e au cours ML (recherche d'entreprise) â ici en pur SQL applicatif.
AprÚs le retrieval : scoring métier et deep match
Les candidats passent ensuite un scoring 5 dimensions (id, marque, texte, catĂ©gorie, spĂ©cifications) pondĂ©rĂ©, avec deux rĂšgles dures : le golden match (rĂ©fĂ©rence exacte â score 1, on ne discute pas) et le brand veto (mauvaise marque explicite â Ă©liminĂ©). Si le meilleur score reste sous le seuil, le deep match s'enclenche : un petit LLM (Haiku) réécrit la requĂȘte en ~3 variantes â nouveaux candidats â re-rank Cohere (cross-encoder) â dĂ©cision. Le LLM n'intervient qu'en dernier recours : la voie rapide est du pur PostgreSQL Ă quelques millisecondes.
Pourquoi fusionner par rangs (RRF) plutĂŽt que par scores ?