2017-01-18 1 views
0

Nach ein paar Tests habe ich festgestellt, dass meine Suchmethode nicht sehr gut funktioniert, wenn einige Wörter der Abfrage kurz ist (2 ~ 3 Buchstaben).Optimierung der Suchfunktion MySQL oder PHP weise

Die Art, wie ich die Suche gemacht habe, besteht darin, eine MySQL-Abfrage für jedes Wort in der vom Besucher eingegebenen Zeichenfolge durchzuführen und dann das Ergebnis jedes Wortes zu filtern, um zu sehen, ob jedes Wort das Ergebnis hat. Sobald ein Ergebnis für alle Wörter zurückgegeben wurde, wird ein Treffer angezeigt und das Ergebnis wird dem Besucher angezeigt.

Aber ich fragte mich, ob das ein effektiver Weg ist, es zu tun. Gibt es einen besseren Weg bei gleicher Funktionalität?

Derzeit dauert der Code, den ich über .7Sec mache MySQL-Abfragen. Und der Rest ist unter .1Sec. Normalerweise würde ich mich nicht viel um meine Suche kümmern .7Sec, Aber ich mag es, eine "LiveSearch" zu erstellen und ist entscheidend, dass es schneller lädt als das.

Hier ist mein Code

public static function Search($Query){ 
     $Querys = explode(' ',$Query); 
     foreach($Querys as $Query) 
     { 
      $MatchingRow = \Database\dbCon::$dbCon -> prepare(" 
       SELECT 
        `Id` 
       FROM 
        `product_products` as pp 
       WHERE 
        CONCAT(
         `Id`, 
         ' ', 
         (SELECT `Name` FROM `product_brands` WHERE `Id` = pp.BrandId), 
         ' ', 
         `ModelNumber`, 
         ' ', 
         `Title`, 
         IF(`isFreeShipping` = 1 OR `isFreeShippingOnOrder` = 1, ' FreeShipping', '') 
        ) 
       LIKE :Title; 
       "); 
      $MatchingRow -> bindValue(':Title','%'.$Query.'%'); 
      try{ 
       $MatchingRow -> execute(); 
       foreach($MatchingRow -> fetchAll(\PDO::FETCH_ASSOC) as $QueryInfo) 
        $Matchings[$Query][$QueryInfo['Id']] = $QueryInfo['Id']; 
      }catch(\PDOException $e){ 
       echo 'Error MySQL: '.$e->getMessage(); 
      } 
     } 
     $TmpMatch = $Matchings; 
     $Matches = array_shift(array_values($TmpMatch)); 
     foreach($TmpMatch as $Query) 
     { 
      $Matches = array_intersect($Matches,$Query); 
     } 
     foreach($Matches as $Match){ 
      $Products[] = new Product($Match); 
     } 
     return $Products; 
    } 
+2

Recherchieren Sie über die Volltextsuche. Ihre Implementierung ist nicht möglich zu optimieren ('like' mit einem Operanden, der mit'% 'beginnt, würde immer einen vollständigen Tabellenscan ergeben). – zerkms

+1

[Volltextsuche in Mysql] (http://dev.mysql.com/doc/refman/5.7/en/fulltext-search.html) –

+0

@zerkms Danke für Sie Kommentare Jungs, Nach dem Lesen erkannte ich, dass ich werde verliere die Funktionalität zu injizieren (für FreeShipping Zwecke) Habe ich Recht, das zu denken? Ich könnte es umgehen, indem Sie einfach die vollständige Suche und dann mit PHP entfernen Artikel, die nicht frei Versand (wenn Kunde suchte es).Aber gibt es einen besseren Weg mit Volltext, um Text basierend auf dem Zustand zu "injizieren"? –

Antwort

0

Wie andere haben bereits angedeutet, fulltext search dein Freund.

Die Logik sollte mehr oder weniger so gehen.

  • eine Textspalte zu Ihrer „product_products“ Tabelle hinzufügen genannt, sagen sie, „FTSearch“
  • ein kleines Skript schreiben, die nur einmal ausgeführt werden, in dem Sie für jedes bestehendes Produkt, den Text schreiben, der hat in der Spalte "FtSearch" gesucht werden. Dies ist natürlich der Text, den Sie in Ihrer Anfrage verfassen (ID + Markenname + Titel usw., einschließlich des FreeShipping-Teils). Sie können dies wahrscheinlich mit einer einzigen SQL-Anweisung tun, aber ich habe keine MySQL-Version zur Hand und kann Ihnen den Code dafür nicht zur Verfügung stellen ... Sie könnten es vielleicht selbst herausfinden.
  • Erstellen Sie einen Volltextindex in der "FtSearch" -Spalte (dies nach mit der FtSearch-Spalte gefüllt spart Ihnen ein wenig Ausführungszeit).
  • Jetzt müssen Sie den Code hinzufügen, der notwendig ist, um sicherzustellen, dass jedes Mal, wenn eines der Felder in die Suchzeichenfolge eingefügt/aktualisiert wird, auch die Suchzeichenfolge eingefügt/aktualisiert wird. Beachten Sie hier, da dies nicht nur den "Title", "ModelNumber" und "FreeShipping" des "product_product" beinhaltet, sondern auch den "Name" der "product_brand". Das heißt, wenn der Name einer product_brand aktualisiert wird, müssen Sie alle Suchstrings aller Produkte neu generieren, die diese Marke haben. Dies kann ein wenig langsam sein, abhängig davon, wie viele Produkte an diese Marke gebunden sind. Ich nehme jedoch an, dass es nicht allzu oft vorkommt, dass eine Marke ihren Namen ändert, und wenn dies der Fall ist, geschieht dies sicherlich in einer Art Verwaltungsschnittstelle, wo solche Dinge normalerweise akzeptabel sind.
  • An diesem Punkt können Sie die Tabelle mit dem MATCH Konstrukt abfragen, was viel schneller ist, als Sie jemals mit Ihrem aktuellen Ansatz erreichen könnten.
+0

Cool, es sucht viel schneller. (0.05 ~ Sec) Aber auch, es kann leicht den DEDICATED Server zu Botleneck ... lol. Wenn die Suchbegriffe zu allgemein sind. Ich suche mit der folgenden Syntax 'match (' ftSearch') gegen (+ firstWord * + otherword * IN BOOLEAN MODE) Beliebige Empfehlung? –

+1

Ein paar: - Wenn es eine Live-Suche ist, während der Benutzer tippt, können Sie wahrscheinlich das '*' am Ende aller Wörter mit Ausnahme der letzten (die noch getippt wird) vermeiden. - Zweitens, starten Sie die Suche, wenn der Benutzer mindestens 2 Zeichen eingegeben hat. - Und zu guter Letzt vermeiden Sie viele Anrufe: Führen Sie eine Abfrage nur durch, wenn der Benutzer einen neuen Buchstaben eingegeben hat, und stellen Sie eine kleine Zeitüberschreitung (200 ms oder so) für den Fall ein, dass der Benutzer weitere Buchstaben eingibt. und führen Sie nur eine Suche durch, wenn das Zeitlimit seit dem letzten eingegebenen Zeichen vergangen ist. – xzoert