Image de couverture : Recherche multilingue : comment pgvector et les embeddings IA brisent la barrière des langues
tech

Recherche multilingue : comment pgvector et les embeddings IA brisent la barrière des langues

10 June 2026
5 min de lecture
7 vues
Sébastien Muler

La barrière des langues en recherche : un problème concret

Imaginez un utilisateur qui tape « kitchen fail compilation » dans votre moteur de recherche. Votre catalogue contient exactement ce qu'il cherche — une vidéo intitulée 料理 大失敗 まとめ —, mais il ne trouve rien. Zéro résultat. Pourtant, le contenu existe. Le concept est identique. Seule la langue diffère.

C'est précisément ce problème que l'équipe de TopVideoHub a documenté sur dev.to, et leur solution est directement applicable à des contextes e-commerce ou SaaS PHP/Symfony : combiner une recherche plein texte classique avec une recherche sémantique vectorielle alimentée par les embeddings OpenAI et stockée dans PostgreSQL via l'extension pgvector.


Pourquoi la recherche plein texte atteint ses limites

Les moteurs de recherche plein texte comme Elasticsearch, Meilisearch ou même le FTS de PostgreSQL fonctionnent sur un principe lexical : ils indexent des tokens (mots ou segments de mots) et calculent un score de correspondance (BM25, TF-IDF). C'est efficace pour des recherches dans une seule langue, mais structurellement incapable de :

  • Relier des synonymes interlinguistiques : kitchen et 料理 n'ont aucun token en commun.
  • Gérer les paraphrases : « vidéo drôle de chat » ne remonte pas « compilation hilarante de chaton ».
  • Comprendre l'intention : une recherche sur « sons pour s'endormir » ne correspond pas lexicalement à « ASMR relaxation ».

Pour un catalogue multilingue — ou même pour un catalogue en français avec des utilisateurs qui cherchent en anglais — ce plafond de verre devient un vrai problème business.


L'architecture hybride : FTS + pgvector

La solution ne consiste pas à remplacer la recherche plein texte existante, mais à l'augmenter avec une couche sémantique. L'architecture repose sur deux composants :

1. Les embeddings OpenAI pour la représentation sémantique

Un embedding est un vecteur de nombres flottants (par exemple 1536 dimensions pour text-embedding-3-small) qui encode le sens d'un texte, indépendamment de sa langue. Deux phrases sémantiquement proches auront des vecteurs proches dans cet espace, même si elles sont dans des langues différentes.

Concrètement, lors de l'indexation de chaque fiche produit ou contenu, on génère son embedding :

// Exemple simplifié avec le SDK OpenAI en PHP
$response = $openai->embeddings()->create([
    'model' => 'text-embedding-3-small',
    'input' => $product->getSearchableText(), // titre + description + tags
]);

$vector = $response->embeddings[0]->embedding; // tableau de 1536 floats

Cet vecteur est ensuite stocké en base de données.

2. pgvector pour le stockage et la recherche vectorielle

pgvector est une extension PostgreSQL qui ajoute un type vector et des opérateurs de distance (cosinus, L2, produit scalaire). Le schéma est minimal :

CREATE EXTENSION IF NOT EXISTS vector;

ALTER TABLE products
    ADD COLUMN embedding vector(1536);

-- Index HNSW pour des recherches approximatives rapides
CREATE INDEX ON products
    USING hnsw (embedding vector_cosine_ops)
    WITH (m = 16, ef_construction = 64);

Une recherche sémantique devient alors une simple requête SQL :

SELECT id, title, 1 - (embedding <=> $1::vector) AS similarity
FROM products
ORDER BY embedding <=> $1::vector
LIMIT 20;

$1 est le vecteur de la requête utilisateur, lui aussi encodé via OpenAI au moment de la recherche.


Le ranking hybride : combiner les deux scores

Ni la recherche lexicale ni la recherche vectorielle n'est parfaite seule. L'approche qui fonctionne en production consiste à fusionner les deux scores avec une pondération ajustable.

Une formule simple et efficace :

$finalScore = ($alpha * $bm25Score) + ((1 - $alpha) * $semanticScore);

Avec $alpha entre 0 et 1 selon le contexte :

  • Pour une recherche e-commerce avec des références produit exactes → favoriser BM25 ($alpha élevé)
  • Pour une recherche conceptuelle ou multilingue → favoriser le sémantique ($alpha faible)

Dans un contexte Symfony, ce paramètre peut être exposé via la configuration de l'application ou ajusté dynamiquement selon la nature de la requête (présence de caractères non-ASCII, longueur de la requête, etc.).


Ce que ça change concrètement pour vos utilisateurs

Cette architecture permet des cas d'usage qui étaient impossibles avec une recherche classique :

  • Un client francophone cherche « imperméable léger randonnée » et trouve des produits dont la fiche est rédigée en anglais (lightweight waterproof hiking jacket).
  • Un utilisateur tape une description approximative (« truc pour faire du café sans machine ») et remonte une cafetière à piston.
  • Une recherche en japonais dans un catalogue principalement en français fonctionne nativement.

Le tout sans avoir à maintenir des traductions ou des dictionnaires de synonymes.


Considérations pratiques pour un projet Symfony/PHP

Coût des embeddings : chaque appel à l'API OpenAI pour générer un embedding a un coût. Il faut mettre en place un pipeline d'indexation asynchrone (avec Messenger par exemple) et ne jamais regénérer un embedding si le contenu n'a pas changé.

Latence au moment de la recherche : l'embedding de la requête utilisateur doit être calculé en temps réel (~100-200ms). Il est possible de le mettre en cache pour les requêtes fréquentes.

Dimensionnalité : text-embedding-3-small (1536 dimensions) offre un bon équilibre coût/performance. Pour des catalogues très larges, envisager text-embedding-3-large uniquement si la qualité de retrieval est insuffisante.

Migration progressive : il n'est pas nécessaire de tout migrer d'un coup. On peut déployer la recherche vectorielle en parallèle, l'activer sur certaines catégories de produits ou pour un pourcentage d'utilisateurs, et mesurer l'impact avant de généraliser.


Conclusion

La combinaison pgvector + embeddings OpenAI + recherche plein texte classique représente aujourd'hui l'état de l'art accessible pour tout projet PHP/Symfony qui gère un catalogue multilingue ou qui veut offrir une expérience de recherche plus intelligente. L'effort d'intégration est raisonnable, l'infrastructure reste PostgreSQL (que vous utilisez probablement déjà), et le gain pour l'utilisateur final est immédiat.

La barrière de la langue en recherche n'est plus une fatalité technique — c'est désormais une question d'architecture.

📖 Cet article s'inspire de la publication originale de Ahmet Gedik sur dev.to, adaptée au contexte PHP/Symfony.

Partager cet article