14.9.2 Поиск по полному тексту с использованием булевых операторов
MySQL может выполнять поиск по полному тексту с использованием булевых операторов, используя модификатор IN BOOLEAN MODE. С этим модификатором определённые символы имеют специальное значение в начале или конце слова в строке поиска. В следующем запросе операторы + и - указывают, что слово должно быть присутствовать или отсутствовать соответственно, для совпадения. Таким образом, запрос извлекает все строки, содержащие слово «“MySQL”», но не содержащие слово «“YourSQL”»:
mysql> SELECT * FROM articles WHERE MATCH (title,body)
-> AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE);
+----+-----------------------+-------------------------------------+
| id | title | body |
+----+-----------------------+-------------------------------------+
| 1 | MySQL Tutorial | DBMS stands for DataBase ... |
| 2 | How To Use MySQL Well | After you went through a ... |
| 3 | Optimizing MySQL | In this tutorial, we show ... |
| 4 | 1001 MySQL Tricks | 1. Never run mysqld as root. 2. ... |
| 6 | MySQL Security | When configured properly, MySQL ... |
+----+-----------------------+-------------------------------------+
При реализации этой функции MySQL использует то, что иногда называют неявной булевой логикой, в которой
+означаетAND-означаетNOT[нет оператора] подразумевает
OR
Поиск по полному тексту с использованием булевых операторов имеет следующие характеристики:
Они не автоматически сортируют строки по убыванию релевантности.
Таблицы
InnoDBтребуют индексаFULLTEXTпо всем столбцам выраженияMATCH()для выполнения булевых запросов. Булевые запросы к индексу поискаMyISAMмогут работать даже без индексаFULLTEXT, хотя запрос в таком режиме будет довольно медленным.-
Минимальная и максимальная длина слова в параметрах поиска по полному тексту применяются к индексам
FULLTEXT, созданным с помощью встроенного парсераFULLTEXTи плагина парсера MeCab.innodb_ft_min_token_sizeиinnodb_ft_max_token_sizeиспользуются для индексов поискаInnoDB.ft_min_word_lenиft_max_word_lenиспользуются для индексов поискаMyISAM.Минимальная и максимальная длина слова в параметрах поиска по полному тексту не применяются к индексам
FULLTEXT, созданным с помощью парсера ngram. Размер токена ngram определяется параметромngram_token_size. Список стоп-слов применяется, управляемый
innodb_ft_enable_stopword,innodb_ft_server_stopword_tableиinnodb_ft_user_stopword_tableдля индексов поискаInnoDBиft_stopword_fileдля индексовMyISAM.Поиск по полному тексту
InnoDBне поддерживает использование нескольких операторов для одного слова поиска, как в этом примере:'++apple'. Использование нескольких операторов для одного слова возвращает ошибку синтаксиса в стандартный вывод. Поиск по полному тексту MyISAM успешно обрабатывает такой же запрос, игнорируя все операторы, кроме оператора, непосредственно примыкающего к искомому слову.Поиск по полному тексту
InnoDBподдерживает только ведущие знаки плюс или минус. Например,InnoDBподдерживает'+apple', но не поддерживает'apple+'. Указание знака плюс или минус в конце вызывает ошибку синтаксиса уInnoDB.Поиск по полному тексту
InnoDBне поддерживает использование ведущего знака плюс со звездочкой ('+*'), комбинацию знаков плюс и минус ('+-') или комбинацию знаков плюс и минус в начале ('+-apple'). Эти некорректные запросы возвращают ошибку синтаксиса.Поиск по полному тексту
InnoDBне поддерживает использование символа@в булевых запросах по полному тексту. Символ@зарезервирован для использования оператором близости@distance.Они не используют порог 50%, который применяется к индексам поиска
MyISAM.
Булевый поиск по полному тексту поддерживает следующие операторы:
-
+Ведущий или заключительный знак плюс указывает, что это слово должно присутствовать в каждой возвращаемой строке.
InnoDBподдерживает только ведущие знаки плюс. -
-Ведущий или заключительный знак минус указывает, что это слово должно не присутствовать ни в одной из возвращаемых строк.
InnoDBподдерживает только ведущие знаки минус.Примечание: Оператор
-действует только для исключения строк, которые в противном случае соответствуют другим поисковым терминам. Таким образом, запрос в булевом режиме, содержащий только термины, предваряемые-, возвращает пустой результат. Он не возвращает «“все строки, за исключением тех, которые содержат какие-либо из исключённых терминов”. -
(нет оператора)
По умолчанию (если не указан ни
+, ни-), слово является необязательным, но строки, содержащие его, оцениваются выше. Это имитирует поведениеMATCH() AGAINST()без модификатораIN BOOLEAN MODE. -
@distanceЭтот оператор работает только с таблицами
InnoDB. Он проверяет, начинаются ли два или более слова в указанном расстоянии друг от друга, измеряемом в словах. Укажите поисковые слова в строке, заключённой в двойные кавычки, непосредственно перед оператором@, например,distanceMATCH(col1) AGAINST('"word1 word2 word3" @8' IN BOOLEAN MODE) -
> <Эти два оператора используются для изменения вклада слова в значение релевантности, присваиваемое строке. Оператор
>увеличивает вклад, а оператор<уменьшает его. Смотрите пример, следующий за этим списком. -
( )Скобки группируют слова в подвыражения. Группы в скобках могут быть вложены.
-
~Ведущая тильда действует как оператор отрицания, делая вклад слова в релевантность строки отрицательным. Это полезно для маркировки слов «“шума”. Строка, содержащая такое слово, оценивается ниже, чем другие, но не исключается полностью, как это было бы с оператором
-. -
*Звездочка служит оператором усечения (или подстановки). В отличие от других операторов, он присоединяется к слову, на которое влияет. Слова совпадают, если они начинаются со слова, предшествующего оператору
*.Если слово указано с оператором усечения, оно не удаляется из булевого запроса, даже если оно слишком короткое или стоп-слово. То, является ли слово слишком коротким, определяется настройкой
innodb_ft_min_token_sizeдля таблицInnoDBилиft_min_word_lenдля таблицMyISAM. Эти параметры не применяются к индексамFULLTEXT, использующим парсер ngram.Слову со звездочкой рассматривается как префикс, который должен присутствовать в начале одного или более слов. Если минимальная длина слова составляет 4, поиск
'+может вернуть меньше строк, чем поискword+the*''+, потому что второй запрос игнорирует слишком короткое словоword+the'the. -
"Фраза, заключённая в двойные кавычки (
"), соответствует только строкам, которые содержат фразу буквально, как она была напечатана. Двигатель поиска по полному тексту разбивает фразу на слова и выполняет поиск в индексеFULLTEXTдля слов. Символы, не являющиеся словами, не обязательно должны совпадать точно: для поиска по фразам достаточно, чтобы совпадения содержали точно такие же слова, как и фраза, в том же порядке. Например,"test phrase"соответствует"test, phrase".Если фраза не содержит слов, которые находятся в индексе, результат пуст. Слова могут отсутствовать в индексе по ряду причин: они могут отсутствовать в тексте, быть стоп-словами или быть короче минимальной длины индексируемых слов.
Следующие примеры демонстрируют некоторые строки поиска, которые используют булевы операторы поиска по полному тексту:
-
'apple banana'Найти строки, содержащие хотя бы одно из двух слов.
-
'+apple +juice'Найти строки, содержащие оба слова.
-
'+apple macintosh'Найти строки, содержащие слово “яблоко”, но повышать рейтинг строк, если они также содержат “макбук”.
-
'+apple -macintosh'Найти строки, содержащие слово “яблоко”, но не “макбук”.
-
'+apple ~macintosh'Найти строки, содержащие слово “яблоко”, но если строка также содержит слово “макбук”, понижать её рейтинг по сравнению со строкой, которая его не содержит. Это менее строго, чем поиск
'+apple -macintosh', для которого присутствие “макбук” вообще исключает строку из результата. -
'+apple +(>turnover <strudel)'Найти строки, содержащие слова “яблоко” и “пирог” или “яблоко” и “штрудель” (в любом порядке), но при этом повышать рейтинг “яблочный пирог” выше, чем “яблочный штрудель”.
-
'apple*'Найти строки, содержащие слова, такие как “яблоко”, “яблоки”, “яблочный сок” или “приложение”.
-
'"some words"'Найти строки, содержащие точную фразу “некоторые слова” (например, строки, содержащие “некоторые мудрые слова”, но не “некоторые шумные слова”). Обратите внимание, что символы
", которые заключают фразу, являются операторными символами, разделяющими фразу. Это не кавычки, которые сами заключают строку поиска.
Порядок сортировки по релевантности для поиска InnoDB в булевом режиме
InnoDB полнотекстовый поиск основан на полнотекстовом движке Sphinx, и используемые алгоритмы основаны на алгоритмах ранжирования BM25 и TF-IDF. По этим причинам, порядок сортировки по релевантности для InnoDB булевого полнотекстового поиска может отличаться от порядка сортировки по релевантности для MyISAM.
InnoDB использует модификацию системы взвешивания “частота термина — обратная частота документа” (TF-IDF), для ранжирования релевантности документа для заданного полнотекстового запроса. Взвешивание TF-IDF основано на частоте появления слова в документе, с поправкой на частоту появления этого слова во всех документах коллекции. Другими словами, чем чаще слово встречается в документе и чем реже оно встречается во всей коллекции документов, тем выше рейтинг документа.
Как рассчитывается релевантность
Значение частоты термина (TF) — это количество раз, когда слово встречается в документе. Значение обратной частоты документа (IDF) слова рассчитывается по следующей формуле, где total_records — количество записей в коллекции, а matching_records — количество записей, в которых встречается искомое слово.
${IDF} = log10( ${total_records} / ${matching_records} ) Когда в документе слово встречается несколько раз, значение IDF умножается на значение TF:
${TF} * ${IDF} Используя значения TF и IDF, рейтинг релевантности документа вычисляется по этой формуле:
${rank} = ${TF} * ${IDF} * ${IDF}Формула продемонстрирована на следующих примерах.
Порядок сортировки по релевантности для поиска по одному слову
Этот пример демонстрирует вычисление порядка сортировки по релевантности для поиска по одному слову.
mysql> CREATE TABLE articles (
-> id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
-> title VARCHAR(200),
-> body TEXT,
-> FULLTEXT (title,body)
->) ENGINE=InnoDB;
Query OK, 0 rows affected (1.04 sec)
mysql> INSERT INTO articles (title,body) VALUES
-> ('MySQL Tutorial','This database tutorial ...'),
-> ("How To Use MySQL",'After you went through a ...'),
-> ('Optimizing Your Database','In this database tutorial ...'),
-> ('MySQL vs. YourSQL','When comparing databases ...'),
-> ('MySQL Security','When configured properly, MySQL ...'),
-> ('Database, Database, Database','database database database'),
-> ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
-> ('MySQL Full-Text Indexes', 'MySQL fulltext indexes use a ..');
Query OK, 8 rows affected (0.06 sec)
Records: 8 Duplicates: 0 Warnings: 0
mysql> SELECT id, title, body,
-> MATCH (title,body) AGAINST ('database' IN BOOLEAN MODE) AS score
-> FROM articles ORDER BY score DESC;
+----+------------------------------+-------------------------------------+---------------------+
| id | title | body | score |
+----+------------------------------+-------------------------------------+---------------------+
| 6 | Database, Database, Database | database database database | 1.0886961221694946 |
| 3 | Optimizing Your Database | In this database tutorial ... | 0.36289870738983154 |
| 1 | MySQL Tutorial | This database tutorial ... | 0.18144935369491577 |
| 2 | How To Use MySQL | After you went through a ... | 0 |
| 4 | MySQL vs. YourSQL | When comparing databases ... | 0 |
| 5 | MySQL Security | When configured properly, MySQL ... | 0 |
| 7 | 1001 MySQL Tricks | 1. Never run mysqld as root. 2. ... | 0 |
| 8 | MySQL Full-Text Indexes | MySQL fulltext indexes use a .. | 0 |
+----+------------------------------+-------------------------------------+---------------------+
8 rows in set (0.00 sec) Всего имеется 8 записей, из которых 3 соответствуют поисковому запросу “база данных”. В первой записи (id 6) поисковое слово встречается 6 раз и имеет рейтинг релевантности 1.0886961221694946. Это значение ранжирования вычисляется с использованием значения TF 6 (искомое слово “база данных” встречается 6 раз в записи id 6) и значения IDF 0,42596873216370745, которое вычисляется следующим образом (где 8 — общее количество записей, а 3 — количество записей, в которых встречается искомое слово):
${IDF} = LOG10( 8 / 3 ) = 0.42596873216370745 Значения TF и IDF затем подставляются в формулу ранжирования:
${rank} = ${TF} * ${IDF} * ${IDF}Выполнение вычислений в клиентской части MySQL возвращает значение ранжирования 1,088696164686938.
mysql> SELECT 6*LOG10(8/3)*LOG10(8/3);
+-------------------------+
| 6*LOG10(8/3)*LOG10(8/3) |
+-------------------------+
| 1.088696164686938 |
+-------------------------+
1 row in set (0.00 sec) Вы можете заметить небольшое различие в значениях ранжирования, возвращаемых оператором SELECT ... MATCH ...
AGAINST и клиентской частью MySQL (1.0886961221694946 против 1.088696164686938). Разница обусловлена тем, как выполняется преобразование между целыми числами и числами с плавающей точкой/двойной точностью внутри InnoDB (вместе с связанными с этим вопросами точности и округления), а также тем, как они выполняются в другом месте, например, в клиентской части MySQL или других типах калькуляторов.
Порядок сортировки по релевантности для поиска по нескольким словам
Этот пример демонстрирует вычисление порядка сортировки по релевантности для полнотекстового поиска по нескольким словам, основанного на таблице articles и данных, используемых в предыдущем примере.
Если вы ищете более одного слова, значение релевантности — это сумма значений релевантности для каждого слова, как показано в этой формуле:
${rank} = ${TF} * ${IDF} * ${IDF} + ${TF} * ${IDF} * ${IDF}Поиск по двум терминам ('mysql tutorial') возвращает следующие результаты:
mysql> SELECT id, title, body, MATCH (title,body)
-> AGAINST ('mysql tutorial' IN BOOLEAN MODE) AS score
-> FROM articles ORDER BY score DESC;
+----+------------------------------+-------------------------------------+----------------------+
| id | title | body | score |
+----+------------------------------+-------------------------------------+----------------------+
| 1 | MySQL Tutorial | This database tutorial ... | 0.7405621409416199 |
| 3 | Optimizing Your Database | In this database tutorial ... | 0.3624762296676636 |
| 5 | MySQL Security | When configured properly, MySQL ... | 0.031219376251101494 |
| 8 | MySQL Full-Text Indexes | MySQL fulltext indexes use a .. | 0.031219376251101494 |
| 2 | How To Use MySQL | After you went through a ... | 0.015609688125550747 |
| 4 | MySQL vs. YourSQL | When comparing databases ... | 0.015609688125550747 |
| 7 | 1001 MySQL Tricks | 1. Never run mysqld as root. 2. ... | 0.015609688125550747 |
| 6 | Database, Database, Database | database database database | 0 |
+----+------------------------------+-------------------------------------+----------------------+
8 rows in set (0.00 sec) В первой записи (id 8) 'mysql' встречается один раз, а 'tutorial' — дважды. Совпадений для 'mysql' — шесть, а для 'tutorial' — два. Клиентская часть MySQL возвращает ожидаемое значение ранжирования, когда эти значения подставляются в формулу ранжирования для поиска по нескольким словам:
mysql> SELECT (1*log10(8/6)*log10(8/6)) + (2*log10(8/2)*log10(8/2));
+-------------------------------------------------------+
| (1*log10(8/6)*log10(8/6)) + (2*log10(8/2)*log10(8/2)) |
+-------------------------------------------------------+
| 0.7405621541938003 |
+-------------------------------------------------------+
1 row in set (0.00 sec) Небольшое различие в значениях ранжирования, возвращаемых оператором SELECT ... MATCH ... AGAINST и клиентской частью MySQL, объясняется в предыдущем примере.
© 2025 Oracle
Licensed under the GPLv2 License.