Configurer Sphinx Search pour une boutique en ligne

Il n'y a pas autant d'informations sur Sphinx que nous le souhaiterions. Un excès d'article ne fait pas de mal.
Les premières étapes du développement de Sphinx m'ont aidé à réaliser les articles Création d'un moteur de recherche d'introduction sur Sphinx + php et Sphinx Exemple de recherche sur un projet réel - Magasin de pièces détachées Tecdoc je vous conseille de commencer par eux.


Pendant un certain temps, une recherche via LIKE pour chaque mot de la requête a fonctionné sur mon site. J'en voulais plus, et voici quelques cas qui seront désormais traités correctement:


  • Formes de mots. La sortie pour «vis» et «vis» doit être la même.
  • Recherche par fragment de mot.
  • Recherchez des nombres non entiers. Séparateur point et virgule.
  • Lettre y
  • Erreurs courantes. Par exemple, «Amortisseur».
  • Synonymes Régulateur et ESC.
  • Langue. mAh et mAh, B et V, AAA latin et cyrillique.
  • Mot composé de lettres et de chiffres. 10x15x4, 6000mAh

Section source et tri facultatif


Le problème doit d'abord contenir des articles en stock, puis temporairement absents, puis archivés. Et ces trois groupes devraient être triés par pertinence. Pour ce faire, vous devez définir les attributs. Dans mon cas, ce sont les champs de dégagement et in_stock de la section source sphinx.conf


sql_query = \ SELECT id, `art`, `name`, `clearance`, `in_stock` \ FROM items_zip WHERE show_flag=1 sql_attr_bool = clearance sql_attr_uint = in_stock 

Ces champs seront utilisés pour générer une sortie en PHP. Je décrirai ci-dessous.


Section d'index dans sphinx.conf


morphologie = stem_enru
La morphologie résout mon premier problème. Une recherche de «roulements», «roulements», «roulements» conduira à un seul résultat.


Les tiges (stem_enru) sont plus rapides, les lemmes (lemmatize_ru) sont plus précis. Je n'ai essayé que des balbutiements. Le choix affectera votre dictionnaire de remplacements de formes de mots. Vous voulez changer - vous devez réécrire.


min_word_len = 1
Index des mots de n'importe quelle longueur.


html_strip = 1
Supprimer les balises html


min_infix_len = 1
La recherche se fera sur un fragment du mot. Index des fragments jusqu'à 1 lettre. Étant donné que j'ai moins de 10 000 éléments dans la base de données, je n'économise pas sur l'index.


expand_keywords = 1
Mène automatiquement la requête au formulaire "(en cours d'exécution | en cours d'exécution = en cours d'exécution)". min_infix_len et expand_keywords entraîneront RV 2205 pour émettre RV2205. Au fait, un tiret est un séparateur équivalent à un espace. Le RV-2205 donnera donc le même RV2205.


charset_table = 0..9, A..Z-> a..z, _, a..z, U + 410..U + 42F-> U + 430..U + 44F, U + 430..U + 44F, U + 401-> U + 0435, U + 451-> U + 0435
Nous apportons l'alphabet latin et l'alphabet cyrillique en minuscules. remplacer par e.


blend_chars = +, &, U + 2C, U + 2E
J'ai beaucoup de nombres non entiers. Ils doivent être entièrement indexés. U + 2C et U + 2E sont un point et une virgule. Par exemple, 1,25 sera indexé en tant que «1,25», «1» et «25».


regexp_filter = (\ d +) \, (\ d +) => \ 1. \ 2
Les décimales dans les nombres peuvent être séparées par des points et des virgules: "1,75", "1,75". Nous mettons tout au point


Synonymes et fautes de frappe


Les unités de mesure peuvent être écrites en russe ou en anglais: mm-mm, mAh-mAh, mW-mW. Ajoutez au dictionnaire des synonymes, dont le chemin est spécifié dans les formes de mots: "mach> mah". Je choisis la langue de l'index selon mes propres préférences.


Le signe ~ indique d'appliquer le remplacement après le gestionnaire de morphologie. Cela vous permet de ne pas écrire toutes les formes de mots et au lieu des règles pour 'crust', 'crust', 'crust' d'écrire "~ cork> body"


Ma liste est complète:


 ~ > esc  > esc  > mah ~ >  ~ >  ~ > buzz ~ > buzz ~ > buzz ~ > buzz ~ > buzz ~ >  ~ >  ~ >  li-po > lipo ~ >  ~ >   >   >  vtx >  ~ >  lollipop > lolipop battery >  ~ >  ~ >  ~ >  mkF >   > BEC  > BEC ~ >  LED >  ~ >  driver >  ~ >  ~ >   > AAA  > AA  > M mm >   > mW  > V  > A deans > t-plug tplug > t-plug 

Coller des lettres aux chiffres


Parfois, les chiffres font partie du nom (par exemple LCD5208D), mais le plus souvent une caractéristique (100mAh, 10x15x4mm). Séparez tous les chiffres des lettres et de l'index.


Cela résoudra plusieurs problèmes:


  • Quelqu'un cherchera "portant 10x15x4", quelqu'un "portant 15x10x4". Les nombres indexés donneront la sortie correcte.
  • Les unités de mesure peuvent ou non être séparées par un espace du nombre: "1,75 mm", "1,75 mm".
  • Pour les titres, cela est également utile. La sortie correcte sera dans les trois options d'enregistrement LCD-5208, LCD 5208 et LCD5208

Avant d'écrire une expression régulière pour séparer les nombres, vous devez unifier les délimiteurs. Il est important de se rappeler que les expressions régulières sont exécutées toutes et séquentiellement.


Nous supprimons le x, lui et l'étoile dans des tailles comme 10x4x4 M3x10:


 regexp_filter = (\d+)[x\x{0445}\*] => \1 x 

Laissez tomber la queue:


 regexp_filter = (\d*\.?\d+)(\D+) => \1 \2 

Et les têtes:


 regexp_filter = (\D+)(\d*\.?\d+) => \1 \2 

Nous éliminons les "mm", car ils ne sont souvent pas indiqués dans le nom du produit.
Créez un fichier stop.txt et écrivez-le dans des mots vides.
Contenu:


  mm 

Maintenant un peu sur PHP


Sphinxapi sera déprécié tôt ou tard. Nous utiliserons Sphinxql. Pour ce faire, connectez-vous à la base de données. Dans mon cas, Sphinx est connecté via l'hébergement, cela ressemble à ceci:


 $opt = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => TRUE, ); $dsn = 'mysql:host=127.0.0.1;port=9306;'; $this->pdo = new PDO($dsn, DB_USER, DB_PASS, $opt); 

Et toutes les communications avec Spinxql sont un seul SELECT transmettant le texte de requête filtré


 $stmt = $this->pdo->prepare("SELECT `id`, WEIGHT() as `w`, in_stock>0 AS stock FROM `items` WHERE MATCH ('".$search."') ORDER BY clearance ASC, stock DESC, w DESC LIMIT ".$limit." OPTION field_weights=(name=10, art=3, cat_names=3, model_names=3)"); 

SphinxQL ne comprend pas les expressions dans la section de tri ORDER BY, donc WEIGHT () et in_stock> 0 ont dû être mis dans des champs. Soit dit en passant, la limite par défaut n'est que de 20.


Le tri produira d'abord des articles en stock, puis temporairement absents, puis archivés. Et tous ces trois groupes seront triés par pertinence (poids).


Grâce à field_weights, nous définissons quels champs auront plus de poids.


En remplissant la demande, nous obtenons un tableau d'identification trié. Mais, malheureusement, la sélection des données via WHERE id IN () violera ce tri. Vous devez former votre demande pour chaque identifiant.


Dans la phase de débogage , la requête SHOW META immédiatement après la requête SELECT aide beaucoup. Surtout pour vérifier les formes de mots du dictionnaire et les filtres d'expressions régulières. Vous pouvez voir la liste des mots clés dans lesquels la requête s'est développée.


Complication de sql_query


Nous vendons des pièces détachées. J'ai décidé d'ajouter le nom de la catégorie de produit et le nom du modèle pour lequel la pièce de rechange est destinée à être ajoutée à l'index. Mais chaque produit peut être lié à plusieurs catégories à la fois et convenir à plusieurs modèles. Et j'ai découvert la fonction GROUP_CONCAT qui permet d'obtenir des données en les regroupant dans une chaîne. Par exemple, le champ categories.name contiendra toutes les catégories de l'élément items_zip.id séparées par des espaces.


 SELECT items_zip.id, `art`, items_zip.`name`, `clearance`, `in_stock`, GROUP_CONCAT(DISTINCT categories.name SEPARATOR ' ') AS cat_names, GROUP_CONCAT(DISTINCT items.family SEPARATOR ' ') AS model_names FROM items_zip LEFT JOIN items_cat ON items_cat.item_id=items_zip.id LEFT JOIN categories ON categories.id=items_cat.cat_id LEFT JOIN zip_comp ON zip_comp.zip_id=items_zip.id LEFT JOIN items ON zip_comp.model_id=items.id WHERE items_zip.show_flag=1 GROUP BY items_zip.id 

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


All Articles