Recherche, ranking et recommandation
Trouver un document, ordonner des résultats, suggérer un article : ces trois problèmes partagent la même architecture — réduire des millions de candidats à quelques dizaines, puis les ordonner finement. C'est l'un des domaines applicatifs les plus répandus de la data science, et celui où l'écart entre l'évaluation hors ligne et la réalité est le plus grand.
📋 Au programme
1. L'architecture commune
1. RÉCUPÉRATION (retrieval) millions → quelques centaines de candidats contrainte : quelques millisecondes → modèles simples et INDEXABLES moyens : BM25, index vectoriel ANN (module 22), filtres métier, règles 2. CLASSEMENT (ranking) centaines → dizaines, ordonnées finement contrainte : dizaines de millisecondes → modèle riche autorisé moyens : gradient boosting de ranking, cross-encoder, réseau profond 3. RE-CLASSEMENT MÉTIER ce qui est réellement affiché diversité, fraîcheur, stocks, marges, équité entre fournisseurs, exclusions réglementaires, dé-duplication
Cette séparation est imposée par la latence : on ne peut pas évaluer un modèle coûteux sur un million d'items en 50 ms. Elle a une conséquence souvent négligée : la qualité du système est plafonnée par l'étage de récupération. Un excellent modèle de classement ne peut pas remonter un item que la récupération n'a pas proposé. Quand un système déçoit, c'est donc le rappel de l'étage 1 qu'il faut mesurer en premier — et c'est une mesure simple : sur un jeu de questions annotées, quelle proportion des bons items figure dans les 200 candidats ?
2. Recherche : lexical, sémantique, hybride
Le module 22 présente la recherche dans le cadre du RAG ; les mêmes briques valent pour une recherche destinée à des humains. BM25 (module 18) reste une référence redoutable : il trouve immédiatement les références exactes, les codes produit et les termes rares. La recherche vectorielle gère les reformulations et les synonymes mais échoue sur ces mêmes termes rares, qu'elle n'a souvent jamais vus à l'entraînement.
La combinaison par fusion de rangs réciproques est robuste et sans paramètre à régler :
BM25 renvoie des scores de 0 à 30, le cosinus de -1 à 1 : les additionner n'a aucun sens, et les normaliser suppose de connaître leurs distributions. Les RANGS, eux, sont directement comparables. document A : rang 1 en BM25, rang 8 en vectoriel → 1/61 + 1/68 = 0,0311 document B : rang 3 en BM25, rang 2 en vectoriel → 1/63 + 1/62 = 0,0320 ← devant Un document bien classé par LES DEUX systèmes remonte, même sans être premier.
Le reste du travail se joue sur la requête et les métadonnées : analyse de la requête (correction orthographique, expansion par synonymes, détection d'intention), filtres (catégorie, date, disponibilité) et gestion des requêtes sans résultat, qui sont le principal motif d'abandon. Sur un corpus technique, un simple dictionnaire de synonymes métier rapporte souvent plus qu'un changement de modèle d'embedding.
3. Learning to rank
Classer n'est pas prédire une valeur : seul l'ordre compte, et les premières positions comptent bien plus que les suivantes — personne ne consulte la page 3. Trois formulations :
- Pointwise — prédire un score de pertinence par item, indépendamment des autres. Simple, mais optimise la mauvaise chose : une erreur en position 1 et une erreur en position 50 pèsent pareil.
- Pairwise — apprendre, pour chaque paire, lequel doit passer devant (RankNet, LambdaRank). Beaucoup plus proche de l'objectif réel.
- Listwise — optimiser directement une métrique de liste comme le NDCG. LambdaMART — gradient boosting (module 14) dont les gradients sont pondérés par le gain de NDCG qu'apporterait l'échange de deux documents — reste l'état de l'art pratique, et est disponible directement dans LightGBM et XGBoost (
objective="lambdarank").
La métrique de référence est le NDCG, qui pondère la pertinence par une remise logarithmique sur le rang :
pertinences réelles des 5 résultats affichés : [3, 0, 2, 3, 1] (0 = inutile, 3 = parfait)
DCG = (2³-1)/log₂(2) + (2⁰-1)/log₂(3) + (2²-1)/log₂(4) + (2³-1)/log₂(5) + (2¹-1)/log₂(6)
= 7/1,00 + 0/1,58 + 3/2,00 + 7/2,32 + 1/2,58
= 7 + 0 + 1,5 + 3,02 + 0,39 = 11,91
classement IDÉAL : [3, 3, 2, 1, 0] → IDCG = 7 + 4,42 + 1,5 + 0,43 + 0 = 13,35
NDCG = 11,91 / 13,35 = 0,89
La normalisation par le classement idéal rend les requêtes COMPARABLES entre elles,
ce que ne permettent ni la précision@k ni le MRR.Les variables d'un modèle de ranking se rangent en trois familles : caractéristiques de la requête (longueur, intention, langue), de l'item (popularité, fraîcheur, qualité, prix) et surtout de l'appariement requête-item (scores BM25 par champ, similarité d'embedding, correspondances exactes, historique de clics sur cette paire). Ce sont ces dernières qui portent l'essentiel du signal.
4. Données de clics et biais de position
Les clics sont la source d'étiquettes la plus abondante — et la plus traîtresse. Un item est cliqué parce qu'il est pertinent, mais surtout parce qu'il était affiché en première position. Les études d'oculométrie montrent un taux de clic en première position cinq à dix fois supérieur à celui de la cinquième, à pertinence égale.
Biais de position les premiers résultats sont bien plus cliqués, à pertinence égale
Biais de sélection on n'observe QUE ce qui a été affiché par la politique en place :
les bons items jamais montrés restent invisibles pour toujours
Biais de confiance les utilisateurs font confiance au système et cliquent "par défaut"
Absence de négatif un non-clic ne signifie pas "non pertinent" : peut-être non VU
(d'où l'importance de journaliser ce qui a été réellement affiché)Entraîner naïvement sur les clics revient donc à apprendre le classement actuel et à le figer : le système se confirme lui-même indéfiniment. Les remèdes : la pondération inverse de propension — chaque clic est pondéré par l'inverse de la probabilité d'examen à cette position, ce qui rend son poids comparable quelle que soit la place occupée —, l'estimation de cette courbe de propension par permutations aléatoires contrôlées sur une petite fraction du trafic, et l'utilisation de signaux moins biaisés que le clic brut : temps de lecture, achat, ou retour en arrière rapide, qui est un signal négatif fort.
5. Filtrage collaboratif et factorisation
L'intuition fondatrice : des utilisateurs qui ont aimé les mêmes choses aimeront les mêmes choses ensuite. Aucune connaissance du contenu n'est nécessaire — seule la matrice d'interactions compte, ce qui est à la fois la force (ça marche sur n'importe quel catalogue) et la faiblesse (ça ne marche pas sur un item neuf).
La factorisation matricielle approche cette matrice très creuse \(R\) par un produit de faible rang \(R \approx P Q^\top\), où chaque utilisateur et chaque item sont représentés par un vecteur latent de dimension \(k\) (typiquement 32 à 256) :
μ la moyenne globale (tout le monde note autour de 3,5) b_u le biais UTILISATEUR (cet utilisateur note systématiquement bas) b_i le biais ITEM (ce film plaît à tout le monde) p_uᵀq_i l'affinité SPÉCIFIQUE (cet utilisateur aime CE genre) Les seuls biais expliquent souvent la moitié du signal : les inclure avant toute sophistication est le meilleur premier pas.
C'est l'idée d'approximation de rang faible du module 8, adaptée au cas où la plupart des entrées sont manquantes : on n'ajuste que sur les interactions observées, d'où l'usage de la descente de gradient stochastique ou des moindres carrés alternés (ALS) plutôt que d'une SVD classique, qui exigerait une matrice complète.
6. Retour implicite
Deux réponses. Les méthodes à confiance pondérée (ALS implicite) traitent les non-interactions comme des négatifs de faible poids, et les interactions répétées comme des positifs de poids croissant. Ou bien l'on change d'objectif : BPR (Bayesian Personalised Ranking) n'apprend pas une valeur mais un ordre — il maximise la probabilité qu'un item vu passe devant un item tiré au hasard. L'échantillonnage de ces négatifs est le détail d'implémentation qui décide de la qualité du résultat : tirer uniformément donne des négatifs trop faciles (l'item tiré est évidemment sans intérêt), tirer parmi les items populaires donne des négatifs informatifs.
7. Two-tower et recommandation séquentielle
L'architecture à deux tours est devenue le standard industriel de l'étage de récupération : un réseau encode l'utilisateur et son contexte, un autre encode l'item, et la pertinence est le produit scalaire des deux vecteurs.
utilisateur + contexte item + métadonnées
│ │
[ tour user ] [ tour item ]
│ │
vecteur u ─────── produit ──────── vecteur i
scalaire
L'astuce : les vecteurs d'items se calculent HORS LIGNE et s'indexent dans une
base vectorielle (module 22). Une requête en ligne ne demande qu'un encodage
utilisateur + une recherche ANN. On obtient la souplesse d'un réseau avec la
latence d'un index — impossible avec un modèle qui croiserait user et item
dès la première couche.La recommandation séquentielle (GRU4Rec, SASRec, BERT4Rec) modélise l'historique comme une séquence et prédit l'action suivante — c'est un transformer appliqué à des identifiants d'items (module 16). Elle capture l'intention du moment, ce que la factorisation matricielle, purement statique, ignore complètement : quelqu'un qui vient de consulter trois perceuses n'est pas dans le même état que sa moyenne historique.
Un point à connaître : au-delà du prototype, les gains viennent moins de l'architecture que des variables et de la fraîcheur des données. Un modèle simple réentraîné toutes les heures bat souvent un modèle sophistiqué réentraîné chaque semaine.
8. Évaluer : hors ligne et en ligne
Précision@k / Rappel@k les basiques, faciles à interpréter MAP, MRR position du premier élément pertinent NDCG@k pertinence graduée avec remise logarithmique : la référence Couverture (catalogue) quelle part du catalogue est réellement recommandée ? Diversité intra-liste les k items proposés se ressemblent-ils trop ? Nouveauté / sérendipité recommande-t-on autre chose que les best-sellers ? Équité entre fournisseurs, auteurs, catégories (module 27)
Le découpage des données mérite une attention particulière : un découpage aléatoire est une fuite (module 12), puisqu'il permet d'entraîner sur le futur d'un utilisateur pour prédire son passé. Il faut découper par date et évaluer sur la période suivante — ou, à défaut, exclure les dernières interactions de chaque utilisateur (leave-last-out).
Le décalage hors ligne / en ligne
C'est la caractéristique la plus déroutante du domaine : les gains mesurés hors ligne se traduisent mal en gains réels. Trois raisons. Les données historiques ont été produites par l'ancien système, donc un nouveau modèle qui propose des items jamais affichés est évalué comme s'il se trompait — alors qu'on ne sait tout simplement pas. Les métriques hors ligne mesurent la reproduction du passé, pas la satisfaction. Et l'effet d'un changement met parfois des semaines à se manifester (fidélité, lassitude), bien au-delà de la durée d'un test. La conclusion pratique : l'évaluation hors ligne sert à filtrer les candidats et à éviter les régressions, mais seule une expérience en ligne (module 9) tranche — avec des métriques de garde-fou pour détecter les effets pervers.
9. Démarrage à froid, popularité, boucles
- Démarrage à froid — un nouvel utilisateur ou un nouvel item n'a pas d'historique, donc pas de vecteur latent. Solutions : s'appuyer sur le contenu (attributs, embedding du texte ou de l'image, module 18), recommander par popularité contextualisée, poser deux ou trois questions d'amorçage, ou exploiter un bandit pour explorer rapidement (module 24).
- Biais de popularité — les modèles entraînés sur des interactions amplifient les items déjà populaires, ce qui pénalise la longue traîne et appauvrit le catalogue utile. Correctifs : échantillonnage négatif pondéré par la popularité, pénalisation explicite dans la fonction de perte, ou contrainte de couverture au re-classement.
- Boucle de rétroaction — le système ne voit que les conséquences de ses propres recommandations, ce qui rétrécit progressivement l'exposition (modules 24 et 26). Les parades : conserver une part d'exploration aléatoire, maintenir un groupe témoin permanent, et surveiller la diversité dans le temps comme métrique de santé.
- Contraintes système — latence, coût d'indexation, fraîcheur des embeddings, cohérence entre les variables d'entraînement et celles servies en ligne (module 26). C'est là, plus que dans le modèle, que se situent les vraies difficultés d'ingénierie.
Ce qu'il faut retenir du module
- Architecture en trois étages ; la qualité est plafonnée par le rappel de la récupération.
- Hybride lexical + vectoriel par fusion de rangs : robuste et sans réglage.
- LambdaMART reste l'état de l'art pratique du ranking ; le NDCG est la métrique de référence, et sa normalisation rend les requêtes comparables.
- Les clics sont biaisés par la position : corriger par propension, sinon le système fige son propre classement.
- La factorisation matricielle est une approximation de rang faible sur données manquantes ; les termes de biais portent la moitié du signal.
- En retour implicite, apprendre un ordre (BPR) plutôt qu'une valeur, et soigner l'échantillonnage des négatifs.
- Two-tower pour la récupération, transformer séquentiel pour l'intention du moment.
- Découper par date, et ne conclure qu'en ligne : le décalage hors ligne/en ligne est structurel.