⚠️ 此页面为自动翻译,翻译可能不完美。
blog-post

Meilisearch 对比 Manticore:把事实说清楚

author image

几天前,Meilisearch 发布了一篇对比 Meilisearch 和 Manticore Search 的文章 。我们喜欢对比,早在 2023 年我们就发布过自己的对比 ,而且附带了你可以复现的基准测试。公平地说,Meilisearch 那篇对比的部分内容是准确的,甚至对 Manticore 还算宽厚。

但关于 Manticore 的几项说法已经过时,或者根本不是你在当前版本里运行时会观察到的情况。所以我们没有争论,而是照常做了我们一直会做的事:启动两个引擎的最新版本(Manticore Search 28.4.4 和 Meilisearch 1.41/1.48)并测试这些说法。下面的每条命令和返回结果都是真实的,欢迎直接复制粘贴验证我们。

“全文搜索和实时分析”——这可能只占了 1%

文章这样介绍 Manticore:

Manticore Search is an open-source search engine built as a continuation of Sphinx, improving its functionality with full-text search and real-time analytics.

Sphinx 本来就是 全文搜索,而实时分析只是后来新增内容中的一小部分。下面是这些年“改进其功能”到底体现在哪里:

“Sphinx 加实时分析”远远低估了它。

“配置复杂”和“高级定制”吗?我们来数命令

文章对 Manticore 的结论:

最适合:需要高级定制、熟悉 SQL、并且要在大规模场景下进行高性能查询的大型项目和团队。

而缺点之一是:“配置复杂:初始配置和调优可能很耗时。”

下面是 Manticore 从零到可搜索的全部“复杂配置”:只要三个命令,没有配置文件,没有 schema:

1. 安装(并启动 - 一行安装器 也会顺带启动服务):

curl https://manticoresearch.com | sh

2. 插入文档。注意此时还没有表——自动建模 会根据数据创建它:

curl -s 0:9308/insert -d '{
  "table": "products",
  "doc": {"title": "yellow travel backpack", "price": 4990, "color": "yellow"}
}' | jq
{
  "table": "products",
  "id": 8938969113712132097,
  "created": true,
  "result": "created",
  "status": 201
}

3. 搜索——全文匹配加上一个数值字段过滤,立即生效:

curl -s 0:9308/search -d '{
  "table": "products",
  "query": {"bool": {"must": [
    {"match": {"*": "backpack"}},
    {"range": {"price": {"lt": 6000}}}
  ]}}
}' | jq
{
  "took": 0,
  "timed_out": false,
  "hits": {
    "total": 1,
    "total_relation": "eq",
    "hits": [
      {
        "_id": 8938969113712132097,
        "_score": 1356,
        "_source": {
          "title": "yellow travel backpack",
          "color": "yellow",
          "price": 4990
        }
      }
    ]
  }
}

数据一落入表中就立刻可查询:文本字段可全文搜索,而且支持按字段搜索,例如 {"match": {"color": "yellow"}}price 这类属性字段则可过滤、排序、分组和分面,无需声明,也无需重新索引。下面是 Manticore 自动推断出的 schema:

+-------+--------+----------------+
| Field | Type   | Properties     |
+-------+--------+----------------+
| id    | bigint |                |
| title | text   | indexed stored |
| color | text   | indexed stored |
| price | uint   |                |
+-------+--------+----------------+

现在看 Meilisearch 做同样的事(我们测试了 latest Docker 标签、v1.41.0,以及最新发布版 v1.48.3)。Meilisearch 的安装器会把二进制下载到当前目录,然后你需要自己运行它,而且在生产模式下启动前还要先配置 master key。添加文档和搜索和 Manticore 一样简单,这点该给它肯定。但接着你再尝试过滤:

curl -s -X POST localhost:7700/indexes/products/search -H "Content-Type: application/json" \
  -d '{"q": "backpack", "filter": "price < 6000"}' | jq
{
  "message": "Index `products`: Attribute `price` is not filterable. This index does not have configured filterable attributes.",
  "code": "invalid_search_filter",
  "type": "invalid_request"
}

既然我们这篇文章本来就要重新核查所有内容,下面就准确列出在 Meilisearch 中开箱即用能做和不能做的事,每一点都已经用文档和一个在线实例验证过:

  • 搜索可立即使用。 默认 searchableAttributes["*"]——每个文档的每个字段都可搜索,无需声明。
  • 过滤不行。 字段必须先在 filterableAttributes 中声明。Meilisearch 的文档 对成本说得很直白:“这一步是强制性的,不能在搜索时完成。……更新 filterableAttributes 需要 Meilisearch 重新索引所有数据,所需时间与数据集规模和复杂度成正比。”
  • 分面也不行。 分面基于同一份 filterableAttributes 列表,因此同样要经历声明和重新索引。在 Manticore 中,分面搜索完全不需要手动构建过滤条件
  • 排序也不行。 根据 Meilisearch 的文档“要让用户在搜索时对结果排序,你必须……把这些属性加入 sortableAttributes 索引设置。”
  • 调整搜索字段也会触发重新索引。 searchableAttributes 的顺序决定相关性,因此限制或重新排序是大多数真实项目都会做的一步,而 “更新 searchableAttributes 会触发索引中所有文档的重新索引。”

这都不是 bug,而是设计取舍,而且每一步都只是一个小小的 API 调用。但它会累积成一种模型:你要按属性逐个声明能力,并且每次改变主意都要为整个数据集支付一次全量重新索引的代价。Manticore 的模型不同:字段有类型——文本字段可全文搜索,属性(数字、字符串、JSON)可过滤、排序、分组和分面,向量可进行 KNN 搜索——而且某种类型的所有能力在插入时就已经可用。这里没有需要维护的逐属性能力注册表,也不需要通过重新索引来改变查询方式。深度定制——排序公式、分词、形态学、字段权重——当然也有(文章的优点列表在这一点上是对的),但它是可选项,不是前提。所以我们不确定“需要高级定制”指向的是不是正确的引擎。

“熟悉 SQL”——可选,不是必需

文章把 Manticore 描述成“适合熟悉 SQL 的团队”的选择。SQL 支持确实是 Manticore 的一个显著优势——你可以用任何 MySQL 客户端、mysqldump,或者 BI 工具来连接它(对比文章自己的集成表把这一点在 Meilisearch 中标成了“Not supported”)。

但注意你刚才在上面看到的内容:整个快速开始演示用的是通过 HTTP 传输的 JSON。实际上,Manticore 几乎所有功能都能通过两种方式使用——喜欢的话可以用 SQL,不喜欢的话可以用一个和 Meilisearch、Elasticsearch 用户非常熟悉的 JSON API。你完全不需要写一行 SQL 就能使用 Manticore。

向量搜索:Meilisearch 自己的表格已经说明了一切

这是我们最喜欢的部分。Meilisearch 文章里的用例表对两个引擎的向量搜索评价如下:

向量搜索。 Meilisearch:基础向量搜索。Manticore Search:更适合混合和高级场景。

我们同意这两列的结论。下面看看在 自动嵌入 下,“混合和高级场景”在实践中是什么样子——不需要外部 embedding 流水线,不需要 API key,模型会自动下载:

CREATE TABLE products_ai (
  title TEXT,
  description TEXT,
  price INT,
  vector FLOAT_VECTOR KNN_TYPE='hnsw' HNSW_SIMILARITY='l2'
    MODEL_NAME='sentence-transformers/all-MiniLM-L6-v2'
    FROM='title,description'
);

直接把文档作为普通 JSON 插入——嵌入向量会自动为你生成(也有一个用于批量处理的 /bulk 端点):

curl -s 0:9308/insert -d '{
  "table": "products_ai",
  "id": 1,
  "doc": {
    "title": "green hiking backpack",
    "description": "Lightweight backpack suitable for hiking trails",
    "price": 5999
  }
}'

curl -s 0:9308/insert -d '{
  "table": "products_ai",
  "id": 3,
  "doc": {
    "title": "trail running shoes",
    "description": "Lightweight shoes with great grip for trails",
    "price": 7500
  }
}'

然后只需一次请求就能运行 混合搜索 ——全文搜索和语义搜索通过 RRF 融合:

curl -s 0:9308/search -d '{
  "table": "products_ai",
  "hybrid": {"query": "gear for a mountain hike"},
  "_source": ["title", "price"],
  "size": 2
}' | jq
{
  "hits": {
    "hits": [
      {
        "_id": 1,
        "_knn_dist": 0.88308269,
        "_hybrid_score": 0.01639344,
        "_source": {
          "title": "green hiking backpack",
          "price": 5999
        }
      },
      {
        "_id": 3,
        "_knn_dist": 1.09160841,
        "_hybrid_score": 0.01612903,
        "_source": {
          "title": "trail running shoes",
          "price": 7500
        }
      }
    ]
  }
}

没有任何文档提到“gear”或“mountain”这个词——这就是开箱即用的语义理解,总共只要两次请求。底层还有 向量量化 用于降低内存占用,KNN 预过滤 让过滤条件在 HNSW 遍历内部生效,以及 持续的 KNN 性能优化 。“更适合混合和高级场景”——是的,这个我们认同。

而且你不必只听我们说,这些在线演示都运行在 Manticore 上:带过滤、分面、容错拼写和语义搜索的目录搜索反向图片搜索 ;以及对话式搜索

相关性:靠测量,不靠争论

搜索质量的说法可以通过实证来检验。我们在 14 组公开 IR 数据集/语料规模上,对 Manticore Search 和 Meilisearch 的全文、向量和混合模式做了基准测试:7 个 BEIR 数据集、ACORD、分别包含 250K 和 8.8M 文档的 MS MARCO Passage、TREC DL 2019/2020、Wayfair 的 WANDS 商品搜索数据集,以及专注拼写错误的 DL-Typo。对于每个引擎/模式组合,我们取每组中表现最好的完整运行结果,并在各组之间计算未加权平均。第一行则是在平均之前先为每组选出各引擎的最佳模式。向量和混合运行在两个引擎上都使用同一个 Qwen3-Embedding-8B 模型。质量评分采用每个数据集的标准指标:NDCG@10,或 MS MARCO 使用的 MRR@10。

模式ManticoreMeilisearch
每个数据集的最佳模式(平均)0.5430.527
向量0.5300.527
混合0.5150.475
全文0.4200.237

按每组各自最好的结果来比,Manticore 在 14 组里有 11 组领先。向量质量几乎持平,分别是 0.530 和 0.527;两个引擎使用同一个嵌入模型,但索引和检索实现仍然不同。混合结果差距更大,Manticore 的 RRF 平均值为 0.515,对比 0.475。

全文搜索的差距最大:0.420 对 0.237。更广泛的基准测试可以解释这一点。使用 BM25 或 BM25 家族排序器的引擎在全文相关性上普遍明显优于 Meilisearch。Meilisearch 采用的是一组按顺序执行的规则 ,依据词匹配、拼写错误、距离、属性和精确度来排序。因此它缺少 BM25 的逆文档频率、词频饱和和文档长度归一化的组合,这也是它在这些标准 IR 数据集上表现较差的主要原因。Typesense 也是更大范围对比中的另一款不使用 BM25 的引擎,表现模式也类似。Meilisearch 的十词查询限制在更长查询中还会进一步拖累结果,因为多出来的词会被忽略。

Manticore 在专注于拼写容错的 DL-Typo 上也领先。

同一套框架还测试了 Elasticsearch、OpenSearch、Qdrant、Typesense、Vespa 和 Weaviate。由于基准服务器可用资源有限,一些引擎没能完成最大规模的测试,所以报告提供了两个按覆盖率控制的排行榜。按所有 8 个引擎都覆盖到的 10 组子集重新计算后,Manticore 的最佳模式平均值排在第二,总体落后于 Qdrant。按全部 14 组计算,在完成全部覆盖的 5 个引擎中它也排第二。Meilisearch 在这两种比较中都记录了更低的平均值。

完整对比 已经包含覆盖率、按数据集拆分的表格,以及每次运行的精确配置。不过这项工作仍在进行中。我们很快会发布完整的方法论和其余细节。我们也会把新的基准测试工具开源,让这类基准测试更容易运行和扩展。

“主要用于复杂的大规模工作负载”——数据并非如此

文章声称:

Manticore 主要用于需要高性能和深度定制的复杂、大规模搜索和分析工作负载。

而在用例表中,Manticore “对于简单 CMS 需求可能有些过度”。

我们查看了匿名遥测 。在报告数据大小指标的 Manticore 实例中:

  • 29% 的数据量小于 1 MB
  • 大约 一半 的数据量小于 100 MB
  • 只有大约 八分之一 超过 10 GB,而少于 1% 超过 1 TB

所以,不,Manticore 并不主要用于大规模工作负载。现实中的大多数 Manticore 部署都是小型项目:网站、目录、博客、内部工具。正好就是表格里提醒你要注意的那类“简单 CMS 需求”。一个 Manticore 容器待机时内存占用不到 200 MB,而且正如你上面看到的,做出一个可用搜索只要三个命令——很难说这对任何场景都是过度配置。

好的一面是,同一个引擎在另一端同样撑得住:从 Elasticsearch 迁移后,在 Manticore 上本地每秒可处理数万次查询 。向下扩展和向上扩展并不互斥。

实时分析:这一点我们也直说

有意思的是,同一张表给了 Manticore 一个我们自己都愿意稍微保守点说的评价:“专为实时数据和分析而设计。”Manticore 确实具备很强的分析能力——列式存储 、聚合、KibanaGrafana 集成、日志管道集成 ——而且它非常适合日志搜索 。但它首先是一款搜索引擎。分析只是它的一个用例,而不是它“主要设计用途”,也不是大多数用户实际使用它的原因。

Meilisearch 文章说得有道理的地方

我们承诺要讲事实,而事实是双向的:

  • 默认就有拼写容错。 这是真的:Meilisearch 默认开启了拼写容错。在 Manticore 中,模糊搜索 是可选开启的——在表定义中设置 min_infix_len='2',并在查询时设置 fuzzy=1。这两个设置都很小,但 Meilisearch 的默认体验更友好。
  • 直接从前端查询。 Meilisearch 的 search API key 让无需后端的搜索成为一级模式。Manticore 传统上是放在后端后面使用的;认证在 27.1.5 中加入 ,所以这方面的差距正在缩小,但就今天而言,这一分还是给 Meilisearch。
  • 文档空缺。 每个项目都有,包括我们自己,也包括 Meilisearch。我们只会反驳“学习曲线陡峭”这点:如果你会一点 SQL 或者 会一点 JSON,就已经足够上手了,而且还有免费的交互式课程 带你从第一张表一路学到向量搜索。

客户端库:把表补完整

既然这篇文章是对Meilisearch 对比文章 的回应,那我们也顺手把它的集成表修正一下。原表把 Go 列了两次,而且给出了相互矛盾的答案(“supported via community”和“not supported”),还把多个官方/社区状态写错了——两边都有,方向也都有问题——并且漏掉了两个语言。下面这版是根据Meilisearch 自己的 SDK 文档Manticore 的 GitHub 组织 核对后的结果:

集成MeilisearchManticore Search
JavaScript (Node.js)官方客户端(基于 TypeScript)官方 JavaScript 客户端
TypeScript †同一个官方 TypeScript 客户端官方 TypeScript 客户端
Python官方客户端(同步 + 异步)官方 syncasyncio 客户端 ✱
PHP官方客户端官方 PHP 客户端
Java官方客户端官方 Java 客户端
Go官方客户端 ✱官方 Go 客户端
Rust社区维护的客户端 ✱官方 Rust 客户端
Elixir †Meilisearch 的 SDK 文档中未列出官方 Elixir 客户端
Dart/Flutter官方客户端无官方客户端(HTTP JSON API)
.NET/C#官方客户端 ✱官方 .NET 客户端
REST API核心接口完整的 HTTP/JSON API
SQL不支持原生 SQL(MySQL 协议)

† — 原表中缺失的语言 • ✱ — 相较原表已纠正状态(对于 Meilisearch 一列,以其当前 SDK 文档为准)

把上面十种语言合在一起看:Manticore 提供 9 种官方客户端——只有 Dart/Flutter 例外。Meilisearch 提供 8 种官方客户端——只有 Rust(社区维护)和 Elixir(未列出)例外。两者都完整支持 REST,而 Manticore 还额外通过 MySQL 协议支持 SQL。所以“广泛的客户端范围”——原文对 Manticore 集成的这句评价——是准确的;只是细节需要更新了。

结论

Meilisearch 是一款不错的搜索引擎,而这篇文章有一点说得没错:它在即时搜索、以前端为中心的使用场景上打磨得很好。不过如果你是在做长期选择,也要把 Meilisearch 自己文章里列出的缺点一并考虑进去——比如一个搜索查询“必须不超过十个词,更多的会被忽略”。这类限制在第六个月往往比第一天更重要。

但更大的问题在于,文章里描述的那个 Manticore——一个面向大规模分析团队的、复杂的、只能靠 SQL 的系统——并不是 2026 年真实存在的 Manticore,而且其中大部分你在大约五分钟的终端时间里就能证伪:

curl https://manticoresearch.com | sh

然后插入一个 JSON 文档并搜索它(关于一行安装器的更多内容见这里 )。没有 schema,没有配置,没有“高级定制”。如果你更想看数字而不是文字,上面的相关性结果、我们的基于基准测试的对比 以及 db-benchmarks.com 都是不错的起点;如果我们这里对 Meilisearch 有任何说错的地方,我们也很乐意更正。我们也希望别人这样对待我们。

有问题或不同意见?欢迎到论坛Slack 里告诉我们。

安装Manticore Search

在 Linux 或 macOS 上用一条命令安装 Manticore Search:

curl https://manticoresearch.com | sh

有关高级安装选项,请参阅完整安装指南手册

安装Manticore Search