Учебник

~ 16 минут

Глава 8.1. Полнотекстовый поиск

Что называется полнотекстовым поиском?
Это нестрогий поиск по тексту, который находится в БД. Нестрогий — означает, что если у вас есть статьи или другие материалы в БД, то вы можете искать по одному или нескольким словам так, чтобы были найдены записи, где есть или все эти слова или только некоторые из них.
Лучшее понимание сути полнотекстового поиска дают поисковые системы в интернете, вроде «Гугл» или «Яндекс». Эти поисковики умеют находить страницы, где встречается заданный пользователем поисковый запрос.

Вы уже немного знаете как можно искать в таблицах БД. Для этого есть оператор LIKE Но этот оператор не совсем подходит для наших задач, потому что он не понимает, что та строка, которую мы ввели — это отдельные слова, а не одно большое слово.

Как работает LIKE

Все дальнейшие примеры поиска мы будем рассматривать применительно к следующей информации в БД:

НазваниеОписание
Конец рабочего дняКогда хорошо поработал
Учим новичка решать задачиТяжело в учении, легко в бою
Когда любишь порядокВсе вещи должны быть на своём месте
Премии на моей бывшей работеГорькая правда
Отличные витаминкиБодрят не по-детски
РыбакНовая техника рыбалки
ВосторгКогда видишь своего кумира
Типичный юзерВ интернете никто не знает что ты — кот
ЕнотикЕнотик бежит записываться на курсы
Колесо опаздывает на встречуКогда нажал тревожную кнопку под столом, а магазин под охраной автоботов
Твоя девушка, когда слышит комплиментЧихуа
Кот-ненавистьКотяра
ТреугольникКрасиво вертится

Пусть это будет таблица гифок. В этой таблице есть текстовый контент. Он находится в полях «Название» и «Описание». Здесь не такие большие тексты, как могут быть в статьях. Но даже этого будет достаточно, чтобы понять, как устроен полнотекстовый поиск, и как его использовать.

Недостатки оператора LIKE

  • Производительность
    MySQL сканирует всю таблицу при поиске
  • Гибкость
    не ищет по нескольким словами, нет операторов поиска
  • Релевантность
    нет способов определить релевантность результатов

Этот оператор подходит для нестрогого поиска без учёта регистра. Но у него есть много особенностей, которые не позволяют применять этот оператор для поиска по тексту, когда вы ищете отдельные слова.

Самая большая проблема связана с тем, что LIKE работает довольно грубо и на тех полях, по которым он ищет, должны быть индексы. Если индексов нет, то базе данных приходится сканировать все таблицы.

Другой недостаток — отсутствие возможности искать по отдельным словам. LIKE не может разбивать строку поиска на слова. Всё что вы указываете, считается одним большим словом. Нет операторов поиска, которые позволяют уточнить запрос.

Т.к. использование LIKE не является полнотекстовым поиском — понятие релевантности отсутствует. Релевантность — насколько то, что вы нашли, соответствует тому, что вы искали.

Оператор LIKE и производительность

Посмотрим, почему LIKE плохо подходит для больших объёмов данных. Мы хотим искать в таблице по полю name, поэтому добавим ему индекс.

Рисунок 1.

SELECT * FROM gifs WHERE name LIKE 'рыб%'

Оператор LIKE умеет использовать символ подстановки «%» — это означает любые символы в любом количестве.
При поиске «рыб%» — поиск отработает быстро. База данных сразу найдёт ответ в своём индексе.

Рисунок 2.

SELECT * FROM gifs WHERE name LIKE '%рыб'

А при поиске «%рыб» — индекс будет бесполезен, поскольку индекс хранит только то, что вы записали в таблицу.

То есть БД не значит что будет под знаком «%», а там может быть что угодно, то индекс в этом случае будет бесполезен. Поэтому база данных, перед тем, как найти то, что вы ищете, будет вынуждена отсканировать всю таблицу, что значительно замедлит поиск.

Поиск по отдельным словам

LIKE не понимает отдельные слова. И если вы используете в поисковом запросе несколько слов, все они будут трактоваться как одно большое.

Если мы ищем слово «рыба», оператор LIKE найдёт совпадения «рыбак», «рыбалка», поскольку «рыба» действительно входит в оба из этих слов.

Но если ввести два слова, то ситуация будет иной. Например, мы хотим найти те записи, где есть слова «енотик» и «кот» в любом порядке: они могут идти друг за другом, могут быть разбросаны в тексте и ещё какой-либо вариант. LIKE этого не понимает, потому что всё, что мы вводим в строку поиска, для него это всё — одно большое слово. А так как именно такого слова нет — он ничего и не найдёт.

SELECT * FROM gifs WHERE title LIKE '%слово%' OR description LIKE '%слово%'

Рисунок 3.

Fulltext индексы

Несмотря на то, что LIKE хорош для определённых сценариев применения, мы не всегда можем его использовать. Чтобы обойти недостатки, связанные с отсутствием релевантности, проблемами с производительностью и поиском по отдельным словам, существует индекс типа Fulltext.

Это особый тип индекса, который можно добавить полям таблицы, для которых требуется организовать полнотекстовый поиск.

Это означает, что если вы собираетесь организовать полнотекстовый поиск внутри вашего сайта по какой-то таблице, то первым делом вам нужно будет добавить этот тип индекса в таблице на те поля, которые нужны для поиска.

Создание индекса выполняется специальным запросом. Делается это один раз.
Добавим на таблицу gifs полнотекстовый индекс на поля title и description:

CREATE FULLTEXT INDEX gif_ft_search ON gifs(title, description)

Как обычно, имя индекса указывается вами произвольно.

Особенности Fulltext-индекса

  • Можно создать только для CHAR, VARCHAR и TEXT полей;
  • Все поля должны быть в одной кодировке;
  • Индекс можно сделать в момент создания таблицы или добавить позже;
  • Комбинировать дополнительные условия поиска следует с осторожностью, особенно при работе с большим числом записей в таблице.

Возможности полнотекстового поиска

Давайте разберёмся, что мы получим в результате добавления полнотекстового индекса.

Во-первых, по этим полям скорость поиска станет выше, чем у LIKE, потому что Fulltext-индекс оптимизирован для поиска в больших объёмах информации.
Во-вторых, можно будет искать по отдельным словам и появится поддержка операторов поиска.
И есть показатель релевантности, по которому можно отсортировать значения.

Релевантность поиска

Разберём подробнее, что называется релевантностью поиска.

Релевантность в поиске — это соответствие найденной информации ожиданиям пользователя.

Когда вы используете поисковые системы вроде Яндекс или Google, то качество работы этой поисковой системы определяется тем, насколько релевантные результаты вы получаете.
То есть если на запрос «Интерактивные курсы HTML» вы получаете первым результатом «Интерактивные курсы HTML-академии», то это означает, что поисковик релевантный, т. к. он нашёл самый подходящий ответ по вашему запросу.

Рисунок 4.

Расчёт релевантности

Релевантность расчитывают на основе множества факторов, среди которых:

  • Частота слова в документе;
  • Насколько часто встречается в других документах;
  • Средний размер самих документов и др.

Рассчитывается релевантность по сложным формулам, которые работают внутри MySQL. По этим формулам документ считается релевантным если в нём, в числе прочих факторов, слово поиска встречается часто в одном документе и редко — в других документах. Тогда первый документ становится ещё более важным с позиции релевантности.

Пример полнотекстового поиска

Полнотекстовый поиск может работать в двух режимах. Первый режим, о котором пойдёт речь далее, называется «натуральным поиском».

Полнотекстовый поиск реализуется двумя операторами: MATCH и AGAINST.
В MATCH указываем — где ищем, то есть указываем, поля, а в AGAINST — что ищем, т. е. поисковый запрос.

SELECT * FROM gifs
WHERE MATCH(title,description) AGAINST('слово')

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

Рисунок 5.

Ищем по слову «рыба» и ничего не находим, потому что у нас нет гифок в названии или описании которых есть слово «рыба» (посмотрите таблицу выше). В отличие от LIKE, MATCH ничего не нашёл, так как он трактует запрос как отдельное слово, а такое слово в искомой таблице не встречается.

Рисунок 6.

А если попытаться найти «енотик кот», то LIKE ничего не нашёл, а полнотекстовый поиск находит три результата. В одном поле встречается одно слово, в другом — другое. В любом случае, это больше похоже на результат, который мы ожидали получить, используя поиск.

Эти примеры отлично показывают, где LIKE проигрывает полнотекстовому поиску, и в каких случаях нам нужен полнотекстовый поиск, а не LIKE.

Показ релевантности

Результат выборки при натуральном поиске автоматически сортируется в порядке убывания релевантности, но значение самой релевантности также можно показать в виде отдельного столбца.

Чтобы увидеть этот показатель, нужно написать специальный запрос, который покажет в виде отдельного поля значение релевантности, расчитанное для каждой из найденных записей.

SELECT title, description, MATCH(title,description) AGAINST('работа') as score
FROM gifs
WHERE MATCH(title,description) AGAINST('работа')

Рисунок 7.

Режим логического поиска

У полнотекстового поиска есть ещё и другой режим, он называется «Логический поиск». Он работает несколько иначе и предлагает нам новые возможности. Эти возможности определяются тем, что в режиме логического поиска можно использовать операторы, с помощью которых можно уточнять ваш запрос, делая его более точным.

Например, операторы позволяют указать одно или несколько слов как обязательные при поиске.

Операторы логического поиска

ОператорОписание
+Это слово должно быть представлено в результатах
-Исключение, слова не должно быть в результатах
>Включить и увеличить вес релевантности слова
<Включить и уменьшить вес релевантности слова
()Объединить слова в выражения
~Убрать значение слова в ранжировании результатов
*****Плейсхолдер в конце слова
» “Искать точное соответствие фразе в кавычках
@Определяет максимальную дистанцию между словами

Оператор «-» работает наоборот: он исключает слова из результатов.
Больше «>» и меньше «<» используются для увеличения или уменьшения веса релевантности слова. Можно эти операторы применять к группе слов, если несколько слов объединить скобками.
Можно указывать замещающие символы, но только в конце с помощью звёздочки «*». Можно искать по точному совпадению, если поместить строку в кавычки. И можно определить максимальную дистанцию между словами, если вы хотите, чтобы были найдены только те документы, где два слова из поискового запроса находятся близко, а не разнесены по всему тексту.

Пример логического поиска

Логический поиск включается, когда мы его активируем ключевыми словами IN BOOLEAN MODE, которые идут после поискового запроса. В этом режиме появляется возможность добавлять операторы.

В отличие от натурального поиска, логический режим поиска не использует сортировку по релевантности (однако, релевантность всё равно можно показывать и сортировать по этому значению явным образом).

SELECT * FROM gifs
WHERE MATCH(title, description) AGAINST('слово' IN BOOLEAN MODE)

Рисунок 8.

Мы активировали режим поиска в логическом режиме. И добавили заменитель «*». Тогда мы находим одно значение, поскольку есть совпадение по слову «рыбак».

Рисунок 9.

Далее можно исключить одно слово из результатов поиска — будет найдено одно значение. А без исключения — найдём два.

Сравнение двух режимов поиска

Разберёмся, где и когда использовать каждый из двух режимов.
Если вы делаете форму на сайте для поиска документов, которые лежат у вас на сайте, и если этот поиск должен работать максимально просто, без особого понимания, что именно надо найти, тогда вам подойдёт поиск натуральный.

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

Ограничения полнотекстового поиска

Конечно, у полнотекстового поиска есть свои ограничения.

  • Требуют создания индекса — накладные расходы;
  • Нет поддержки словоформ;
  • Нет плейсхолдеров в произвольном месте;
  • Минимальная длина слова — три символа;
  • Поиск только сразу по всем полям в индексе.

Эти ограничения главным образом связаны с тем, что полнотекстовый поиск требует индекса. Этот индекс нужно сначала создать. Но затем такой индекс требует дополнительных ресурсов: место, где хранятся все метаданные по всем записям в таблице и время, которое требуется на добавление информации по индексу при создании новых записей в таблице.

Несмотря на то, что полнотекстовый поиск похож на то, как работают поисковые системы, поисковики всё-таки умнее и продвинутей.
Например, поисковые системы поддерживают морфологию языка, это выражается в поддержке словоформ. А полнотекстовый поиск этого не умеет. То есть, вы не можете искать, склоняя слова или меняя число.
Минимальная длина слова, которое можно искать — это три символа. То есть, меньше, чем три символа, вы искать не можете. С такими настройками полнотекстовый поиск работает по умолчанию.

И ещё один важный аспект. Если вы добавили полнотекстовый поиск на два поля title и description, так чтобы поиск происходил сразу по этим двум полям сразу, то поиск всегда и будет происходить одновременно по этим двум полям. Если вам всё-таки нужно искать как по обоим полям сразу, так и по этим полям по отдельности, то нужно сделать три индекса: на первое поле, на второе и на оба поля.

LIKE или FULLTEXT

Сравним, где лучше использовать LIKE, а где больше подходит FULLTEXT.

LIKE подходит, когда мы не занимаемся поиском в его традиционном понимании: когда нам нужно выполнить сравнение без учёта регистра, или когда мы хотим максимально быстро и без заморочек найти хоть что-то хотя бы немного подходящее под наш запрос.

FULLTEXT подходит, когда в таблице много записей, потому что он работает быстрей, чем LIKE. Когда нужен сложный поиск с поддержкой операторов поиска. Когда нужна релевантность, потому что люди привыкли, что те же поисковые системы возвращают результаты, начиная с самых подходящих. И пользователи вашего сайта будут ожидать того же. Когда нужна поддержка стоп-слов и других настроек, которые позволяют немного глубже «тюнить» поиск.

Поделитесь, как вам глава?

Оцените главу

Продолжить

Если вы обнаружили ошибку или неработающую ссылку, выделите ее и нажмите Ctrl + Enter