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 ~macintosh'Найти строки, содержащие слово «“apple”», но если строка также содержит слово «“macintosh”», присваивать ей более низкий ранг, чем если строка его не содержит. Это «мягче», чем поиск
'+apple -macintosh', при котором наличие «“macintosh”» вообще исключает строку из результатов. -
'+apple +(>turnover <strudel)'Найти строки, содержащие слова «“apple”» и «“turnover”», или «“apple”» и «“strudel”» (в любом порядке), но присваивать строке «“apple turnover”» более высокий ранг, чем «“apple strudel”».
-
'apple*'Найти строки, содержащие такие слова, как «“apple”», «“apples”», «“applesauce”» или «“applet”».
-
'"some words"'Найти строки, содержащие точную фразу «“some words”» (например, строки, содержащие «“some words of wisdom”», но не «“some noise 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 соответствуют запросу «“database”». В первой записи (id 6) искомое слово встречается 6 раз, и ее оценка релевантности равна 1.0886961221694946. Это значение рассчитано с помощью значения TF равного 6 (слово «“database”» встречается 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.