DanLevy.net

Recherche vectorielle sémantique et autres sujets pour se faire des amis et des amants

Le paysage complet de la recherche : exacte, floue, sémantique, hybride — et quand les superposer.

La recherche n’est pas une chose unique, et la recherche sémantique ne remplace pas le reste.

« Trouver l’utilisateur avec l’email dan@example.com » et « trouve-moi des articles sur le débogage pour un nouvel ingénieur » sont tous deux décrits comme de la recherche, mais ils n’ont presque rien en commun en tant que problèmes d’ingénierie. Le premier a une réponse correcte et un accès par index en O(log n). Le second n’a pas de réponse correcte — seulement de la pertinence — et nécessite de comprendre le langage, l’intention et le sens.

Les ingénieurs les plus convaincants sur les décisions de recherche — ceux qui gagnent les arguments et livrent le bon système — comprennent l’ensemble du paysage. Ils savent quel outil utiliser et pourquoi, et ils peuvent l’expliquer clairement.

Cet article couvre la couche sémantique : ce que fait réellement la recherche vectorielle, quand elle gagne, et où elle devrait rester à l’écart. La version utile n’est pas « embarquez tout ». C’est savoir quand les vecteurs ont leur place à côté de la recherche lexicale, floue et par correspondance exacte dans une architecture hybride.

La moitié lexicale et floue du tableau — tsvector, pg_trgm, pg_search — se trouve dans Guide de recherche textuelle Postgres 2026.


Termes en un coup d’œil

Embedding (plongement lexical) — Une liste dense de nombres à virgule flottante produite par un modèle, représentant un morceau de texte (ou une image, un audio, etc.) comme un point dans un espace de haute dimension. Le contenu sémantiquement lié atterrit à proximité ; le contenu non lié atterrit loin.

Recherche lexicale — Recherche basée sur la correspondance exacte de mots et de tokens. Rapide, déterministe et correcte pour les termes connus. Ne comprend pas les synonymes, les paraphrases ou les équivalents interlangues.

Recherche sémantique — Recherche basée sur le sens plutôt que sur les tokens. Une requête pour « comment gérer les timeouts » peut correspondre à un document intitulé « configuration des politiques de retry » sans aucun mot partagé, car leurs embeddings sont géométriquement proches.

Vecteur — Une liste de nombres. Dans les contextes de recherche, la sortie d’un modèle d’embedding. La « recherche vectorielle » trouve les vecteurs les plus proches d’un vecteur requête par distance géométrique.

FTS (Full-Text Search) — Recherche lexicale intégrée de Postgres, propulsée par tsvector / tsquery. Tokenise, racinise et indexe le texte pour les requêtes par mots-clés. Solide pour la prose et la recherche de termes exacts ; aveugle au sens.

BM25 — Un algorithme de classement pour la recherche lexicale (utilisé par Elasticsearch, Qdrant, et d’autres). Score les résultats par fréquence de terme pondérée par la rareté du terme dans le corpus. Meilleur que la correspondance brute par mots-clés ; toujours lexical.

HNSW (Hierarchical Navigable Small World) — L’index standard de plus proches voisins approximatifs pour la recherche vectorielle. Construit un graphe de proximité en couches pour des requêtes de similarité rapides et à haut rappel. pgvector, Qdrant, Weaviate et la plupart des autres l’utilisent.

RRF (Reciprocal Rank Fusion) — Un algorithme pour fusionner des listes de résultats classées provenant de plusieurs systèmes de récupération. Utilise uniquement la position dans le classement — aucune normalisation de score nécessaire. Un résultat bien classé dans les listes FTS et vectorielles obtient un score combiné plus fort qu’un résultat qui domine une seule liste.


Ce que fait réellement la recherche sémantique

Les embeddings vectoriels convertissent le texte (ou les images, l’audio, etc.) en une liste de nombres — un point dans un espace de haute dimension. Un modèle d’embedding est entraîné pour que le texte sémantiquement lié atterrisse à proximité dans cet espace. « Chien » et « canin » se retrouvent proches. « Courir un marathon » et « exécuter un script Python » se retrouvent loin malgré un mot partagé.

La recherche de similarité dans cet espace trouve les documents dont le sens est le plus proche du sens de la requête, indépendamment de la superposition exacte des mots.

Cela signifie :

La recherche lexicale (tsvector, pg_trgm) ne peut rien faire de tout cela. Elle opère sur des mots et des caractères, pas sur le sens. Les outils ne sont pas interchangeables — ils résolvent des problèmes différents.


Quand pgvector gagne

Construire du RAG. La génération augmentée par récupération (RAG) récupère les morceaux de documents dont le sens est le plus proche de la question de l’utilisateur, puis les transmet à un modèle de langage comme contexte. Cette étape de récupération est une opération vectorielle. Le FTS manquera les paraphrases, les synonymes et les correspondances conceptuelles qu’un morceau pertinent pourrait exprimer différemment. L’avantage de pgvector sur un store vectoriel autonome : il s’exécute dans votre instance Postgres existante — aucun service séparé à déployer, opérer ou synchroniser.

Les utilisateurs décrivent ce qu’ils veulent, pas ce qu’ils cherchent. « Articles sur la construction de la confiance en tant que nouveau manager » n’a aucun mot-clé qui apparaît de manière fiable dans les posts pertinents. « Un framework léger pour gérer les effets de bord » peut ne pas utiliser ces mots exacts dans la documentation. La recherche vectorielle correspond à l’intention, pas à l’orthographe.

Trouver des éléments similaires. Produits associés, tickets de support similaires, rapports de bugs en double, articles que vous pourriez aussi aimer. « Trouver des issues similaires à celle-ci » est une recherche de plus proches voisins — embarquer l’élément, trouver ses voisins géométriques. Une mise en garde importante : la recherche vectorielle retourne toujours des résultats, même quand rien n’est genuinely similaire. Pour les cas de déduplication et de recommandation, filtrez par un seuil minimum de similarité (par ex. similarité cosinus ≥ 0,80) pour éviter de faire remonter des correspondances à faible confiance comme si elles étaient significatives.

Déduplication sémantique. Avant d’indexer du contenu pour du RAG ou de la recherche, vous devez souvent identifier les quasi-doublons dans le corpus — articles révisés plusieurs fois, tickets de support soumis en double, entrées de base de connaissances qui se superposent significativement. Embarquez les documents et filtrez par seuil de similarité cosinus pour signaler ou fusionner les quasi-doublons avant qu’ils ne polluent votre index. Cela empêche la récupération de retourner plusieurs morceaux quasi-identiques et de diluer la fenêtre de contexte.

Recherche multilingue. Les modèles d’embedding multilingues mappent le contenu sémantiquement équivalent à travers les langues dans des vecteurs proches. Une requête en espagnol pour « perder peso » peut correspondre à un article en anglais sur « sustainable weight loss habits » — aucun token partagé, même sens sous-jacent. Le FTS nécessite une configuration de dictionnaire par langue et gère mal les requêtes interlangues. pg_trgm est agnostique à la langue mais orthographique, pas sémantique.

Configurer pgvector

De l’installation de l’extension à la requête de similarité, la configuration tient en quelques instructions SQL :

CREATE EXTENSION IF NOT EXISTS vector;
ALTER TABLE documents ADD COLUMN embedding vector(1536);
-- HNSW est généralement le premier index à essayer pour des datasets de taille modérée
CREATE INDEX documents_embedding_idx
ON documents USING hnsw (embedding vector_cosine_ops);
-- Requête de recherche sémantique
SELECT id, title, 1 - (embedding <=> $1::vector) AS similarity
FROM documents
ORDER BY embedding <=> $1::vector
LIMIT 10;

<=> est la distance cosinus. 1 - distance_cosinus donne la similarité cosinus (1,0 = identique, 0,0 = orthogonal). Pour ivfflat (l’alternative plus ancienne et plus rapide à construire), utilisez lists = sqrt(row_count) comme point de départ.

Ce que pgvector ne gère pas bien


Recherche hybride : le cas pour les deux

La documentation technique est l’exemple le plus clair où aucun outil ne suffit seul.

Les utilisateurs qui cherchent « comment configurer les timeouts » ont besoin d’une correspondance conceptuelle : un article intitulé « Définir les politiques de retry et les limites de connexion » n’a aucun mot-clé en commun mais est exactement ce qu’il leur faut.

Les mêmes utilisateurs cherchent aussi withRetry(), ECONNRESET et ERR_SOCKET_TIMEOUT. Ces chaînes exactes doivent apparaître — la correspondance sémantique peut ne pas les trouver de manière fiable, et un faux positif (conceptuellement similaire mais pas la bonne API) est activement trompeur.

La recherche vectorielle gère les requêtes conceptuelles. Le FTS gère les termes exacts. Aucun ne gère bien les deux seul.

La solution est la recherche hybride : exécuter les deux et fusionner les résultats.

Reciprocal Rank Fusion

Reciprocal Rank Fusion (RRF) est l’algorithme standard pour combiner des listes classées provenant de différents systèmes de récupération. Il ne nécessite pas de normaliser les scores entre les systèmes — il utilise uniquement les positions de classement. Un résultat qui apparaît haut dans les deux listes obtient un score combiné plus fort qu’un résultat qui domine une seule liste.

WITH fts_results AS (
SELECT id,
ROW_NUMBER() OVER (ORDER BY ts_rank(search_vector, query) DESC) AS rank
FROM documents, to_tsquery('english', $1) query
WHERE search_vector @@ query
LIMIT 50
),
vector_results AS (
SELECT id,
ROW_NUMBER() OVER (ORDER BY embedding <=> $2::vector) AS rank
FROM documents
ORDER BY embedding <=> $2::vector
LIMIT 50
),
rrf AS (
SELECT
COALESCE(f.id, v.id) AS id,
COALESCE(1.0 / (60 + f.rank), 0) +
COALESCE(1.0 / (60 + v.rank), 0) AS rrf_score
FROM fts_results f
FULL OUTER JOIN vector_results v ON f.id = v.id
)
SELECT d.id, d.title, rrf.rrf_score
FROM rrf
JOIN documents d ON d.id = rrf.id
ORDER BY rrf_score DESC
LIMIT 10;

Le 60 au dénominateur est la constante RRF. Des valeurs plus élevées atténuent les différences de position de classement ; des valeurs plus basses les amplifient. La valeur par défaut de 60 fonctionne bien pour la plupart des types de contenu.

Le RRF évite le problème plus difficile de normaliser ts_rank (un score de fréquence logarithmique) contre la distance cosinus (une mesure géométrique). Ils ne sont pas comparables. Le RRF demande seulement : « à quelle hauteur ce résultat est-il apparu dans chaque liste ? »

Recherche hybride avec les trigrammes aussi

Pour la recherche面向 utilisateur sur du contenu mixte — où les utilisateurs peuvent chercher un nom de personne, un concept ou un terme exact dans la même session — la fusion à trois voies gère tout :

WITH trgm_results AS (
SELECT id,
ROW_NUMBER() OVER (ORDER BY similarity(title, $1) DESC) AS rank
FROM documents
WHERE title % $1
LIMIT 50
),
fts_results AS (
SELECT id,
ROW_NUMBER() OVER (ORDER BY ts_rank(search_vector, to_tsquery('english', $1)) DESC) AS rank
FROM documents
WHERE search_vector @@ to_tsquery('english', $1)
LIMIT 50
),
vector_results AS (
SELECT id,
ROW_NUMBER() OVER (ORDER BY embedding <=> $2::vector) AS rank
FROM documents
ORDER BY embedding <=> $2::vector
LIMIT 50
),
rrf AS (
SELECT
COALESCE(t.id, f.id, v.id) AS id,
COALESCE(1.0 / (60 + t.rank), 0) +
COALESCE(1.0 / (60 + f.rank), 0) +
COALESCE(1.0 / (60 + v.rank), 0) AS rrf_score
FROM trgm_results t
FULL OUTER JOIN fts_results f ON t.id = f.id
FULL OUTER JOIN vector_results v ON COALESCE(t.id, f.id) = v.id
)
SELECT d.id, d.title, rrf.rrf_score
FROM rrf
JOIN documents d ON d.id = rrf.id
ORDER BY rrf_score DESC
LIMIT 10;

Cela gère : les correspondances floues de noms (trigrammes), les correspondances exactes de mots-clés (FTS) et les requêtes conceptuelles (vecteur). Une seule barre de recherche peut servir les trois intentions utilisateur.


Architectures hybrides multi-couches

Les applications réelles ont rarement une seule surface de recherche. Elles en ont plusieurs, chacune avec un besoin différent :

SurfaceCe que les utilisateurs cherchentCouches recommandées
Recherche blog / documentationMots-clés + conceptsFTS + pgvector (RRF)
Recherche de noms utilisateurs/clientsNoms avec fautes de frappepg_trgm
Recherche de produitsNoms, descriptions, « similaire à »pg_trgm + FTS + pgvector
Déduplication de tickets support« Issues similaires à celle-ci »pgvector uniquement
Recherche SKU/commande interneIdentifiants exactsIndex B-tree
RAG sur grande base de connaissancesQuestions en langage naturelpgvector (documents chunkés)
E-commerce « vous pourriez aussi aimer »Similarité comportementale + sémantiquepgvector
AutocomplétionPréfixe, tolérance orthographiquepg_trgm

Ce ne sont pas des hypothèses. La plupart des applications riches en contenu ont besoin d’au moins deux surfaces de recherche distinctes avec des formes de requête différentes. La tentation est de choisir une approche et de l’utiliser partout — généralement la recherche vectorielle maintenant, puisque c’est le choix à la mode. Cela conduit à des embeddings coûteux pour des problèmes où un index trigramme aurait été plus rapide, moins cher et plus correct.

La règle empirique

Ajoutez une couche quand un mode d’échec apparaît que la couche actuelle ne peut pas corriger :


Si vous avez besoin d’un store vectoriel dédié

pgvector gère beaucoup de recherche applicative avant que vous ayez besoin d’une autre base de données. Le seuil approximatif dépend du nombre de vecteurs, des paramètres d’index, du taux d’écriture, des filtres, du matériel et de la concurrence, donc traitez toute règle « moins de 10M de vecteurs » comme une hypothèse de départ à benchmarker, pas comme une limite produit. Quand vous le dépassez vraiment — très haute concurrence, exigences de latence p99 très basses, milliards de vecteurs, ou besoins sérieux d’isolation multi-tenant — le paysage des bases de données vectorielles dédiées est large et vaut la peine d’être compris.

Ce que signifient réellement les colonnes de la matrice

Recherche hybride signifie que la recherche par mots-clés BM25 et la similarité vectorielle s’exécutent en une seule requête, fusionnées via RRF. Sans cela, vous choisissez soit un mode de recherche, soit vous fusionnez deux requêtes vous-même.

Vecteurs clairsemés (sparse) vont plus loin que BM25. Un vecteur clairsemé SPLADE a ~30 000 dimensions (une par terme de vocabulaire), ~98 % de zéros. Les positions non nulles indiquent quels termes comptent et dans quelle mesure. Une requête pour « chiens » pondère aussi « canin » et « animal de compagnie » — précision niveau BM25 plus expansion de termes à l’intérieur d’un index vectoriel. Si cette colonne est fausse, vous avez besoin d’une couche FTS séparée pour les requêtes de termes exacts.

# SPLADE : ~30 000 dims, ~60 non-nulles — seules les positions de vocabulaire pertinentes s'activent
def encode_splade(text: str) -> dict:
tokens = tokenizer(text, return_tensors="pt", truncation=True, max_length=512)
with torch.no_grad():
output = model(**tokens)
vec = torch.log1p(torch.relu(output.logits)).max(dim=1).values.squeeze()
return {"indices": vec.nonzero().squeeze().tolist(), "values": vec[vec != 0].tolist()}

SQL / similaire à SQL concerne vraiment le filtrage. La recherche vectorielle sans filtrage est une démo. Vous avez toujours besoin du scope tenant, des plages de dates, des permissions et des filtres par catégorie. Le SQL complet (pgvector, LanceDB) exprime cela à côté de vos joins existants. Les bases dédiées utilisent des objets de filtre JSON (Qdrant, Pinecone), un DSL de requête (Elasticsearch, Milvus) ou GraphQL (Weaviate). Ils fonctionnent ; le SQL devient plus attractif à mesure que la logique de filtrage se complexifie.

-- pgvector : la similarité vectorielle n'est qu'une expression parmi d'autres
SELECT id, title, 1 - (embedding <=> $1) AS score
FROM documents
WHERE tenant_id = $2
AND category = ANY($3::text[])
AND created_at > NOW() - INTERVAL '90 days'
ORDER BY embedding <=> $1
LIMIT 10;
# Qdrant : filtre équivalent en objet Python — même résultat, plus de cérémonie
results = client.query_points(
collection_name="documents", query=query_embedding,
query_filter=models.Filter(must=[
models.FieldCondition(key="tenant_id", match=models.MatchValue(value=tenant_id)),
models.FieldCondition(key="category", match=models.MatchAny(any=categories)),
models.FieldCondition(key="created_at", range=models.DatetimeRange(gte=cutoff)),
]),
limit=10,
)

Multimodal natif signifie que la base de données fournit des modèles d’embedding pour du contenu non textuel. Vous lui donnez une URL d’image brute ; elle gère la vectorisation. La plupart des bases sont agnostiques à l’embedding — vous possédez le pipeline d’embedding. Marqo et Weaviate (via les modules CLIP/ImageBind) ferment cette boucle.

# Marqo : POST d'images brutes, requête en texte — aucun step d'embedding externe
mq.index("products").add_documents(
[{"id": "shoe-001", "image": "https://cdn.example.com/shoes/001.jpg"}],
tensor_fields=["image"]
)
results = mq.index("products").search(q="lightweight shoes for summer")
# Retourne shoe-001 malgré zéro superposition de mots-clés — CLIP gère le match cross-modal

Index sur disque est un levier de coût. Les index HNSW résidents en RAM peuvent nécessiter plusieurs Go de RAM par million de vecteurs de 1536 dimensions une fois les vecteurs bruts, le surcoût du graphe et les métadonnées comptabilisés. Les alternatives natives disque (Milvus DiskANN, Elasticsearch DiskBBQ, le format Lance de LanceDB, le tier object storage de Turbopuffer) échangent souvent un peu de latence de requête contre un coût d’infrastructure plus bas. Pour les workloads RAG où la latence du modèle domine déjà, ce compromis vaut souvent le benchmark.

Dimensions max est une migration cachée dans votre architecture. text-embedding-3-large utilise 3072 dims, Jina v3 peut émettre des embeddings plus grands, et les modèles de recherche poussent toujours plus haut. Certains services managés publient des plafonds de dimensions durs ; d’autres documentent des plafonds élevés ou pas de plafond pratique pour les modèles d’embedding typiques. Vérifiez la documentation actuelle avant de vous engager. Choisissez quelque chose avec de la marge ; migrer un index vectoriel parce que vous avez atteint un plafond de dimensions est un sprint douloureux.

Dernière vérification contre la documentation publique des projets et les pages produit le 8 mai 2026. Traitez le tableau ci-dessous comme une aide à la décision, pas comme un substitut à la vérification des limites actuelles, des prix et des feature flags des services managés.

Le paysage

Base de donnéesDéploiementLicenceRecherche hybrideVecteurs clairsemésSQL / similaire SQLMultimodalIndex disqueDims maxSweet Spot
pgvectorSelf-host / managé (Supabase, Neon, RDS)OSS (PostgreSQL)Manuel (RRF via SQL)✅ SQL complet✅ HNSW sur disque16 000 stockage ; 2 000 indexé vectorDéjà sur Postgres ; nombre de vecteurs modéré
QdrantSelf-host / CloudApache 2.0✅ BM25 natif✅ Support mature❌ (REST/gRPC)65 535Requêtes filtrées à grande échelle ; métadonnées complexes
WeaviateSelf-host / CloudBSD 3✅ BM25 natif + RRF❌ (GraphQL / gRPC)✅ via modules65 535Patterns d’accès GraphQL ; vectorisation intégrée
PineconeCloud uniquementPropriétaire✅ (ajouté 2024)✅ (serverless)20 000Simplicité managée ; pas d’équipe ops
Milvus / ZillizSelf-host / Cloud (Zilliz)Apache 2.0✅ Natif✅ Similaire SQL (Milvus Query Language)✅ DiskANN32 768Échelle milliard ; entreprise on-prem
ChromaEmbarqué / self-hostApache 2.065 535Dev local et prototypage uniquement
LanceDBEmbarqué / CloudApache 2.0✅ SQL via DataFusion✅ Natif✅ (format Lance)IllimitéEdge / serverless ; lakehouse multimodal
OramaEmbarqué / CloudApache 2.0✅ Full-text + vectorVarieApps JS/edge ; recherche site/app légère
TurbopufferCloud uniquement (serverless)Propriétaire✅ BM25 + vector✅ (object storage)16 000SaaS multi-tenant ; millions de namespaces
ElasticsearchSelf-host / Elastic CloudSSPL / AGPLv3✅ RRF + ELSER sparse✅ (ELSER)✅ Query DSL✅ DiskBBQ4 096Déjà sur stack Elastic ; recherche entreprise hybride
OpenSearchSelf-host / AWS managéApache 2.0✅ RRF + Neural Search✅ Query DSL✅ FAISS + HNSW16 000Natif AWS ; alternative Elastic open-source
VespaSelf-host / CloudApache 2.0✅ Natif✅ Tensors / classement lexical✅ YQL✅ TensorsEffectivement illimitéRecherche + classement + systèmes de recommandation
ClickHouseSelf-host / CloudApache 2.0Manuel✅ SQL complet✅ Colonnaire + HNSWVarieAnalytics/logs avec recherche vectorielle à côté de l’OLAP
MongoDB AtlasCloud / self-hostSSPL✅ Intégré✅ MQL + aggregation✅ HNSW8 192Déjà sur MongoDB ; document + vector en un
Redis (VSS)Self-host / Redis CloudRSALv2 / SSPL✅ (RediSearch)❌ RAM uniquement32 768Latence ultra-basse ; recherche vectorielle couche cache
MarqoCloud / self-hostApache 2.0✅ Focus natifVarieMultimodal end-to-end : image + texte + vidéo

Quelques éléments qui ne rentrent pas dans le tableau

Le multi-tenancy de Turbopuffer est construit autour de très hauts nombres de namespaces. Son positionnement public et ses études de cas clients mettent en avant des workloads comme le corpus volumineux et lourd en namespaces de Notion. Si chaque utilisateur ou organisation a besoin d’une recherche vectorielle isolée, cette architecture peut changer l’économie, mais benchmarquez toujours votre propre forme de tenant.

Le mode embarqué de LanceDB est ce qui se rapproche le plus de « SQLite pour la recherche vectorielle ». Il s’exécute en-process, ne nécessite aucun serveur, et fonctionne dans Lambda, Cloudflare Workers et les environnements edge. Le format colonnaire Lance rend l’opération embarquée pratique à vraie échelle.

Chroma est le plus fort en dev/test et déploiements de petites applications. Si vous visez de très grands corpus, de la HA, une opération lourde sur disque ou une recherche hybride de première classe, évaluez un store orienté production avant de promouvoir le prototype en infrastructure.

Vespa est ce vers quoi on se tourne quand la récupération n’est que la moitié du produit. Il combine la récupération lexicale, la recherche de plus proches voisins, les tensors, les expressions de classement, le regroupement et le serving en ligne. Cette puissance est réelle, mais la complexité opérationnelle et de modélisation l’est aussi. Il convient plus aux équipes recherche/recommandation qu’à « ajouter de la recherche sémantique à mon app CRUD. »

ClickHouse appartient à la conversation quand la recherche est attachée à l’analytique. Si votre source de vérité est les événements, logs, traces ou métriques, ClickHouse garde la distance vectorielle, le filtrage, l’agrégation et l’indexation full-text sérieuse dans un seul moteur SQL. Pas une base de données vectorielle dédiée, mais souvent la réponse boring-right pour la récupération analytique.

Les vecteurs clairsemés sont comment on obtient une correspondance de mots-clés de qualité BM25 à l’intérieur d’un index vectoriel — sans exécuter un moteur full-text séparé. Qdrant et Elasticsearch ont des implémentations particulièrement matures ici. Si la recherche hybride est critique et qu’une architecture à deux systèmes est un deal-breaker, le support des vecteurs clairsemés est ce qu’il faut chercher.

Choisir quand vous avez dépassé pgvector


La seule chose à ne pas faire

N’utilisez pas la recherche vectorielle comme recherche textuelle floue pour des choses qui ont des réponses correctes.

« Trouve-moi l’utilisateur avec l’email dan@example.com » n’est pas un problème de recherche vectorielle. « Trouve la commande avec l’ID ORD-12345 » non plus. Embarquer ORD-12345 et chercher par similarité cosinus retournera quelque chose — mais ce sera peut-être faux. Un identifiant a une réponse correcte. Une correspondance approximative sur un identifiant est un bug.

La recherche vectorielle retourne la chose la plus similaire dans votre dataset, même quand rien n’est réellement pertinent. Elle ne sait pas quand aucune bonne réponse n’existe. C’est bien pour des documents associés. C’est un problème sérieux pour la recherche d’enregistrement exacte, où une réponse fausse mais confiante est pire qu’un résultat vide.

La même logique s’applique dans l’autre sens : n’utilisez pas le FTS pour des requêtes où l’utilisateur décrit un concept. « articles sur la prise de décisions difficiles sous incertitude » ne contient aucun mot-clé fiable. Le FTS retournera soit du bruit, soit rien. Utilisez le bon outil pour la forme de requête.


Le tableau complet

La plupart des systèmes de recherche en production ont besoin de plus d’une couche :

Ce ne sont pas des outils concurrents. Ils sont complémentaires. Un système de recherche bien construit choisit la bonne couche pour chaque forme de requête — et quand les formes de requête se superposent, il exécute plusieurs couches et fusionne les résultats.

Les équipes qui livrent de bonnes fonctionnalités de recherche comprennent l’ensemble du stack. Celles qui ne le font pas attrapent une base de données vectorielle, embarquent tout, et se demandent pourquoi les recherches exactes retournent parfois le mauvais enregistrement.