Quelle est la meilleure façon de mettre en œuvre la recherche à facettes ? Trouver le bon chemin : comment la navigation à facettes affecte le référencement (traduction). Patcher JQuery UI Slider : configurer une redirection

Les gens modernes essaient de consacrer de moins en moins de temps au shopping. Les catalogues de produits lents font fuir les clients, le magasin perd des clients et une partie de ses bénéfices. Rendez votre boutique en ligne plus attractive grâce à la technologie à facettes À facettes - c'est-à-dire prédéfini. recherche. Créer index à facettes et accélérer considérablement la recherche de produits et le travail de l'ensemble du catalogue.

Note: Le mécanisme de recherche à facettes est disponible à partir de la version 15.0.1 du module Blocs d'informations et intégré à composant Composant- il s'agit d'un code de programme, conçu dans un shell visuel, qui remplit une fonction spécifique d'un module pour afficher des données dans la partie Public. Nous pouvons insérer ce bloc de code dans les pages d’un site Web sans écrire directement de code. Filtre intelligent Le composant prépare un filtre pour la sélection dans le bloc d'informations et affiche un formulaire de filtre pour filtrer les éléments. Le composant doit être connecté avant le composant d'affichage des éléments du catalogue, sinon la liste des éléments ne sera pas filtrée. Le composant est standard, inclus dans la distribution du module et contient trois modèles : .défaut, visuel_horizontal Et visuel_vertical. (Les deux derniers modèles ne sont pas pris en charge, ils restent pour maintenir la compatibilité.)

Dans l'éditeur visuel, le composant est situé le long du chemin Contenu > Catalogue > Filtre intelligent.

Le composant appartient au module Blocs d'information.

En savoir plus sur la recherche à facettes

Créons index à facettes en quelques étapes simples :

Les index de facettes doivent-ils être recréés ?

Les index à facettes sont recréés automatiquement ou vous devez les recréer manuellement, en fonction des actions effectuées :

Automatiquement Ajout de nouveaux ou modification de ceux existants marchandises.
ne crée pas de nouvelles propriétés.
Manuellement Le système vous en informera avec un message en haut des pages
partie administrative.
J'en ai ajouté de nouveaux ou je les ai modifiés rubriques du catalogue.
Lors de l'ajout d'une nouvelle propriété ou de la suppression d'une propriété de filtre intelligent.
Lors du déchargement de marchandises, par exemple depuis 1C, si les marchandises créer de nouvelles propriétés.

La recherche à facettes améliore les performances du catalogue de produits. Pour l'utiliser il vous faut :

  1. Créer des index à facettes pour un catalogue de produits ;
  2. Surveillez les notifications concernant la nécessité de recréer manuellement les index.

Le filtre intelligent ou recherche à facettes est un filtre par catégorie de produits, visible dans les grands magasins en ligne et sur le même Yandex.market. Il permet de trier systématiquement les produits avec les propriétés dont l'utilisateur a besoin, en éliminant tout ce qui est inutile. C'est une option très pratique qui permet de trouver rapidement le produit ou le matériel souhaité sur le site.

Passons donc directement à l'installation et à la configuration des modules dont nous avons besoin

Tout d’abord, nous devrons télécharger et installer les modules suivants : API de recherche, recherche de base de données de l’API de recherche, API d’entité et vues.

Sur la page des modules, nous activons :

  • API de recherche
  • Rechercher des vues
  • Recherche dans la base de données
  • API d'entité
  • Vues
  • Vues de l'interface utilisateur
  • Coutils

Création d'un serveur de recherche

Allons à Configuration > Recherche et métadonnées > API de recherche(/admin/config/search/search_api) et cliquez sur Ajouter un serveur.
Saisissez ensuite le nom du serveur dans la liste déroulante Classe de service choisir Service de base de données Et enregistrer.

Création d'un index

Allons à Configuration > Recherche et métadonnées > API de recherche(/admin/config/search/search_api), cliquez sur Ajouter un serveur (Ajouter un index).
Entrez le nom de l'index dans le champ Type d'élément (Type d'élément) sélectionner ' Matériel', dans le champ Serveur choisir Serveur de base de données, Cliquez sur Création d'un index.


Dans le formulaire qui s'ouvre, cochez les cases par lesquelles le tri sera effectué et enregistrez.
Pour pouvoir trier par nom de nœud, activez le titre et sélectionnez le type en face dans la liste déroulante chaîne, mais non texte intégral. Vous ne pouvez pas trier par texte intégral.

Dans le prochain formulaire qui s'ouvre Filtres(workflow) J'ai tout laissé par défaut, allez dans l'onglet Voir (Statut), et appuyez sur Indexer maintenant (Indexer maintenant).
Une fois l'indexation terminée, nous créerons une page de recherche.

Création d'une page de recherche

Allons à Structure > Vues et cliquez Ajouter une nouvelle vue (Ajouter une nouvelle vue).
Dans la nouvelle vue de la liste déroulante Montrer (Montrer) sélectionnez l'index que nous avons créé précédemment, remplissez les champs restants (nom, titre et chemin) selon vos besoins.


Ensuite, cliquez sur Enregistrer et configurer(Continuer et modifier) Configurez la vue comme d'habitude. Dans les critères de filtrage, j'ai ajouté l'affichage uniquement des documents publiés et le type de nœud souhaité et configuré l'affichage des champs nécessaires (vous devez ajouter ces champs à l'index afin de pouvoir filtrer selon eux).

À ce stade, nous avons terminé la configuration de la vue, passons maintenant directement au filtre à facettes.

A/search_api_ranges.module +++ b/search_api_ranges.module @@ -144.11 +144.8 @@ function search_api_ranges_minmax($variables, $order = "ASC") ( // sinon notre min/max serait toujours égal à l'entrée de l'utilisateur. $filters = &$query->getFilter()->getFilters(); foreach ($filters as $key => $filter) ( - - // Recherche de tableau : les filtres de style ancien sont des objets que nous pouvons ignorer. - if (is_array ($filter)) ( - if ($filter == $variables["range_field"] || ($filter != $variables["range_field"] && $filter == "")) ( - $ current_filter = $filters [$key]; + if(isset($filter->tags) && is_array($filter->tags))( + if(in_array("facet:".$variables["range_field"], $ filter->tags ))( unset($filters[$key]); ) )

Patcher JQuery UI Slider : configurer une redirection

Dans la version 7x-1.5 du module, j'ai rencontré le fait que si le widget slider se trouvait sur une page autre que la page de recherche, alors après avoir changé la fourchette de prix, la direction était redirigée vers la page en cours, et non vers la recherche page.
L'erreur réside dans la fonction search_api_ranges_block_slider_view_form_submit()(fichier search_api_ranges.module, ligne 364).
Je n’ai pas vraiment regardé ce qu’il y avait là et pourquoi, j’ai juste modifié un peu le code à la ligne 427 :

Drupal_goto($chemin, array("query" => array($params), "langue" => $langue)); + drupal_goto($values["chemin"], array("query" => array($params), "langue" => $langue));

après quoi le problème a été résolu.

( "query": ( "et": [ ( "terms": ("pays": ["be", "fr"]) ), ( "terms": ("category": ["livres", "films " ]) ) ] ) )

Pour les compteurs, nous pouvons utiliser les agrégations intégrées d'Elasticsearch. Chacune des deux facettes est stockée sous la forme d'un champ unique dans l'index, nous pouvons donc utiliser l'agrégation de termes dans chacun de ces champs. L'agrégation renverra un compteur pour la valeur de ce champ.

( "query": ( "et": [ ( "terms": ("pays": ["be", "fr"]) ), ( "terms": ("category": ["livres", "films " "]) ) ]), "agrégations": ( "pays": ( "termes": ("champ": "pays")), "catégories": ( "termes": ("champ": "catégorie" ) ) ) )

Si vous deviez exécuter cette requête, vous remarquerez que les compteurs sont désactivés. Les deux pays non sélectionnés, le Portugal et le Brésil, ont un compteur de 0. Bien qu'il y ait des résultats réels si l'on veut les sélectionner (en raison du bord ORinner). Cela se produit car, par défaut, Elasticsearch effectue ses agrégations sur l'ensemble de résultats. Cela signifie que si vous sélectionnez la France, les filtres de l'autre pays auront un score de 0 car le jeu de résultats ne contient que des éléments de France.

Pour résoudre ce problème, nous devons demander à Elasticsearch d'effectuer l'agrégation sur l'ensemble de données, en ignorant la requête. Nous pouvons le faire en définissant nos clusters comme globaux.

( "query": ( "et": [ ( "terms": ("pays": ["be", "fr"]) ), ( "terms": ("category": ["livres", "films " "]) ) ]), "agrégations": ( "all_products": ( "global": (), "agrégations": ( "pays": ( "termes": ("champ": "pays")), " catégories": ( "termes": ("champ": "catégorie") ) ) ) ) )

Si nous faisions simplement cela, nos compteurs seraient toujours les mêmes car ils s'appuieraient toujours sur l'ensemble des données, quels que soient nos filtres. Nos unités doivent devenir un peu plus complexes, pour que cela fonctionne, nous devons leur ajouter des filtres. Chaque agrégation doit s'appuyer sur un ensemble de données avec tous les filtres appliqués sauf le sien. Ainsi, l'agrégation par compte en France compte sur le jeu de données avec le filtre catégorie appliqué, mais pas le filtre pays :

( "query": ( "et": [ ( "terms": ("pays": ["be", "fr"]) ), ( "terms": ("category": ["livres", "films " "]) ) ]), "agrégations": ( "all_products": ( "global": (), "agrégations": ( "pays": ( "filtre": ( "et": [ ( "termes": ( "category": ["livres","films"]) ) ] ), "agrégations": ( "filtered_countries": ( "terms": ("field": "country") ) ) ), "categories": ( "filter": ( "et": [ ( "terms": ("country": ["be","fr"]) ) ) ]), "agrégations": ( "filtered_categories": ( "terms": ( " champ": "catégorie") ) ) ) ) ) ) )

( "pris": 153, "timed_out": false, "_shards": ( "total": 5, "successful": 5, "failed": 0), "hits": ( "total": 3, "max_score ": 0, "hits": ["..."]), "agrégations": ( "all_products": ( "doc_count": 21, "filteredcategories": ( "doc_count": 13, "categories": ( "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ ( "key": "films", "doc_count": 6 ), ( "key": "musique", "doc_count": 4 ), ( "key": "books", "doc_count": 3 ) ] ) ), "filtered_countries": ( "doc_count": 15, "countries": ( "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ ( "key": "fr", "doc_count": 6 ), ( "key": "br", "doc_count": 4 ), ( "key": "be", "doc_count": 3 ), ( "key": "pt", "doc_count": 2 ) ] ) ) ) ) )

Cadre Yii2

$terms = QueryHelper::terms("categories.name" , "ma catégorie" ) ; $nested = QueryHelper:: imbriqué ("string_facet" , QueryHelper:: filter ([ QueryHelper:: term ("string_facet.facet_name" , [ "value" => $id , "boost" => 1 ] ), QueryHelper :: term ("string_facet.facet_value" , ​​​​[ "value" => $value , "boost" => 1 ] ) , ] ) ) ; $filter = QueryHelper::should ($nested) ;

Dans cet article (niveau webmaster - avancé), nous parlerons de ce qu'on appelle l'intersection de différentes manières. navigation « à facettes ». Pour faciliter l'apprentissage de la matière, je vous recommande de parcourir l'article Wikipédia « Classification à facettes » et la publication en anglais (mais avec des images !) « Concevez une meilleure navigation à facettes pour vos sites Web ».

La navigation à facettes qui filtre par couleur ou par gamme de prix peut être utile pour vos visiteurs, mais elle nuit souvent aux résultats de recherche car elle crée plusieurs combinaisons d'URL avec du contenu en double. En raison des doublons, les moteurs de recherche ne seront pas en mesure d'analyser rapidement le site à la recherche de mises à jour de contenu, ce qui affecte en conséquence l'indexation. Pour minimiser ce problème et aider les webmasters à rendre la recherche de navigation à facettes conviviale, nous aimerions :

Idéal pour les utilisateurs et la recherche Google

Chemin clair vers les pages de produits/articles :

Représentation de l'URL de la page de catégorie :
http://www.example.com/category.php?category=gummy-candies

Représentation d'URL spécifique au produit :
http://www.example.com/product.php?item=swedish-fish

Doublons indésirables causés par la navigation à facettes

La même page est accessible depuis différentes adresses web :

Page canonique



URL : exemple.com/product.php ? item=poisson-suédois

Page en double



URL : exemple.com/product.php ? item=poisson-suédois&category=bonbons-gummy&price=5-10


catégorie=bonbons gommeux&taste=aigre&prix=5-10

Les erreurs:

  • Inutile pour Google puisque les utilisateurs recherchent rarement [marmelade au prix de 9:55 $].
  • Cela n'a aucun sens pour les robots d'exploration du Web, qui trouveront le même article (« salade de fruits ») dans les pages de catégorie parent (soit « Jummy », soit « Sour Gummy »).
  • Un point négatif pour le propriétaire du site, car les demandes d'indexation sont diluées avec de nombreuses versions d'une même catégorie.
  • Un point négatif pour le propriétaire du site, car inutile et charge supplémentaire sur la bande passante du site
Pages blanches:


URL : exemple.com/category.php ? catégorie=bonbons gommeux&taste=sour&price=over-10

Les erreurs:

  • Le code des moteurs de recherche est renvoyé incorrectement (dans ce cas, la page doit renvoyer un code 404)
  • Page blanche pour les utilisateurs


Les pires solutions (pas conviviales pour la recherche) pour la navigation à facettes

Exemple n°1 : Des paramètres non standard sont utilisés dans le cadre de l'URL : virgules et parenthèses à la place clé=valeur&:

  • exemple.com/category? [ catégorie:bonbons gommeux ][ tri:prix bas à haut ][ sid:789 ]
  • example.com/category?category , bonbons gommeux , trier , lowtohigh , sid , 789
Comment:
exemple.com/category? catégorie=bonbons gommeux&sort=de faible à élevé&sid=789

Exemple n°2: Utiliser des répertoires ou des chemins de fichiers plutôt que des paramètres dans des listes de valeurs qui ne modifient pas le contenu de la page :
example.com/c123 /s789/ product?swedish-fish
(où /c123/ catégorie, /s789/ identifiant de session, ce qui ne modifie pas le contenu de la page)

Bonne décision:

  • exemple.com /gummy-candy/ product?item=poisson-suédois&sid=789(le répertoire, /gummy-candy/, modifie le contenu de la page de manière significative)
La meilleure décision :
  • example.com/product?item=swedish-fish& catégorie=bonbons gommeux&sid=789 (Les paramètres d'URL offrent une plus grande flexibilité aux moteurs de recherche pour déterminer comment explorer efficacement)
Il est difficile pour les robots d'exploration de différencier les valeurs utiles (telles que "gummy-candy") des valeurs inutiles (telles que "SESSIONID") lorsque ces valeurs sont placées directement dans les chemins de liens. D'un autre côté, les paramètres d'URL offrent aux moteurs de recherche la flexibilité de tester et de déterminer rapidement quand une valeur donnée ne nécessite pas l'accès du robot à toutes les options.

Les valeurs courantes qui ne modifient pas le contenu de la page et doivent être répertoriées comme paramètres d'URL incluent :

  • ID de session
  • Suivi d'identité
  • ID de référent
  • Horodatages
Exemple n°3: Convertissez les valeurs générées par l'utilisateur (éventuellement infinies) en paramètres d'URL explorables et indexables, mais inutiles pour la recherche.
Utilisation de données mineures générées par les utilisateurs du site (telles que la longitude/latitude ou "il y a quelques jours") dans les adresses explorées et indexées :
  • exemple.com/find-a-doctor? rayon=15&latitude=40,7565068&longitude=-73,9668408
  • example.com/article?category=health& il y a jours = 7
Comment:
  • exemple.com/find-a-doctor? ville=san-francisco&quartier=soma
  • example.com/articles?category=health& date=10-janvier-2014
Au lieu de permettre à l'utilisateur de générer des valeurs pour créer des URL explorables (ce qui se traduit par des possibilités infinies avec très peu de valeur pour les visiteurs), il est préférable de publier une catégorie de page pour les valeurs les plus populaires, en plus vous pouvez inclure des informations supplémentaires pour faire en sorte que la page offre plus de valeur qu'une page de recherche classique avec des résultats. Vous pouvez également envisager de placer les valeurs générées par l'utilisateur dans un répertoire distinct, puis d'utiliser robots.txt pour empêcher l'exploration à partir de ce répertoire.
  • exemple.com /filtration/ trouver un médecin?radius=15&latitude=40.7565068&longitude=-73.9668408
  • exemple.com /filtration/ articles?category=santé&days-ago=7
Et dans robots.txt :
Agent utilisateur: *
Refuser: /filtration/

Exemple n°4. Ajout de paramètres d'URL sans logique.

  • exemple.com /bonbons-gummy/sucettes/bonbons-gummy/ bonbons gommeux/produit?poisson-suédois
  • exemple.com/product? cat=bonbons-gummy&cat=sucettes&cat=bonbons-gummy&cat=bonbons-gummy&item=poisson-suédois
Bonne décision:
  • example.com /gummy-candy/ product?item=swedish-fish
La meilleure décision :
  • exemple.com/product? item=poisson-suédois&category=bonbons gommeux
Les paramètres d'URL superflus ne font qu'augmenter la duplication, ce qui rend l'exploration et l'indexation du site moins efficaces. Par conséquent, il est nécessaire de se débarrasser des paramètres d’URL inutiles et de nettoyer périodiquement les liens indésirables avant de générer de nouvelles URL. Si de nombreux paramètres sont nécessaires pour une session utilisateur, vous pouvez masquer les informations dans les cookies plutôt que d'ajouter constamment des valeurs comme cat=gummy-candy&cat=sucettes&cat=gummy-candy& ...

Exemple n°5: Suggérer des améliorations supplémentaires (filtrage) lorsqu'il y a des résultats nuls.

Mal:
Autoriser les utilisateurs à sélectionner des filtres lorsqu'il y a des éléments nuls à affiner.


Clarification d'une page avec zéro résultat (par exemple, prix = supérieur à 10), ce qui frustre les utilisateurs et provoque des requêtes inutiles auprès des moteurs de recherche.

Comment:
Créez des liens uniquement lorsqu'il existe des éléments que l'utilisateur peut sélectionner. Si le résultat est zéro, le lien est marqué « gris » (c'est-à-dire non cliquable). Pour améliorer encore la convivialité, pensez à inclure un indicateur du nombre d’éléments disponibles à côté de chaque filtre.


L'affichage d'une page avec aucun résultat (par exemple, prix = supérieur à 10) n'est pas autorisé, de plus il est interdit aux utilisateurs d'effectuer des clics inutiles et il est interdit aux moteurs de recherche d'explorer cette page inutile.

Il est nécessaire d'éviter l'apparition d'adresses inutiles et de minimiser l'espace pour le visiteur en créant des URL uniquement lorsque les produits sont disponibles. Cela contribuera à maintenir l'engagement des utilisateurs sur votre site (moins de clics sur le bouton de retour lorsqu'aucun produit n'est trouvé) et réduira le nombre d'URL possibles connues des moteurs de recherche. De plus, si une page n'est pas simplement « temporairement en rupture de stock » mais qu'il est peu probable qu'elle contienne un jour des informations pertinentes, vous pouvez envisager de lui attribuer un code de réponse 404. Sur votre page 404, vous pouvez concevoir un message utile pour les utilisateurs avec plus d'options dans la navigation, ou un champ de recherche permettant aux utilisateurs de trouver des produits associés.

Pour les nouveaux sites dont les webmasters envisagent de mettre en œuvre une navigation à facettes, il existe plusieurs options pour optimiser l'exploration (l'ensemble des adresses de votre site connues de Google) des pages de contenu unique et réduire l'entrée des pages en double dans l'index des moteurs de recherche (consolidation de l'indexation signaux).

Déterminez les paramètres d'URL requis pour que les moteurs de recherche explorent chaque page de contenu individuelle (c'est-à-dire déterminez les paramètres nécessaires pour créer au moins un chemin de clic vers chaque élément). Les paramètres requis peuvent inclure item-id ,category-id , page etc.

Déterminez quels paramètres seront utiles aux visiteurs dans leurs requêtes et lesquels sont susceptibles de provoquer une duplication dans l'exploration et l'indexation. Dans l'exemple de confiserie (marmelade), le paramètre URL « goût » pourrait être utile aux utilisateurs ayant des requêtes dans l'exemple. goût = aigre . Il est cependant logique de considérer que le paramètre « prix » provoque des duplications inutiles catégorie=bonbons gommeux&goût=aigre& prix=plus de 10 . Autres exemples courants :

  • Paramètres précieux pour les moteurs de recherche : item-id ,category-id , name , brand...
  • Paramètres inutiles : session-id , price-range ...
Examinons la mise en œuvre de l'une des nombreuses options de configuration pour les URL contenant des paramètres inutiles. Assurez-vous simplement que les paramètres d'URL « inutiles » ne sont pas réellement requis pour que les robots des moteurs de recherche les explorent ou pour que l'utilisateur trouve chaque produit individuel !

Option 1 : et liens internes

Marquez toutes les URL inutiles avec le . Cela réduira les coûts de main-d'œuvre du robot de recherche et empêchera une diminution de la fréquence d'exploration. Vous devez gérer le scanning globalement via robots.txt (Note du traducteur : voir article " ").
Utilisez l'attribut rel="canonical" pour séparer les pages de l'index de recherche des pages qui n'y sont pas nécessaires (par exemple, sur la page prix=5-10 vous pouvez ajouter l'attribut rel="canonical", indiquant la catégorie de toutes les marmelades aigre example.com/category.php?category=gummy-candies&taste=sour& page = tout ).

Option 2 : Robots.txt et interdiction

Les URL avec des paramètres inutiles sont incluses dans le répertoire /filtering/, qui sera fermé dans robots.txt (interdire). Cela permettra à tous les moteurs de recherche d’explorer uniquement le lien (contenu) « correct » du site, mais bloquera immédiatement l’exploration des URL indésirables. Par exemple ( example.com/category.php?category=gummy-candies), si les paramètres précieux étaient l'article, la catégorie et le goût, et que l'identifiant de session et le prix étaient superflus, alors l'URL du goût ressemblerait à ceci :
example.com/category.php?category=gummy-candies& goût = aigre, mais tous les paramètres inutiles, comme le prix, seront inclus dans l'URL dans un répertoire prédéfini - /filtering/ :
exemple.com /filtration/ category.php?category=gummy-candies&price=5-10,
qui sera alors interdit via robots.txt :
Agent utilisateur: *
Interdire : /filtrage/

Option 3 : hôtes séparés

Assurez-vous que les meilleures solutions répertoriées ci-dessus (par exemple pour les adresses inutiles) s'appliquent toujours. Sinon, les moteurs de recherche ont déjà formé une grande masse de liens dans l'index. Ainsi, votre travail visera à réduire la croissance des pages inutiles explorées par Googlebot et à consolider les signaux d'indexation.

Utilisez des paramètres avec un encodage standard et un format clé=valeur.

Assurez-vous que les valeurs qui ne modifient pas le contenu de la page, telles que les ID de session, sont implémentées en tant que clé=valeur plutôt qu'en tant que répertoires.

N'autorisez pas les clics et ne générez pas d'URL lorsqu'il n'y a aucun élément à filtrer.

Ajoutez une logique au mappage des paramètres d'URL : supprimez les paramètres inutiles plutôt que d'ajouter constamment des valeurs (par exemple, évitez la génération de liens comme celle-ci : example.com/product?cat=gummy-candy&cat=lollipops &cat=gummy-candy&item=swedish-fish).

Stockez les paramètres importants dans les URL en les répertoriant en premier (puisque les URL sont visibles dans les résultats de recherche) et en dernier les paramètres les moins pertinents (par exemple, l'ID de session).
Évitez cette structure de lien : exemple.com/category.php? identifiant de session=123&identifiant de suivi=456&category=bonbons-gummy&taste=sour
Configurez les paramètres d'URL dans les outils pour les webmasters si vous comprenez clairement le fonctionnement des liens sur votre site.

Assurez-vous que lorsque vous utilisez JavaScript pour manipuler dynamiquement le contenu (trier/filtrer/masquer) sans mettre à jour l'URL, il existe sur votre site des adresses Web réelles qui ont une valeur de recherche, telles que les catégories principales et les pages de produits, qui sont explorables et indexables. Essayez de ne pas utiliser uniquement la page d'accueil (c'est-à-dire une seule URL) pour l'ensemble de votre site, mais via JavaScript pour modifier dynamiquement le contenu avec la navigation - cela, malheureusement, ne donnera aux utilisateurs qu'une seule URL dans les recherches. De plus, vérifiez que les performances n'affectent pas les performances du filtrage dynamique, car cela interférerait avec la capacité de l'utilisateur à travailler avec le site.

Améliorez l'indexation de différentes pages d'un même contenu en précisant l'attribut rel="canonical" sur la version privilégiée de la page. L'attribut rel="canonical" peut être utilisé dans un ou plusieurs domaines.

Optimisez l'indexation du contenu paginé (par exemple, page=1 et page=2 de la catégorie "bonbons gommeux") en :

  • Ajoutez un attribut rel="canonical" à une série de pages indiquant la catégorie canonique avec le paramètre "view-all" (par exemple, page=1, page=2 et page=3 de la catégorie "bonbons gommeux" avec with rel=”canonique” sur catégorie=bonbons-gummy&page=all), en veillant à ce que la page soit pertinente pour les utilisateurs et se charge rapidement.
  • Utilisez le balisage de pagination rel="next" et rel="prev" pour indiquer la relation entre les pages individuelles (voir l'article "Pagination avec rel="next" et rel="prev" ").
Incluez uniquement des liens canoniques dans vos plans de site.

Nous avons jeté un coup d'œil rapide à l'installation et à la syntaxe de base de PINQ, un portage de LINQ to PHP. Dans cet article, nous verrons comment utiliser PINQ pour simuler la fonctionnalité de recherche à facettes dans MySQL.

Dans cet article, nous ne couvrirons pas tous les aspects de la recherche à facettes. Les personnes intéressées peuvent rechercher des informations appropriées sur Internet.

Une recherche à facettes typique fonctionne comme ceci :

  • L'utilisateur saisit un ou plusieurs mots-clés pour effectuer une recherche. Par exemple, « routeur » pour rechercher des produits dans lesquels le mot « routeur » apparaît dans la description, les mots-clés, le nom de la catégorie, les balises, etc.
  • Le site renvoie une liste de produits répondant à ces critères.
  • Le site propose plusieurs liens pour personnaliser vos termes de recherche. Par exemple, cela peut vous permettre de spécifier des fabricants de routeurs spécifiques, de définir une fourchette de prix ou d'autres fonctionnalités.
  • L'utilisateur peut continuer à spécifier des critères de recherche supplémentaires afin d'obtenir l'ensemble de données qui l'intéresse.

La recherche à facettes est très populaire et constitue un outil puissant visible sur presque tous les sites Web de commerce électronique.

Malheureusement, la recherche à facettes n'est pas intégrée à MySQL. Alors, que devons-nous faire si nous utilisons toujours MySQL, mais que nous souhaitons donner cette opportunité à l'utilisateur ?

Avec PINQ, qui a une approche similaire, puissante et simple, nous pouvons obtenir le même comportement que si nous utilisions d'autres moteurs de bases de données.

Extension de la démo de la première partie

Commentaire: Tout le code de cette partie et de la première partie peut être trouvé dans le référentiel.

Dans cet article, nous développerons la démo de la première partie avec une amélioration significative sous la forme de recherche de facettes.

Commençons par index.php et ajoutons-y les lignes suivantes :

$app->get("demo2", function () use ($app) ( global $demo; $test2 = new pinqDemo\Demo($app); return $test2->test2($app, $demo->test1 ($app)); )); $app->get("demo2/facet/(key)/(value)", function ($key, $value) use ($app) ( global $demo; $test3 = new pinqDemo\Demo($app); return $test3->test3($app, $demo->test1($app), $key, $value); ));

Le premier itinéraire nous amène à une page pour afficher tous les articles qui correspondent à la recherche par mot clé. Pour garder l'exemple simple, nous sélectionnons tous les livres de la table book_book. Il affichera également l'ensemble de données résultant et un ensemble de liens pour spécifier les critères de recherche.

Dans les applications réelles, après avoir cliqué sur ces liens, tous les filtres à facettes s'ajusteront aux valeurs limites de l'ensemble de données résultant. L'utilisateur pourra ainsi ajouter séquentiellement de nouvelles conditions de recherche, par exemple sélectionner d'abord un fabricant, puis préciser une fourchette de prix, etc.

Mais dans cet exemple, nous n'implémenterons pas ce comportement - tous les filtres refléteront les valeurs limites de l'ensemble de données d'origine. C'est la première limitation et le premier candidat à l'amélioration de notre démo.

Comme vous pouvez le voir dans le code ci-dessus, les fonctions réelles se trouvent dans un autre fichier appelé pinqDemo.php. Jetons un coup d'œil au code correspondant qui fournit la fonction de recherche à facettes.

Classe d'aspect

La première étape consiste à créer une classe qui représente un aspect. En général, un aspect doit contenir plusieurs propriétés :

  • Les données sur lesquelles il opère ( $données)
  • La clé par laquelle le regroupement est effectué ( $clé)
  • Type de clé ($type). Il peut s'agir de l'un des éléments suivants :
    • spécifier la chaîne complète pour une correspondance exacte
    • indiquer une partie de la chaîne (généralement la première) à rechercher par motif
    • indiquer une plage de valeurs, pour un regroupement par plage
  • si le type de clé est une plage de valeurs, vous devez définir un pas de valeur pour déterminer les limites inférieure et supérieure de la plage ; ou si le type fait partie d'une chaîne, vous devez spécifier combien de premières lettres seront utilisées pour le regroupement ($range)

Regroupement- la partie la plus critique de l'aspect. Toutes les informations agrégées qu'un aspect peut renvoyer dépendent des critères de regroupement. Généralement, les critères de recherche les plus utilisés sont « Chaîne complète », « Partie de chaîne » ou « Plage de valeurs ».

Espace de noms classFacet ( utilisez Pinq\ITraversable, Pinq\Traversable; class Facet ( public $data; // Ensemble de données d'origine public $key; // champ par lequel regrouper public $type; // F: ligne entière; S: chaînes de début ; R: range; public $range; // ne joue un rôle que si $type != F ... public function getFacet() ( $filter = ""; if ($this->type == "F") / / ligne entière ( ... ) elseif ($this->type == "S") // début de ligne ( ... ) elseif ($this->type == "R") // plage de valeurs ​​( $ filter = $this->data ->groupBy(function($row) ( return floor($row[$this->key] / $this->range) * $this->range; )) -> select(function (ITraversable $data) ( return ["key" => $data->last()[$this->key], "count" => $data->count()]; )); ) return $filtre; ) ) )

La fonction principale de cette classe est de renvoyer un ensemble de données filtré basé sur l'ensemble de données d'origine et les propriétés d'aspect. À partir du code, vous pouvez voir que différents types de comptes utilisent différentes manières de regrouper les données. Dans le code ci-dessus, nous avons montré à quoi pourrait ressembler le code si nous regroupons les données selon une plage de valeurs par incréments spécifiés dans plage $.

Définition des aspects et affichage des données sources

Fonction publique test2($app, $data) ( $facet = $this->getFacet($data); return $app["twig"]->render("demo2.html.twig", array("facet" = > $facet, "data" => $data)); ) fonction privée getFacet($originalData) ( $facet = array(); $data = \Pinq\Traversable::from($originalData); // 3 exemples de création différents objets d'aspect, et renvoie les aspects $filter1 = new \classFacet\Facet($data, "author", "F"); $filter2 = new \classFacet\Facet($data, "title", "S", 6 ) ; $filter3 = nouveau \classFacet\Facet($data, "price", "R", 10); $facet[$filter1->key] = $filter1->getFacet(); $facet[$filter2-> clé ] = $filter2->getFacet(); $facet[$filter3->key] = $filter3->getFacet(); return $facet; )

Dans la méthode getFacet(), nous procédons comme suit :

  • Convertissez les données d'origine en un objet Pinq\Traversable pour un traitement ultérieur
  • Nous créons trois aspects. L'aspect « auteur » regroupera par champ d'auteur et implémentera le regroupement par ligne entière ; aspect 'titre' - par le champ titre avec regroupement par partie de ligne (par les 6 premiers caractères) ; aspect 'prix' - par le champ prix avec regroupement par gamme (par incréments de 10)
  • Enfin, nous extrayons les aspects et les renvoyons à la fonction test2 afin qu'ils puissent être affichés dans le modèle.

Aspects de sortie et données filtrées

Dans la plupart des cas, les filtres seront affichés sous forme de ligne et vous amèneront à visualiser le résultat filtré.

Nous avons déjà créé un itinéraire ("demo2/facet/(key)/(value)") pour afficher les résultats de recherche à facettes et filtrer les liens.

L'itinéraire prend deux paramètres, en fonction de la clé filtrée et de la valeur de cette clé. La fonction test3 liée à cette route est présentée ci-dessous :

Fonction publique test3($app, $originalData, $key, $value) ($data = \Pinq\Traversable::from($originalData); $facet = $this->getFacet($data); $filter = null; if ($key == "author") ( $filter = $data ->where(function($row) use ($value) ( ​​​​return $row["author"] == $value; )) ->orderByAscending( function($row) use ($key) ( return $row["price"]; )) ; ) elseif ($key == "price") ( ... ) else //$key== title ( .. . ) return $app["twig"]->render("demo2.html.twig", array("facet" => $facet, "data" => $filter)); )

Fondamentalement, en fonction de la clé, nous appliquons un filtrage (une fonction anonyme dans l'instruction Where) en fonction de la valeur transmise et obtenons l'ensemble de données filtrées suivant. Nous pouvons également définir l'ordre de filtrage des données.

Enfin, nous affichons les données brutes (avec les filtres) dans le modèle. Cet itinéraire utilise le même modèle que celui utilisé dans "demo2".

Barre de recherche

    (% pour k, v en facette %)
  • ((k|capitaliser))
    • (% pour vv en v %)
    • ((vv.count))((vv.clé))
    • (%fin pour%)
    (%fin pour%)

Nous devons nous rappeler que les aspects générés par notre application sont des tableaux imbriqués. Au premier niveau, il s'agit d'un ensemble de tous les aspects, et, dans notre cas, il y en a trois (respectivement pour l'auteur, le titre, le prix).

Chaque aspect a un tableau clé-valeur, nous pouvons donc le parcourir en utilisant les méthodes normales.

Remarquez comment nous construisons les URL de nos liens. Nous utilisons à la fois la clé de boucle externe (k) et les clés de boucle interne (vv.key) comme paramètres pour la route ("demo2/facet/(key)/(value)"). La taille des tableaux (vv.count) est utilisée pour l'affichage dans le modèle.

La première image montre l'ensemble de données d'origine et la deuxième image est filtrée par fourchette de prix de 0 $ à 10 $ et triée par auteur.

Super, nous avons pu simuler la recherche à facettes dans notre application !

Avant de conclure cet article, nous devons jeter un dernier regard sur notre exemple et déterminer ce qui peut être amélioré et quelles sont nos limites.

Améliorations possibles

En général, il s’agit d’un exemple très basique. Nous venons de passer en revue la syntaxe et les concepts de base et de les implémenter à titre d'exemple fonctionnel. Comme indiqué précédemment, nous avons plusieurs domaines qui pourraient être améliorés pour une plus grande flexibilité.

Nous devons implémenter des critères de recherche « superposés », puisque l'exemple actuel nous limite à la possibilité d'appliquer le filtrage de recherche uniquement à l'ensemble de données d'origine ; nous ne pouvons pas appliquer la recherche à facettes à un résultat déjà filtré. C’est la plus grande amélioration que je puisse imaginer.

Restrictions

La recherche de facettes implémentée dans cet article présente de sérieuses limitations (qui peuvent également s'appliquer à d'autres implémentations de recherche de facettes) :

Nous récupérons les données de MySQL à chaque fois

Cette application utilise le framework Silex. Comme tout framework à point d'entrée unique comme Silex, Symfony, Laravel, son fichier index.php (ou app.php) est appelé à chaque fois qu'une route est analysée et que les fonctions du contrôleur sont exécutées.

Si vous regardez le code dans notre index.php, vous remarquerez que la ligne de code suivante :

$demo = nouveau pinqDemo\Demo($app);

est appelé à chaque fois que la page d'application est affichée, ce qui signifie que les lignes de code suivantes sont exécutées à chaque fois :

Démo de classe ( private $books = ""; public function __construct($app) ( $sql = "select * from book_book order by id"; $this->books = $app["db"]->fetchAll($sql ); )

Est-ce que ce sera mieux si nous n'utilisons pas de framework ? Eh bien, malgré le fait que développer des applications sans frameworks n'est pas une bonne idée, je peux dire que nous rencontrerons les mêmes problèmes : les données (et l'état) ne sont pas préservées entre les différentes requêtes HTTP. Il s'agit d'une caractéristique fondamentale du HTTP. Cela peut être évité en utilisant des mécanismes de mise en cache.

Nous avons enregistré plusieurs requêtes SQL en utilisant des aspects. Au lieu de transmettre une requête de sélection pour récupérer les données et trois requêtes group by avec les clauses Where correspondantes, nous avons exécuté une seule requête Where et utilisé PINQ pour obtenir les informations agrégées.

Conclusion

Dans cette partie, nous avons implémenté la possibilité de rechercher des facettes dans une collection de livres. Comme je l'ai dit, il ne s'agit que d'un petit exemple qui peut être amélioré et qui présente un certain nombre de limites.