2017-01-18 14 views
0

いくつかのテストを実行した後、クエリの一部の単語が短い場合(2〜3文字)、検索メソッドがうまく機能しないことに気づきました。検索機能の最適化MySQLまたはPHPの賢明

私が検索を行ったのは、訪問者が入力した文字列のすべての単語に対してMySQLクエリを作成し、各単語の結果をフィルタリングして各単語にその結果があるかどうかを確認することです。すべての単語に対して1つの結果が返されると、一致とilはその結果を訪問者に示します。

しかし、それが効果的な方法であるかどうかは分かりませんでした。同じ機能を維持しながら、より良い方法はありますか?

現在、私が持っているコードは、.7SecがMySQLクエリを作成するのに要します。残りのものは0.1秒未満です。 通常、私は7Secを取って検索することについてはあまり気にしませんが、Idは「LiveSearch」を作成するのが好きで、それより速く読み込むことが重要です。

はここfulltext searchはあなたの友人である、私のコード

他の人が既に提案してきたように
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

フルテキスト検索の調査を行います。あなたの実装は最適化することはできません( '%'で始まるオペランドで 'like 'は常に完全なテーブルスキャンの場合です)。 – zerkms

+1

[mysqlの全文検索](http://dev.mysql.com/doc/refman/5.7/en/fulltext-search.html) –

+0

@zerkmsコメントありがとうございます、読者の後で、私は(FreeShippingのpurpusesのために)注射するfunctionallityを緩めるそれを考えることは正しいですか? 私は単純に完全な検索を行い、その後、無料の配送ではない(顧客がそれを検索した場合)PHPのアイテムを削除することで回避することができます。しかし、条件に基づいてテキストを「注入」するフルテキストでは、より良い方法がありますか? –

答えて

0

です。

ロジックはこれほど多かれ少なかれ次のようになります。

  • 「FtSearch」
  • が持っているテキスト、既存の各製品に対して、あなたが書いている、一度だけ実行されます小さなスクリプトを書く、と言う、と呼ばれるあなたの「product_products」テーブルにテキスト列を追加します。 「FtSearch」欄に検索される。これはもちろん、クエリで作成するテキスト(ID +ブランド名+タイトルなど、FreeShipping部分を含む)です。あなたはおそらく単一のSQL文でこれを行うことができますが、私は手元にmysqlを持っておらず、そのコードを提供することはできません...自分でそれを見つけることができるかもしれません。
  • 「FtSearch」列に全文索引を作成します(にFtSearch列を移入した後にを実行すると、実行時間が短縮されます)。
  • 検索文字列に含まれるフィールドが挿入/更新されるたびに検索文字列を挿入/更新するために必要なコードを追加する必要があります。これには、「product_product」の「Title」、「ModelNumber」、「FreeShipping」だけでなく、「product_brand」の「Name」も含まれているため、ここで注意してください。これは、product_brandの名前が更新された場合、そのブランドを持つすべての製品のすべての検索文字列を再生成する必要があることを意味します。これは、そのブランドに縛られている製品の数に応じて、少し遅いかもしれません。しかし、ブランドがその名前を変更することはあまり頻繁に起こらないと想定しています。そうした場合、それは通常受け入れられる管理インターフェースの中で起こります。
  • この時点でMATCH構成を使用してテーブルを照会することができます。この方法は、現在の方法を使用してこれまでに得ることのできる高速です。
+0

クールで、はるかに速く検索できます。 (0.05〜秒)しかし、それは簡単にDEDICATEDサーバのボトルネックになるかもしれません...笑。検索語があまりにも一般的な場合。私は以下の構文で 'match(' ftSearch')を検索しています(+ firstWord * + otherword * BOOLEAN MODEの中) recomentationはありますか? –

+1

少数: - ユーザーが入力中にライブ検索を行っている場合は、最後に入力された単語(まだタイプされているもの)を除くすべての単語の末尾に '*'を表示しないでください。 - 第2に、ユーザーが2文字以上入力したときに検索を開始します。 - 最後に、多くの呼び出しを避けます:ユーザーが新しい文字を入力した場合にのみクエリを実行し、さらにユーザーがさらに文字を入力する場合は小さなタイムアウト(200 ms程度)を設定し、最後の入力された文字からタイムアウトが経過したときにのみ検索を行います。 – xzoert