В этом посте мы обсудим, как быстро начать использовать Manticore Search с Docker.
Installing and running
Официальные Docker‑образы размещены по адресу
https://hub.docker.com/r/manticoresearch/manticore/
.
Чтобы запустить Manticore Search, достаточно выполнить:
$ docker run --name manticore -p 9306:9306 -d manticoresearch/manticore
Рецепт Docker размещён на github для тех, кто хочет расширить существующие образы.
Контейнер Manticore Search не имеет постоянного хранилища, и при остановке контейнера все изменения теряются. Простой способ обеспечить постоянство — смонтировать несколько папок на локальном компьютере.
Папки, для которых мы хотим обеспечить постоянство:
- /etc/sphinxsearch — расположение файла sphinx.conf
- /var/lib/manticore/data — используется для файлов индексов
- /var/lib/manticore/log — используется для файлов журналов
Мы создаём папку manticore/ в домашнем каталоге, где создадим папки etc/, data/ и logs/, а также добавим корректный sphinx.conf в ~/manticore/etc/. Мы можем использовать
sphinx.conf
, включённый в репозиторий рецепта.
К команде запуска мы добавляем монтирования:
$ 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
Контейнер можно остановить, просто выполнив:
$ docker stop manticore
Образ Docker также поставляется с утилитами indexer и indextoo, которые можно запускать с помощью команды exec Docker:
$ 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 и посмотрим доступные индексы:
$ mysql -P9306 -h0
mysql> SHOW TABLES;
+-------+-------------+
| Index | Type |
+-------+-------------+
| dist1 | distributed |
| testrt| rt |
+-------+-------------+
2 rows in set (0.00 sec)
Теперь посмотрим наш RT‑индекс:
mysql> DESCRIBE testrt;
+---------+--------+
| Field | Type |
+---------+--------+
| id | bigint |
| title | field |
| content | field |
| gid | uint |
+---------+--------+
4 rows in set (0.00 sec)
Поскольку RT‑индексы изначально пусты, сначала добавим в него некоторые данные
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, который является основной рабочей лошадкой.
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)
Как видно из набора результатов, мы получаем только идентификатор документа и атрибуты. Значения полнотекстовых полей не возвращаются, поскольку текст только индексируется, а не хранится, и восстановить оригинальный текст невозможно.
Теперь добавим фильтрацию и более сложную сортировку:
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(). В этом примере мы сортируем сначала по весу, а затем по целочисленному атрибуту.
Приведённый выше поиск выполняет простое совпадение, когда все слова должны присутствовать. Но можно сделать больше (это лишь простой пример):
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:
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_query = \
SELECT id, group_id, UNIX_TIMESTAMP(date_added) AS date_added, title, content \
FROM documents
И мы используем этот фрагмент SQL для создания нашей тестовой таблицы в MySQL:
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_attr_uint = group_id
sql_attr_timestamp = date_added
После настройки мы можем запустить процесс индексации:
$ 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
Индекс создан и готов к использованию:
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 терминами, но не совпасть с другим:
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)