Mysql
 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`;

Прочетете повече за това от референтната страница на MySQL API

Недостатъкът на това е, че няма да търси транспониране на букви или думи „подобни, звучи като“.

** АКТУАЛИЗИРАНЕ **

Използвайки Lucene за вашето търсене, просто ще трябва да създадете задание за cron (всички уеб хостове имат тази "функция"), където тази задача просто ще изпълни PHP скрипт (напр. "cd /path/to/script; php searchindexer.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.
}

Ето страхотни сайтове за Lucene в Java , PHP и .Net .

В заключение всеки метод за търсене има своите плюсове и минуси:

  • Споменахте търсене на Сфинкс и изглежда много добре, стига да можете да накарате deamon да работи на вашия уеб хост.
  • Zend Lucene изисква cron задание за повторно индексиране на базата данни. Въпреки че е доста прозрачно за потребителя, това означава, че всички нови данни (или изтрити данни!) не винаги са в синхрон с данните във вашата база данни и следователно няма да се покажат веднага при търсене на потребител.
  • MySQL FULLTEXT търсенето е добро и бързо, но няма да ви даде цялата сила и гъвкавост на първите две.

Моля, не се колебайте да коментирате, ако съм забравил/пропуснал нещо.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Инсталиране на gem:Неуспешно изграждане на родно разширение на gem (не мога да намеря заглавни файлове)

  2. GROUP_CONCAT с ограничение

  3. Върнете ред само ако стойността не съществува

  4. Функция MySQL RADIANS() – Преобразуване от градуси в радиани

  5. DATE_FORMAT() Примери – MySQL