Одна из давно запрашиваемых функций теперь доступна в последней версии кода: перколятные запросы.
Если вы хотите пройти интерактивный курс, перейдите сюда .
Перколятные запросы также известны как постоянные запросы, перспективный поиск, маршрутизация документов, поиск в обратном направлении или обратный поиск.
Обычный способ выполнения поисков заключается в хранении документов, которые мы хотим искать, и выполнении запросов к ним. Однако бывают случаи, когда мы хотим применить запрос к поступающему новому документу, чтобы определить совпадение. Существует несколько сценариев, где это необходимо. Например, система мониторинга не только собирает данные, но и должна уведомлять пользователя о различных событиях. Это может быть достижение некоторого порога метрики или появление определённого значения в мониторируемых данных. Другой похожий случай — агрегирование новостей. Вы можете уведомлять пользователя о любой свежей новости, но пользователь может захотеть получать уведомления только по определённым категориям или темам. Более того, их могут интересовать только определённые «ключевые слова».
Здесь традиционный поиск не подходит, поскольку он предполагает выполнение желаемого поиска по всей коллекции, что умножается на количество пользователей, и в итоге у нас появляется множество запросов, работающих по всей коллекции, что создает значительную дополнительную нагрузку. Чтобы решить эту проблему, возникла идея хранить вместо этого запросы и проверять их против поступающего нового документа или пакета документов.
Обходной путь был возможен с использованием индекса реального времени, в который добавлялись только новые документы, запросы проверялись, а RT обрезался. Но это было далеко не решение. Наконец, мы добавляем эту функциональность в Manticore Search (и, соответственно, для всех, кто обновляется с Sphinx Search).
Для хранения запросов используется новый тип индекса, основанный на индексе реального времени. Индекс percolate позволяет добавлять запросы, просматривать их или удалять.
Сопоставление запросов осуществляется с помощью нового оператора, который принимает на вход документ или список документов и возвращает, какие запросы получили совпадение.
Обратите внимание, что индекс 'percolate' не является заменой существующего индекса, он не хранит документы. В обычном случае документы вставляются в индекс, как и раньше. Перколятные запросы могут выполняться после вставки, тем же рабочим процессом или другим процессом, работающим независимо от процесса вставки (который может быть выполнен cron‑задачей или запускаться при вставках). Последний вариант предпочтительнее, чтобы PQ не задерживали подтверждение (для конечного пользователя) вставки, но это зависит от рабочего процесса приложения.
Хранение перколятных запросов
Как указано выше, перколятные запросы хранятся в специальном индексе реального времени, определённом как тип percolate.
Простой индекс PQ требует лишь определения типа и пути:
index pq {
type = percolate
path = /var/lib/sphinxsearch/pq
}
Чтобы сделать его доступным, просто выполните команду RELOAD INDEXES :
MySQL [(none)]> RELOAD INDEXES; SHOW TABLES LIKE 'pq';
Query OK, 0 rows affected (0.00 sec)
+-------+-----------+
| Index | Type |
+-------+-----------+
| pq | percolate |
+-------+-----------+
1 row in set (0.00 sec)
Идентификатор документа поддерживает автоинкремент; при вставках вам не нужно генерировать id, как для обычных RT‑индексов. Вставка нового запроса требует обязательного текстового поля 'query', которое содержит выражение полнотекстового поиска.
MySQL [(none)]> INSERT INTO pq(query) VALUES('catch me');
Query OK, 1 rows affected (0.00 sec)
MySQL [(none)]> SELECT * FROM pq;
+------+----------+------+---------+
| UID | Query | Tags | Filters |
+------+----------+------+---------+
| 1 | catch me | | |
+------+----------+------+---------+
1 row in set (0.00 sec)
Существует 2 необязательных атрибута со специальным использованием.
Первый — 'tags', который поддерживает набор строк (подобно строковому MVA). Теги можно использовать для фильтрации PQ при выполнении SELECT или DELETE, они не участвуют в перколятных поисках.
MySQL [(none)]> insert into pq(query,tags) values('catch me if','tag1');
Query OK, 1 rows affected (0.00 sec)
MySQL [(none)]> SELECT * FROM pq WHEREtags='tag1';
+------+-------------+------+---------+
| UID | Query | Tags | Filters |
+------+-------------+------+---------+
| 2 | catch me if | tag1 | |
+------+-------------+------+---------+
2 rows in set (0.00 sec)
Второй — 'filters', содержащий дополнительные правила запросов, в которых можно хранить фильтрацию атрибутов в формате SphinxQL. Атрибуты, используемые здесь, должны быть объявлены в конфигурации индекса так же, как атрибуты в RT‑индексе. Чтобы включить новый атрибут, можно просто использовать ALTER RTINDEX RECONFIGURE.
index pq {
type = percolate
path = /var/lib/sphinxsearch/pq
rt_attr_uint = catId
}
MySQL [(none)]> ALTER RTINDEX pq RECONFIGURE;
Query OK, 0 rows affected (0.00 sec)
MySQL [(none)]> INSERT INTO pq(query,tags,filters) VALUES('catch me','tag2,tag1','catId=10');
Query OK, 1 rows affected (0.00 sec)
MySQL [(none)]> select * from pq;
+------+-------------+-----------+-----------+
| UID | Query | Tags | Filters |
+------+-------------+-----------+-----------+
| 3 | catch me | | |
| 4 | catch me if | tag1 | |
| 5 | catch me | tag2,tag1 | catid=10 |
+------+-------------+-----------+-----------+
3 rows in set (0.00 sec)
Если мы хотим включить поиск текста по отдельным полям, необходимо определить полнотекстовые поля в конфигурации индекса и выполнить переустановку.
index pq {
type = percolate
path = /var/lib/sphinxsearch/pq
rt_field = subject
rt_field = content
rt_attr_uint = catId
}
MySQL [(none)]> ALTER RTINDEX pq RECONFIGURE;
Query OK, 0 rows affected (0.00 sec)
MySQL [(none)]> INSERT INTO pq(query,tags,filters) VALUES('@subject match by field','tag2,tag3','catId=10');
Query OK, 1 rows affected (0.00 sec)
MySQL [(none)]> INSERT INTO pq(query,tags,filters) VALUES('@subject match by field','tag2,tag3','catId=20');
Query OK, 1 rows affected (0.00 sec)
Выполнение перколятных запросов
Функцию CALL PQ можно использовать для одного перколятного индекса (пока), который задаётся первым параметром функции. Второй параметр, обязательный, содержит документ или список документов. Передаваемый документ(ы) может быть обычным текстом или объектом JSON. Объект JSON позволяет передавать несколько текстовых полей, поэтому возможны совпадения по отдельным полям, а также атрибуты, проверяемые по выражению, определённому в атрибуте 'filters' перколятного запроса. Это означает, что запрос может быть не только выражением полнотекстового совпадения, но также может включать фильтры атрибутов, что позволяет более сложное сопоставление (например, кто‑то ищет определённые ключевые слова, но хочет получать уведомления только для определённых типов или категорий статей).
По умолчанию CALL PQ ожидает документы в формате JSON, поэтому для выполнения самого простого примера нам нужно передать 0 as docs_json. Также набор результатов по умолчанию содержит только ID запроса, но мы можем использовать опцию query, чтобы отобразить всю сохранённую информацию.
MySQL [(none)]> CALL PQ('pq','catch me',0 AS docs_json,1 AS query);
+------+----------+------+---------+
| UID | Query | Tags | Filters |
+------+----------+------+---------+
| 6 | catch me | | |
+------+----------+------+---------+
1 row in set (0.00 sec)
Чтобы выполнить сопоставление по отдельным полям или дополнительную фильтрацию атрибутов, нам нужно передать документы в виде объекта JSON.
MySQL [(none)]> CALL PQ('pq','{"subject":"expect to match by field","content":"here is some content","catid":20}',1 AS query);
+------+--------------------------+-----------+-----------+
| UID | Query | Tags | Filters |
+------+--------------------------+-----------+-----------+
| 10 | @subject match by field | tag2,tag3 | catid=20 |
+------+--------------------------+-----------+-----------+
1 row in set (0.00 sec)
CALL PQ имеет ещё 2 параметра выполнения: опция 'docs' полезна, когда на входе более одного документа, так как она указывает, какой документ совпал с поиском (начиная с индекса 1).
MySQL [(none)]> CALL PQ('pq',('catch me if can','catch me'),0 AS docs_json,1 AS docs,1 AS verbose);
+------+-----------+-------------+------+---------+
| UID | Documents | Query | Tags | Filters |
+------+-----------+-------------+------+---------+
| 6 | 1,2 | catch me | | |
| 7 | 1 | catch me if | tag1 | |
+------+-----------+-------------+------+---------+
2 rows in set (0.00 sec)
При выполнении CALL PQ команда SHOW META предоставляет информацию о выполненной функции, такую как время выполнения, количество запросов и совпавших документов, общее число хранимых запросов.
Когда в CALL PQ установлен параметр 'verbose', отображается дополнительная информация, например время, затраченное на каждый запрос.
MySQL [(none)]> SHOW META;
+-------------------------+-----------+
| Name | Value |
+-------------------------+-----------+
| Total | 0.000 sec |
| Setup | 0.000 sec |
| Queries matched | 2 |
| Document matches | 2 |
| Total queries stored | 6 |
| Term only queries | 6 |
| Fast rejected queries | 3 |
| Time per query | 32, 21 |
| Time of matched queries | 53 |
+-------------------------+-----------+
9 rows in set (0.00 sec)
Обратная связь
Поскольку это новая функция, добавленная в Manticore, открывающая новые сценарии использования Manticore Search, мы приглашаем всех протестировать её и предоставить любые отзывы. Пока мы продолжаем работу над ней, осталось несколько вещей, прежде чем мы сможем назвать её готовой к продакшн. Мы будем благодарны за любую помощь в тестировании.