在 Docker 中开始使用 Manticore Search

在这篇文章中,我们将讨论如何快速开始使用 Docker 中的 Manticore Search。

安装和运行

官方 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/ 文件夹,并在 ~/manticore/etc/ 中添加一个有效的 sphinx.conf 文件。我们可以使用配方仓库中包含的 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 镜像还配备了 indexerindextoo 工具,可以通过 Docker 的 exec 命令运行:

$ docker exec -it manticore indexer --all --rotate

运行查询

连接并进行一些测试的简单方法是使用 SphinxQL 协议。为此,您需要一个 mysql 命令行客户端。

虽然它实现了 MySQL 协议,但 SphinxQL 并不完全兼容 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,'HP 商务笔记本清单','Elitebook Probook',10);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO testrt VALUES(2,'戴尔商务笔记本清单','Latitude Precision Vostro',10);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO testrt VALUES(3,'戴尔游戏笔记本清单','Inspirion Alienware',20);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO testrt VALUES(4,'联想笔记本清单','Yoga IdeaPad',30);
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO testrt VALUES(5,'华硕超极本和笔记本清单','Zenbook Vivobook',30);
Query OK, 1 row affected (0.01 sec)

现在我们有了一些数据,可以进行一些查询。

全文搜索通过特殊子句 MATCH 来完成,这是主要的工作马。

mysql> SELECT * FROM testrt WHERE MATCH('笔记本清单');
+------+------+
| id   | gid  |
+------+------+
| 1    | 10   |
| 2    | 10   |
| 3    | 20   |
| 5    | 30   |
+------+------+
4 rows in set (0.00 sec)

如您所见,在结果集中我们只能获取文档 id 和属性。由于文本仅被索引而未保存,因此不会返回全文字段值,无法重建原始文本。

现在让我们添加一些过滤和更多排序:

mysql> SELECT *,WEIGHT() FROM testrt WHERE MATCH('笔记本清单') 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('"商务笔记本"/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]    | 清单     |
| docs[0]       | 5        |
| hits[0]       | 5        |
| keyword[1]    |        |
| docs[1]       | 4        |
| hits[1]       | 4        |
| keyword[2]    | 商务    |
| docs[2]       | 2        |
| hits[2]       | 2        |
| keyword[3]    | 笔记本  |
| docs[3]       | 5        |
| hits[3]       | 5        |
+---------------+----------+
15 rows in set (0.00 sec)

在这里,我们搜索4个词,但即使只找到3个词(4个中的3个),也可以匹配。搜索将首先给包含所有单词的文档更高的排名。我们还添加了一个SHOW META命令。SHOW META返回关于先前执行的查询的信息,即找到的记录数量(in total_found)、执行时间(in time)以及关于搜索关键词的统计信息。

使用普通索引

与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’,即Docker主机的静态IP地址。有关更多详细信息,请查看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)

安装Manticore Search

安装Manticore Search