blog-post

Manticore Search: 3 years after forking from Sphinx

在2017年5月,我们对Sphinxsearch 2.3.2进行了分叉,称之为 Manticore Search 。以下是关于Manticore Search作为Sphinx的分叉及我们自那以来取得的成就的简要报告。

我们为什么要分叉Sphinx?


首先,我们为什么要进行分叉?在2016年底,Sphinxsearch的工作暂停了。使用Sphinx的用户和一些支持该项目开发的客户对此感到担忧,因为:

  • 错误长时间未被修复
  • 长期承诺的新功能未能推出
  • 与Sphinx团队的沟通中断

几个月后,情况没有改变,2017年6月中旬,一群积极主动且经验丰富的Sphinx用户和支持客户聚在一起,决定尝试以Manticore Search的名义保持该产品作为一个分叉。我们成功地召回了大部分之前在不同公司工作的Sphinx团队,吸引了投资,并在短时间内恢复了项目的全面工作。

我们的目标是什么?


该分叉旨在实现三个目标:

  1. 一般代码支持:错误修复,小型和大型新功能
  2. 支持Sphinx和Manticore用户
  3. 比之前更密集的产品开发。不幸的是,到那时Elasticsearch在许多方面已经超越了Sphinx。

这样的事情包括:

  • 没有复制
  • 没有自动ID
  • 没有JSON接口
  • 没有办法动态创建/删除索引
  • 没有文档存储
  • 不成熟的实时索引
  • 专注于全文搜索而不是一般搜索

使得Sphinx成为一个非常高度专业化的解决方案,在许多情况下需要手动调整。到那时,许多用户已经迁移到Elasticsearch。这很遗憾,因为Sphinx中的基本数据结构和算法在性能上在许多情况下是潜在的,实际上也优于Elasticsearch。而SQL在Sphinx中的发展远远好于Elasticsearch,即使现在,对许多人来说也很有吸引力。

除了支持现有的Sphinx用户外,Manticore的全球目标是实现上述和其他功能,使Manticore Search在大多数用例中成为Elasticsearch的真正替代品。

我们已经做了什么


更加积极的开发

如果你查看 github提交统计 ,你会发现自从分叉发生(2017年中期)以来,开发速度大幅增长:

img

在2021年3月之前的三年半时间里,我们发布了39个新版本。在2020年,我们每两个月发布一个新版本。

复制

许多用户已经等待Sphinx的复制多年。我们在Manticore中实现的第一个大功能之一就是复制。和Manticore中的所有内容一样,我们尽量使其易于使用。例如,要连接到集群,你只需运行如下命令:

JOIN CLUSTER posts at 'neighbour-server';

这将使集群中的索引出现在当前节点上。

Manticore的复制是:

  • 同步的
  • 基于Galera库,该库也用于MariaDB和Percona XtraDB。

自动ID

没有 自动ID ,Sphinx / Manticore大多被视为另一个数据库(mysql,postgres等)的扩展,因为必须有某种生成ID的东西。我们实现了基于UUID_SHORT算法的自动ID。唯一性保证每秒每台服务器最多可插入1600万条,这在所有情况下都应该足够。

mysql> create table idx(doc text);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into idx(doc) values('abc def');
Query OK, 1 row affected (0.00 sec)

mysql> select * from idx;
+---------------------+---------+
| id                  | doc     |
+---------------------+---------+
| 1514145039905718278 | abc def |
+---------------------+---------+
1 row in set (0.00 sec)

mysql> insert into idx(doc) values('def ghi');
Query OK, 1 row affected (0.00 sec)

mysql> select * from idx;
+---------------------+---------+
| id                  | doc     |
+---------------------+---------+
| 1514145039905718278 | abc def |
| 1514145039905718279 | def ghi |
+---------------------+---------+
2 rows in set (0.00 sec)

文档存储

在Sphinx 2.3.2及更早版本中,你只能将文档的原始文本保存在字符串属性中,这些属性(像所有属性一样)需要存储在内存中以获得最佳性能。许多用户这样做,浪费了不必要的RAM,这很昂贵,并可能在大容量时导致意外的性能问题。在Manticore中,我们 创建了 一种新的数据类型text,它结合了全文索引和将值存储在磁盘上的延迟读取(即在查询的最后阶段提取值)。"存储"字段的值不可过滤,不能排序或分组。它们只是压缩后存储在磁盘上,因此不需要将它们存储在mysql/hbase/postgres和其他数据库中(除非确实需要)。这被证明是一个非常有用且常用的功能。从那时起,Manticore现在只需要自身即可实现搜索应用程序。

实时索引

在Sphinx 2.3.2及更早版本中,许多用户在使用实时索引时遇到困难,因为这常常导致崩溃和其他副作用。我们修复了大多数已知的错误和设计缺陷,并且我们仍在进行一些优化(主要与自动OPTIMIZE和读/写/合并隔离相关)。但可以安全地说,实时索引可以在生产中使用,实际上许多用户确实这样做。提到我们添加的一些功能:

  • 多线程:在单个实时索引的多个磁盘块中进行搜索是并行进行的
  • OPTIMIZE改进:默认情况下,块的合并不是到1,而是到服务器核心数*2(可以通过 cutoff 选项进行调整)。

我们正在进行自动OPTIMIZE的工作,以便用户根本不必担心压缩问题。

charset_table = cjk, non_cjk

之前,如果您想支持除英语或俄语以外的其他语言,您通常需要在 charset_table 中维护大型数组。这很不方便。我们通过将您可能需要的所有内容放入名为 non_cjk(用于大多数语言)和 cjk(用于中文、韩文和日文)的内部 charset_table 数组中来简化这一过程。non_cjk 数组是 charset_table 的默认数组。现在,您可以毫无问题地用英语、俄语和例如土耳其语进行搜索:

mysql> create table idx(doc text);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into idx(doc) values('abc абв öğrenim');
Query OK, 1 row affected (0.00 sec)

mysql> select * from idx where match('abc');
+---------------------+----------------------+
| id                  | doc                  |
+---------------------+----------------------+
| 1514145039905718280 | abc абв öğrenim      |
+---------------------+----------------------+
1 row in set (0.00 sec)

mysql> select * from idx where match('абв');
+---------------------+----------------------+
| id                  | doc                  |
+---------------------+----------------------+
| 1514145039905718280 | abc абв öğrenim      |
+---------------------+----------------------+
1 row in set (0.00 sec)

mysql> select * from idx where match('ogrenim');
+---------------------+----------------------+
| id                  | doc                  |
+---------------------+----------------------+
| 1514145039905718280 | abc абв öğrenim      |
+---------------------+----------------------+
1 row in set (0.00 sec)

官方 Docker 镜像

我们发布并维护了官方的 docker 镜像 用于 Manticore Search。只要有 docker,您现在可以在几秒钟内在任何地方运行 Manticore。

  ~ docker run --name manticore --rm -d manticoresearch/manticore && docker exec -it manticore mysql && docker stop manticore

525aa92aa0bcef3e6f745ddeb11fc95040858d19cde4c9118b47f0f414324a79
mysql> create table idx(f text);
mysql> desc idx;
+-------+--------+----------------+
| Field | Type   | Properties     |
+-------+--------+----------------+
| id    | bigint |                |
| f     | text   | indexed stored |
+-------+--------+----------------+

此外,manticore:dev 标签始终指向 Manticore Search 的最新开发版本。

软件包仓库

所有新版本和最新开发版本可以在 https://repo.manticoresearch.com/ 找到。

从那里您还可以 轻松通过 YUM 和 APT 安装 Manticore 。我们还支持 Homebrew,并为 Windows 维护构建。

NLP:自然语言处理

在 NLP 方面,我们做了以下改进:

  • 使用 ICU 库 的中文分词
  • 大多数语言的默认停用词开箱即用:
mysql> create table idx(doc text) stopwords='en';
Query OK, 0 rows affected (0.05 sec)

mysql> call keywords('to be or not to be that is the question', 'idx');
+------+-----------+------------+
| qpos | tokenized | normalized |
+------+-----------+------------+
| 10   | question  | question   |
+------+-----------+------------+
1 row in set (0.01 sec)
  • 更多语言 的 Snowball 2.0 支持
  • 更简单的语法高亮:
mysql> insert into idx(doc) values('Polly wants a cracker');
Query OK, 1 row affected (0.09 sec)

mysql> select highlight() from idx where match('polly cracker');
+-------------------------------------+
| highlight()                         |
+-------------------------------------+
| <b>Polly</b> wants a <b>cracker</b> |
+-------------------------------------+
1 row in set (0.10 sec)

新的多任务模式

对于多任务,Manticore 现在使用协程。除了代码变得更简单、更可靠外,不再需要为不同的索引使用不同的 dist_threads 值以使搜索能够最佳并行化。现在有一个全局设置 threads,默认等于服务器上的核心数量。在大多数情况下,您根本不需要触碰它以获得最佳性能。

WHERE 中的 OR 支持

在 Sphinx 2/3 中,您无法轻松使用操作符 OR 按属性过滤,这是一大限制。我们在 Manticore 中修复了这个问题:

mysql> select i, s from t where i = 1 or s = 'abc';
+------+------+
| i    | s    |
+------+------+
|    1 | abc  |
|    1 | def  |
|    2 | abc  |
+------+------+
3 rows in set (0.00 sec)

Sphinx 3:
mysql> select * from t where i = 1 or s = 'abc';
ERROR 1064 (42000): sphinxql: syntax error, unexpected OR, expecting $end near 'or s = 'abc''

通过 HTTP 支持 JSON 协议

SQL 很酷。我们喜欢 SQL。在 Sphinx / Manticore 中,关于查询语法的一切都可以通过 SQL 完成。但在某些情况下,最佳解决方案是使用 JSON 接口,就像在 Elasticsearch 中一样。SQL 非常适合查询设计,而 JSON 在您需要将复杂查询集成到应用程序中时表现出色。

此外,HTTP 允许做很多有趣的事情:使用外部 HTTP 负载均衡器和代理,这使得实现身份验证、RBAC 等变得相当简单。

针对更多语言的新客户端

使用特定编程语言的客户端比使用 HTTP 上的 JSON 更简单。我们为 phppythonjavajavascriptelixirgo 实现了新的客户端。它们大多数基于新的 JSON 接口,其代码是自动生成的,使我们能够更快地为客户端添加新功能。

HTTPS 支持

安全性很重要。我们已将 HTTPS 支持 开箱即用。尽管最好不要将 Manticore Search 实例暴露在互联网上,因为没有内置的身份验证,但现在在局域网中从客户端到 Manticore Search 传输查询和结果更安全。mysql 接口的 SSL 也得到了支持。

FEDERATED 支持

除了 SphinxSE(一个内置的 mysql 引擎,允许您将 Sphinx/Manticore 更紧密地与 mysql 集成) 您现在可以使用 MySQL 的 FEDERATED 引擎,该引擎在 MySQL 和 MariaDB 中可用。

ProxySQL 支持

ProxySQL 也得到了支持 ,您可以使用它来做一些相当有趣的事情,扩展 Manticore Search 的功能。

RT 模式

我们所做的主要变化之一是通过 CREATE/ALTER/DROP 表的命令式方式与 Manticore 进行交互。正如您从上面的 SQL 示例中看到的,您不再需要在配置中定义索引。与其他数据库一样,您现在可以在 Manticore 中动态创建、修改和删除索引,而无需编辑配置、重启实例、删除实时索引文件以及所有这些麻烦。数据模式现在与服务器的设置完全分离。这是默认模式。我们称之为 RT 模式

但是声明式模式(我们称之为 Plain 模式)仍然得到支持。我们不认为它是一个遗留物,也不打算摆脱它。就像您可以通过 yaml 文件或特定命令与 Kubernetes 进行双向通信一样,您也可以以类似的方式与 Manticore 进行通信:

  • 您可以在配置中描述一切,并受益于轻松的配置移植和更快的索引部署,
  • 或者您可以动态创建索引,这使得将其更容易集成到您的应用程序中

不可能也不计划混合使用模式。

过筛索引

正常的搜索方式是存储我们想要搜索的文档,并对其执行查询。然而,在某些情况下,我们希望将查询应用于传入的新文档,以发出匹配的信号。有一些场景是需要这样做的。例如,监控系统不仅收集数据,还希望在不同事件上通知用户。这可能是达到某个指标的阈值,或者在监控数据中出现某个特定值。另一个类似的情况是新闻聚合。您可以通知用户任何新鲜的新闻,但用户可能只想被通知某些类别或主题。进一步说,他们可能只对某些“关键词”感兴趣。如果您使用 percolate index,所有这些现在在 Manticore 中都是可能的。

mysql> create table t(f text, j json) type='percolate';
mysql> insert into t(query,filters) values('abc', 'j.a=1');
mysql> call pq('t', '[{"f": "abc def", "j": {"a": 1}}, {"f": "abc ghi"}, {"j": {"a": 1}}]', 1 as query);
+---------------------+-------+------+---------+
| id                  | query | tags | filters |
+---------------------+-------+------+---------+
| 8215503050178035714 | abc   |      | j.a=1   |
+---------------------+-------+------+---------+

工作 比 Elasticsearch 更快

新的用户友好文档 - https://manual.manticoresearch.com

对于关键的 Manticore Search 功能,大多数支持的客户端都有示例。手册中的搜索当然使用 Manticore Search 作为后端。还有其他内容:

  • 智能搜索结果高亮显示在搜索结果中
  • HTTP 示例可以一键直接复制为带参数的 curl 命令
  • 此外,我们特别注册了短域名 mnt.cr,以便您可以通过在浏览器中按 CTRL-T/CMD-T 快速找到您现在需要的信息,例如 mnt.cr/proximity , mnt.cr/quorum , mnt.cr/percolate

互动课程 - https://play.manticoresearch.com

为了让您更容易入门 Manticore Search,我们创建了一个互动课程平台 https://play.manticoresearch.com ,当然还有课程本身,您可以直接在浏览器中进行,无需安装任何东西。在几秒钟内,您可以看到 Manticore Search 复制如何工作 或如何 高亮搜索结果

Github 作为错误跟踪器

我们使用 Github 作为公共错误/任务跟踪器。

Sphinx 3


Sphinx 3.0.1 于 2017 年 12 月发布。直到 2018 年 10 月,还有三个版本发布,2020 年 7 月又发布了一个版本(3.3.1,截止到 2021 年 3 月的最后版本)。出现了许多有趣的功能,包括二级索引和一些机器学习能力。那么问题是什么呢?人们为什么需要 Manticore?原因之一是,不幸的是,Sphinx 3 的第一个版本和最后一个版本目前都不是开源的:

  • 从某种意义上说,Sphinx 3 的代码不可用
  • 更广泛的开源 意义上也是如此。在下载页面上 Sphinx 现在在“延迟 FOSS”许可证下可用。这个许可证到底是什么,在哪里可以找到并没有披露。尚不清楚:
  • 是否仍然是 GPLv2(即“延迟 FOSS”意味着延迟 GPLv2),因为代码可能基于 Sphinx 2,而 Sphinx 2 是 GPLv2(像 Manticore 一样)。但那么源代码在哪里?
  • 或者它不是 GPLv2,因为二进制文件没有附带许可证,并且不知道代码是否基于 Sphinx 2?GPLv2 的限制适用吗?由于没有许可证文本,分发 Sphinx 3 二进制文件是否可以随意?
  • 自 2020 年 7 月以来没有发布新版本。有 很多错误 ,包括重大崩溃。它们何时会被修复?

有很多问题,没有答案。这一切使得使用 Sphinx 3 对于关心法律方面和项目稳定性的公司和个人来说非常冒险。并不是很多公司有可能将员工的时间投入到看起来被冻结且许可证不明确的项目中。

总的来说,Sphinx 3 现在可以被视为一种专有解决方案,适用于具有非常特定目标的有限用户群。很遗憾,开源世界失去了 Sphinx。我们只能希望未来会有所改变。

有基准测试吗?


是的!让我们测试包含 1M+ 条来自 HackerNews 的评论和数值属性的 数据集

关于测试的更多信息:

  • 从数据集中构建的普通索引。索引文件的大小约为 1GB
  • 一组各种查询(132 个请求),从全文搜索到过滤和分组
  • 在具有不同内存限制的裸金属服务器上运行的 Docker
  • 我们使用 PHP 脚本中的 mysqli 客户端通过 SQL 发出查询
  • 在每个新查询之前,我们清除所有缓存,包括操作系统缓存并重启 Docker,然后进行 5 次尝试,最低响应时间进入统计数据。

结果:

100 兆字节限制:

img

500 兆字节限制:

img

1000 兆字节限制:

img

Manticore Search 的未来


因此,我们已经拥有一个在明确的开源许可证 GPLv2 下积极开发的产品,具有复制、自动 ID、正常工作的实时索引、JSON 接口、良好的文档、互动课程等更多功能。接下来是什么?我们的路线图是:

新的 Manticore 引擎

自 2020 年初以来,我们一直在开发一个列式存储和处理库,具有默认索引(与 Clickhouse 相对)。对于 Manticore 和 Sphinx 用户,它将解决以下问题:

  • 在大量文档和属性中快速搜索所需的大量 RAM
  • 次优的分组性能
  • 当部分属性不适合 RAM 时的次优过滤性能

我们已经准备好了一个 测试版 ,以下是一些初步结果,比较了 Manticore Columnar Library + Manticore Search 与 Elasticsearch 在相同数据集上的表现(不包括全文查询,即主要是分组查询):

img

仍然有很多工作要做。该库在更宽松的开源许可证 Apache 2.0 下可用,可以在 Manticore Search 以及其他项目中使用(如果他们愿意,也可以在 Sphinx 中使用)。

自动优化

我们意识到手动调用 OPTIMIZE 进行实时索引压缩是多么不方便。我们正在努力解决这个问题,并希望它能包含在下一个版本中。请在 twitter 上关注我们,以免错过。

与 Kibana 的集成

由于用户现在可以使用新的 Manticore 引擎进行更多分析,因此能够轻松可视化这些数据也很不错。Grafana 很酷,但在进行全文搜索时可能有点棘手。Kibana 也很好,很多人都知道并使用它。我们有一个 Manticore Search 和 Kibana 之间集成的 alpha 版本。它尚未公开,但一旦我们完成了错误修复并可以将其视为 beta 版本,它将开源。

Logstash 集成

Manticore Search 已经具有 JSON 协议。我们将改进 PUT 和 POST 方法,使其与 Elasticsearch 的 INSERT/REPLACE 查询兼容。此外,我们计划使其能够根据首次插入的文档动态创建索引。所有这些将允许您从 Logstash、Fluentd、Beats 等将数据写入 Manticore Search,而不是 Elasticsearch。

自动分片

这是另一个正在进行的项目。我们已经了解了将要面临的困难,以及或多或少的解决方案。我们计划在第二季度进行。

Logstash 的替代方案

Logstash 要求用户花费大量时间来开始从新的 自定义 日志类型中摄取数据。如果您添加任何新行,解析规则将必须更新。在过去的几个月里,我们一直在开发一个几乎可以完全解决这个问题的系统。它将允许您几乎无需帮助地解析日志,并提供一个友好的用户界面来命名字段并进行最终微调。

如果您喜欢我们所做的,请关注我们:

安装Manticore Search

安装Manticore Search