L'utilisateur a cherché "chaussures de running Nike bleues taille 10."

Notre recherche sémantique a parfaitement compris l'intention. Elle a retourné des chaussures de running. Des chaussures de sport. Des baskets de performance. Toutes très pertinentes pour le concept de "chaussures de running."

Juste un problème : aucune n'était Nike. Et aucune n'était bleue. Et la taille 10 n'était nulle part dans les filtres.

J'ai fixé les résultats, confus. Le modèle d'embedding comprenait clairement "chaussures de running." Mais il avait décidé que "Nike" et "Adidas" étaient assez proches en sens pour être interchangeables. Ce qui, sémantiquement, est un peu vrai--les deux sont des marques de sport. Mais ce n'est pas ce que l'utilisateur voulait.

Pendant ce temps, notre recherche par mots-clés avait le problème inverse. Quand quelqu'un cherchait "chaussures confortables pour entraînement marathon," elle ne retournait rien. Personne n'avait écrit "entraînement marathon" dans les descriptions de produits. La recherche par mots-clés cherchait des correspondances exactes qui n'existaient pas.

Les deux systèmes de recherche fonctionnaient correctement. Les deux échouaient pour nos utilisateurs.

Le piège : choisir une approche

Quand nous avons ajouté la recherche sémantique pour la première fois, l'équipe a eu un débat : devrait-on remplacer la recherche par mots-clés entièrement, ou les garder séparées ?

Nous avons essayé de remplacer les mots-clés par les vecteurs. Les recherches conceptuelles se sont améliorées. Les correspondances exactes se sont dégradées. Les codes produits ne retournaient rien. Les requêtes spécifiques à une marque retournaient des concurrents.

Nous avons essayé de les garder séparées. "Utiliser la recherche par mots-clés pour les SKUs, la recherche sémantique pour les descriptions." Ça semble raisonnable jusqu'à ce que vous réalisiez : qui décide quel mode utiliser ? L'utilisateur ne sait pas. Et beaucoup de requêtes sont les deux--"chaussures de running Nike bleues" est une requête par mots-clés (Nike, bleu) ET une requête sémantique (chaussures de running).

"Différentes requêtes ont besoin de différents signaux de classement, et vous ne pouvez souvent pas dire à quel type vous avez affaire."

L'insight : on ne peut pas additionner les scores, mais on peut comparer les rangs

Je lisais un article sur la fusion de recherche quand j'ai trouvé l'astuce.

Le problème avec la combinaison de recherche par mots-clés et sémantique est que leurs scores sont incompatibles. La recherche par mots-clés (BM25) peut retourner des scores de 0-20. La recherche vectorielle (similarité cosinus) retourne des scores de 0-1. Vous ne pouvez pas simplement les additionner--les échelles sont complètement différentes et varient par requête.

Mais voici ce que vous pouvez comparer : les positions de rang.

Si un document est classé #1 dans les résultats par mots-clés et #5 dans les résultats sémantiques, ça veut dire quelque chose. Le document est très pertinent pour les mots-clés ET modérément pertinent pour le sens. Les documents qui apparaissent dans les deux listes sont probablement plus pertinents que les documents qui apparaissent dans une seule.

La formule s'appelle Reciprocal Rank Fusion (RRF) : RRF_score = 1/(rang + k) où k est une constante (typiquement 60) qui contrôle à quel point les positions de tête dominent.

Les documents pertinents de plusieurs façons devraient monter au-dessus des documents pertinents d'une seule façon.

L'implémentation

Lancez les deux recherches en parallèle. Construisez des maps de rang pour chacune. Calculez les scores RRF en combinant les rangs réciproques. Triez par score RRF final.

Maintenant "chaussures de running Nike bleues" fonctionne correctement. La recherche sémantique trouve des chaussures de running. La recherche par mots-clés trouve Nike et bleu. Les produits qui correspondent aux deux critères--des chaussures de running Nike qui sont bleues--sont boostés en apparaissant dans les deux ensembles de résultats.

Ce que j'ai mal fait initialement

J'ai lancé les recherches séquentiellement. Grosse erreur. Les deux recherches sont indépendantes--lancez-les en parallèle. La latence totale devrait être max(latence_mots_clés, latence_sémantique), pas la somme.

J'ai oublié les timeouts. Que se passe-t-il quand une recherche timeout ? J'ai ajouté une logique de fallback : si la sémantique timeout, retourner les résultats par mots-clés seuls (avec un flag de qualité). Un hybride dégradé est mieux que pas de résultats.

J'ai utilisé la mauvaise valeur de k. La constante k contrôle à quel point faire confiance aux positions de tête. k=20 fait dominer les positions de tête. k=60 est équilibré (le choix standard). k=100 est démocratique--les positions #1 et #5 ont un poids similaire. J'ai commencé avec k=20 parce que je voulais que les correspondances exactes gagnent. Mais ça rendait les résultats trop étroits--les utilisateurs se plaignaient de ne pas voir d'alternatives. k=60 marchait mieux pour notre cas d'usage.

Je n'ai pas classifié les requêtes. Certaines requêtes sont évidemment que des mots-clés. Codes produits. SKUs. Numéros de modèle. Lancer une recherche sémantique sur "SKU-12345" est du compute gaspillé. J'ai ajouté une classification de requêtes pour sauter les recherches inutiles sur 20% des requêtes sans nuire à la pertinence.

Quand NE PAS utiliser ça


Le takeaway

Pendant des mois, j'ai pensé à la recherche par mots-clés et la recherche sémantique comme des approches concurrentes. Vous en choisissez une. Vous l'optimisez. Vous acceptez ses compromis.

Mais elles ne sont pas en concurrence--elles sont complémentaires. La recherche par mots-clés trouve les termes exacts. La recherche sémantique trouve le sens. RRF les combine sans avoir besoin de normaliser les scores, parce qu'elle ne regarde que les rangs.

"Chaussures de running Nike bleues" retourne maintenant des chaussures de running Nike bleues. La recherche sémantique trouve des produits pertinents pour le running. La recherche par mots-clés trouve des produits qui sont Nike et bleus. Les produits qui satisfont les deux critères flottent vers le haut.

Aucune des recherches ne pouvait le faire seule. Ensemble, elles y arrivent.