De nombreuses applications doivent permettre aux utilisateurs de personnaliser les requêtes de manière à compléter ce que les requêtes de recherche seules peuvent faire. Dans ce chapitre, vous allez découvrir le filtrage, une technique qui permet de spécifier qu'une requête de recherche n'est exécutée que sur le sous-ensemble des documents contenus dans un index qui satisfont à une condition donnée.
Introduction aux requêtes booléennes
Avant de pouvoir mettre en place des filtres, vous devez comprendre comment les requêtes composées sont mises en œuvre dans Elasticsearch.
Une requête composée permet à une application de combiner deux ou plusieurs requêtes individuelles, de sorte qu'elles s'exécutent ensemble et, le cas échéant, renvoient un ensemble de résultats combinés. La manière standard de créer des requêtes composées dans Elasticsearch est d'utiliser une requête booléenne.
Une requête booléenne sert d'enveloppe à deux ou plusieurs requêtes ou clauses individuelles. Il existe quatre façons différentes de combiner les requêtes :
bool.must: la clause doit correspondre. Si plusieurs clauses sont données, elles doivent toutes correspondre (comme une opération logique ET).bool.shouldLorsqu'il est utilisé sansmust, au moins une clause doit correspondre (comme dans une opération logique OR). Combinée àmust, chaque clause correspondante augmente le score de pertinence du document.bool.filterLes résultats de la recherche ne sont considérés que comme des documents correspondant à la (aux) clause(s).bool.must_notLes résultats de la recherche ne sont pas pris en compte : seuls les documents qui ne correspondent pas à la (aux) clause(s) sont considérés comme des candidats aux résultats de la recherche.
Comme vous pouvez probablement le deviner, les requêtes booléennes sont assez complexes et peuvent être utilisées de différentes manières. Dans ce chapitre, vous apprendrez à combiner la clause de recherche plein texte à correspondances multiples mise en œuvre dans les chapitres précédents avec un filtre qui restreint les résultats à une catégorie de documents. Rappelons que l'ensemble de données utilisé pour ce tutoriel comprend un champ category qui peut être défini comme sharepoint, teams ou github.
Ajout d'un filtre à une requête
La requête multi-correspondance qui est actuellement mise en œuvre dans l'application tutorielle utilise la structure suivante :
Pour ajouter un filtre qui limite la recherche à une catégorie spécifique, la requête doit être développée comme suit :
Examinons en détail les nouveaux composants de cette requête.
Tout d'abord, la requête multi_match a été déplacée à l'intérieur d'une clause bool.must. La clause bool.must est généralement l'endroit où la requête de base est définie. Notez que must accepte une liste de requêtes à rechercher, ce qui permet de combiner plusieurs requêtes de base si nécessaire.
Le filtrage est mis en œuvre dans une section bool.filter, à l'aide d'un nouveau type de requête, la requête term. L'utilisation d'une requête match ou multi_match pour un filtre n'est pas une bonne idée, car il s'agit de requêtes de recherche en texte intégral. Pour les besoins du filtrage, la requête doit renvoyer une réponse absolue vraie ou fausse pour chaque document et non un score de pertinence comme le font les requêtes de correspondance.
Le terme " requête" permet d'effectuer une recherche exacte de la valeur d'un champ donné. Ce type de requête est utile pour rechercher des identifiants, des labels, des étiquettes ou, comme dans le cas présent, des catégories.
Cette requête ne fonctionne pas bien avec les champs qui sont indexés pour la recherche en texte intégral. Les champs de type "chaîne" se voient attribuer un type de texte par défaut et leur contenu est analysé et séparé en mots individuels avant d'être indexé. Elasticsearch attribue aux champs de type chaîne un type secondaire de mot-clé, qui indexe le contenu du champ dans son ensemble, ce qui le rend plus approprié pour le filtrage avec la requête term. En utilisant un nom de champ category.keyword dans la partie filtre de la requête, la variante typée keyword du champ est utilisée au lieu de la variante par défaut text.
Spécification d'un filtre
Avant que la requête filtrée puisse être mise en œuvre, il est nécessaire d'ajouter un moyen pour les utilisateurs finaux de saisir le filtre souhaité. La solution mise en œuvre dans ce tutoriel recherche un modèle category:<category-name> dans le texte de la requête de recherche. Ajoutons une fonction appelée extract_filters() à app.py pour rechercher des expressions de filtre :
Cette fonction accepte la requête saisie par l'utilisateur et renvoie un tuple contenant les filtres trouvés dans la requête, ainsi que la requête modifiée après suppression des filtres. Pour rechercher le motif de filtrage, il utilise une expression régulière. La fonction est conçue pour être complétée par des filtres supplémentaires.
Lorsqu'un filtre est trouvé, la liste filters est complétée par une expression de filtre correspondante qui, dans ce cas, est basée sur la requête term, comme indiqué ci-dessus.
Pour mieux comprendre le fonctionnement de cette fonction, démarrez une session Python (assurez-vous d'abord que l'environnement virtuel est activé) et exécutez le code suivant :
Le tuple renvoyé par la fonction doit être :
Mise en œuvre de la recherche filtrée
Il reste à modifier la fonction handle_search() pour qu'elle envoie une requête actualisée combinant l'expression de recherche en texte intégral et un filtre, si l'utilisateur en a indiqué un. Vous trouverez ci-dessous la nouvelle version de cette fonction :
La requête a été modifiée pour envoyer une expression bool, et l'expression de recherche a été déplacée à l'intérieur d'une section must. La fonction extract_filters() renvoie la partie filtre de la requête sous la forme qu'elle doit être envoyée à Elasticsearch, de sorte qu'elle est insérée dans le dictionnaire de requêtes, également sous la clé de premier niveau bool.
Essayez une requête de recherche telle que work from home category:sharepoint pour voir comment seuls les documents de la catégorie donnée sont renvoyés.
Filtres de gamme
Elasticsearch prend en charge une variété de filtres en plus du filtre term. Un autre filtre couramment utilisé est le filtre range, qui fonctionne avec des nombres et des dates. Ajoutons un filtre year qui permet de restreindre les résultats en fonction de l'année de la dernière mise à jour, indiquée dans le champ updated_at.
Vous trouverez ci-dessous une version actualisée de la fonction extract_filters() qui recherche les filtres category:<category> et year:<yyyy>:
Cette version ajoute une deuxième expression régulière pour trouver year:yyyy dans la chaîne de requête. Il crée un filtre range pour le champ updated_at et fixe les limites inférieure et supérieure de l'intervalle à l'année indiquée après les deux points, qui est capturée dans l'expression régulière sous la forme m.group(1).
Il y a une petite complication, car le champ updated_at contient des dates complètes, et dans ce filtre, il ne faut regarder que l'année. Heureusement, lorsque le filtre d'intervalle est utilisé avec un champ de date, les limites de l'intervalle peuvent être améliorées par des calculs de date. Le suffixe ||/y ajouté aux paramètres gte (limite inférieure) et lte (limite supérieure) de l'intervalle indique que la valeur donnée est une année qui doit être complétée pour former une date complète pouvant être comparée au champ.
Grâce à cette modification, vous pouvez inclure une requête telle que year:2020 work from home pour afficher les résultats de l'année demandée uniquement. La requête peut également inclure les deux filtres, par exemple year:2020 category:teams work from home.
La requête match-all
Avant de passer à un nouveau sujet, essayez de ne saisir qu'un filtre dans le champ de texte de la requête de recherche, par exemple category:github. Malheureusement, aucun résultat n'est renvoyé, mais le comportement attendu dans ce cas serait de recevoir tous les résultats correspondant à la catégorie demandée.
La fonction extract_filters() renvoie un tuple dont le premier élément contient le(s) filtre(s) et le second une chaîne de requête vide. La requête multi_match reçoit la chaîne vide et renvoie une liste de résultats vide, car rien ne correspond à une chaîne vide.
Pour répondre à ce cas particulier, la requête multi_match peut être remplacée par match_all lorsque le texte de la recherche est vide. La version de la fonction handle_search() ci-dessous ajoute une logique à cet effet. Mettre à jour la fonction dans app.py.
Avec cette version, vous pouvez demander tous les documents qui correspondent à une catégorie. Notez que tous les résultats renvoyés ont le même score de 1,0, car il n'y a pas de termes de recherche pour calculer les scores.
Précédemment
PaginationSuivant
Recherche à facettes