Как найти подобные результаты и вид подобием?

Как я запрашиваю для записей, заказанных подобием?

Например, поиск "Переполнения Запаса" возвратился бы

  1. Переполнение стека
  2. Переполнение SharePoint
  3. Математическое переполнение
  4. Благоразумное переполнение
  5. Переполнение VFX

Например, поиск "LO" возвратился бы:

  1. pabLO picasso
  2. michelangeLO
  3. сайда jackson

С чем я нуждаюсь в помощи:

  1. Используя поисковую систему, чтобы индексировать и искать таблицу MySQL, для лучших результатов

    • Используя поисковую систему Сфинкса, с PHP

    • Используя механизм Lucene с PHP

  2. Используя полнотекстовое индексирование, для нахождения подобных/содержащих строк


Что не работает хорошо

  • Расстояние Левенштейна очень ошибочно. (UDF, Запрос)
    Поиск "собаки" дает мне:
    1. собака
    2. трясина
    3. назад
    4. большой
    5. эхо
  • LIKE лучшие результаты возвратов, но возвраты ничто для долгих запросов, хотя подобные строки действительно существуют
    1. собака
    2. dogid
    3. dogaral
    4. догма

67
задан OMG Ponies 5 May 2011 в 23:46
поделиться

2 ответа

Я обнаружил, что расстояние Левенштейна может быть хорошим, когда вы ищете полную строку по сравнению с другой полной строкой, но когда вы ищете ключевые слова внутри строки, этот метод не возвращает ( иногда) желаемые результаты. Кроме того, функция 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 .

В заключение у каждого метода поиска есть свои плюсы и минусы:

  • Вы упомянули поиск Sphinx , и он выглядит очень хорошо, если вы можете запустить демон на своем веб-хосте. .
  • Zend Lucene требует задания cron для повторного индексирования базы данных.Хотя это совершенно прозрачно для пользователя, это означает, что любые новые данные (или удаленные данные!) Не всегда синхронизируются с данными в вашей базе данных и, следовательно, не будут сразу отображаться при поиске пользователя.
  • MySQL FULLTEXT поиск хорош и быстр, но не даст вам всей мощности и гибкости первых двух.

Не стесняйтесь комментировать, если я что-то забыл / пропустил.

83
ответ дан 24 November 2019 в 14:40
поделиться

1. Сходство

Для Левенштейна в MySQL я нашел это из www.codejanitor.com/wp/2007/02/10/levenshtein-distance-as-a-mysql-stored-function

SELECT 
    column, 
    LEVENSHTEIN(column, 'search_string') AS distance 
FROM table 
WHERE 
    LEVENSHTEIN(column, 'search_string') < distance_limit
ORDER BY distance DESC

2. Содержит, нечувствителен к регистру

Используйте оператор MySQL LIKE , который по умолчанию не чувствителен к регистру. % является подстановочным знаком, поэтому может быть любая строка до и после search_string .

SELECT 
    *
FROM 
    table
WHERE 
    column_name LIKE "%search_string%"

3. Содержит, чувствителен к регистру

Справочник MySQL помогает:

Набор символов и сопоставление по умолчанию - latin1 и latin1_swedish_ci, поэтому небинарные сравнения строк по умолчанию нечувствительны к регистру. Это означает, что если вы выполняете поиск с col_name LIKE 'a%', вы получите все значения столбцов, которые начинаются с A или a. Чтобы сделать этот поиск чувствительным к регистру, убедитесь, что один из операндов имеет чувствительное к регистру или двоичное сопоставление. Например, если вы сравниваете столбец и строку, которые оба имеют набор символов latin1, вы можете использовать оператор COLLATE, чтобы заставить любой операнд иметь сопоставление latin1_general_cs или latin1_bin ...

Моя установка MySQL не поддерживает latin1_general_cs или latin1_bin , но у меня было нормально использовать сопоставление utf8_bin , поскольку двоичный utf8 чувствителен к регистру:

SELECT 
    *
FROM 
    table
WHERE 
    column_name LIKE "%search_string%" COLLATE utf8_bin

2. / 3. отсортировано по Левенштейну Расстояние

SELECT 
    column, 
    LEVENSHTEIN(column, 'search_string') AS distance // for sorting
FROM table 
WHERE 
    column_name LIKE "%search_string%"
    COLLATE utf8_bin // for case sensitivity, just leave out for CI
ORDER BY
    distance
    DESC
21
ответ дан 24 November 2019 в 14:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: