4.9.MySQL 协议支持与 SphinxQL

优质
小牛编辑
120浏览
2023-12-01

Sphinx的searchd守护程序从 版本0.9.9-rc2开始支持MySQL二进制网络协议,并且能够通过标准的MySQL API访问。例如,“mysql”命令行程序可以很好地工作。以下是用MySQL客户端对Sphinx进行查询的例子:

$ mysql -P 9306
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 0.9.9-dev (r1734)
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> SELECT * FROM test1 WHERE MATCH('test') 
-> ORDER BY group_id ASC OPTION ranker=bm25;
+------+--------+----------+------------+
| id   | weight | group_id | date_added |
+------+--------+----------+------------+
|  4 |   1442 |    2 | 1231721236 |
|  2 |   2421 |    123 | 1231721236 |
|  1 |   2421 |    456 | 1231721236 |
+------+--------+----------+------------+
3 rows in set (0.00 sec)

请注意mysqld甚至根本没有在测试机上运行。所有事情都是searchd自己搞定的。

新的访问方法是对原生API的一种补充,原生API仍然完美可用。事实上,两种访问方法可以同时使用。另外,原生API仍旧是默认的访问方法。MySQL协议支持需要经过额外的配置才能启用。当然这只需要更动一行配置文件,加入一个协议为mysql41的监听器(listener)就可以了:

listen = localhost:9306:mysql41

如果仅仅支持这个协议但不支持SQL语法,那没什么实际意义。因此Sphinx现在还支持SQL的一个很小的子集,我们给这个子集起个绰号,叫SphinxQL。目前已经实现的语句有:

  • SELECT
  • SHOW WARNINGS
  • SHOW STATUS
  • SHOW META

SELECT语句,语法仿照标准SQL,但有一些Sphinx特有的扩展,也缺少一些标准SQL的特性(比如(目前)不支持JOIN)。具体地说:

  • 列列表子句。列名、任意表达式以及星号(“*”)都允许出现在列列表中(即“SELECT @id, group_id*123+456 FROM test1”是合法的)。与标准SQL不同,任何计算出的表达式都必须有一个有效的标识符作为别名。目前,特殊名称必须有一个前导的“at”符号(@), 例如@id和@weight。这个限制未来会被放宽。.
  • • FROM子句。FROM子句列举了要从哪些索引中进行搜索。与标准SQL不同,逗号的意思类似它在Query()API调用中的意思,代表全文索引的枚举,而不代表JOIN。
  • • WHERE子句。这个子句的内容既可以对应到全文查询,也可以对应过滤器。比较操作符(=, !=, <, >, <=, >=)、IN()、AND、NOT和BETWEEN等都被支持,她们直接映射成过滤器。而OR操作符尚未得到支持,但未来会支持。支持 MATCH(‘query’)这种形式,它被映射成一个全文查询。系统按照全文查询规则理解查询。在WHERE子句中最多只能有一个MATCH()。
  • • GROUP BY子句。目前仅支持根据一个列进行分组, 但这个列可以是一个计算出来的表达式。
    SELECT *, group_id*1000+article_type AS gkey FROM example GROUP BY gkey
    系统支持将聚集函数(AVG(),MIN(),MAC(),SUM())用在列列表子句中。这些聚集函数的参数既可以是简单的属性也可以是任意表达式。 COUNT(*)被隐含支持,因为使用GROUP BY就会导致@count这列自动被包括在结果集合中。未来可能会添加显式的支持。COUNT(DISTINCT attr)也被支持。目前每个查询中至多只能有一个COUNT(DISTINCT),而且参数必须是属性。这两种限制未来都可能被放宽。
    SELECT *, AVG(price) AS avgprice, COUNT(DISTINCT storeid)
    FROM products
    WHERE MATCH('ipod')
    GROUP BY vendorid
  • WITHIN GROUP ORDER BY子句。这个子句是Sphinx引入的,它使我们可以控制一个分组中最优的行是怎样选出的。这个自己的语法跟标准的ORDER BY子句相同:
    SELECT *, INTERVAL(posted,NOW()-7*86400,NOW()-86400) AS timeseg
    FROM example WHERE MATCH('my search query')
    GROUP BY siteid
    WITHIN GROUP ORDER BY @weight DESC
    ORDER BY timeseg DESC, @weight DESC
  • ORDER BY子句。不同于标准SQL,只能根据列名(而不是表达式)排序,必须显式地写明ASC(升序)或者DESC(降序)。不过列名可以是通过表达式计算出来的。
    SELECT *, @weight*10+docboost AS skey FROM example ORDER BY skey
  • LIMIT子句。支持LIMIT N和LIMIT M,N两种格式。与标准SQL不同(但是就像在Sphinx API中那样),默认有个隐含的LIMIT 0,20。
  • • OPTION子句。这是Sphinx引入的特殊扩展,它使我们可以设置一些只影响一个查询的选项。语法如下:
    OPTION <optionname>=<value> [ , ... ]
    支持设置的选项和允许设置的值如下:
    • 'ranker' - 以下值之一 'proximity_bm25', 'bm25', 'none', 'wordcount', 'proximity', 'matchany', 或者 'fieldmask'
    • 'max_matches' - 整数(当前查询的最大匹配数目)
    • 'cutoff' - 整数(最大匹配数阈值)
    • 'max_query_time' - 整数(最大搜索时间阈值,毫秒)
    • 'retry_count' - 整数(分布式重试数目)
    • 'retry_delay' - 整数(分布式重试的延迟时间,毫秒)
    例子:
    SELECT * FROM test WHERE MATCH('@title hello @body world')
    OPTION ranker=bm25, max_matches=3000

SHOW WARNINGS语句,用于获取上一条查询产生的警告信息。返回的信息还包括该查询本身:

mysql> SELECT * FROM test1 WHERE MATCH('@@title hello') \G
ERROR 1064 (42000): index test1: syntax error, unexpected TOK_FIELDLIMIT
near '@title hello'
mysql> SELECT * FROM test1 WHERE MATCH('@title -hello') \G
ERROR 1064 (42000): index test1: query is non-computable (single NOT operator)
mysql> SELECT * FROM test1 WHERE MATCH('"test doc"/3') \G
*************************** 1. row ***************************
  id: 4
weight: 2500
group_id: 2
date_added: 1231721236
1 row in set, 1 warning (0.00 sec)
mysql> SHOW WARNINGS \G
*************************** 1. row ***************************
Level: warning
Code: 1000
Message: quorum threshold too high (words=2, thresh=3); replacing quorum operator
   with AND operator
1 row in set (0.00 sec)

SHOW STATUS语句,显示一些很有用的性能计数器。仅当searchd启动时带有--iostats--cpustats开关时,IO和CPU计数器才分别可用。

mysql> SHOW STATUS;
+--------------------+-------+
| Variable_name    | Value |
+--------------------+-------+
| uptime       | 216   |
| connections    | 3   |
| maxed_out      | 0   |
| command_search   | 0   |
| command_excerpt  | 0   |
| command_update   | 0   |
| command_keywords   | 0   |
| command_persist  | 0   |
| command_status   | 0   |
| agent_connect    | 0   |
| agent_retry    | 0   |
| queries      | 10  |
| dist_queries     | 0   |
| query_wall     | 0.075 |
| query_cpu      | OFF   |
| dist_wall      | 0.000 |
| dist_local     | 0.000 |
| dist_wait      | 0.000 |
| query_reads    | OFF   |
| query_readkb     | OFF   |
| query_readtime   | OFF   |
| avg_query_wall   | 0.007 |
| avg_query_cpu    | OFF   |
| avg_dist_wall    | 0.000 |
| avg_dist_local   | 0.000 |
| avg_dist_wait    | 0.000 |
| avg_query_reads  | OFF   |
| avg_query_readkb   | OFF   |
| avg_query_readtime | OFF   |
+--------------------+-------+
29 rows in set (0.00 sec)

SHOW META语句,显示关于上一条查询的一些额外的元信息(meta-information),比如查询时间和关于关键词的统计信息:

mysql> SELECT * FROM test1 WHERE MATCH('test|one|two');
+------+--------+----------+------------+
| id   | weight | group_id | date_added |
+------+--------+----------+------------+
|  1 |   3563 |    456 | 1231721236 |
|  2 |   2563 |    123 | 1231721236 |
|  4 |   1480 |    2 | 1231721236 |
+------+--------+----------+------------+
3 rows in set (0.01 sec)
mysql> SHOW META;
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| total     | 3   |
| total_found   | 3   |
| time      | 0.005 |
| keyword[0]  | test  |
| docs[0]     | 3   |
| hits[0]     | 5   |
| keyword[1]  | one   |
| docs[1]     | 1   |
| hits[1]     | 2   |
| keyword[2]  | two   |
| docs[2]     | 1   |
| hits[2]     | 2   |
+---------------+-------+
12 rows in set (0.00 sec)