# Getting started with Manticore Search in Docker

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

### Installing and running


Официальные Docker‑образы размещены по адресу <https://hub.docker.com/r/manticoresearch/manticore/>.
Чтобы запустить Manticore Search, достаточно выполнить:


```bash
$ docker run --name manticore -p 9306:9306 -d manticoresearch/manticore
```


Рецепт Docker размещён на [github](https://github.com/manticoresoftware/docker) для тех, кто хочет расширить существующие образы.

Контейнер Manticore Search не имеет постоянного хранилища, и при остановке контейнера все изменения теряются. Простой способ обеспечить постоянство — смонтировать несколько папок на локальном компьютере.

Папки, для которых мы хотим обеспечить постоянство:
- /etc/sphinxsearch — расположение файла sphinx.conf
- /var/lib/manticore/data — используется для файлов индексов
- /var/lib/manticore/log — используется для файлов журналов


Мы создаём папку `manticore/` в домашнем каталоге, где создадим папки `etc/`, `data/` и `logs/`, а также добавим корректный `sphinx.conf` в `~/manticore/etc/`. Мы можем использовать [sphinx.conf](https://github.com/manticoresoftware/docker/blob/master/sphinx.conf), включённый в репозиторий рецепта.
К команде запуска мы добавляем монтирования:


```bash
$ docker run --name manticore -v ~/manticore/etc/:/etc/sphinxsearch/ -v ~/manticore/data/:/var/lib/manticore/data -v ~/manticore/logs/:/var/lib/manticore/log -p 9306:9306 -d manticoresearch/manticore
```


Контейнер можно остановить, просто выполнив:


```bash
$ docker stop manticore
```


Образ Docker также поставляется с утилитами `indexer` и `indextoo`, которые можно запускать с помощью команды `exec` Docker:


```bash
$ docker exec -it manticore indexer --all --rotate
```




### Running queries

Простейший способ подключиться и выполнить несколько тестов — использовать протокол SphinxQL. Для этого нужен клиент командной строки mysql.

Хотя он реализует протокол MySQL, SphinxQL не на 100 % совместим с синтаксисом MySQL. Существуют специфические расширения, такие как оператор MATCH \[самая мощная вещь в Manticore\] или WITHIN GROUP BY, и многие функции, доступные в MySQL, не реализованы (или являются заглушками лишь для совместимости с коннектором MySQL, например) или JOIN‑ы между индексами, которые пока не поддерживаются.

Сначала подключимся к Manticore Search и посмотрим доступные индексы:


```sql
$ mysql -P9306 -h0
mysql> SHOW TABLES;
+-------+-------------+
| Index | Type        |
+-------+-------------+
| dist1 | distributed |
| testrt| rt          |
+-------+-------------+
2 rows in set (0.00 sec)

```


Теперь посмотрим наш RT‑индекс:


```sql
mysql> DESCRIBE testrt;
+---------+--------+
| Field | Type     |
+---------+--------+
| id      | bigint |
| title   | field  |
| content | field  |
| gid     | uint   |
+---------+--------+
4 rows in set (0.00 sec)

```


Поскольку RT‑индексы изначально пусты, сначала добавим в него некоторые данные


```sql
mysql> INSERT INTO testrt VALUES(1,'List of HP business laptops','Elitebook Probook',10);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO testrt VALUES(2,'List of Dell business laptops','Latitude Precision Vostro',10);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO testrt VALUES(3,'List of Dell gaming laptops','Inspirion Alienware',20);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO testrt VALUES(4,'Lenovo laptops list','Yoga IdeaPad',30);
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO testrt VALUES(5,'List of ASUS ultrabooks and laptops','Zenbook Vivobook',30);
Query OK, 1 row affected (0.01 sec)
```


Теперь у нас есть данные, мы можем выполнять запросы.

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


```sql
mysql> SELECT * FROM testrt WHERE MATCH('list of laptops');
+------+------+
| id   | gid  |
+------+------+
| 1    | 10   |
| 2    | 10   |
| 3    | 20   |
| 5    | 30   |
+------+------+
4 rows in set (0.00 sec)
```


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

Теперь добавим фильтрацию и более сложную сортировку:


```sql
mysql> SELECT *,WEIGHT() FROM testrt WHERE MATCG('list of laptops') AND gid>10 ORDER BY WEIGHT() DESC,gid DESC;
+------+------+----------+
| id   | gid  | weight() |
+------+------+----------+
| 5    | 30   | 2334     |
| 3    | 20   | 2334     |
+------+------+----------+
2 rows in set (0.00 sec)
```


Функция WEIGHT() возвращает вычисленный коэффициент совпадения. Если порядок не указан, результат сортируется по убыванию по баллу, предоставленному WEIGHT(). В этом примере мы сортируем сначала по весу, а затем по целочисленному атрибуту.

Приведённый выше поиск выполняет простое совпадение, когда все слова должны присутствовать. Но можно сделать больше (это лишь простой пример):


```sql
mysql> SELECT *,WEIGHT() FROM testrt WHERE MATCH('"list of business laptops"/3');
+------+------+----------+
| id   | gid  | weight() |
+------+------+----------+
| 1    | 10   | 2397     |
| 2    | 10   | 2397     |
| 3    | 20   | 2375     |
| 5    | 30   | 2375     |
+------+------+----------+
4 rows in set (0.00 sec)

mysql> SHOW META;
+---------------+----------+
| Variable_name | Value    |
+---------------+----------+
| total         | 4        |
| total_found   | 4        |
| time          | 0.000    |
| keyword[0]    | list     |
| docs[0]       | 5        |
| hits[0]       | 5        |
| keyword[1]    | of       |
| docs[1]       | 4        |
| hits[1]       | 4        |
| keyword[2]    | business |
| docs[2]       | 2        |
| hits[2]       | 2        |
| keyword[3]    | laptops  |
| docs[3]       | 5        |
| hits[3]       | 5        |
+---------------+----------+
15 rows in set (0.00 sec)
```


Здесь мы ищем 4 слова, но совпадение может быть найдено даже если найдено только 3 из 4 слов. Поиск будет ранжировать выше документы, содержащие все слова. Мы также добавили команду SHOW META. SHOW META возвращает информацию о ранее выполненном запросе: количество найденных записей (в total_found), время выполнения (в time) и статистику по ключевым словам поиска.


### Using plain indexes

В отличие от RT, обычный индекс также требует настройки источника. В нашем примере мы используем MySQL‑источник.

Добавьте в ваш sphinx.conf:


```ini
source src1
{
type = mysql

sql_host = 172.17.0.1
sql_user = test
sql_pass =
sql_db = test
sql_port = 3306 # optional, default is 3306

sql_query_pre = SET NAMES utf8

sql_query = \
SELECT id, group_id, UNIX_TIMESTAMP(date_added) AS date_added, title, content \
FROM documents

sql_attr_uint = group_id
sql_attr_timestamp = date_added

}
index test1
{

source = src1
path = /var/lib/manticore/data/test1
min_word_len = 1

}
```


В этом примере мы предполагаем, что MySQL запущен на локальном хосте, но поскольку Manticore Search работает внутри Docker‑контейнера, нам нужно использовать ‘172.17.0.1’, статический IP‑адрес Docker‑хоста. Для получения более подробной информации см. документацию Docker. Также необходимо скорректировать учётные данные MySQL соответственно.

Затем мы рассматриваем sql_query — запрос, который извлекает данные.


```sql
sql_query = \
SELECT id, group_id, UNIX_TIMESTAMP(date_added) AS date_added, title, content \
FROM documents
```


И мы используем этот фрагмент SQL для создания нашей тестовой таблицы в MySQL:


```sql
DROP TABLE IF EXISTS test.documents;
CREATE TABLE test.documents
(
id INTEGER PRIMARY KEY NOT NULL AUTO_INCREMENT,
group_id INTEGER NOT NULL,
date_added DATETIME NOT NULL,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL
);

INSERT INTO test.documents ( id, group_id, date_added, title, content ) VALUES
( 1, 1, NOW(), 'test one', 'this is my test document number one. also checking search within phrases.' ),
( 2, 1, NOW(), 'test two', 'this is my test document number two' ),
( 3, 2, NOW(), 'another doc', 'this is another group' ),
( 4, 2, NOW(), 'doc number four', 'this is to test groups' );
```


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

Если не указано, остальные столбцы индексируются как полнотекстовые поля. Столбцы, которые должны использоваться как атрибуты, необходимо объявить. В нашем примере group_id и date_added являются атрибутами:

```sql
sql_attr_uint = group_id
sql_attr_timestamp = date_added
```


После настройки мы можем запустить процесс индексации:


```bash
$ docker exec -it manticore indexer test1 --rotate
using config file '/etc/sphinxsearch/sphinx.conf'...
indexing index 'test1'...
collected 4 docs, 0.0 MB
sorted 0.0 Mhits, 100.0% done
total 4 docs, 193 bytes
total 0.015 sec, 12335 bytes/sec, 255.65 docs/sec
total 4 reads, 0.000 sec, 8.1 kb/call avg, 0.0 msec/call avg
total 12 writes, 0.000 sec, 0.1 kb/call avg, 0.0 msec/call avg
```


Индекс создан и готов к использованию:


```sql
mysql> SHOW TABLES;
+-------+-------------+
| Index | Type        |
+-------+-------------+
| dist1 | distributed |
| rt    | rt          |
| test1 | local       |
+-------+-------------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM test1;
+------+----------+------------+
| id   | group_id | date_added |
+------+----------+------------+
| 1    | 1        | 1507904567 |
| 2    | 1        | 1507904567 |
| 3    | 2        | 1507904567 |
| 4    | 2        | 1507904567 |
+------+----------+------------+
4 rows in set (0.00 sec)
```


Быстрый тест поиска, который должен совпасть с 2 терминами, но не совпасть с другим:


```sql
mysql> SELECT * FROM test1 WHERE MATCH('test document -one');
+------+----------+------------+-------+
| id   | group_id | date_added | tag   |
+------+----------+------------+-------+
| 2    | 1        | 1519040667 | 2,4,6 |   
+------+----------+------------+-------+
1 row in set (0.00 sec)
```
