Перколейт-запросы

Одна из давно запрошенных функций теперь доступна в последнем коде: перколейт-запросы.

Если вы хотите пройти интерактивный курс, перейдите сюда .

Перколейт-запросы также известны как постоянные запросы, проспективный поиск, маршрутизация документов, обратный поиск или инверсный поиск.

Обычный способ поиска заключается в хранении документов, по которым мы хотим выполнять поиск, и выполнении запросов к ним. Однако бывают случаи, когда мы хотим применить запрос к новому входящему документу, чтобы определить совпадение. Существует несколько сценариев, когда это желательно. Например, система мониторинга не только собирает данные, но также желает уведомлять пользователя о различных событиях. Это может быть достижение какого-то порога для метрики или определенного значения, появляющегося в контролируемых данных. Другой похожий случай - агрегация новостей. Можно уведомлять пользователя о любых свежих новостях, но пользователь может хотеть получать уведомления только для определенных категорий или тем. Идя дальше, они могут быть заинтересованы только в определенных “ключевых словах”.

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

Обходное решение было возможно с использованием Real-Time индекса, на котором добавлялись только новые документы, тестировались запросы, и RT усекался. Но это было далеко не решением. Наконец, мы добавляем эту функциональность в Manticore Search (и, следовательно, для всех, кто обновляется от Sphinx Search).

Для хранения запросов используется новый тип индекса, основанный на Real Time индексе. Индекс percolate позволяет добавлять, просматривать или удалять запросы.

Сопоставление запросов осуществляется новым оператором, который принимает на вход документ или список документов и возвращает, какие запросы нашли совпадение.

Обратите внимание, что индекс ‘percolate’ не является заменой существующего индекса, он не хранит документы. В обычном случае использования документы вставляются в индекс как и раньше. Перколейт-запросы могут быть выполнены либо после выполнения вставки тем же работником, либо другим работником, работающим независимо от работника вставки (который может быть выполнен заданием cron или инициирован вставками). Последний был бы предпочтительнее, чтобы PQ не задерживали подтверждение (конечному пользователю) вставки, но это зависит от рабочего процесса приложения.

Хранение Перколейт-запросов

Как указано выше, Перколейт-запросы хранятся в специальном Real-Time индексе, определенном как тип 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)

Идентификатор документа поддерживает автоматическое приращение, при выполнении вставок вам не нужно генерировать идентификатор, как для обычных 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. Также набор результатов по умолчанию содержит только идентификатор запроса, но мы можем использовать опцию 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, мы приглашаем всех протестировать ее и предоставить нам любую обратную связь. Между тем мы продолжаем работать над этим, есть несколько вещей, которые остаются до того, как мы сможем назвать это готовым к производству. Мы будем признательны за любую помощь в тестировании.

Установить Manticore Search

Установить Manticore Search