В этом учебном пособии мы рассмотрим операторы полнотекстового поиска, доступные в Manticore Search.
Введение в операторы полнотекстового поиска и базовый поиск
Все операции поиска в Manticore Search основаны на стандартных булевых операторах (AND, OR, NOT), которые можно использовать в комбинации и произвольном порядке, чтобы комбинировать или исключать ключевые слова в поиске для получения более релевантных результатов.
По умолчанию самым простым оператором полнотекстового поиска является AND, который предполагается, когда вы просто перечисляете несколько слов в запросе.
AND является оператором по умолчанию, с которым запрос
fast slow
вернет документы, содержащие оба термина: ‘fast’ и ‘slow’. Если один термин есть в документе, а другой отсутствует, документ не будет включен в результирующий список.
По умолчанию слова ищутся во всех доступных полнотекстовых полях.
SELECT * FROM testrt WHERE MATCH('fast slow');
OR используется для получения документов, соответствующих любому из терминов (или обоим). Термины должны разделяться вертикальной чертой, например,
fast | slow
. Это найдет документы с fast
или slow
.
SELECT * FROM testrt WHERE MATCH('fast | slow');
У оператора OR приоритет выше, чем у AND, поэтому запрос ‘find me fast|slow’ может быть интерпретирован как ‘найди мне (fast|slow)’:
SELECT * FROM testrt WHERE MATCH('find me fast | slow');
NOT гарантирует, что термин, отмеченный
-
или !
, не будет в результатах. Любые документы, содержащие такой термин, будут исключены. Например, fast !slow
найдет документы с fast
, если только в них нет slow
. Будьте осторожны, используя его, пытаясь сузить поиск, так как это может стать слишком специфичным и исключить хорошие документы.
SELECT * FROM testrt WHERE MATCH('find !slow');
SELECT * FROM testrt WHERE MATCH('find -slow');
MAYBE является специальным оператором, который работает как
OR
, но требует, чтобы левый термин всегда был в результатах, в то время как правый термин является необязательным. Но когда оба условия выполнены, документ получит более высокий рейтинг в поиске. Например, fast MAYBE slow
найдет документы с fast
или slow
, но документы, содержащие оба термина, будут иметь более высокий балл.
SELECT * FROM testrt WHERE MATCH('find MAYBE slow');
Примеры использования
Давайте подключимся к Manticore, используя клиент mysql:
# mysql -P9306 -h0
Для булевых поисков можно использовать оператор OR |
:
MySQL [(none)]> select * from testrt where match('find | me fast');
+------+------+------------------------+----------------+
| id | gid | title | content |
+------+------+------------------------+----------------+
| 1 | 1 | find me | fast and quick|
| 2 | 1 | find me fast | quick |
| 6 | 1 | find me fast now | quick |
| 5 | 1 | find me quick and fast | quick |
+------+------+------------------------+----------------+
4 rows in set (0.00 sec)
У оператора OR приоритет выше, чем у AND, запрос find me fast|slow
интерпретируется как find me (fast|slow)
:
MySQL [(none)]> SELECT * FROM testrt WHERE MATCH('find me fast|slow');
+------+------+------------------------+----------------+
| id | gid | title | content |
+------+------+------------------------+----------------+
| 1 | 1 | find me | fast and quick|
| 2 | 1 | find me fast | quick |
| 6 | 1 | find me fast now | quick |
| 3 | 1 | find me slow | quick |
| 5 | 1 | find me quick and fast | quick |
+------+------+------------------------+----------------+
5 rows in set (0.00 sec)
Для отрицаний оператор NOT можно указать как -
или !
:
MySQL [(none)]> select * from testrt where match('find me -fast');
+------+------+--------------+---------+
| id | gid | title | content |
+------+------+--------------+---------+
| 3 | 1 | find me slow | quick |
+------+------+--------------+---------+
1 row in set (0.00 sec)
Необходимо отметить, что полные отрицательные запросы не поддерживаются в Manticore по умолчанию, и невозможно выполнить только -fast
(это станет возможным с версии 3.5.2).
Другим базовым оператором является MAYBE
. Термин, определенный с помощью MAYBE, может присутствовать или отсутствовать в документах. Если он присутствует, это повлияет на рейтинг, и документы, содержащие его, будут оценены выше.
MySQL [(none)]> select * from testrt where match('find me MAYBE slow');
+------+------+------------------------+----------------+
| id | gid | title | content |
+------+------+------------------------+----------------+
| 3 | 1 | find me slow | quick |
| 1 | 1 | find me | fast and quick|
| 2 | 1 | find me fast | quick |
| 5 | 1 | find me quick and fast | quick |
| 6 | 1 | find me fast now | quick |
+------+------+------------------------+----------------+
5 rows in set (0.00 sec)
Оператор поля
Если мы хотим ограничить поиск только специфическим полем, можно использовать оператор ‘@’:
mysql> select * from testrt where match('@title find me fast');
+------+------+------------------------+---------+
| id | gid | title | content |
+------+------+------------------------+---------+
| 2 | 1 | find me fast | quick |
| 6 | 1 | find me fast now | quick |
| 5 | 1 | найди меня быстро и быстро | быстро |
+------+------+------------------------+---------+
3 rows in set (0.00 sec)
Мы также можем указать несколько полей, чтобы ограничить поиск:
mysql> select * from testrt where match('@(title,content) найди меня быстро');
+------+------+------------------------+----------------+
| id | gid | title | content |
+------+------+------------------------+----------------+
| 1 | 1 | найди меня | быстро и быстро |
| 2 | 1 | найди меня быстро | быстро |
| 6 | 1 | найди меня быстро сейчас | быстро |
| 5 | 1 | найди меня быстро и быстро | быстро |
+------+------+------------------------+----------------+
4 rows in set (0.00 sec)
Оператор поля также может быть использован для выполнения ограничения поиска только на первых x словах. Например:
mysql> select * from testrt where match('@title ленивый пес');
+------+------+----------------------------------------------------------------------------+---------------------------------------+
| id | gid | title | content |
+------+------+----------------------------------------------------------------------------+---------------------------------------+
| 4 | 1 | Быстрая коричневая лисица перепрыгивает через ленивую собаку | Пять боксеров прыгают быстро |
| 7 | 1 | Быстрая коричневая лисица делает шаг назад и перепрыгивает через ленивую собаку | Пять боксеров прыгают быстро |
| 8 | 1 | Коричневая и красивая лисица делает шаг назад и перепрыгивает через ленивую собаку | Пять боксеров прыгают быстро |
+------+------+----------------------------------------------------------------------------+---------------------------------------+
4 rows in set (0.00 sec)
Однако, если мы ищем только в 5 первых словах, мы ничего не получаем:
mysql> select * from testrt where match('@title[5] ленивый пес');
Пустой набор (0.00 sec)
В некоторых ситуациях поиск может быть выполнен по нескольким индексам, которые могут не иметь одинаковых полей полнотекстового поиска.
По умолчанию указание поля, которого нет в индексе, приведет к ошибке запроса. Чтобы преодолеть это, можно использовать специальный оператор @@relaxed
:
mysql> select * from testrt where match('@(title,keywords) ленивый пес');<br></br>ERROR 1064 (42000): index testrt: ошибка запроса: поле 'keywords' не найдено в схеме
mysql> select * from testrt where match('@@relaxed @(title,keywords) ленивый пес');
+------+------+----------------------------------------------------------------------------+---------------------------------------+
| id | gid | title | content |
+------+------+----------------------------------------------------------------------------+---------------------------------------+
| 4 | 1 | Быстрая коричневая лисица перепрыгивает через ленивую собаку | Пять боксеров прыгают быстро |
| 7 | 1 | Быстрая коричневая лисица делает шаг назад и перепрыгивает через ленивую собаку | Пять боксеров прыгают быстро |
| 8 | 1 | Коричневая и красивая лисица делает шаг назад и перепрыгивает через ленивую собаку | Пять боксеров прыгают быстро |
+------+------+----------------------------------------------------------------------------+---------------------------------------+
3 rows in set, 1 warning (0.01 sec)
Неопределенный поиск
Неопределенное соответствие позволяет сопоставлять только некоторые из слов из строки запроса, например:
mysql> select * from testrt where match('"лисица птица ленивый пес"/3');
+------+------+----------------------------------------------------------------------------+---------------------------------------+
| id | gid | title | content |
+------+------+----------------------------------------------------------------------------+---------------------------------------+
| 4 | 1 | Быстрая коричневая лисица перепрыгивает через ленивую собаку | Пять боксеров прыгают быстро |
| 7 | 1 | Быстрая коричневая лисица делает шаг назад и перепрыгивает через ленивую собаку | Пять боксеров прыгают быстро |
| 8 | 1 | Коричневая и красивая лисица делает шаг назад и перепрыгивает через ленивую собаку | Пять боксеров прыгают быстро |
+------+------+----------------------------------------------------------------------------+---------------------------------------+
3 rows in set (0.00 sec)
В этом случае мы используем оператор QUORUM
и указываем, что допустимо совпадение только 3 слов. Поиск с /1
эквивалентен логическому поиску OR, в то время как поиск с /N
, где N — это количество вводимых слов, эквивалентен логическому поиску AND.
Вместо абсолютного числа вы также можете указать число от 0.0 до 1.0 (что соответствует 0% и 100%), и Manticore найдет только те документы, в которых есть хотя бы указанный процент данных слов. Тот же пример выше также мог быть написан как "лисица птица ленивый пес"/0.3
и он бы соответствовал документам с как минимум 30% из 4 слов.
mysql> select * from testrt where match('"лисица птица ленивый пес"/0.3');
+------+------+----------------------------------------------------------------------------+---------------------------------------+
| id | gid | title | content |
+------+------+----------------------------------------------------------------------------+---------------------------------------+
| 4 | 1 | Быстрая коричневая лисица перепрыгивает через ленивую собаку | Пять боксеров прыгают быстро |
| 7 | 1 | Быстрая коричневая лисица делает шаг назад и перепрыгивает через ленивую собаку | Пять боксеров прыгают быстро |
| 8 | 1 | Коричневая и красивая лисица делает шаг назад и прыгает через ленивую собаку | Пять боксерских волшебников быстро прыгают |
+------+------+----------------------------------------------------------------------------+---------------------------------------+
3 rows in set (0.00 sec)
Расширенные операторы
Кроме простых операторов существует много расширенных операторов, которые используются реже, но в некоторых случаях могут быть абсолютно необходимыми.
Одним из самых часто используемых расширенных операторов является оператор фраз.
Оператор фраз совпадает только в том случае, если указанные слова найдены в точном порядке. Это также ограничит слова находиться в одном и том же поле:
mysql> SELECT * FROM testrt WHERE MATCH('"быстрая коричневая лисица"');
+------+------+-------------------------------------------------------------------+---------------------------------------+
| id | gid | title | content |
+------+------+-------------------------------------------------------------------+---------------------------------------+
| 4 | 1 | Быстрая коричневая лисица прыгает через ленивую собаку | Пять боксерских волшебников быстро прыгают |
| 7 | 1 | Быстрая коричневая лисица делает шаг назад и прыгает через ленивую собаку | Пять боксерских волшебников быстро прыгают |
+------+------+-------------------------------------------------------------------+---------------------------------------+
2 rows in set (0.00 sec)
Более расслабленной версией оператора фраз является оператор строгого порядка.
Оператор порядка требует, чтобы слова находились в точно таком же порядке, как указано, но другие слова допускаются между:
mysql> SELECT * FROM testrt WHERE MATCH('найти << меня << быстро');
+------+------+------------------------+---------+
| id | gid | title | content |
+------+------+------------------------+---------+
| 2 | 1 | найти меня быстро | быстро |
| 6 | 1 | найти меня быстро сейчас | быстро |
| 5 | 1 | найти меня быстро и быстро | быстро |
+------+------+------------------------+---------+
3 rows in set (0.00 sec)
Еще одна пара операторов, которые работают с позициями слов, - это операторы начала/конца поля.
Эти операторы ограничивают слово присутствовать в начале или в конце поля.
mysql> SELECT * FROM testrt WHERE MATCH('^найти меня быстро$');
+------+------+------------------------+---------+
| id | gid | title | content |
+------+------+------------------------+---------+
| 2 | 1 | найти меня быстро | быстро |
| 5 | 1 | найти меня быстро и быстро | быстро |
+------+------+------------------------+---------+
2 rows in set (0.00 sec)
Оператор близости похож на оператор AND, но добавляет максимальное расстояние между словами, чтобы они все еще могли считаться совпадением. Рассмотрим этот пример только с оператором AND:
mysql> SELECT * FROM testrt WHERE MATCH('коричневая лисица прыгает');
+------+------+----------------------------------------------------------------------------+---------------------------------------+
| id | gid | title | content |
+------+------+----------------------------------------------------------------------------+---------------------------------------+
| 4 | 1 | Быстрая коричневая лисица прыгает через ленивую собаку | Пять боксерских волшебников быстро прыгают |
| 7 | 1 | Быстрая коричневая лисица делает шаг назад и прыгает через ленивую собаку | Пять боксерских волшебников быстро прыгают |
| 8 | 1 | Коричневая и красивая лисица делает шаг назад и прыгает через ленивую собаку | Пять боксерских волшебников быстро прыгают |
+------+------+----------------------------------------------------------------------------+---------------------------------------+
3 rows in set (0.00 sec)
Наш запрос возвращает 2 результата: один, в котором все слова близко друг к другу, и второй, где одно из слов более удалено.
Если мы хотим совпадать только в том случае, если слова находятся на определенном расстоянии, мы можем ограничить это с помощью оператора близости:
mysql> SELECT * FROM testrt WHERE MATCH('"коричневая лисица прыгает"~5');
+------+------+---------------------------------------------+---------------------------------------+
| id | gid | title | content |
+------+------+---------------------------------------------+---------------------------------------+
| 4 | 1 | Быстрая коричневая лисица прыгает через ленивую собаку | Пять боксерских волшебников быстро прыгают |
+------+------+---------------------------------------------+---------------------------------------+
1 row in set (0.00 sec)
Более обобщенная версия оператора близости - это оператор NEAR
. В случае близости указывается одно расстояние для набора слов, в то время как оператор NEAR
работает с 2 операндами, которые могут быть либо отдельными словами, либо выражениями.
В следующем примере ‘коричневая’ и ‘лисица’ должны быть на расстоянии 2, а ‘лисица’ и ‘прыгает’ на расстоянии 6:
mysql> SELECT * FROM testrt WHERE MATCH('коричневая NEAR/2 лисица NEAR/6 прыгает');
+------+------+-------------------------------------------------------------------+---------------------------------------+
| id | gid | title | content |
+------+------+-------------------------------------------------------------------+---------------------------------------+
| 4 | 1 | Быстрая коричневая лисица прыгает через ленивую собаку | Пять боксерских волшебников быстро прыгают |
| 7 | 1 | Быстрая коричневая лисица делает шаг назад и прыгает через ленивую собаку | Пять боксерских волшебников быстро прыгают |
+------+------+-------------------------------------------------------------------+---------------------------------------+
2 rows in set (0.00 sec)
The query leaves out one document which doesn’t match the first NEAR
condition (the last one here):
mysql> SELECT * FROM testrt WHERE MATCH('brown NEAR/3 fox NEAR/6 jumps');
+------+------+----------------------------------------------------------------------------+---------------------------------------+
| id | gid | title | content |
+------+------+----------------------------------------------------------------------------+---------------------------------------+
| 4 | 1 | The quick brown fox jumps over the lazy dog | The five boxing wizards jump quickly |
| 7 | 1 | The quick brown fox take a step back and jumps over the lazy dog | The five boxing wizards jump quickly |
| 8 | 1 | The brown and beautiful fox take a step back and jumps over the lazy dog | The five boxing wizards jump quickly |
+------+------+----------------------------------------------------------------------------+---------------------------------------+
3 rows in set (0.09 sec)
A variation of the NEAR
operator is NOTNEAR
, which matches only if the operands have a minimum distance between them.
mysql> SELECT * FROM testrt WHERE MATCH('"brown fox" NOTNEAR/5 jumps');
+------+------+-------------------------------------------------------------------+---------------------------------------+
| id | gid | title | content |
+------+------+-------------------------------------------------------------------+---------------------------------------+
| 7 | 1 | The quick brown fox take a step back and jumps over the lazy dog | The five boxing wizards jump quickly |
+------+------+-------------------------------------------------------------------+---------------------------------------+
1 row in set (0.00 sec)
Manticore can also detect sentences in plain texts and paragraphs in HTML content.
For indexing sentences the index_sp option needs to be enabled, while paragraphs also require html_strip =1. Let’s take the following example:
mysql> select * from testrt where match('"the brown fox" jumps')G
*************************** 1. row ***************************
id: 15
gid: 2
title: The brown fox takes a step back. Then it jumps over the lazydog
content:
1 row in set (0.00 sec)
The document includes 2 sentences, while the phrase is found in the first one ‘jumps’ is only in the second sentence.
With the SENTENCE operator we can restrict the search to match only if the operands are in the same sentence:
mysql> select * from testrt where match('"the brown fox" SENTENCE jumps')G
Empty set (0.00 sec)
We can see that the document is not a match any more. If we correct the search query so all the words are from the same sentence we’ll see a match:
mysql> select * from testrt where match('"the brown fox" SENTENCE back')G<br></br>*************************** 1. row ***************************<br></br>id: 15<br></br>gid: 2<br></br>title: The brown fox takes a step back. Then it jumps over the lazydog<br></br>content:<br></br>1 row in set (0.00 sec)
To demonstrate the PARAGRAPH let’s use the following search:
mysql> select * from testrt where match('Samsung Galaxy');
+------+------+-------------------------------------------------------------------------------------+---------+
| id | gid | title | content |