5
votes

PHP / SQL - Amélioration de la fonction de recherche / recherche floue

J'essaie de créer une recherche de produits pour mon site, où un utilisateur peut rechercher des produits dans plusieurs langues et (espérons-le) obtenir des résultats de recherche flous s'il n'y a pas de correspondance exacte.

  • J'ai une table pro_search qui contient les colonnes id, pro_id, en, de, es, fr, ça .
  • La colonne pro_id fait référence à l'ID des produits dans leur propre table.
  • Les colonnes en, de, es, fr, it ont la traduction meta de chaque produit dans différentes langues.
  • La méta n'est que des mots-clés séparés par des espaces
  • $ term est le terme de recherche.
  • $ lang fait référence à la langue choisie par les utilisateurs

Je fais donc d'abord une requête SQL de base 'LIKE' pour voir s'il y a des correspondances, s'il n'y a pas de résultats, j'interroge tous les produits et crée un tableau trié par leur similitude en utilisant le similar_text () function

Par exemple, je recherche «chemise», c'est bien si la méta de ce produit comprend juste le mot «chemise», mais si la méta inclut «tshirt de marque bleu», ceci est plus descriptif et donne à l'utilisateur une chance de rechercher par marque, mais signifie que la recherche sera plus que probablement floue plutôt que d'être trouvée avec une requête SQL LIKE .

Ceci cela fonctionne en quelque sorte, mais je me demandais comment cela pourrait être amélioré, y a-t-il une meilleure façon de rechercher ou comment les gens font-ils normalement? Dois-je diviser la méta en chaque mot-clé individuel et essayer de voir combien de mots correspondent plutôt que de faire correspondre le terme à l'ensemble de la méta?

    $ids = [];

    $params = ['%'.$term.'%'];
    $sql = "SELECT * FROM pro_search WHERE $lang LIKE ?";
    $stmt = DB::run($sql,$params);

    $count = $stmt->rowCount();
    if($count > 0){

        // product search
        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
            $id = $row["pro_id"];
            array_push($ids,$id);
        }
        show_products($ids);

    }else{

        // product fuzzy search
        $sql = "SELECT * FROM pro_search";
        $stmt = DB::run($sql);
        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
            $id = $row["pro_id"];
            $result = $row[$lang];
            similar_text($term,$result,$similarity);
            $similar_array[$similarity][] = $id;
        }

        $closest_match = array_keys($similar_array);
        rsort($closest_match);
        $match_count = count($closest_match);

        for($i=0; $i<$match_count; $i++){
            foreach($similar_array[$closest_match[$i]] as $id){
                array_push($ids,$id);
            }
        }
        show_products($ids);
    }

J'ai déjà posé des questions similaires et les gens m'ont indiqué différentes façons de comparer le terme à la méta (comme levenshtein), mais tout ce que j'ai vu a comparé deux mots simples (comme des pommes et des oranges) et ce n'est tout simplement pas assez bon pour une vraie vie application avec des milliers de produits et un utilisateur peut rechercher littéralement n'importe quoi (comme dans $ term = 'littéralement n'importe quoi'; )

Questions clés:

  • Si ma méta ne contient que le nom du produit ou plusieurs mots-clés (trop de mots-clés signifie qu'un mot individuel est moins similaire à l'ensemble)?
  • Si j'ai plusieurs mots clés dans la méta, devrais-je être prendre chaque mot-clé individuel et le comparer à la recherche terme?
  • Serait-il également possible d'avoir des mots clés à exclure pour produits individuels.


5 commentaires

Avez-vous pensé à utiliser une base de données uniquement pour cette exigence? Elasticsearch pourrait être en mesure de gérer tout cela avec des performances plus élevées que l'écriture de code personnalisé. Avoir plusieurs visites simultanées sur cette recherche entraînera sinon des temps de chargement très élevés


"Comment les gens le font-ils normalement?" - le meilleur choix est de créer un index Elastic, il possède de nombreuses fonctionnalités que vous ne pouvez tout simplement pas obtenir en SQL. Nous avons essayé SQL dans notre projet, mais nous avons eu du mal avec les fautes de frappe, les alias, les classements, etc., Elastic a des fonctionnalités intégrées pour le traitement du langage naturel.


Je n'ai jamais utilisé la recherche élastique auparavant, mais je vais l'examiner même si je n'aime pas avoir trop de dépendances


Quel SGBDR utilisez-vous? Certains moteurs offrent des fonctionnalités qui peuvent vous aider si vous ne voulez pas vous lancer et payer pour des tiers. SQL Server a Recherche en texte intégral , tout comme PostgreSQL , et < a href = "https://dev.mysql.com/doc/refman/8.0/en/fulltext-search.html" rel = "nofollow noreferrer"> MySQL .


J'utilise mySQL, merci je regarderai également la recherche en texte intégral. Je finirai probablement par tester une combinaison de choses


3 Réponses :


2
votes

Vous pouvez utiliser SOUNDEX dans sql

SELECT * FROM users 
           WHERE SOUNDEX(job) 
LIKE CONCAT('%',SUBSTRING(SOUNDEX('Manual worker'),2),'%');

Et des choses comme Manuel de travail fonctionneront. Il vous suffit d'ajuster la valeur (actuellement 2 ) en fonction de vos besoins.

Je vois que vous avez déjà essayé l'algorithme de Levenshtein mais vous devriez avoir un œil sur cette adaptation (qui est également compatible avec les chaînes UTF-8)

Pour mon cas, le soundex était plus efficace, cela dépendra de la manière dont vos utilisateurs vont interagir avec votre application.


Mais comme dit dans le commentaire, des tiers comme ElasticSearch ou Algolia peut être bien plus efficace.

Pour ma part je ne l'ai jamais utilisé car la société ne nous autorise pas à utiliser des logiciels tiers. C'est pourquoi j'ai essayé à la fois Levensthein et Soundex


3 commentaires

Je ne suis pas sûr que vous compreniez ce que je vous demande, j'ai déjà examiné levenshtein et soundex mais cet article sur soundex est comme ce que j'ai dit en comparant simplement deux mots simples ( SOUNDEX ('Sure'), SOUNDEX ( 'Shore') ). Disons que j'ai des produits: ouvrier, ouvrier électrique, boîte de vitesses manuelle, manuel d'instructions Chacun d'entre eux a une méta qui comprend ce titre et d'autres mots-clés pertinents. Je souhaite qu'un utilisateur puisse rechercher un manuel ou un travailleur dans une autre langue et lorsqu'il est mal orthographié.


C'est ce que j'ai essayé d'expliquer. En combinant Levenshtein et Soundex, cela pourrait fonctionner avec votre cas d'utilisation. Mais peut-être que vous aurez trop de faux positifs. Mais si vous en avez la possibilité, vous aurez un meilleur résultat en utilisant Algolia ou des tiers comme ça. Désolé si ma réponse n'était pas claire


Désolé, ouais, ce n'est pas une question très claire pour commencer, mais je ne sais pas comment je peux être plus claire. Je ne suis pas sûr de pouvoir comparer un terme individuel à un tableau de mots-clés ou à tous les mots-clés sous forme de chaîne de manière à obtenir les meilleurs résultats sans ralentir complètement mon site



3
votes

Vous pouvez penser un peu différemment si vous êtes toujours en train de concevoir le système. En termes de recherche, faites simplement une recherche exacte et faites dans la base de données comme suggéré précédemment, car c'est beaucoup plus rapide - mais "apprenez de chaque interaction".

  • Types d'utilisateurs dans un certain terme
  • Vous effectuez une recherche exacte, si vous le trouvez bien
  • sinon faites une recherche floue pour chaque partie du terme saisi. Toujours pas trouvé, vous faites soundex. Vous essayez de trouver quelque chose! Mais présentez une longue liste à l'utilisateur pour filtrer.
  • Finalement, l'utilisateur en sélectionne un. Dès qu'ils le font, vous ajoutez le terme qu'ils ont saisi au produit qu'ils ont sélectionné.

L'idée fondamentale est que vous apprenez de chaque interaction et que vous enrichissez votre recherche. De plus, chaque fois qu'un terme est l'utilisateur et l'utilisateur clique réellement sur votre article, vous comptez sur cette association terme-produit au fur et à mesure que votre confiance dans cette association terme-produit s'améliore.

De même, chaque fois que vous présentez une option, très facilement l'utilisateur devrait être en mesure de dire "Pas ceci", puis de le guider à travers une hiérarchie présélectionnée de vos éléments et éventuellement, quand il en sélectionne un, vous enregistrez son terme de recherche dans celui produit.

Donc, sur quelques mois, si vous obtenez suffisamment d'utilisateurs, vous disposerez d'un riche ensemble de données de termes de recherche organiques pour votre catégorie de produits avec un niveau de confiance pour chaque terme.


7 commentaires

Salut, merci pour votre réponse, cela sonne bien en théorie, mais je ne suis pas sûr de savoir si cela fonctionnerait dans la pratique. Par exemple, si j'ajoute des termes à la méta en fonction du taux de clics, je pourrais finir par avoir de mauvaises orthographes, etc. étant ajoutées à la méta, cela signifiera simplement que la recherche exacte originale est plus susceptible de devenir floue car il y en a tellement fautes d'orthographe aléatoires dans la méta. Ou comment feriez-vous la recherche initiale pour commencer? Comme je compare un terme avec une, virgule, séparé, liste, de, mots-clés existe-t-il un meilleur moyen de comparer le terme avec des mots-clés individuels


les fautes d'orthographe en sont un bon exemple. les éléments mal orthographiés, je pense, devraient aller en méta Votre objectif n'est pas d'être un professeur d'anglais de 5e année mais de fournir des résultats efficacement aux clients. Donc, si suffisamment de personnes se trompent de la même manière, vous les avez toutes aidées. Je ne considérerais même pas cela comme des "méta-données" - plutôt comme des données de recherche. les méta-données peuvent être une catégorisation plus formelle du produit. Il suffit de voir google, amazon, etc. comment les recherches mal orthographiées fonctionnent également très bien.


Merci encore pour votre commentaire, mais comment feriez-vous la recherche initiale si ce que je recherche contient plusieurs fautes d'orthographe? Une requête SQL LIKE renverra moins de produits réels, plus il y aura de termes supplémentaires dans la base de données. Comme pour la recherche initiale avant qu'elle ne devienne floue?


Si vos utilisateurs sont d'accord avec cette "approche de l'IA des pauvres", dites que les recherches mal orthographiées deviendront valides "au fil du temps de manière organique". Tous les systèmes d'inventaire ont une certaine catégorisation des articles. Votre organisation a probablement cela aussi - votre recherche par défaut peut donc être simplement des recherches exactes sur ceux-ci. Ainsi, aucun article mal orthographié n'est acceptable le jour 1. Lorsqu'une personne comme moi commence à utiliser le système, vos "orthographes alternatives" et votre association avec les produits commenceront à croître avec le "niveau de confiance".


Comment allez-vous stocker les termes de recherche et sur quel produit l'utilisateur clique? Tout ce à quoi je peux penser, c'est comme un tableau associatif où chaque mot est ajouté au produit lorsqu'ils cliquent dessus à partir d'une recherche, puis un score ajouté à chaque mot en fonction du nombre de fois où il est cliqué, mais cela me ramène à mon problème original du moment où je fais une nouvelle recherche, je dois interroger tous les produits pour obtenir tous les tableaux de termes qui correspondent aux produits et qui incluent ce mot, puis les classer par score qui ne sera pas vraiment efficace


De plus, quand vous dites «votre organisation a probablement cela», je suis l'organisation qui développe tout moi-même à partir de zéro, essayant simplement de comprendre les choses au fur et à mesure, donc je ne sais pas de quelle autre manière je les classerais?


Avez-vous examiné les API de traitement du langage naturel? ( cloud.google.com/natural-language/#features ). Et pour la catégorisation des produits, il existe des normes industrielles telles que ungm.org/Public/UNSPSC . Vous pouvez simplement avoir un 1 à plusieurs de votre produit à l'un de ces codes de catégorie. Vous obtenez maintenant une hiérarchie pour accéder gratuitement à votre produit en fonction d'une norme. Il existe des normes concurrentes afin que vous puissiez également en examiner d'autres pour classer vos articles. Donc, par défaut, je parcoure ces catégories pour accéder à votre article.



4
votes

Vous recherchez des Recherches en texte intégral AVEC EXPANSION DE RECHERCHE

MySQL prend en charge la recherche de texte en utilisant l'opérateur LIKE et l'expression régulière. Cependant, lorsque la colonne de texte est grande et que le nombre de lignes dans un tableau est augmenté, l'utilisation de ces méthodes présente certaines limites:

  • Performances: MySQL doit parcourir toute la table pour trouver le texte exact basé sur un modèle dans l'instruction LIKE ou un modèle dans les expressions régulières.
  • Recherche flexible: avec l'opérateur LIKE et les recherches d'expressions régulières, il est difficile d'avoir une requête de recherche flexible, par exemple pour trouver un produit dont la description contient une voiture mais pas un classique.
  • Classement par pertinence: il n'y a aucun moyen de spécifier quelle ligne de l'ensemble de résultats est la plus pertinente pour les termes de recherche.

En raison de ces limitations, MySQL a étendu une très belle fonctionnalité dite de recherche en texte intégral. Techniquement, MySQL crée un index à partir des mots des colonnes de recherche de texte intégral activées et effectue des recherches sur cet index. MySQL utilise un algorithme sophistiqué pour déterminer les lignes correspondant à la requête de recherche.

Pour ce faire, les colonnes qui seront utilisées pour la recherche doivent être de type TEXT et index de type FULLTEXT, l'index peut être donné en utilisant ALTER TABLE ou CREATE INDEX et si vous utilisez phpMyAdmin pour gérer vos bases de données, vous pouvez le faire en allant dans la structure de cette table, puis cliquez sur Plus sous Action de cette colonne et choisissez Texte intégral.

Après cela, vous pouvez effectuer une recherche en utilisant la syntaxe MATCH AGAINST. MATCH () prend les colonnes à rechercher. AGAINST prend une chaîne à rechercher et un modificateur facultatif qui indique le type de recherche à effectuer.

Recherches en texte intégral AVEC EXPANSION DE QUESTION:

Dans certains cas, les utilisateurs souhaitent rechercher des informations sur la base des connaissances dont ils disposent. Les utilisateurs utilisent leur expérience pour définir des mots-clés pour rechercher des informations, et généralement ces mots-clés sont trop courts.

Pour aider les utilisateurs à trouver des informations en fonction des mots-clés trop courts, le moteur de recherche en texte intégral MySQL introduit un concept appelée extension de requête.

L'expansion de requête est utilisée pour élargir le résultat de la recherche des recherches en texte intégral basé sur un retour automatique de pertinence (ou une extension de requête aveugle). Techniquement, le moteur de recherche en texte intégral MySQL effectue les étapes suivantes lorsque l'extension de requête est utilisée:

  • Tout d'abord, le moteur de recherche en texte intégral MySQL recherche toutes les lignes qui correspondent à la requête de recherche.
  • Deuxièmement, il vérifie toutes les lignes du résultat de la recherche et trouve les mots pertinents.
  • Troisièmement, il effectue à nouveau une recherche basée sur les mots pertinents au lieu des mots clés d'origine fournis par les utilisateurs.

L'exemple suivant vous montre comment rechercher un produit dont le nom de produit ou la méta contient au moins un mot (chemise tshirt).

SELECT * FROM products WHERE MATCH(product_name,product_meta) AGAINST('shirt tshirt' WITH QUERY EXPANSION)

Vous pouvez lisez plus d'informations dans le document MYSQL (le lien au début de la réponse) et ici

Ne manquez pas non plus Comment affiner la recherche en texte intégral MySQL


0 commentaires