从向量搜索到强大的 REST API,Elasticsearch 为开发人员提供了最全面的搜索工具包。探索 GitHub 上的示例笔记本,尝试新事物。您也可以立即开始免费试用或在本地运行 Elasticsearch。
二进制量化矢量搜索使用 BBQ 的 Elasticsearch 比使用 FAISS 的 OpenSearch 快 5 倍。Elastic 收到了来自社区的请求,希望澄清 Elasticsearch 和 OpenSearch 之间的性能差异,尤其是在语义搜索/矢量搜索领域,因此我们进行了这些性能测试,以提供清晰的、数据驱动的比较。

二进制量化对决
以原始形式存储高维向量会耗费大量内存。量化技术可将这些矢量压缩为紧凑的表示形式,从而大大减少内存占用。然后,搜索在压缩空间内进行,从而降低了计算复杂度,加快了搜索速度,尤其是在大型数据集中。
Elastic 致力于使 Lucene 成为性能一流的矢量引擎。在 Elasticsearch 8.16 中,我们在 Lucene 的基础上引入了更好的二进制量化(BBQ),并在 8.18 和 9.0 中进一步发展。BBQ 基于一种新的标量量化方法,将 float32 维度减少到比特,在保持高排名质量的同时,减少了 ~95% 内存。
另一方面,OpenSearch 使用多种矢量引擎:nmslib(现已废弃)、Lucene 和 FAISS。在 上 一篇 博客 中,我们比较了 Elasticsearch 和 OpenSearch 的向量搜索。我们使用了三个不同的数据集,并在两种产品上测试了不同的引擎和配置组合。
本博客重点介绍这两种产品目前提供的二进制量化算法。我们使用 BBQ 对 Elasticsearch 进行了测试,并使用FAISS 的二进制量化(openai_vectorRally track)对 OpenSearch 进行了测试。
主要目的是评估两种解决方案在相同召回率下的性能。召回是什么意思?召回率是衡量搜索系统成功检索到多少相关结果的指标。
在这项评估中,recall@k 尤为重要,其中k代表所考虑的顶级结果的数量。因此,Recall@10、Recall@50 和 Recall@100分别用来衡量有多少真正相关的结果出现在检索结果的前 10、50 和 100 项中。召回率以 0 到 1 的范围表示(或 0% 到 100% 精确度)。这一点很重要,因为我们讨论的是近似 KNN (ANN),而不是精确 KNN,后者的召回率总是 1 (100%).
对于每个k值,我们还指定了n, 即在应用最终排名之前考虑的候选者数量。这意味着,对于 Recall@10、Recall@50 和 Recall@100,系统首先使用二进制量化算法检索n 个候选项,然后对它们进行排序,以确定前k 个结果是否包含预期的相关项。
通过控制n,我们可以分析效率和精度之间的权衡。较高的n通常会增加召回率,因为有更多候选者可供排序,但同时也会增加延迟和 降低 吞吐量。相反,n越小,检索速度越快,但如果初始集合中包含的相关候选信息太少,则可能会降低召回率。
在这次比较中,Elasticsearch 在相同的设置下比 OpenSearch 的延迟更低,吞吐量更高。
方法
完整的配置,以及 Terraform 脚本、Kubernetes 清单和特定的 Rally 轨道,都可在此仓库 openai_vector_bq 下找到。
与之前的基准测试一样,我们使用的 Kubernetes 集群由以下部分组成:
- 1 个用于 Elasticsearch 9.0 的节点池,包含 3 台
e2-standard-32机器(128GB 内存和 32 个 CPU) - 1 个用于 OpenSearch 2.19 的节点池,包含 3 台
e2-standard-32机器(128GB 内存和 32 个 CPU) - 1 个用于 Rally 的节点池,包含 2 台
e2-standard-4机器(16GB 内存和 4 个 CPU)

我们建立了一个版本为 9.0 的 Elasticsearch 集群和一个版本为 2.19 的 OpenSearch 集群。
Elasticsearch 和 OpenSearch 都使用了完全相同的设置进行测试:我们使用了经过 一些修改的 openai_vector Rally track,它使用了来自 NQ 数据集 的 250 万份文档,并使用 OpenAI 的 text-embedding-ada-002 模型 生成了丰富的嵌入。
结果报告了在不同召回级别(召回率@10、召回率@50 和召回率@100)下,使用 8 个客户端同时执行搜索操作所测出的延迟和吞吐量。我们只使用一个分片,没有副本。
我们运行了以下 k-n-rescore 组合,例如10-2000-2000,或k:10、n:2000和rescore:2000将检索 n 个候选者(2000)中的前 k(10),并对 2000 个结果进行重新评分(相当于 "超抽样因子 "1)。每次搜索运行 10.000 次,预热 1000 次:
召回@10
- 10-40-40
- 10-50-50
- 10-100-100
- 10-200-200
- 10-500-500
- 10-750-750
- 10-1000-1000
- 10-1500-1500
- 10-2000-2000
回忆@50
- 50-150-150
- 50-200-200
- 50-250-250
- 50-500-500
- 50-750-750
- 50-1000-1000
- 50-1200-1200
- 50-1500-1500
- 50-2000-2000
Recall@100
- 100-200-200
- 100-250-250
- 100-300-300
- 100-500-500
- 100-750-750
- 100-1000-1000
- 100-1200-1200
- 100-1500-1500
- 100-2000-2000
为了复制基准,Rally-elasticsearch 和 rally-opensearch 的 Kubernetes 清单都将所有相关变量外部化到了 ConfigMap 中,可在此处(ES)和此处(OS)查看。可以自定义search_ops参数,以测试 k、n 和 rescore 的任意组合。
OpenSearch Rally 配置
/k8s/rally-openai_vector-os-bq.yml
Opensearch 索引配置
然后,ConfigMap 中的变量将用于索引配置,某些参数则保持不变。OpenSearch 中的 1 位量化是通过 将压缩级别设置为 "32x " 来配置的 。
index-vectors-only-mapping-with-docid-mapping.json
Elasticsearch Rally 配置
/k8s/rally-openai_vector-es-bq.yml
Elasticsearch 索引配置
index-vectors-only-mapping-with-docid-mapping.json
实施结果
对结果有多种解释方法。对于延迟和吞吐量,我们绘制了每个召回级别的简化图和详细图。如果我们考虑到每项指标 "越高越好",就很容易发现其中的差异。不过,延迟是负值(实际上越低越好),而吞吐量是正值。在简化图表中,我们使用(召回率/延迟)*10000 (简称 "速度")和 召回率*吞吐量,因此这两个指标都意味着速度越快和吞吐量越大越好。让我们开始吧。
召回 @ 10 - 简化
在这种召回水平下,Elasticsearch BBQ 比 OpenSearch FAISS快 5 倍 (平均快 3.9 倍),吞吐量平均高出 3.2 倍。


召回 @ 10 - 详细


| 工作 | latency.mean | 吞吐量平均值 | 平均调用次数 | |
|---|---|---|---|---|
| Elasticsearch-9.0-BBQ | 10-100-100 | 11.70 | 513.58 | 0.89 |
| Elasticsearch-9.0-BBQ | 10-1000-100 | 27.33 | 250.55 | 0.95 |
| Elasticsearch-9.0-BBQ | 10-1500-1500 | 35.93 | 197.26 | 0.95 |
| Elasticsearch-9.0-BBQ | 10-200-200 | 13.33 | 456.16 | 0.92 |
| Elasticsearch-9.0-BBQ | 10-2000-2000 | 44.27 | 161.40 | 0.95 |
| Elasticsearch-9.0-BBQ | 10-40-40 | 10.97 | 539.94 | 0.84 |
| Elasticsearch-9.0-BBQ | 10-50-50 | 11.00 | 535.73 | 0.85 |
| Elasticsearch-9.0-BBQ | 10-500-500 | 19.52 | 341.45 | 0.93 |
| Elasticsearch-9.0-BBQ | 10-750-750 | 22.94 | 295.19 | 0.94 |
| OpenSearch-2.19-faiss | 10-100-100 | 35.59 | 200.61 | 0.94 |
| OpenSearch-2.19-faiss | 10-1000-1000 | 156.81 | 58.30 | 0.96 |
| OpenSearch-2.19-faiss | 10-1500-1500 | 181.79 | 42.97 | 0.96 |
| OpenSearch-2.19-faiss | 10-200-200 | 47.91 | 155.16 | 0.95 |
| OpenSearch-2.19-faiss | 10-2000-2000 | 232.14 | 31.84 | 0.96 |
| OpenSearch-2.19-faiss | 10-40-40 | 27.55 | 249.25 | 0.92 |
| OpenSearch-2.19-faiss | 10-50-50 | 28.78 | 245.14 | 0.92 |
| OpenSearch-2.19-faiss | 10-500-500 | 79.44 | 97.06 | 0.96 |
| OpenSearch-2.19-faiss | 10-750-750 | 104.19 | 75.49 | 0.96 |
召回 @ 50 - 简化
在这种召回水平下,Elasticsearch BBQ 比 OpenSearch FAISS 快多达 5 倍 (平均快 4.2 倍),平均 吞吐量多 3.9 倍 。


详细结果 - 召回率 @ 50


| 任务 | 平均时延 | 吞吐量平均值 | 平均召回率 | |
|---|---|---|---|---|
| Elasticsearch-9.0-BBQ | 50-1000-1000 | 25.71 | 246.44 | 0.95 |
| Elasticsearch-9.0-BBQ | 50-1200-1200 | 28.81 | 227.85 | 0.95 |
| Elasticsearch-9.0-BBQ | 50-150-150 | 13.43 | 362.90 | 0.90 |
| Elasticsearch-9.0-BBQ | 50-1500-1500 | 33.38 | 202.37 | 0.95 |
| Elasticsearch-9.0-BBQ | 50-200-200 | 12.99 | 406.30 | 0.91 |
| Elasticsearch-9.0-BBQ | 50-2000-2000 | 42.63 | 163.68 | 0.95 |
| Elasticsearch-9.0-BBQ | 50-250-250 | 14.41 | 373.21 | 0.92 |
| Elasticsearch-9.0-BBQ | 50-500-500 | 17.15 | 341.04 | 0.93 |
| Elasticsearch-9.0-BBQ | 50-750-750 | 31.25 | 248.60 | 0.94 |
| OpenSearch-2.19-faiss | 50-1000-1000 | 125.35 | 62.53 | 0.96 |
| OpenSearch-2.19-faiss | 50-1200-1200 | 143.87 | 54.75 | 0.96 |
| OpenSearch-2.19-faiss | 50-150-150 | 43.64 | 130.01 | 0.89 |
| OpenSearch-2.19-faiss | 50-1500-1500 | 169.45 | 46.35 | 0.96 |
| OpenSearch-2.19-faiss | 50-200-200 | 48.05 | 156.07 | 0.91 |
| OpenSearch-2.19-faiss | 50-2000-2000 | 216.73 | 36.38 | 0.96 |
| OpenSearch-2.19-faiss | 50-250-250 | 53.52 | 142.44 | 0.93 |
| OpenSearch-2.19-faiss | 50-500-500 | 78.98 | 97.82 | 0.95 |
| OpenSearch-2.19-faiss | 50-750-750 | 103.20 | 75.86 | 0.96 |
召回 @ 100
在这种召回水平下,Elasticsearch BBQ 比 OpenSearch FAISS快 5 倍 (平均快 4.6 倍),吞吐量 平均高 3.9 倍。


详细结果 - Recall @ 100


| 工作 | latency.mean | 吞吐量平均值 | 平均调用次数 | |
|---|---|---|---|---|
| Elasticsearch-9.0-BBQ | 100-1000-1000 | 27.82 | 243.22 | 0.95 |
| Elasticsearch-9.0-BBQ | 100-1200-1200 | 31.14 | 224.04 | 0.95 |
| Elasticsearch-9.0-BBQ | 100-1500-1500 | 35.98 | 193.99 | 0.95 |
| Elasticsearch-9.0-BBQ | 100-200-200 | 14.18 | 403.86 | 0.88 |
| Elasticsearch-9.0-BBQ | 100-2000-2000 | 45.36 | 159.88 | 0.95 |
| Elasticsearch-9.0-BBQ | 100-250-250 | 14.77 | 433.06 | 0.90 |
| Elasticsearch-9.0-BBQ | 100-300-300 | 14.61 | 375.54 | 0.91 |
| Elasticsearch-9.0-BBQ | 100-500-500 | 18.88 | 340.37 | 0.93 |
| Elasticsearch-9.0-BBQ | 100-750-750 | 23.59 | 285.79 | 0.94 |
| OpenSearch-2.19-faiss | 100-1000-1000 | 142.90 | 58.48 | 0.95 |
| OpenSearch-2.19-faiss | 100-1200-1200 | 153.03 | 51.04 | 0.95 |
| OpenSearch-2.19-faiss | 100-1500-1500 | 181.79 | 43.20 | 0.96 |
| OpenSearch-2.19-faiss | 100-200-200 | 50.94 | 131.62 | 0.83 |
| OpenSearch-2.19-faiss | 100-2000-2000 | 232.53 | 33.67 | 0.96 |
| OpenSearch-2.19-faiss | 100-250-250 | 57.08 | 131.23 | 0.87 |
| OpenSearch-2.19-faiss | 100-300-300 | 62.76 | 120.10 | 0.89 |
| OpenSearch-2.19-faiss | 100-500-500 | 84.36 | 91.54 | 0.93 |
| OpenSearch-2.19-faiss | 100-750-750 | 111.33 | 69.95 | 0.94 |
烧烤炉的改进
自首次发布以来,BBQ 已经取得了长足的进步。在 Elasticsearch 8.16 上,为了便于比较,我们将 8.16 的基准运行与当前的基准运行放在一起,我们可以看到召回率和延迟从那时起有了怎样的改善。

在 Elasticsearch 8.18 和 9.0 中,我们重写了量化向量的核心算法。因此,8.16 版的 BBQ 已经很不错了,而最新版本则更加出色。您可以在这里和这里了解相关信息。简而言之,每个矢量都通过优化的标量量化进行了单独量化。因此,用户可以在不影响性能的情况下获得更高的向量搜索准确性,使 Elasticsearch 的向量检索功能更加强大。
结论
在 Elasticsearch BBQ 和 OpenSearch FAISS 的性能比较中,Elasticsearch 在矢量搜索方面明显优于 OpenSearch,在各种召回级别中,Elasticsearch 的查询速度平均提高了 5 倍,吞吐量提高了 3.9 倍。
主要发现包括
- Recall@10:与 OpenSearch FAISS 相比,Elasticsearch BBQ 的速度快达 5 倍(平均快 3.9 倍),吞吐量平均高出 3.2 倍。
- Recall@50:与 OpenSearch FAISS 相比,Elasticsearch BBQ 的速度快达 5 倍(平均快 4.2 倍),吞吐量平均高出 3.9 倍。
- Recall@100:与 OpenSearch FAISS 相比,Elasticsearch BBQ 的速度快达 5 倍(平均快 4.6 倍),吞吐量平均高出 3.9 倍。
这些结果凸显了 Elasticsearch BBQ 的效率和性能优势,尤其是在高维向量搜索场景中。Elasticsearch 8.16 中引入的更好的二进制量化(BBQ)技术在保持较高排序质量的同时,大幅减少了内存(~95% ),是大规模矢量搜索应用的上佳选择。
在 Elastic,我们坚持不懈地创新,改进 Apache Lucene 和 Elasticsearch,为搜索和检索用例(包括 RAG(检索增强生成))提供最佳的向量数据库。在 Lucene 10 的基础上,我们最近取得的进步大大提高了性能,使矢量搜索比以前更快、更节省空间。本博客就是这种创新的又一例证。




