Как найти похожие результаты и отсортировать по сходству?

Как запросить записи, упорядоченные по сходству?

Eg. поиск "переполнение запасов" вернет

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

Eg. поиск "LO" вернул бы:

  1. Пабло Пикассо
  2. Michelangelo
  3. Джексон ПолЛок

С чем мне нужно помочь:

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

  2. Использование полнотекстовой индексации для поиска похожих /содержащих строки


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

  • расстояние Левенштейна очень неустойчиво. ( UDF , запрос )
    Поиск «собака» дает мне:
    1. собака
    2. болотный
    3. назад
    4. большой
    5. эхо
  • LIKE возвращает лучшие результаты, но ничего не возвращает для длинных запросов, хотя подобные строки существуют
    1. собака
    2. dogid
    3. dogaral
    4. догма
66 голосов | спросил Robinicks 27 J000000Tuesday10 2010, 00:49:48

2 ответа


0

Я обнаружил, что расстояние Левенштейна может быть хорошим, когда вы ищете полную строку по другой полной строке, но когда вы ищете ключевые слова в строке, этот метод не возвращает (иногда) требуемые результаты. Более того, функция SOUNDEX не подходит для языков, отличных от английского, поэтому она довольно ограничена. Вы можете сойти с рук как, но это действительно для базовых поисков. Возможно, вы захотите посмотреть на другие методы поиска того, чего вы хотите достичь. Например:

Вы можете использовать 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. Для строк Юникода я бы порекомендовал 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 (ig «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 хорош и быстр, но не даст вам всех возможностей и гибкости первых двух.

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

ответил Yanick Rochon 27 J000000Tuesday10 2010, 01:08:30
0

Кажется, что ваше определение сходства - это семантическое сходство. Таким образом, чтобы построить такую ​​функцию подобия, вы должны использовать семантические меры сходства. Обратите внимание, что объем работ по этой проблеме может варьироваться от нескольких часов до нескольких лет, поэтому рекомендуется принять решение о масштабах перед началом работы. Я не выяснил, какие данные у вас есть, чтобы построить отношение сходства. Я предполагаю, что у вас есть доступ к набору данных документов и набору запросов. Вы можете начать с совпадения слов (например, условной вероятности). Вы быстро обнаружите, что получаете список стоп-слов , связанных с Большинство слов просто потому, что они очень популярны. Использование подъема условной вероятности позаботится о стоп-словах, но сделает отношение подверженным ошибкам в небольшом количестве (в большинстве случаев). Вы можете попробовать Жакара , но, поскольку он симметричен, он выиграет много отношений не найти. Тогда вы можете рассмотреть отношения, которые появляются только на небольшом расстоянии от базового слова. Вы можете (и должны) учитывать отношения, основанные на общем корпусе (например, Википедии) и конкретных пользователях (например, его электронных письмах).

Очень скоро у вас будет множество мер сходства, когда все меры хороши и имеют некоторое преимущество над другими.

Чтобы объединить такие меры, я хотел бы свести проблему к проблеме классификации.

Вы должны создать набор данных из слов и пометить их как «связанные». Чтобы создать большой набор данных с метками, вы можете:

  • Используйте источники известных связанных слов (например, старые добрые категории Википедии) для позитива
  • Большинство слов, не связанных как родственные, не связаны.

Затем используйте все меры, которые у вас есть, как особенности пар. Теперь вы находитесь в области контролируемой проблемы классификации. Создайте классификатор на основе набора данных, оцените его в соответствии с вашими потребностями и получите меру сходства, соответствующую вашим потребностям.

ответил DaL 6 52015vEurope/Moscow11bEurope/MoscowFri, 06 Nov 2015 13:22:58 +0300 2015, 13:22:58

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

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132