Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Comment améliorer la recherche ? #4098

Open
pierre-24 opened this issue Dec 25, 2016 · 9 comments
Open

Comment améliorer la recherche ? #4098

pierre-24 opened this issue Dec 25, 2016 · 9 comments
Labels
C-Back Concerne le back-end Django C-Search Concerne la recherche (et ElasticSearch) Feedback Ticket ou PR en attente de retours

Comments

@pierre-24
Copy link
Member

pierre-24 commented Dec 25, 2016

Zoyeux nowel les gens !

Puisque c'est enfin noël, donc enfin les vacances, j'ai (enfin) du temps pour m'attaquer à un truc que je garde en tête depuis deux mois : la recherche (voir #4096). En effet, @SpaceFox a déjà dit plusieurs fois qu'il vaudrait mieux passer à Elasticsearch (ES), plus puissant (ou en fait plus exploitable, puisque dessous, c'est Lucene à chaque fois) que ce que ZdS utilise actuellement. Bref, une meilleure recherche et un retour de la barre de recherche en barre d’accueil. D'ailleurs, je cite le renard :

[...] Ensuite, contrairement à aujourd'hui où on renvoie tous les résultats en vrac, il faudrait catégoriser les résultats (contenus rédigés d'abord, forums ensuite) et les champs de recherche (terme trouvé dans le titre prioritaire sur le terme trouvé dans le corps de texte, avec un système de poids – de mémoire c'est assez simple à faire).

Sauf que pour ça, il va falloir répondre à la question "qu'est ce qu'on attend comme résultat d'une recherche".

Quelques éléments avant de continuer

En préambule, il est important de savoir que ES classe ces données en documents, qui correspondent grosso modo à une ligne de BDD (on est dans un contexte NoSQL), donc un post, un topic (qui sont différents types de document), etc.

Scoring et boosting

Avant toute chose, il est bon de comprendre comment ES classe les résultats suite à une recherche. Si on effectue la recherche d'un terme dans l'ensemble des documents, ceux-ci sont classés par score, que ES calcule comme étant le produit TF * IDF, où la partie TF (term frequencies) est le nombre de fois qu'un terme apparait dans un document et IDF (inverse document frequencies) est l'importance du terme dans l'ensemble des documents.

Évidement, l'histoire ne s'arrête pas là, puisqu'on peut modifier le score par différents moyens, qui relèvent du boost:

  • Booster des champs à priori : si le terme recherché est contenu dans un champ, le score est multiplié par le facteur de boost du champ (par défaut, 1.0).
  • Booster le score à postériori: si le document obtenu possède d'autres propriétés (exemple idiot, booster le score si le post trouvé à "aidé l'auteur du sujet").
  • Booster un type de document par rapport à un autre : c'est un cas particulier du précédent, mais je tenais à le préciser.

Actuellement, je n'ai aucune idée de l'ordre de grandeur du facteur de boost, si c'est 2, 5, 10 ou 100, j'ai pas encore eu assez de données pour tester. Dans l'absolu, il faudra ajuster ça empiriquement.

tokenizer(s) et analyzer(s)

Afin d'effectuer ces recherches, le mieux est de ne pas faire des recherches fulltext (passer tout le texte en revue) mais de ne rechercher que certains termes. Par ailleurs, il est toujours mieux d'éviter d'avoir à ce casser la tête avec les problèmes de singulier/pluriel (par défaut "table" et "tables" ne sont pas les mêmes mots).

Du coup, chaque champ indexé passe par un analyzer, découpé en trois étapes :

Entrée → character filter → tokenizer → token filter → sortie
  • character filter: tâche de nettoyage basique, telle qu'enlever les tags HTML (oui, ES fait le job pour nous si on lui demande gentiment). Il y en a trois qui sont disponibles par défaut et qui font plus ou moins de remplacement (HTML, terme et expression régulière) ;
  • tokenizer: découpe le texte en différents tokens. Bon, y'a plein de tokenizer disponibles, mais par défaut, il coupe après chaque espace.
  • token filter: altère la liste de tokens obtenue pour les "normaliser", en enlevant ou modifiant les tokens. Typiquement: enlever certains mots ("le", "la", "les" et autres en français), convertir les caractères unicodes en caractères ASCII standard, convertir le tout en minuscule, et ainsi de suite. Et encore une fois, y'en a une pléthore qui sont disponibles.

Et de manière générale, y'a moyen d'expliquer à ES que nous, on cause français, donc c'est plutôt pas mal.

Ici, je propose très clairement d'utiliser un analyzer qui comprend le français (donc qui vire les déterminants et met les mots au singulier), qui vire le HTML, qui passe tout en minuscule et qui remappe tout en ascii standard. Si vous voyez d'autres token filter intéressants, dites le moi.

Et alors ?

Bon, je me répette, le but du jeu, c'est d'avoir la recherche la plus performante possible. Évidement, y'a pas de réponse unique, même Google n'a pas encore trouvé ;)

Quoi ?

Premièrement, il faut se mettre d'accord sur ce qu'on on indexe. Actuellement, il s'agit de

  • Topics ;
  • Posts ;
  • Contenus (articles, tutos, futurs tribunes)
  • Extraits et conteneur des contenus

À noter qu'à différents moments, on a également proposé d'indexer les utilisateurs. En soit, c'est pas difficile, mais à part le nom (et éventuellement la biographie), je vois pas trop quoi indexer.

Je propose éventuellement de booster les contenus sur les résultats issus du forum, mais tout dépend ce qu'on cherche à récupérer de la recherche. Je propose également de booster les topics par rapport aux messages et les contenus par rapport à ce qu'ils contiennent. La logiquue étant que si le terme recherché est dans le titre (du topic ou du contenu), il y a beaucoup de chance que la discussion porte dessus.

Comment ?

Deuxièmement, il faut définir ce qu'on indexe pour chacun des modèles (et comment on les boostent, éventuellement). Et troisièmement, il faut définir ce qui affecte les résultats.

Voici une petite proposition (notez que comme j'ai dit, je n'ai aucune idée de la valeur du facteur de boost, je place juste un ordre d'importance).

Topic

Champ Indexation Boost
Titre Oui 2.0
Sous-titre Oui 1.5
Forum Oui ---
Auteur Non ---
Dernier message Non ---
Est résolu éventuellement 1.0
Est verrouillé éventuellement 1.0
Est en post-it éventuellement 1.0
Tags du forum Oui 3.0
  • Les topics en post-it sont boostés ;
  • Les topics résolus sont boostés ;
  • Les topics verouillés sont dévallués (à discuter, puisque tout les sujets de bêta finissent verouillés) ;
  • Il faut tenir compte que certains topics sont dans des forums privés.

Post

Champ Indexation Boost
Auteur Non ---
Editeur Non ---
Adresse IP de l'auteur Non ---
Position éventuellement 1.0
Texte Non ---
Texte en Html Oui 2.0
Likes éventuellement 1.0
Dislikes éventuellement 1.0
Date de publication éventuellement 1.0
Date d'édition Non ---
Est visible Oui 1.0
Texte de masquage Non --
Est utile éventuellement
  • On peut éventuellement booster (ou pas) en fonction du ratio like/dislike, mais c'est dangereux. Pareil pour le "est utile" ;
  • On peut éventuellement booster les posts plus récents (à la Google) ;
  • On peut éventuellement booster un peu le post si c'est le premier du topic ;
  • On doit supprimer tout les posts qui sont masqués ;
  • Pas oublier de tenir compte que certains posts sont issus de topics situés dans des forums privés.

Contenus

(en fait les contenus publiés)

Champ Indexation Boost
Type de contenu éventuellement 1.0
Slug du contenu publié Non ---
Pk du contenu publié Non ---
Date de publication éventuellement ---
Date de mise à jour éventuellement ---
Auteurs Non ----
Tailles des fichiers téléchargeables Non ---

(... et de la partie non publiée)

Champ Indexation Boost
Titre Oui 2.0
Description Oui 1.5
Old pk Non ---
Sous-Catégorie Oui 3.0
Tags du contenu Oui 3.0
Image du tutoriel Non ---
Galerie d'images Non ---
Sujet beta associé Non ---
Licence Non ---
Aides Non ---
Chemin relatif images Non ---
Derniere note Non ---
Est verrouillé Non ---
Support du Javascript Non ---
  • On peut éventuellement booster les contenus plus récents (à la Google) ;
  • On peut éventuellement booster un certain type de contenu par rapport à un autre ;
  • On peut éventuellement booster les billets qui sont en page d'acceuil.

Extraits et conteneurs

Tout d'abord, je propose de ne pas indexer tout les conteneurs et ne pas indexer les extraits tels quels, mais seulement la forme qu'ils ont quand ils sont publiées, soit tout les extraits d'un même chapitre rassemblés.

Cette proposition est assez forte, mais possède selon moi plusieurs avantages:

  • Tout le parsing md → html est déjà fait à la publication, il "suffit" de lire le fichier HTML généré et de l'indexer.
  • Pas besoin de taper dans git, ce qui n'est jamais un désavantage.
  • Est-il vraiment nécessaire d'avoir une granularité aussi fine (parties, chapitres, sections) dans les résultats de recherche ?

Mais évidement, ça se discute.

Et du coup,

Champ Indexation Boost
Titre Oui 2.0
slug Non ---
introduction Non ---
conclusion Non ---
parent Non ---
Position dans le parent Non ---
Enfants Non ---
Contenu Oui 1.0
  • Ici, je vois pas l'intérêt de booster en fonction de la position
  • Comme j'ai dit, l'intro et la conclusion sont déjà dans le champ "contenu", qui est le résultat de la publication, parsé en HTML et toussa :)

Et donc ?

Si on suis ce que je viens de dire, ce qu'on obtient est une recherche qui sort en priorité les contenus sur les forums, qui donne la priorité aux tags et au titre envers les différents champs de texte et qui discrimine éventuellement selon différents critères plus ou moins objectifs (date de publication, position, ...).

C'est un peu ma vision de ce que la recherche devrait donner, mais c'est ma vision, donc n'hésitez pas à argumenter.

Bon amusement ;)

@artragis
Copy link
Member

Bonjour,

Pour revenir sur la différence boost solr/boost elastic search : le boost solr est forcément normalisé, et la somme des boosts d'un document est égale à 1 (du moins c'est ce que disait la documentation haystack), sur elastic search, tu peux clairement booster plus librement, et quand il y a de la liberté, je suis un fan de la suite de fibonacci. (1, 2, 3, 5, 8, 13, 21... mais je pense que déjà 13 c'est énorme)

Je pense clairement qu'il faut booster les posts en fonction des +/-1. Il ne sert pas de les booster en mode stéroïde mais au moins la pertinence sera accrue.

Sinon je vois que tu as mis un "éventuellement" à "est utile". Je pense qu'il faut clairement indexer ça quitte à booster légèrement.

Autre chose qui m'a clairement choqué : tu n'indexe pas la licence. Pour moi on doit --dans le futur-- donner la possibilité aux gens qui le veulent, surtout si le nombre de contenus augmente toujours, la possibilité de filtrer en fonction des licences. Le libre c'est aussi ça.

Pour l'idée de réduire la granularité de stockage, tu reviens aux origines de la zep-12 qu'on avait dû abandonner à cause de haystack, donc je te soutiens totalement.

@pierre-24
Copy link
Member Author

Je pense clairement qu'il faut booster les posts en fonction des +/-1. Il ne sert pas de les booster en mode stéroïde mais au moins la pertinence sera accrue.

Je suis d'accord, mais j'ai peur de faire ressortir les trolls, qui se mangent plein de pouces verts ;)

Sinon je vois que tu as mis un "éventuellement" à "est utile". Je pense qu'il faut clairement indexer ça quitte à booster légèrement.

Chui d'accord :)

Autre chose qui m'a clairement choqué : tu n'indexe pas la licence. Pour moi on doit --dans le futur-- donner la possibilité aux gens qui le veulent, surtout si le nombre de contenus augmente toujours, la possibilité de filtrer en fonction des licences. Le libre c'est aussi ça.

Oui. Après, y'a deux solution : soit j'indexe uniquement ce qui est actuellement nécessaire (j'ai besoin d'un petit peu plus que ce que j'ai présenté, en pratique, pour l'affichage), soit j'indexe tout les champs potentiels en disant "ça servira bien un jour". Faut voir ce que ça nous coute en terme de stockage et de réactivité :)

Pour l'idée de réduire la granularité de stockage, tu reviens aux origines de la zep-12 qu'on avait dû abandonner à cause de haystack, donc je te soutiens totalement.

Me souvenais plus qu'on aie dit ça, mais ça doit être pour ça que ça ressort instinctivement aujourd'hui :)

Après, en pratique, je sais pas encore exactement comment je vais indexer ça convenablement. J'ai 2 pistes, on verra ce que ça va donner :)

@artragis
Copy link
Member

Me souvenais plus qu'on aie dit ça, mais ça doit être pour ça que ça ressort instinctivement aujourd'hui :)

bah en fait au départ on avait dit qu'on ferait tout pivoter sur le html généré pour un chapitre. Mais quand on est arrivé à la recherche on s'est rendu compte que haystack n'aimait pas trop alors on a demandé de l'aide à Hugo.

Je pense qu'il faut faire confiance à elasticsearch : indexer en français à partir d'un texte html, le truc sait très bien le faire.

@pierre-24 pierre-24 added C-Back Concerne le back-end Django Feedback Ticket ou PR en attente de retours S-Évolution labels Dec 26, 2016
@Situphen
Copy link
Member

Cette idée est super chouette !

Les topics verouillés sont dévallués (à discuter, puisque tout les sujets de bêta finissent verouillés) ;

Les sujets de la bêta finissent verrouillés quand ils vont en validation et/ou qu'ils sont publiés non ? Donc personnellement je n'en tiendrait pas compte et je resterais sur du "les topics verrouillés sont dévalués" :)

@pierre-24
Copy link
Member Author

Disons que je suis très prudent et que je demande au gens de vérifier que j'ai pas oublié quelque chose :)

@DevHugo
Copy link
Contributor

DevHugo commented Jan 9, 2017

Je suis désolé, j'était partis en vacances et du coup, j'arrive un peu après la bataille !

Je pense qu'il faut faire confiance à elasticsearch : indexer en français à partir d'un texte html, le truc sait > très bien le faire.

Pour solr, j'avais pas trouvé de tokenizer, token filter ou autre qui vire toutes les balises HTML ! Du coup, je le faisait à la main. Si tu as trouvé comment faire mieux, bravo a toi !

Ne pas prendre ce message comme un souhait de truc à implémenter de suite, la PR en cours est très bien comme elle est, on pourrait améliorer avec le temps. C'est plus la liste de noël (comment ça noël est déjà passé ?) ^^

Je pense que c'est déjà un énorme pas, mais que la discussion n'a pas porté sur un point pour moi qui est aussi important que la pertinence des algos du moteur de recherche, les critères de recherche et même peut-être qui serais encore mieux, les facets.

Pour moi, tu va arriver rapidement à la limite de ce que tu peux faire pour aider le moteur de recherche à fournir des résultats pertinent. Il va falloir jouer sur plusieurs autres tableaux.

Facet

Spacefox, à l'époque avait fournit une liste de facet:

Tutoriels, articles, tribunes publiés

  • Tags hiérarchiques (facette)
  • Titre
  • Sous-titre
  • Date de publication (facette)
  • Date de dernière mise à jour (facette)
  • Auteurs (facette)
  • Contenu intégral (toutes les intros, toutes les conclusions, toutes les parties)

Sujets de forums

  • Tags hiérarchiques (facette)
  • Titre
  • Sous-titre
  • Date de publication (facette)
  • Date du dernier post (facette)
  • Auteur (facette)
  • Groupe d'appartenance (public ou non)
  • Contenu du premier message

Messages de forums

  • Sujet
  • Auteur (facette)
  • Date de publication (facette)
  • Groupe d'appartenance (public ou non)
  • Contenu du message
    Source

ElasticSearch fait ça de base, faut juste attaquer la bonne adresse. Avec Solr, c'était assez simple, je suppose qu'avec ElasticSearch ça doit être aussi facile.

Tu peux ajouter des critères de recherche comme « Est résolu », « Est en post-it », « Est verrouillé ».

Sur le moteur de recherche

Pour les topics, tu as mit que tu voulais indexer les forums. Je suis complètement d'accord qu'il va falloir enregistrer la donnée pour pouvoir après afficher le bon forum selon les droits correspondant aux utilisateurs. Mais je suis pas sur que l'indexer directement sans jouer sur son boosting soit une bonne idée. Si l'utilisateur tape dans la recherche un mot clé contenant le nom d'un forum, il va se retrouver avec tous les sujets du forum. Ça va si les contenus sont boostés suffisamment pour apparaître en premier mais sinon les résultats pertinents vont être fondu dans la masse.
Pour les deux boost : Je pense que c'est une très bonne idée de booster les 2 attributs Est résolu, Est en post-it. Mais je vois ça plus comme des critères de recherche.

Tu es sur que tu dois indexer ce type de champ ? j'aurais juste sauvegardé son contenu sans l'indexer.

@pierre-24
Copy link
Member Author

Grosso modo, je suis d'accord avec ce que tu dis sur les facets, à terme ce serait beaucoup plus gérable de les utiliser. Et oui, c'est facile avec ES ;)

Pour les topics, tu as mit que tu voulais indexer les forums. Je suis complètement d'accord qu'il va falloir enregistrer la donnée pour pouvoir après afficher le bon forum selon les droits correspondant aux utilisateurs. Mais je suis pas sur que l'indexer directement sans jouer sur son boosting soit une bonne idée. Si l'utilisateur tape dans la recherche un mot clé contenant le nom d'un forum, il va se retrouver avec tous les sujets du forum. Ça va si les contenus sont boostés suffisamment pour apparaître en premier mais sinon les résultats pertinents vont être fondu dans la masse.

Je crois que j'ai fourché sur indexé. En effet, dans la version finale, le forum est sauvegardé, mais la recherche n'as pas lieu sur ce champ. Donc ça rejoint ce que tu dis :-)

Pour les deux boost : Je pense que c'est une très bonne idée de booster les 2 attributs Est résolu, Est en post-it. Mais je vois ça plus comme des critères de recherche.

Voir point précédent.

@DevHugo
Copy link
Contributor

DevHugo commented Jan 17, 2017

Juste pour garder en mémoire.

@A-312
Copy link
Contributor

A-312 commented Sep 3, 2018

@Situphen Situphen added the C-Search Concerne la recherche (et ElasticSearch) label Sep 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-Back Concerne le back-end Django C-Search Concerne la recherche (et ElasticSearch) Feedback Ticket ou PR en attente de retours
Projects
Status: À trier
Development

No branches or pull requests

5 participants