По следам поиска в "деталях" - релевантность
25.9.2001
Помнится в статье "Безопасный и удобный поиск" была такая фраза:
"Наверное, в том же Яндексе все видели ссылочку "сортировать по релевантности". Это оно и есть. Сортировка результатов по количеству совпадений слов. Отчасти, кстати, такая сортировка снимает проблему обработки логики поиска. Но с БД MySQL делать такую сортировку очень сложно. Надо сперва выбрать, где есть все слова, потом записи, где разные слова (исключив предыдущие). Если у вас постраничный вывод? то вообще дело труба!"
На данный момент (начиная с MySQL 3.23.23) это не совсем так. Можно сказать, что с точностью до наоборот ? с БД MySQL делать такую сортировку очень просто с использованием FULLTEXT полей.
Для вывода результатов поиска по релевантности необходимо:
1. Требуемые поля VARCHAR, либо любые из разновидностей полей TEXT (SMALLTEXT, MEDIUMTEXT и т.п.) сделать ключами FULLTEXT:
ALTER TABLE table ADD FULLTEXT(field)
Или во всеми любимом phpMyAdmin'е, который я слегка подправил для работы с FULLTEXT полями (архив прилагается ? вдруг кому пригодится).
2. Дальше ? еще проще:
$query = "SELECT *, MATCH field AGAINST ('$searchwords') as relev FROM table ORDER BY relev DESC"
Далее можно навешивать всякие LIMIT'ы и прочее для удобного вывода.
3. Все::)
Заметки:
1. По умолчанию установлен поиск слов, содержащих не менее 4 символов. Правится установкой #define MIN_WORD_LEN 4 в исходнике ft_static.c, хотя на мой взгляд править это не нужно.
2. Недоступны символы % в поисковой фразе, слова в поисковой фразе парсятся с использованием списка разделетелей.
3. Список разделителей слов правится в исходнике ft_static.c.
4. Необходимо минимум десяток записей в таблице для начала вычисления релевантности.
5. Нельзя поле relev использовать в клаузе WHERE:
SELECT *, MATCH field AGAINST ('$searchwords') as relev FROM table WHERE relev>0 ORDER BY relev DESC
хотя можно:
SELECT *, MATCH field AGAINST ('$searchwords') as relev FROM table WHERE MATCH field AGAINST ('$searchwords')>0 ORDER BY relev DESC
6. При создании индексов FULLTEXT возможны 2 варианта:
CREATE TABLE table ( field1 VARCHAR (255), field2 TEXT, FULLTEXT (field1, field2) )
и
CREATE TABLE table ( field1 VARCHAR (255), field2 TEXT, FULLTEXT (field1), FULLTEXT (field2) )
В первом случае возможен запрос:
SELECT *, MATCH field1, field2 AGAINST ('$searchwords') as relev FROM table ORDER BY relev DESC
релевантность вычисляется у всех полей сразу.
Во втором случае такой запрос выдаст ошибку. Здесь вычисляем релевантность следующим образом:
SELECT *, MATCH field1 AGAINST ('$searchwords')+MATCH field2 AGAINST ('$searchwords') as relev FROM table ORDER BY relev DESC
Второй вариант несколько сложнее в запросах, однако, на мой взгляд лучше, т.к. увеличивается гибкость поиска ? к каждому из полей можно задать, например, коэффициент значимости и при суммировании релевантностей полей умножать их на этот коэффициент. Поисковая фраза будет "больше" искаться в полях с большим коэффициентом. Например, если мы делаем поиск по проиндексированным страницам каталога ресурсов, то поле имени страницы обычно задают с большим коэффициентом, чем поля мета-тегов описаний или ключевых слов.
7. Скорость достаточно высокая ? даже в некоторых случаях быстрее like поиска
8. Все вышесказанное работает начиная с версии MySQL 3.23.23