现在,长期以来被请求的功能已在最新代码中可用:感知查询。
如果你想进行交互式课程,请点击 这里 。
感知查询也被称为持久查询、预测搜索、文档路由、反向搜索或逆向搜索。
通常的搜索方式是存储要搜索的文档并对其执行查询。然而,在某些情况下,我们希望对新传入的文档应用查询以发出匹配信号。有些场景需要这种功能。例如,监控系统不仅仅收集数据,还希望在不同事件中通知用户。这可能是达到某个指标的阈值,或者在监控数据中出现某个特定值。另一个类似的案例是新闻聚合。你可以通知用户任何新鲜新闻,但用户可能只想被通知特定类别或主题。更进一步,他们可能只对某些"关键词"感兴趣。
在这种情况下,传统搜索并不适合,因为它假定对整个集合执行所需的搜索,这会随着用户数量的增加而成倍增长,最终导致大量查询在整个集合上运行,这可能会带来额外的负载。为了克服这一点,产生了一个想法:存储查询并针对新传入的文档或文档批次对其进行测试。
之前可以通过使用实时索引(Real-Time index)来变通解决,只在其上添加新文档,测试查询,然后截断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索引那样生成ID。插入新查询需要一个强制的’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)
有两个具有特殊用途的可选属性。
第一个是’tags’,它支持字符串包(类似字符串MVA)。标签可用于在执行SELECT或DELETE时过滤PQ,它们在执行感知搜索时没有作用。
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开辟了新的使用场景,我们欢迎大家测试并提供任何形式的反馈。同时我们将继续在此方面工作,在我们可以称其为生产就绪之前还有一些事情需要完成。我们将感谢任何帮助测试的努力。