sql >> データベース >  >> RDS >> Mysql

類似の結果を見つけて類似度で並べ替える方法は?

    別の完全な文字列に対して完全な文字列を検索する場合、レーベンシュタイン距離が適切である可能性があることがわかりましたが、文字列内のキーワードを検索する場合、このメソッドは(場合によっては)目的の結果を返しません。また、SOUNDEX関数は英語以外の言語には適していないため、かなり制限されています。あなたはLIKEで逃げることができます、しかしそれは本当に基本的な検索のためです。達成したいことについて、他の検索方法を調べたいと思うかもしれません。例:

    Lucene を使用できます プロジェクトの検索ベースとして。これはほとんどの主要なプログラミング言語で実装されており、非常に高速で用途が広いでしょう。この方法は、部分文字列だけでなく、文字の転置、接頭辞、接尾辞(すべて組み合わせて)も検索するため、おそらく最適です。ただし、別のインデックスを保持する必要があります(CRONを使用して、独立したスクリプトからインデックスを更新することもあります)。

    または、MySQLソリューションが必要な場合は、フルテキスト機能は非常に優れており、ストアドプロシージャよりも確かに高速です。テーブルがMyISAMでない場合は、一時テーブルを作成してから、全文検索を実行できます:

    CREATE TABLE IF NOT EXISTS `tests`.`data_table` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `title` varchar(2000) CHARACTER SET latin1 NOT NULL,
      `description` text CHARACTER SET latin1 NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1 ;
    

    データジェネレーター を使用します わざわざ自分で作成したくない場合は、ランダムデータを生成します...

    ** **:列タイプはlatin1_binである必要があります latin1で大文字と小文字を区別せずに、大文字と小文字を区別して検索を実行する 。 Unicode文字列の場合、utf8_binをお勧めします 大文字と小文字を区別し、utf8_general_ciの場合 大文字と小文字を区別しない検索の場合。

    DROP TABLE IF EXISTS `tests`.`data_table_temp`;
    CREATE TEMPORARY TABLE `tests`.`data_table_temp`
       SELECT * FROM `tests`.`data_table`;
    
    ALTER TABLE `tests`.`data_table_temp`  ENGINE = MYISAM;
    
    ALTER TABLE `tests`.`data_table_temp` ADD FULLTEXT `FTK_title_description` (
      `title` ,
      `description`
    );
    
    SELECT *,
           MATCH (`title`,`description`)
           AGAINST ('+so* +nullam lorem' IN BOOLEAN MODE) as `score`
      FROM `tests`.`data_table_temp`
     WHERE MATCH (`title`,`description`)
           AGAINST ('+so* +nullam lorem' IN BOOLEAN MODE)
     ORDER BY `score` DESC;
    
    DROP TABLE `tests`.`data_table_temp`;
    

    詳細については、MySQLAPIリファレンスページ>

    これの欠点は、文字の転置や「似たような」単語を検索しないことです。

    **更新 **

    Luceneを検索に使用すると、cronジョブを作成する必要があります(すべてのWebホストにこの「機能」があります)。このジョブはPHPスクリプト(例:「cd / path / to / script;phpsearchindexer.php」」を実行するだけです。 )インデックスを更新します。その理由は、何千もの「ドキュメント」(行、データなど)のインデックス作成に数秒、場合によっては数分かかる場合があるためですが、これはすべての検索が可能な限り高速に実行されるようにするためです。したがって、サーバーによって実行される遅延ジョブを作成することをお勧めします。それは一晩かもしれません、または次の時間で、これはあなた次第です。 PHPスクリプトは次のようになります。

    $indexer = Zend_Search_Lucene::create('/path/to/lucene/data');
    
    Zend_Search_Lucene_Analysis_Analyzer::setDefault(
      // change this option for your need
      new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive()
    );
    
    $rowSet = getDataRowSet();  // perform your SQL query to fetch whatever you need to index
    foreach ($rowSet as $row) {
       $doc = new Zend_Search_Lucene_Document();
       $doc->addField(Zend_Search_Lucene_Field::text('field1', $row->field1, 'utf-8'))
           ->addField(Zend_Search_Lucene_Field::text('field2', $row->field2, 'utf-8'))
           ->addField(Zend_Search_Lucene_Field::unIndexed('someValue', $someVariable))
           ->addField(Zend_Search_Lucene_Field::unIndexed('someObj', serialize($obj), 'utf-8'))
      ;
      $indexer->addDocument($doc);
    }
    
    // ... you can get as many $rowSet as you want and create as many documents
    // as you wish... each document doesn't necessarily need the same fields...
    // Lucene is pretty flexible on this
    
    $indexer->optimize();  // do this every time you add more data to you indexer...
    $indexer->commit();    // finalize the process
    

    次に、これが基本的に検索方法です(基本検索):

    $index = Zend_Search_Lucene::open('/path/to/lucene/data');
    
    // same search options
    Zend_Search_Lucene_Analysis_Analyzer::setDefault(
       new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive()
    );
    
    Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding('utf-8');
    
    $query = 'php +field1:foo';  // search for the word 'php' in any field,
                                     // +search for 'foo' in field 'field1'
    
    $hits = $index->find($query);
    
    $numHits = count($hits);
    foreach ($hits as $hit) {
       $score = $hit->score;  // the hit weight
       $field1 = $hit->field1;
       // etc.
    }
    

    Java のLuceneに関する優れたサイトは次のとおりです。 、 PHP 、および。Net

    結論 各検索方法には、独自の長所と短所があります:

    • スフィンクス検索 についておっしゃいました Webホストでデーモンを実行できる限り、非常に見栄えがします。
    • Zend Luceneでは、データベースのインデックスを再作成するためにcronジョブが必要です。ユーザーには非常に透過的ですが、これは、新しいデータ(または削除されたデータ!)がデータベース内のデータと常に同期しているとは限らないため、ユーザー検索ですぐに表示されないことを意味します。
    • MySQL FULLTEXT検索は優れていて高速ですが、最初の2つの機能と柔軟性をすべて提供できるわけではありません。

    何か忘れたり、見逃したりした場合は、遠慮なくコメントしてください。



    1. 列dbo、ユーザー定義関数、または集計dbo.Splitfnが見つからないか、名前があいまいです

    2. InformaticaPowerCenterでのEasysoftODBCドライバーの使用

    3. SQLのデータ型のサイズを変更します

    4. データベースプロキシのフェイルオーバー時間の比較-ProxySQL、MaxScale、HAProxy