首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Elasticsearch 的过滤向量搜索速度比 OpenSearch 快 8 倍

Elasticsearch 的过滤向量搜索速度比 OpenSearch 快 8 倍

原创
作者头像
点火三周
发布2026-08-02 13:33:03
发布2026-08-02 13:33:03
1281
举报

为什么搜索速度对人工智能代理和上下文工程至关重要

我们在包含 2000 万篇文档的语料库上进行的基准测试表明,Elasticsearch 在过滤向量搜索方面比 OpenSearch 的吞吐量高出 8 倍,并且在我们测试的所有配置中都实现了更高的 Recall@100。上下文工程不仅仅依赖于快速的向量检索。随着工作流程的迭代,团队还需要强大的相关性控制(例如混合搜索和过滤)、操作简便性和可预测的性能。但是,由于代理通常在每个请求中多次运行检索、推理、再检索的循环,检索延迟会成为一个倍增器,因此这方面的改进将直接转化为更好的端到端响应速度和更低的成本。

OpenSearch 与 Elasticsearch:过滤向量搜索基准测试的吞吐量比较
OpenSearch 与 Elasticsearch:过滤向量搜索基准测试的吞吐量比较

图 1:吞吐量。

对于上下文工程而言,检索并非一次性步骤。代理和应用程序会反复运行循环,例如检索→推理→检索,以优化查询、验证事实、构建相关的上下文并完成任务。这种模式在代理工作流和迭代检索增强生成(RAG)中很常见。由于每个用户请求都可能多次调用检索,因此会增加响应延迟和/或基础设施成本。

上下文工程将庞大的上下文池转换为有限的 LLM 上下文窗口。
上下文工程将庞大的上下文池转换为有限的 LLM 上下文窗口。

图 1:上下文工程通过重复检索和整理,将大型上下文池(文档、内存、工具、聊天记录)转换为有限的大型语言模型 (LLM) 上下文窗口。

上下文工程的优化实施是一项新​​兴技术。迭代次数因工作流程而异。这些基准测试结果中最根本的关键概念是上下文工程具有方向性:迭代检索会成倍增加延迟。

为什么向量搜索的性能至关重要?

想象一下,一位购物助理回答这个问题:“我需要一个价格低于 60 美元的随身背包,可以装下 15 英寸的笔记本电脑,防水,并且周五之前能送到。”

在生产环境中,助手很少只发出一次向量查询就停止。它会运行一个检索循环来构建正确的上下文,并且每一步通常都会受到诸如可用性、地区、发货承诺、品牌规则和政策资格等筛选条件的限制。

第一步:理解意图并将其转化为约束条件。

代理将请求转换为结构化过滤器和语义查询,例如:

  • 筛选条件:有现货、可配送至用户邮编、周五前送达、价格低于 60 美元、有效商品信息
  • 矢量查询:“可携带15英寸笔记本电脑的防水背包”

步骤 2:检索候选对象,然后进行筛选。

它经常使用不同的方法重复检索,以避免错过好的匹配项:

  • “旅行背包,可携带笔记本电脑”
  • “15英寸防水通勤背包”
  • “轻便登机背包”

每个查询都使用相同的资格筛选器,因为检索不相关或不可用的项目会浪费上下文信息。

步骤 3:展开确认细节并降低风险。

然后,代理再次检索以验证影响最终答案的关键属性:

  • 材质和防水性能描述
  • 尺寸和笔记本电脑隔层适配
  • 退货政策或保修限制
  • 库存不足时的替代方案

这是多步骤上下文工程:检索、推理、检索、组装。

为什么延迟和召回对上下文工程至关重要

每个用户会话中,这些交互可能涉及数十次筛选检索调用。这使得每次调用的延迟直接倍增端到端响应时间,而低召回率则迫使代理进行额外的重试,或导致其错过符合条件的项目,从而降低答案质量。

要点:在上下文相关的系统中,过滤近似最近邻(ANN)并非单次查找,而是一项在约束条件下重复进行的操作。因此,即使大型语言模型(LLM)是最显眼的组件,向量搜索性能也会立即体现在延迟、吞吐量和成本上。

基准测试

结果

在图 2 中,每个点代表一个测试配置。最佳结果出现在左上角附近,这意味着更高的召回率和更低的延迟。Elasticsearch 的结果始终比 OpenSearch 更靠近左上角,表明在相同的工作负载设置下,Elasticsearch 的速度和准确性都更胜一筹。

图 2:回忆率与平均延迟(重新评分 1)。
图 2:回忆率与平均延迟(重新评分 1)。

图 2:回忆率与平均延迟的关系,重新评分为 1。

一些关键见解
  • s_n_r_value:简写形式size_numCandidates_rescoreOversample(在这些测试中,k 和 numCandidates 均等于 numCandidates),例如,100_500_1表示 size=100,numCandidates=500 和 k=500,rescore oversample=1
  • 召回率:该配置下测得的召回率(Recall@100)
  • 平均延迟(毫秒):每次查询的平均端到端延迟
  • 吞吐量:每秒查询次数
  • 召回率:Elasticsearch 相对于 OpenSearch 的相对召回率提升(Elasticsearch 值减去 OpenSearch 值)/ OpenSearch
  • 延迟 Xs:OpenSearch 平均延迟除以 Elasticsearch 平均延迟
  • 吞吐量 Xs:Elasticsearch 吞吐量除以 OpenSearch 吞吐量

引擎

`s_n_r_value`

记起

平均延迟(毫秒)

吞吐量

记起 %

延迟 Xs

吞吐量 Xs

Elasticsearch

100_250_1

0.7704

25

534.75

9.70%

2.28

1.91

OpenSearch

100_250_1

0.7023

57.08

279.58

Elasticsearch

100_500_1

0.8577

25.42

524.14

7.20%

2.4

2

OpenSearch

100_500_1

0.8001

60.9

262.12

Elasticsearch

100_750_1

0.8947

29.67

528.09

5.72%

2.25

2.21

OpenSearch

100_750_1

0.8463

66.76

239.11

Elasticsearch

100_1000_1

0.9156

29.65

534.5

4.66%

2.46

2.44

OpenSearch

100_1000_1

0.8748

72.88

219.01

Elasticsearch

100_1500_1

0.9386

31.84

497.3

3.38%

2.71

2.68

OpenSearch

100_1500_1

0.9079

86.16

185.4

Elasticsearch

100_2000_1

0.9507

34.69

457.2

2.57%

2.98

2.96

OpenSearch

100_2000_1

0.9269

103.36

154.55

Elasticsearch

100_2500_1

0.9582

37.9

418.43

1.99%

3.28

3.26

OpenSearch

100_2500_1

0.9395

124.29

128.53

Elasticsearch

100_3000_1

0.9636

41.86

379.4

1.62%

3.46

3.44

OpenSearch

100_3000_1

0.9482

144.67

110.34

Elasticsearch

100_4000_1

0.9705

50.28

316.21

1.06%

3.87

3.85

OpenSearch

100_4000_1

0.9603

194.36

82.22

Elasticsearch

100_5000_1

0.9749

58.77

270.91

0.73%

4.43

4.41

OpenSearch

100_5000_1

0.9678

260.33

61.38

Elasticsearch

100_6000_1

0.9781

66.75

238.59

0.52%

4.91

4.89

OpenSearch

100_6000_1

0.973

327.44

48.81

Elasticsearch

100_7000_1

0.9804

74.64

213.49

0.38%

5.28

5.27

OpenSearch

100_7000_1

0.9767

394.24

40.53

Elasticsearch

100_8000_1

0.9823

82.28

193.59

0.27%

6.86

6.83

OpenSearch

100_8000_1

0.9797

564.14

28.33

Elasticsearch

100_9000_1

0.9837

90.08

176.96

0.16%

7.63

7.61

OpenSearch

100_9000_1

0.9821

687.25

23.25

Elasticsearch

100_10000_1

0.9848

97.64

163.31

0.08%

8.38

8.36

OpenSearch

100_10000_1

0.984

818.64

19.53

例如,在100_9000_1OpenSearch 上,每次检索平均耗时 687 毫秒,而 Elasticsearch 每次检索平均耗时 90 毫秒;在一个 10 步检索循环中,大约需要额外等待 10 x (687 - 90) = 6 秒。

查看完整结果

方法论

我们使用 Python 发送查询并跟踪响应时间和其它统计数据,向搜索引擎发送了以下查询。请注意,任何向量搜索引擎的性能都取决于其核心参数的调优方式:考虑多少候选答案、重新评分的频率以及返回多少上下文信息。这些设置直接影响召回率(找到正确答案的可能性)和延迟(获得结果的速度)。

在我们的基准测试中,我们使用了与代理检索循环中通常调整的相同的候选列表、重评分和结果大小设置,并测量了 Elasticsearch 在此工作负载下的性能。然后,我们使用相同的设置运行 OpenSearch 作为参考。

OpenSearch

代码语言:javascript
复制
GET <INDEX_NAME>/_search
{
  "query": {
    "knn": {
      "<DENSE_VECTOR_FIELD_NAME>": {
        "vector": [...],
        "k": <NUMBER_OF_CANDIDATES>,
        "method_parameters": {
          "ef_search": <NUMBER_OF_CANDIDATES>
        },
        "rescore": {
          "oversample_factor": <OVERSAMPLE>
        },
        "filter": {
          <SOME_FILTER>
        }
      }
    }
  },
  "size": <RESULT_SIZE>,
  "_source": {
    "excludes": [
      "<DENSE_VECTOR_FIELD_NAME>"
    ]
  }
}
  • "size": <RESULT_SIZE>返回给客户端的命中次数。在此基准测试中,结果集大小为 100,以计算 Recall@100。
  • "k": <NUMBER_OF_CANDIDATES>:最近邻候选对象的数量。
  • "ef_search": <NUMBER_OF_CANDIDATES>要检查的向量数量。
  • "oversample_factor": <OVERSAMPLE>:在重新评分之前检索到多少个候选向量。

Elasticsearch

代码语言:javascript
复制
GET <INDEX_NAME>/_search
{
  "query": {
    "knn": {
      "field": "<DENSE_VECTOR_FIELD_NAME>",
      "query_vector": [...],
      "k": <NUMBER_OF_CANDIDATES>,
      "num_candidates": <NUMBER_OF_CANDIDATES>,
      "rescore_vector": {
        "oversample": <OVERSAMPLE>
      },
      "filter": {
        <SOME_FILTER>
      }
    }
  },
  "size": <RESULT_SIZE>,
  "_source": {
    "excludes": [
      "<DENSE_VECTOR_FIELD_NAME>"
    ]
  }
}
  • "size": <RESULT_SIZE>返回给客户端的命中次数。在此基准测试中,结果集大小为 100,以计算 Recall@100。
  • "k": <NUMBER_OF_CANDIDATES>:从每个分片返回的最近邻居的数量。
  • "num_candidates": <NUMBER_OF_CANDIDATES>:在进行搜索时,每个分片要考虑的最近邻候选数knn
  • "oversample": <OVERSAMPLE>:在重新评分之前检索到多少个候选向量。

例子

Knn查询语句100_500_1如下:

OpenSearch

代码语言:javascript
复制
GET search_catalog_128/_search
{
  "query": {
    "knn": {
      "search_catalog_embedding": {
        "vector": [...],
        "k": 500,
        "method_parameters": {
          "ef_search": 500
        },
        "rescore": {
          "oversample_factor": 1
        },
        "filter": {
          "term": {
            "valid": true
          }
        }
      }
    }
  },
  "size": 100,
  "_source": {
    "excludes": [
      "search_catalog_embedding"
    ]
  }
}

Elasticsearch

代码语言:javascript
复制
GET search_catalog_128/_search
{
  "query": {
    "knn": {
      "field": "search_catalog_embedding",
      "query_vector": [...],
      "k": 500,
      "num_candidates": 500,
      "rescore_vector": {
        "oversample": 1
      },
      "filter": {
        "term": {
          "valid": true
        }
      }
    }
  },
  "size": 100,
  "_source": {
    "excludes": [
      "search_catalog_embedding"
    ]
  }
}

完整的配置,以及 Terraform 脚本、Kubernetes 清单和基准测试代码,都可以在此存储库的es-9.3-vs-os-3.5-vector-search文件夹中找到。

集群设置

我们在六台 e2-standard-16 云服务器上进行了测试,每台服务器配备 16 个 vCPU 和 64 GB 内存。在每台服务器上,我们为运行搜索引擎节点的每个 Kubernetes pod 分配了 15 个 vCPU 和 56 GB 内存,并为 JVM 堆保留了 28 GB 内存。

集群运行的是 Elasticsearch 9.3.0 和 OpenSearch 3.5.0(Lucene 10.3.2)。由于两个系统在此基准测试中使用了相同的 Lucene 版本,因此我们观察到的吞吐量和延迟差异不能仅仅归因于 Lucene,而是反映了每个引擎在集成和执行过滤后的 k 近邻 (kNN) 检索和重评分方面存在的差异。我们使用了一个包含三个主分片和一个副本的索引(总共 6 个分片,每个节点 1 个)。

我们还使用同一区域内的另一台服务器来运行基准测试客户端并收集计时统计数据。

Elasticsearch 和 OpenSearch 基准测试的集群设置
Elasticsearch 和 OpenSearch 基准测试的集群设置

图 2:集群设置示意图。

数据集

为了进行这项基准测试,我们使用了一个包含 2000 万份文档的大规模电子商务风格目录嵌入数据集,旨在反映现实世界大规模过滤向量检索。

每个文档代表一个目录项,包含:

  • 用于近似 kNN 检索的 128 维稠密向量嵌入。
  • 用于筛选的结构化元数据字段(例如,项目有效性和可用性以及其他目录约束),从而实现常见的生产模式,即检索最近的邻居,但仅限于符合条件的子集内。

我们选择这个数据集是因为它捕捉到了我们在生产环境中遇到的智能体和 RAG 类系统的核心性能挑战:仅靠向量相似度是不够的,检索经常受到过滤器的限制,系统必须在这些限制下保持高召回率和低延迟。与规模较小的问答类数据集相比,包含 2000 万篇文档的语料库也能更好地反映过滤式人工神经网络系统在实践中面临的规模和候选词压力。

结论

在现代人工智能架构中,尤其是在围绕上下文工程构建的架构中,向量搜索速度并非无关紧要的实现细节,而是一个关键的倍增器。当智能体和工作流迭代执行“检索→推理→检索”流程时,检索性能直接影响端到端延迟、吞吐量以及输入模型的上下文质量。

在我们的基准测试中,当正确性取决于检索到正确的文档(而不仅仅是相似的向量)时,Elasticsearch 始终比 OpenSearch 提供更高的召回率和更低的延迟。在受控数据集上,这种差异显而易见;在生产环境中,这些优势会随着大量检索调用而累积,从而提高响应速度、增加容量余量并降低基础设施成本。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 为什么搜索速度对人工智能代理和上下文工程至关重要
  • 为什么向量搜索的性能至关重要?
  • 为什么延迟和召回对上下文工程至关重要
  • 基准测试
    • 结果
      • 一些关键见解
    • 方法论
    • 集群设置
    • 数据集
  • 结论
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档