Comment nous avons appris à prédire la demande d'un utilisateur et à accélérer le chargement des résultats de recherche

Les suggestions de recherche (sjest) ne sont pas seulement un service utilisateur, mais également un modèle de langage très puissant qui stocke des milliards de requêtes de recherche, prend en charge la recherche floue, la personnalisation et bien plus encore. Nous avons appris à utiliser sujest afin de prédire la requête finale de l'utilisateur et de charger les résultats de la recherche avant de cliquer sur le bouton «Rechercher».


L'introduction de cette technologie - le pré-rendu - a nécessité de nombreuses solutions intéressantes dans le développement mobile, le développement du runtime de recherche, des journaux et des métriques. Et, bien sûr, nous avions besoin d'un classificateur sympa qui détermine s'il faut charger une requête de recherche à l'avance: ce classificateur doit trouver un équilibre entre l'accélération de téléchargement, le trafic supplémentaire et la charge de recherche. Aujourd'hui, je vais parler de la façon dont nous avons réussi à créer un tel classificateur.




1. L'idée fonctionnera-t-elle?


Dans les tâches de recherche, il est rarement clair à l'avance qu'une bonne solution existe. Et dans notre cas, nous ne savions pas non plus au départ quelles données étaient nécessaires pour construire un classificateur suffisamment bon. Dans une telle situation, il est utile de commencer par quelques modèles très simples qui vous permettent d'évaluer les avantages potentiels du développement.


L'idée la plus simple s'est avérée être la suivante: nous chargerons les résultats de la recherche à la première invite de la suggestion de recherche; lorsque l'invite change, nous supprimons le téléchargement précédent et commençons à télécharger un nouveau candidat. Il s'est avéré qu'un tel algorithme fonctionne bien et presque toutes les demandes peuvent être préchargées, cependant, la charge sur les backends de recherche augmente en conséquence et le trafic utilisateur augmente en conséquence. Il est clair qu'une telle solution ne peut pas être mise en œuvre.


L'idée suivante était également assez simple: il est nécessaire de charger les indices de recherche probables non pas dans tous les cas, mais uniquement lorsque nous sommes suffisamment convaincus qu'ils sont vraiment nécessaires. La solution la plus simple serait un classificateur qui fonctionne directement en runtime en fonction des données que possède déjà le sajest.


Le premier classificateur a été construit en utilisant seulement dix facteurs. Ces facteurs dépendent de la distribution des probabilités sur l'ensemble des invites (idée: plus le «poids» de la première invite est élevé, plus il est probable qu'il soit saisi) et de la longueur de l'entrée (idée: moins l'utilisateur doit saisir de lettres, plus il est sûr de précharger). La beauté de ce classificateur était aussi que pour le construire, il n'était pas nécessaire de libérer quoi que ce soit. Les facteurs nécessaires pour le candidat peuvent être collectés en faisant une requête http au démon sajest, et les cibles sont construites selon les journaux les plus simples: le candidat est considéré comme "bon" si la demande totale de l'utilisateur la correspond complètement. Il a été possible de constituer un tel pool, de former plusieurs régressions logistiques et de construire un diagramme de dispersion en quelques heures seulement.


Les métriques du pré-rendu ne sont pas complètement organisées comme dans la classification binaire habituelle. Seuls deux paramètres sont importants, mais ce n'est pas la précision ou l'exhaustivité.


Soit r- nombre total de demandes, p- le nombre total de tous les prétendants, ep- le nombre total de prétendants réussis, c'est-à-dire ceux qui correspondent finalement à l'entrée de l'utilisateur. Ensuite, deux caractéristiques intéressantes sont calculées comme suit:


overhead= fracp+repr1


efficacité= fracepr


Par exemple, si exactement un prérendeur par demande est effectué et que la moitié des prérendeurs réussissent, l'efficacité du prérendeur sera de 50%, ce qui signifie qu'il a été possible d'accélérer le chargement de la moitié des demandes. Dans le même temps, pour les demandes dans lesquelles le prérendeur a réussi, aucun trafic supplémentaire n'a été créé; pour les demandes pour lesquelles le prérendeur a échoué, une demande supplémentaire a dû être définie; donc le nombre total de demandes est une fois et demie plus grand que l'original, les demandes «supplémentaires» 50% du nombre d'origine, donc fraisgénéraux=0,5.


Dans ces coordonnées, j'ai dessiné le premier nuage de points. Il ressemblait à ceci:



Ces valeurs contenaient une bonne quantité d'hypothèses, mais au moins il était déjà clair que, très probablement, un bon classificateur fonctionnerait: accélérer le chargement de plusieurs dizaines de pour cent des demandes, augmenter la charge de plusieurs dizaines de pour cent est un changement intéressant.


C'était intéressant de voir comment fonctionne le classificateur. En effet, il s'est avéré que la longueur de la requête s'est avérée être un facteur très fort: si l'utilisateur a déjà presque saisi le premier indice, et il est fort probable en même temps, vous pouvez pré-extraire. Ainsi, la prédiction du classificateur augmente fortement vers la fin de la requête.


margin prefix candidate -180.424   -96.096    -67.425    -198.641    -138.851    -123.803    -109.841    -96.805    -146.568     -135.725     -125.448     -58.615      31.414     -66.754      1.716         

Un prérendeur sera utile même s'il s'est produit au moment de la saisie de la toute dernière lettre de la demande. Le fait est que les utilisateurs passent encore un peu de temps à cliquer sur le bouton «Rechercher» après avoir saisi la demande. Ce temps peut également être enregistré.


2. Première mise en œuvre


Après un certain temps, il a été possible d'assembler un design pleinement fonctionnel: l'application a recherché des indices de recherche dans le démon du sajest. Il a envoyé, entre autres, des informations sur l'opportunité de précharger le premier indice. L'application, ayant reçu l'indicateur approprié, a téléchargé les résultats et, si la saisie de l'utilisateur a finalement coïncidé avec le candidat, a rendu les résultats.


À ce moment, le classificateur a acquis de nouveaux facteurs, et le modèle n'était plus une régression logistique, mais tout à fait un CatBoost . Initialement, nous avons déployé des seuils assez conservateurs pour le classificateur, mais même ils nous ont permis de charger instantanément près de 10% des résultats de recherche. Ce fut une version très réussie, car nous avons réussi à déplacer de manière significative les quantiles mineurs de la vitesse de téléchargement du SERP, et les utilisateurs l'ont remarqué et ont commencé à revenir statistiquement de manière significative à la recherche: une accélération significative de la recherche a affecté la fréquence des utilisateurs effectuant des sessions de recherche!


3. Autres améliorations


Bien que la mise en œuvre ait réussi, la solution était encore extrêmement imparfaite. Une étude approfondie des journaux d'opérations a montré qu'il existe plusieurs problèmes.


  1. Le classificateur est instable. Par exemple, il peut s'avérer que par le préfixe Yandex il prédit la demande Yandex, par le préfixe Yandex il ne prédit rien et par le préfixe Yandex il prédit à nouveau la demande Yandex. Ensuite, notre première implémentation simple fait deux demandes, même si elle pourrait bien se gérer avec une seule.


  2. Le prérendeur ne sait pas comment traiter les indices mot à mot. Un clic sur une invite de mot à mot fait apparaître un espace supplémentaire dans la demande. Par exemple, si un utilisateur a entré Yandex, sa première invite serait Yandex; mais si l'utilisateur a utilisé l'indication mot par mot, l'entrée sera déjà la chaîne «Yandex» et la première invite sera «Cartes Yandex». Cela entraînera des conséquences désastreuses: la demande Yandex déjà téléchargée sera rejetée, mais la demande de carte Yandex sera chargée. Après cela, l'utilisateur clique sur le bouton «Rechercher» et ... attendra la livraison complète de l'émission à la demande de Yandex.


  3. Dans certains cas, les candidats n'ont aucune chance de réussir. Une recherche de coïncidence inexacte fonctionne de la manière la plus sujette, de sorte que le candidat ne peut, par exemple, contenir qu'un seul mot parmi ceux saisis par l'utilisateur; ou l'utilisateur peut faire une faute de frappe, puis la première invite ne correspondra jamais exactement à son entrée.



Bien sûr, laisser une prérenderie avec de telles imperfections était une honte, même si elle était utile. J'ai été particulièrement offensé par le problème des indices mot à mot. Je considère l' introduction de conseils de mot à mot dans la recherche mobile Yandex comme l'une de mes meilleures implémentations depuis tout le temps que j'ai travaillé dans l'entreprise, mais ici le prérendeur ne sait pas comment travailler avec eux! Dommage, pas autrement.


Tout d'abord, nous avons résolu le problème de l'instabilité du classifieur. La solution a été choisie très simple: même si le classifieur a retourné une prédiction négative, nous n'arrêtons pas de charger le candidat précédent. Cela permet d'économiser des demandes supplémentaires, car lorsque le même candidat reviendra la prochaine fois, vous n'aurez pas besoin de télécharger à nouveau le problème correspondant. En même temps, cela vous permet de charger les résultats plus rapidement, car le candidat est téléchargé au moment où le classificateur a travaillé pour lui pour la première fois.


Puis vint le tour des indices proverbiaux. Un serveur sagest est un démon sans état, il est donc difficile d'implémenter la logique associée au traitement du candidat précédent pour le même utilisateur. Rechercher simultanément des invites pour une demande d'utilisateur et une demande d'utilisateur sans espace de fin signifie en fait doubler le RPS par un démon sajest, ce n'était donc pas une bonne option non plus. En conséquence, nous l'avons fait: le client passe dans un paramètre spécial le texte du candidat, qui se charge en ce moment; si ce candidat, jusqu'à des espaces, est similaire à l'entrée utilisateur, nous le donnons, même si le candidat pour l'entrée actuelle a changé.


Après cette version, il est finalement devenu possible de saisir des requêtes à l'aide d'invites mot à mot et de profiter de la prélecture! C'est assez drôle qu'avant cette version, seuls les utilisateurs qui avaient fini de saisir leur demande à l'aide du clavier, sans un sjest, utilisaient la prélecture.


Enfin, nous avons réglé le troisième problème à l'aide de ML: ajout de facteurs sur les sources d'indices, coïncidence avec les entrées des utilisateurs; de plus, grâce au premier lancement, nous avons pu collecter plus de statistiques et apprendre des données mensuelles.


4. Quel est le résultat


Chacune de ces versions a généré des dizaines de pour cent d'augmentation des téléchargements instantanés. La meilleure partie est que nous avons pu améliorer les performances de la pré-rendu de plus de deux fois, pratiquement sans toucher à la partie sur l'apprentissage automatique, mais seulement en améliorant la physique du processus. C'est une leçon importante: souvent la qualité du classificateur n'est pas le goulot d'étranglement du produit, mais son amélioration est la tâche la plus intéressante et donc le développement en est distrait.


Malheureusement, les SERP instantanément chargés ne sont pas un succès complet; la sortie chargée doit encore être rendue , ce qui ne se produit pas instantanément. Nous devons donc encore travailler pour mieux convertir les téléchargements de données instantanés en rendus instantanés des résultats de recherche.


Heureusement, les implémentations implémentées nous permettent déjà de parler du pré-rendu comme d'une fonctionnalité assez stable; nous avons également testé les implémentations décrites dans la clause 2: toutes ensemble conduisent également au fait que les utilisateurs eux-mêmes commencent à effectuer des sessions de recherche plus souvent. C'est une autre leçon utile: des améliorations significatives de la vitesse du service peuvent affecter statistiquement de manière significative sa rétention.


Dans la vidéo ci-dessous, vous pouvez voir comment le prérendeur fonctionne maintenant sur mon téléphone.


Source: https://habr.com/ru/post/fr455427/


All Articles