# Introduction to full-text operators and basic search

В этом учебном пособии мы рассмотрим операторы полнотекстового поиска, доступные в Manticore Search.

# Введение в операторы полнотекстового поиска и базовый поиск

Все операции поиска в Manticore Search основаны на стандартных булевых операторах (AND, OR, NOT), которые можно использовать в комбинации и произвольном порядке для объединения или исключения ключевых слов в поиске более релевантных результатов.

Оператор полнотекстового поиска по умолчанию и самый простой — это AND, который подразумевается, когда вы просто перечисляете несколько слов в поиске.

![Full-Text-Operators-in-Manticore_AND](./manticore-full-text-operators-definitive-guide/Full-Text-Operators-in-Manticore_AND-oqrugx63xg8ezov2jmez5z2j6aehaqp0vmtov5gh6w.png "Full-Text-Operators-in-Manticore_AND")**AND** — это оператор по умолчанию, с помощью которого запрос **`fast slow`** вернет документы, содержащие оба термина: 'fast' и 'slow'. Если один термин присутствует в документе, а другой — нет, документ не будет включен в результирующий список. 
По умолчанию слова будут искаться во всех доступных полнотекстовых полях.

```sql
SELECT * FROM testrt WHERE MATCH('fast slow');

```

![Full-Text-Operators-in-Manticore_OR](./manticore-full-text-operators-definitive-guide/Full-Text-Operators-in-Manticore_OR-oqruhgwpwyzfri2eccy54c37ndp6sdvdycivxyn7k8.png "Full-Text-Operators-in-Manticore_OR")**OR** используется для соответствия любому термину (или обоим). Термины должны быть разделены вертикальной чертой, например, **`fast | slow`**. Он найдет документы с `fast` или `slow`.

```sql
SELECT * FROM testrt WHERE MATCH('fast | slow');

```
Оператор OR имеет более высокий приоритет, чем AND, поэтому запрос **'find me fast|slow'** может быть интерпретирован как 'найди мне (fast|slow)':


```sql
SELECT * FROM testrt WHERE MATCH('find me fast | slow');
```

![NOT](./manticore-full-text-operators-definitive-guide/Full-Text-Operators-in-Manticore_NOT-1-ouyihor8jcz7ulw8ge49i39crd81gfa5mhswo6fx8o.png) **NOT** гарантирует, что термин, отмеченный `-` или `!`, отсутствует в результатах. Любые документы, содержащие такой термин, будут исключены. Например, **`fast !slow`** найдет документы с `fast`, если только в них нет `slow`. Будьте осторожны, используя его, пытаясь сократить поиск, так как это может сделать его слишком специфичным и исключить хорошие документы.


```sql
SELECT * FROM testrt WHERE MATCH('find !slow');

SELECT * FROM testrt WHERE MATCH('find -slow');
```

![MAYBE](./manticore-full-text-operators-definitive-guide/MAYBE-ovsmxs1rjjx4r9zfqopp5gjggdkxynqlt08kfhb56w.png "MAYBE")**MAYBE** — это специальный оператор, который работает как `OR`, но требует, чтобы левый термин всегда присутствовал в результатах, в то время как правый термин является необязательным. Но когда оба термина присутствуют, документ получит более высокий рейтинг в поиске. Например, **`fast MAYBE slow`** найдет документы с `fast` или `slow`, но документы, содержащие оба термина, будут иметь более высокий балл.

```sql
SELECT * FROM testrt WHERE MATCH('find MAYBE slow');
```

## Примеры использования

Давайте подключимся к Manticore, используя клиент mysql:

```sql
# mysql -P9306 -h0
```

Для булевых поисков можно использовать оператор OR `|`:


```sql
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)`:


```sql
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 может быть указан как `-` или `!`:


```sql
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, может присутствовать или отсутствовать в документах. Если он присутствует, это повлияет на рейтинг, и документы, содержащие его, будут оценены выше.


```sql
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)

```

## Оператор поля

Если мы хотим ограничить поиск только определенным полем, можно использовать оператор '@':


```sql
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 | find me quick and fast |  quick  |
+------+------+------------------------+---------+
3 rows in set (0.00 sec)

```
Мы также можем указать несколько полей, чтобы ограничить поиск:


```sql
mysql> select * from testrt where match('@(title,content) 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)
```

Оператор поля также может быть использован для ограничения поиска только на первые x слов. Например:

```sql
mysql> select * from testrt where match('@title lazy dog');
+------+------+----------------------------------------------------------------------------+---------------------------------------+
| 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 |
+------+------+----------------------------------------------------------------------------+---------------------------------------+
4 rows in set (0.00 sec)
```

Однако, если мы ищем только в первых 5 словах, мы ничего не получаем:

```sql
mysql> select * from testrt where match('@title[5] lazy dog');
Empty set (0.00 sec)

```
В некоторых ситуациях поиск может выполняться по нескольким индексам, которые могут не иметь одинаковых полнотекстовых полей.  
По умолчанию указание поля, которого нет в индексе, приведет к ошибке запроса. Чтобы обойти это, можно использовать специальный оператор `@@relaxed`:


```sql
mysql> select * from testrt where match('@(title,keywords) lazy dog');<br></br>ERROR 1064 (42000): index testrt: query error: no field 'keywords' found in schema
```

```sql
mysql> select * from testrt where match('@@relaxed @(title,keywords) lazy dog');
+------+------+----------------------------------------------------------------------------+---------------------------------------+
| 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, 1 warning (0.01 sec)
```


## Неопределенный поиск

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


```sql
mysql> select * from testrt where match('"fox bird lazy dog"/3');
+------+------+----------------------------------------------------------------------------+---------------------------------------+
| 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.00 sec)
```

В этом случае мы используем оператор `QUORUM` и указываем, что допустимо сопоставить только 3 слова. Поиск с `/1` эквивалентен булевому поиску OR, в то время как поиск с `/N`, где N — это количество входных слов, эквивалентен поиску AND.

Вместо абсолютного числа вы также можете указать число от 0.0 до 1.0 (что соответствует 0% и 100%), и Manticore будет сопоставлять только документы с как минимум указанным процентом данных слов. Тот же пример выше также мог быть записан как `"fox bird lazy dog"/0.3`, и он будет соответствовать документам с как минимум 30% из 4 слов.

```sql
mysql> select * from testrt where match('"fox bird lazy dog"/0.3');
+------+------+----------------------------------------------------------------------------+---------------------------------------+
| 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.00 sec)
```


## Расширенные операторы

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

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


```sql
mysql> SELECT * FROM testrt WHERE MATCH('"quick brown fox"');
+------+------+-------------------------------------------------------------------+---------------------------------------+
| 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 |
+------+------+-------------------------------------------------------------------+---------------------------------------+
2 rows in set (0.00 sec)

```
Более расслабленная версия оператора фразы — это оператор строгого порядка.  
Оператор порядка требует, чтобы слова были найдены в точно таком же порядке, как указано, но между ними допускаются другие слова:


```sql
mysql> SELECT * FROM testrt WHERE MATCH('find << me << fast');
+------+------+------------------------+---------+
| id   | gid  | title                  | content |
+------+------+------------------------+---------+
|    2 |    1 | find me fast           |  quick  |
|    6 |    1 | find me fast now       |  quick  |
|    5 |    1 | find me quick and fast |  quick  |
+------+------+------------------------+---------+
3 rows in set (0.00 sec)

```
Еще одна пара операторов, которые работают с позициями слов, — это операторы начала/конца поля.  
Эти операторы ограничат слово, чтобы оно присутствовало в начале или в конце поля.

```sql
mysql> SELECT * FROM testrt WHERE MATCH('^find me fast$');
+------+------+------------------------+---------+
| id   | gid  | title                  | content |
+------+------+------------------------+---------+
|    2 |    1 | find me fast           |  quick  |
|    5 |    1 | find me quick and fast |  quick  |
+------+------+------------------------+---------+
2 rows in set (0.00 sec)

```
Оператор близости похож на оператор AND, но добавляет максимальное расстояние между словами, чтобы они все еще могли считаться совпадением. Рассмотрим этот пример только с оператором AND:

```sql
mysql> SELECT * FROM testrt WHERE MATCH('brown fox 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.00 sec)
```

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


```sql
mysql> SELECT * FROM testrt WHERE MATCH('"brown fox jumps"~5');
+------+------+---------------------------------------------+---------------------------------------+
| id   | gid  | title                                       | content                               |
+------+------+---------------------------------------------+---------------------------------------+
|    4 |    1 | The quick brown fox jumps over the lazy dog |  The five boxing wizards jump quickly |
+------+------+---------------------------------------------+---------------------------------------+
1 row in set (0.00 sec)
```

Более обобщённая версия оператора близости — оператор `NEAR`. В случае оператора близости указывается одно расстояние для набора слов, тогда как оператор `NEAR` работает с 2 операндами, которые могут быть как отдельными словами, так и выражениями.

В следующем примере 'brown' и 'fox' должны находиться на расстоянии не более 2, а 'fox' и 'jumps' — на расстоянии не более 6:

```sql
mysql> SELECT * FROM testrt WHERE MATCH('brown NEAR/2 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 |
+------+------+-------------------------------------------------------------------+---------------------------------------+
2 rows in set (0.00 sec)
```

Запрос исключает один документ, который не соответствует первому условию `NEAR` (последний здесь):

```sql
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)
```

Вариацией оператора `NEAR` является `NOTNEAR`, который совпадает только если между операндами есть минимальное расстояние.

```sql
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 также может обнаруживать предложения в обычных текстах и абзацы в HTML‑контенте.
Для индексации предложений необходимо включить параметр **[index_sp](http://mnt.cr/index_sp)**, а для абзацев также требуется **[html_strip](http://mnt.cr/html_strip)=1**. Возьмём следующий пример:


```sql
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)
```

Документ содержит 2 предложения, при этом фраза найдена в первом, а 'jumps' находится только во втором предложении.

С оператором SENTENCE мы можем ограничить поиск так, чтобы совпадение происходило только если операнды находятся в одном предложении:


```sql
mysql> select * from testrt where match('"the brown fox" SENTENCE jumps')G
Empty set (0.00 sec)
```

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

```sql
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)
```

Чтобы продемонстрировать оператор PARAGRAPH, используем следующий поиск:


```sql
mysql> select * from testrt where match('Samsung  Galaxy');
+------+------+-------------------------------------------------------------------------------------+---------+
| id   | gid  | title                                                                               | content |
+------+------+-------------------------------------------------------------------------------------+---------+
|    9 |    2 | <h1>Samsung Galaxy S10</h1>Is a smartphone introduced by Samsung in 2019            |         |
|   10 |    2 | <h1>Samsung</h1>Galaxy,Note,A,J                                                     |         |
+------+------+-------------------------------------------------------------------------------------+---------+
2 rows in set (0.00 sec)
```

У этих 2 документов разные HTML‑теги

Если добавить оператор PARAGRAPH, останется только документ, в котором поисковые термины найдены в единственном теге.

Более общие операторы — ZONE и его вариант ZONESPAN. "zone" — это текст внутри HTML‑ или XML‑тега.

Теги, которые следует учитывать для зон, необходимо объявить в настройке `index_zones`, например `index_zones = h*, th, title`.

Например:

```sql
mysql> select * from testrt where match('hello world');
+------+------+-------------------------------+---------+
| id   | gid  | title                         | content |
+------+------+-------------------------------+---------+
|   12 |    2 | Hello world                   |         |
|   14 |    2 | <h1>Hello world</h1>          |         |
|   13 |    2 | <h1>Hello</h1> <h1>world</h1> |         |
+------+------+-------------------------------+---------+
3 rows in set (0.00 sec)
```

У нас есть 3 документа, где 'hello' и 'world' находятся в обычном тексте, в разных зонах одного типа или в одной зоне.

```sql
mysql> select * from testrt where match('ZONE:h1 hello world');
+------+------+-------------------------------+---------+
| id   | gid  | title                         | content |
+------+------+-------------------------------+---------+
|   14 |    2 | <h1>Hello world</h1>          |         |
|   13 |    2 | <h1>Hello</h1> <h1>world</h1> |         |
+------+------+-------------------------------+---------+
2 rows in set (0.00 sec)
```

В этом случае слова находятся в зонах H1, но они не обязаны быть в одной зоне. Если мы хотим ограничить совпадение одной зоной, можно использовать ZONESPAN:

```sql
mysql> select * from testrt where match('ZONESPAN:h1 hello world');
+------+------+----------------------+---------+
| id   | gid  | title                | content |
+------+------+----------------------+---------+
|   14 |    2 | <h1>Hello world</h1> |         |
+------+------+----------------------+---------+
1 row in set (0.00 sec)
```

Надеемся, из этой статьи вы узнали, как работают [операторы полнотекстового поиска](https://docs.manticoresearch.com/latest/html/searching/boolean_query_syntax.html) в Manticore. Если вы хотите получить практический опыт и изучить их ещё лучше, вы можете [попробовать наш интерактивный курс](https://play.manticoresearch.com/fulltextintro/) прямо сейчас в браузере.


### [Интерактивный курс](https://play.manticoresearch.com/fulltextintro/)

[![img](./manticore-full-text-operators-definitive-guide/Manticore-Full-text-operators-Interactive-course.png)](https://play.manticoresearch.com/fulltextintro/)  

Вы можете узнать больше о полнотекстовом сопоставлении, попробовав наш "Вводный курс по операторам полнотекстового поиска" [интерактивный курс](https://play.manticoresearch.com/fulltextintro/), который включает командную строку для более простого обучения.
