最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Elasticsearch BBQ与OpenSearch FAISS:向量搜索性能对比

网站源码admin1浏览0评论

Elasticsearch BBQ与OpenSearch FAISS:向量搜索性能对比

基于二进制量化的向量搜索:Elasticsearch使用BBQ技术比OpenSearch搭配FAISS快5倍。我们收到社区要求,希望能解释Elasticsearch与OpenSearch在语义搜索/向量搜索方面的性能差异。因此,我们进行了一系列性能测试,以提供清晰、数据驱动的比较。

二进制量化对决

存储高维向量的原始形式可能会占用大量内存。量化技术能够将这些向量压缩成紧凑的表示形式,显著减少内存占用。搜索过程在压缩空间中进行,这减少了计算复杂度,尤其是在处理大型数据集时,提高了搜索速度。

Elastic致力于使Lucene成为顶级的向量引擎。我们在Elasticsearch 8.16中引入了Better Binary Quantization(BBQ),并在8.18和9.0版本中进一步优化。BBQ基于一种新的标量量化方法,将float32维度缩减至比特,提供约95%的内存减少,同时保持高质量的排名。

另一方面,OpenSearch使用多个向量引擎:nmslib(现已弃用)、Lucene和FAISS。在之前的博客中,我们比较了Elasticsearch与OpenSearch的向量搜索性能。我们使用三个不同的数据集,在两种产品上测试了不同引擎和配置的组合。

本文主要关注两种产品中现有的二进制量化算法。我们使用openai_vector Rally track测试了Elasticsearch搭配BBQ与OpenSearch搭配FAISS的二进制量化。

主要目标是评估两种解决方案在相同召回水平下的性能。什么是召回?召回是衡量搜索系统成功检索到相关结果的比例的一项指标。

在此评估中,召回@k尤其重要,其中k代表考虑的顶级结果数量。因此,召回@10召回@50召回@100分别衡量在检索的前10、50和100个项目中出现多少真正相关的结果。召回的表达范围从0到1(或0%到100%的精确度)。这是重要的,因为我们讨论的是近似KNN(ANN)而不是精确KNN,其中召回总是1(100%)。

对于每个k值,我们还指定了n,即在应用最终排名之前考虑的候选项数量。这意味着对于召回@10、召回@50和召回@100,系统首先使用二进制量化算法检索n个候选项,然后对其进行排名,以确定顶级k结果是否包含预期的相关项目。

通过控制n,我们可以分析效率与准确性之间的权衡。较高的n通常增加召回率,因为有更多的候选项可用于排名,但也增加延迟并减少吞吐量。相反,较低的n可以加快检索速度,但如果初始集合中包含的相关候选项太少,可能会降低召回率。

在这次比较中,Elasticsearch在相同的设置下表现出更低的延迟和更高的吞吐量。

方法

完整的配置以及Terraform脚本、Kubernetes清单和具体的Rally track都可以在这个仓库中的openai_vector_bq找到。

与之前的基准测试一样,我们使用了一个Kubernetes集群,该集群由以下节点池组成:

  • 1个用于Elasticsearch 9.0的节点池,包含3台e2-standard-32机器(128GB RAM和32个CPU)
  • 1个用于OpenSearch 2.19的节点池,包含3台e2-standard-32机器(128GB RAM和32个CPU)
  • 1个用于Rally的节点池,包含2台e2-standard-4机器(16GB RAM和4个CPU)

我们分别设置了一个Elasticsearch 9.0集群和一个OpenSearch 2.19集群。

两者均使用相同的设置进行测试:我们使用openai_vector Rally track,并进行了一些修改——该track使用了来自NQ数据集的250万份文档,并使用OpenAI的text-embedding-ada-002模型生成的嵌入进行了丰富。

代码语言:javascript代码运行次数:0运行复制
{  "source-file": "open_ai_corpus-initial-indexing.json.bz2",  "document-count": 2580961,  "compressed-bytes": 32076749416,  "uncompressed-bytes": 90263571686}

结果报告了在不同召回水平(召回@10、召回@50和召回@100)下测量的延迟和吞吐量,使用8个同时客户端进行搜索操作。我们使用了单一分片,没有副本。

我们运行了以下k-n-rescore组合,例如10-2000-2000,或k:10n:2000rescore:2000将检索顶级k(10)个候选项(2000),在2000个结果上应用重排序(相当于“过采样因子”为1)。每次搜索运行10000次,前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

召回@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

代码语言:javascript代码运行次数:0运行复制
apiVersion: v1kind: ConfigMapmetadata:  name: rally-params-os  labels:    app: rally-opensearchdata:  user-tags.json: |    {      "product": "OpenSearch",      "product-version": "OpenSearch-2.19.0",      "product-label": "OpenSearch-2.19-faiss",      "benchmark-run": "19-feb-recall@100"    }  track-params.json: |    {      "mapping_type": "vectors-only-mapping-with-docid",      "standalone_search_clients": 8,      "standalone_search_iterations": 5000,      "ann_threshold": 0,      "vector_mode": "on_disk",      "compression_level": "32x",      "vector_method_name": "hnsw",      "vector_method_engine": "faiss",      "search_ops": [        [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]      ]    }

OpenSearch索引配置

ConfigMap中的变量用于索引配置,某些参数保持不变。OpenSearch中的1-bit量化通过将压缩级别设置为“32x”进行配置。

index-vectors-only-mapping-with-docid-mapping.json

代码语言:javascript代码运行次数:0运行复制
{  "settings": {    {% if preload_pagecache %}    "index.store.preload": [      "vec", "vex", "vem", "veq", "veqm", "veb", "vebm"    ],    {% endif %}    "index.number_of_shards": {{ number_of_shards | default(1) }},    "index.number_of_replicas": {{ number_of_replicas | default(0) }},    "index.knn": true,    "index.knn.advanced.approximate_threshold": {{ ann_threshold | default(15000) }}  },  "mappings": {    "dynamic": false,    "properties": {      "docid": {        "type": "keyword"      },      "emb": {        "type": "knn_vector",        "dimension": 1536,        "space_type": "innerproduct",        "data_type": "float",        "mode": {{ vector_mode | default("in_memory") | tojson }},        "compression_level": {{ compression_level | default("32x") | tojson }},        "method": {          "name": {{ vector_method_name | default("hnsw") | tojson }},          "engine": {{ vector_method_engine | default("faiss") | tojson }},          "parameters": {            "ef_construction": 100,            "m": 16          }        }      }    }  }}

Elasticsearch Rally配置

/k8s/rally-openai_vector-es-bq.yml

代码语言:javascript代码运行次数:0运行复制
apiVersion: v1kind: ConfigMapmetadata:  name: rally-params-es  labels:    app: rally-elasticsearchdata:  user-tags.json: |    {      "product": "Elasticsearch",      "product-version": "Elasticsearch-9.0.0-ade01164",      "product-label": "Elasticsearch-9.0-BBQ",      "benchmark-run": "19-feb-recall@100"    }  track-params.json: |    {      "mapping_type": "vectors-only-mapping-with-docid",      "standalone_search_clients": 8,      "standalone_search_iterations": 5000,      "vector_index_type": "bbq_hnsw",      "search_ops": [        [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]      ]    }

Elasticsearch索引配置

index-vectors-only-mapping-with-docid-mapping.json

代码语言:javascript代码运行次数:0运行复制
{  "settings": {    {# non-serverless-index-settings-marker-start #}    {%- if build_flavor != "serverless" or serverless_operator == true -%}    {% if preload_pagecache %}    "index.store.preload": [ "vec", "vex", "vem", "veq", "veqm", "veb", "vebm" ],    {% endif %}    "index.number_of_shards": {{ number_of_shards | default(1) }},    "index.number_of_replicas": {{ number_of_replicas | default(0) }}    {%- endif -%}    {# non-serverless-index-settings-marker-end #}  },  "mappings": {    "dynamic": false,    "properties": {      "docid": {        "type": "keyword"      },      "emb": {        "type": "dense_vector",        "element_type": "float",        "dims": 1536,        "index": true,        "similarity": "dot_product",        "index_options": {          "type": {{ vector_index_type | default("bbq_hnsw") | tojson }},          "ef_construction": 100,          "m": 16        }      }    }  }}

结果

结果可以从多种角度进行解读。对于延迟和吞吐量,我们在每个召回水平绘制了简化和详细的图表。如果我们考虑每个指标的“值越高越好”,就很容易看到差异。然而,延迟是一个负面指标(越低越好),而吞吐量是一个正面指标。对于简化图表,我们使用(召回率 / 延迟) * 10000(简称“速度”)和召回率 * 吞吐量,因此两个指标都意味着更高的速度和吞吐量更好。让我们看看结果。

召回@10 - 简化

在该召回水平,Elasticsearch BBQ的速度最多比OpenSearch FAISS快5倍(平均快3.9倍),吞吐量平均比后者多3.2倍

召回@10 - 详细

任务

平均延迟

平均吞吐量

平均召回

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

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倍

详细结果 - 召回@100

任务

平均延迟

平均吞吐量

平均召回

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的改进

自从BBQ首次发布以来,它取得了显著的进步。在Elasticsearch 8.16中,为了进行比较,我们包括了8.16的基准运行结果,并可以看到召回率和延迟的改善。

在Elasticsearch 8.18和9.0中,我们重写了量化向量的核心算法。因此,虽然8.16中的BBQ表现良好,但最新版本更为出色。您可以在这里和这里阅读相关内容。简而言之,每个向量通过优化的标量分位数单独量化。结果是,用户在不影响性能的情况下,享受更高的向量搜索准确性,使Elasticsearch的向量检索更加强大。

结论

在Elasticsearch BBQ与OpenSearch FAISS的性能比较中,Elasticsearch在向量搜索方面显著优于OpenSearch,在各种召回水平下,查询速度最多快5倍,平均吞吐量高3.9倍。

主要发现包括:

  • 召回@10:Elasticsearch BBQ速度最多快5倍(平均快3.9倍),平均吞吐量比OpenSearch FAISS高3.2倍。
  • 召回@50:Elasticsearch BBQ速度最多快5倍(平均快4.2倍),平均吞吐量比OpenSearch FAISS高3.9倍。
  • 召回@100:Elasticsearch BBQ速度最多快5倍(平均快4.6倍),平均吞吐量比OpenSearch FAISS高3.9倍。

这些结果突出了Elasticsearch BBQ在高维向量搜索场景中的效率和性能优势。Elasticsearch 8.16中引入的Better Binary Quantization(BBQ)技术提供了显著的内存减少(约95%),同时保持高质量的排名,使其成为大规模向量搜索应用的最佳选择。

在Elastic,我们不断创新,以改进Apache Lucene和Elasticsearch,为搜索和检索用例(包括RAG,检索增强生成)提供最佳的向量数据库。我们的最新进展显著提升了性能,使向量搜索更快、更高效。这篇博客是这一创新的又一例证。

发布评论

评论列表(0)

  1. 暂无评论