PHP в деталях

По следам поиска в "деталях" - релевантность



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


Содержание раздела