使用 Elasticsearch 设计大规模向量搜索

作者:Jim Ferenczi

第 1 部分:高保真密集向量搜索

简介

在设计向量搜索体验时,可用选项的数量之多可能会让人感到不知所措。最初,管理少量向量很简单,但随着应用程序的扩展,这很快就会成为瓶颈。

在本系列博文中,我们将探讨使用 Elasticsearch 在各种数据集和用例中运行大规模向量搜索的成本和性能。

我们从最大的公开可用向量数据集之一开始本系列:Cohere/msmarco-v2-embed-english-v3。该数据集包括从 MSMARCO-passage-v2 集合中的网页中提取的 1.38 亿个段落,使用 Cohere's latest embed-english-v3 model 嵌入到 1024 个维度中。

对于这个实验,我们定义了一个可重现的轨道(track),你可以在自己的 Elastic 部署上运行它,以帮助你对自己的高保真密集向量搜索体验进行基准测试。

它专为实时搜索用例量身定制,其中单个搜索请求的延迟必须很低(<100ms)。它使用我们的开源工具 Rally 对 Elasticsearch 版本进行基准测试。

在本文中,我们对浮点向量使用默认的自动量化。这将运行向量搜索的 RAM 成本降低了 75%,而不会影响检索质量。我们还提供了在索引数十亿个维度时合并和量化的影响的见解。

我们希望此轨迹可以作为有用的基准,特别是如果你手头没有特定于你的用例的向量。

关于嵌入的注释

选择适合你需求的正确模型超出了本博客文章的范围,但在下一节中,我们将讨论压缩向量原始大小的不同技术。

Matryoshka Representation Learning (MRL)

通过将最重要的信息存储在较早的维度中,Matryoshka 嵌入等新方法可以缩小维度,同时保持良好的搜索准确性。使用这种技术,某些模型的大小可以减半,并且在 MTEB 检索基准上仍保持 90% 的 NDCG@10。但是,并非所有模型都兼容。如果你选择的模型未针对 Matryoshka 缩减进行训练,或者其维数已经处于最小值,则你必须直接在向量数据库中管理维数。

幸运的是,mixedbread 或 OpenAI 的最新模型内置了对 MRL 的支持。

对于这个实验,我们选择专注于维数固定(1024 个维度)的用例,使用其他模型的维数将是另一个话题。

嵌入量化学习

模型开发人员现在通常提供具有各种权衡的模型来解决高维向量的费用问题。这些模型不是仅仅关注降维,而是通过调整每个维度的精度来实现压缩。

通常,嵌入模型被训练为使用 32 位浮点生成维度。但是,训练它们以降低精度生成维度有助于最大限度地减少错误。开发人员通常会发布针对众所周知的精度优化的模型,这些精度与编程语言中的本机类型直接一致。

例如,int8 表示一个有符号整数,范围从 -127 到 127,而 uint8 表示一个无符号整数,范围从 0 到 255。二进制是最简单的形式,表示一位(0 或 1),对应于每个维度的最小可能单位。

在训练期间实施量化可以微调模型权重,以最大限度地减少压缩对检索性能的影响。但是,深入研究训练此类模型的细节超出了本博客的范围。

在下一节中,我们将介绍一种在所选模型缺少此功能时应用自动量化的方法。

自适应嵌入量化

在模型缺乏量化感知嵌入的情况下,Elasticsearch 采用自适应量化方案,默认将浮点量化为 int8。

这种通用的 int8 量化通常会导致可忽略不计的性能损失。这种量化的好处在于它对数据漂移的适应性。

它采用动态方案,可以不时重新计算量化边界以适应数据中的任何变化。

大规模基准测试

粗略估计

MSMARCO-v2 数据集包含 1.383 亿个文档和 1024 维向量,用于存储原始浮点向量的原始大小超过 520GB。使用强力搜索(brute force)整个数据集在单个节点上需要数小时。

幸运的是,Elasticsearch 提供了一种称为 HNSW(hierachical navigable small world graph - 分层可导航小世界图)的数据结构,旨在加速最近邻搜索(nearest neighbor search)。此结构允许快速近似最近邻搜索,但要求每个向量都位于内存中。

从磁盘加载这些向量的成本非常高,因此我们必须确保系统有足够的内存将它们全部保存在内存中。

每个向量有 1024 个维度,每个维度 4 字节,因此每个向量需要 4 千字节的内存。

此外,我们还需要考虑将分层可导航小世界 (HNSW) 图加载到内存中所需的内存。在图中每个节点的默认设置为 32 个邻居的情况下,每个向量需要额外的 128 字节(每个邻居 4 字节)内存来存储图,这相当于存储向量维度内存成本的约 3%。

确保有足够的内存来满足这些要求对于实现最佳性能至关重要。

在 Elastic Cloud 上,我们的向量搜索优化配置文件为 JVM(Java 虚拟机)保留了总节点内存的 25%,每个数据节点上 75% 的内存可用于加载向量的系统页面缓存。对于具有 60GB RAM 的节点,这相当于 45GB 的页面缓存可用于向量。向量搜索优化配置文件适用于所有云解决方案提供商 (CSP) AWS、Azure 和 GCP。

为了满足所需的 520GB 内存,我们需要 12 个节点,每个节点具有 60GB RAM,总计 720GB。

在撰写本文时,此设置可部署在我们的 Cloud 环境中,AWS 上的总成本为每小时 14.44 美元:(请注意,Azure 和 GCP 环境的价格会有所不同):

通过利用自动量化到字节,我们可以将内存需求减少到 130gb,这仅仅是原始大小的四分之一。

应用相同的 25/75 内存分配规则,我们可以在 Elastic Cloud 上分配总共 180 gb 的内存。

在撰写本博客时,此优化设置在 Elastic Cloud 上的总成本为每小时 3.60 美元(请注意,Azure 和 GCP 环境的价格会有所不同)

在 Elastic Cloud 上开始免费试用,只需选择新的 Vector Search 优化配置文件即可开始使用。

在这篇文章中,我们将使用我们为试验大规模向量搜索性能而创建的基准来探索这种经济高效的量化。通过这样做,我们旨在展示如何在保持高搜索准确性和效率的同时实现显着的成本节省。

基准测试配置

msmarco-v2-vector rally track 定义了将要使用的默认映射。

它包括一个具有 1024 个维度的密集向量字段,使用自动 int8 量化进行索引,以及一个关键字类型的 doc_id 字段,用于唯一标识每个段落。

对于此实验,我们测试了两种配置:

  • 默认(default):这作为基线,使用 Elasticsearch 上的默认选项的赛道。
  • 积极合并(aggressive merge):此配置提供了一个具有不同权衡的比较点。

如前所述,Elasticsearch 中的每个分片都由段组成。段是数据的不可变部分,包含直接查找和搜索数据的必要结构。

文档索引涉及在内存中创建段,这些段会定期刷新到磁盘。

为了管理段的数量,后台进程会合并段以将总数保持在一定预算以下。

这种合并策略对于向量搜索至关重要,因为 HNSW 图在每个段内都是独立的。每个密集向量字段搜索都涉及在每个段中查找最近的邻居,这使得总成本取决于段的数量。

默认情况下,Elasticsearch 合并大小大致相等的段,遵循由每个层允许的段数控制的分层策略。

此设置的默认值为 10,这意味着每个级别不应有超过 10 个大小相似的段。例如,如果第一级包含 50MB 的段,则第二级将包含 500MB 的段,第三级将包含 5GB 的段,依此类推。

积极合并配置将默认设置调整为更积极:

  • 它将每个层的段设置为 5,从而实现更积极的合并。
  • 它将最大合并段大小从 5GB 增加到 25GB,以最大化单个段中的向量数量。
  • 它将最低段大小设置为 1GB,人为地将第一级从 1GB 开始。

通过这种配置,我们期望搜索速度更快,但索引速度较慢。

对于此实验,我们在两种配置中都保留了 HNSW 图的 m、ef_construction 和 confidence_interval 选项的默认设置。对这些索引参数的实验将成为另一篇博客的主题。在第一部分中,我们选择专注于改变合并和搜索参数。

运行基准测试时,将负责发送文档和查询的负载驱动程序与评估系统(Elasticsearch 部署)分开至关重要。加载和查询数亿个密集向量需要额外的资源,如果一起运行,这些资源会干扰评估系统的搜索和索引功能。

为了最大限度地减少系统和负载驱动程序之间的延迟,建议在与 Elastic 部署相同的云提供商区域中运行负载驱动程序,最好在同一个可用区中。

对于此基准测试,我们在 AWS 上配置了一个 im4gn.4xlarge 节点,该节点与 Elastic 部署位于同一区域,具有 16 个 CPU、64GB 内存和 7.5TB 磁盘。此节点负责将查询和文档发送到 Elasticsearch。通过以这种方式隔离负载驱动程序,我们可以确保准确测量 Elasticsearch 的性能,而不会受到额外资源需求的干扰。

我们使用以下配置运行了整个基准测试:

    "track.params": {
        "mapping_type": "vectors-only",
        "vector_index_type": "int8_hnsw",
        "number_of_shards": 4,
        "initial_indexing_bulk_indexing_clients": 12,
        "standalone_search_clients": 8
    }

initial_indexing_bulk_indexing_clients 值为 12 表示我们将使用 12 个客户端从负载驱动程序中提取数据。Elasticsearch 数据节点中总共有 23.9 个 vCPU,使用更多客户端发送数据可提高并行性,使我们能够充分利用部署中的所有可用资源。

对于搜索操作,standalone_search_clients 和 parallel_indexing_search_clients 值为 8 表示我们将使用 8 个客户端从负载驱动程序并行查询 Elasticsearch。最佳客户端数量取决于多种因素;在此实验中,我们选择了客户端数量以最大化所有 Elasticsearch 数据节点的 CPU 使用率。

为了比较结果,我们在同一个部署上运行了第二个基准测试,但这次我们将参数 assault_merge 设置为 true。这有效地将合并策略更改为更激进,使我们能够评估此配置对搜索性能和索引速度的影响。

索引性能

在 Rally 中,挑战配置了要执行和报告的计划操作列表。

每个操作负责针对集群执行操作并报告结果。

对于我们的新轨道(track),我们将第一个操作定义为初始文档索引,这涉及批量索引整个语料库。接下来是等待合并完成索引,等待批量加载过程结束时后台合并完成。

此操作不使用强制合并;它只是等待自然合并过程完成后再开始搜索评估。

下面,我们报告轨道这些操作的结果,它们对应于 Elasticsearch 中数据集的初始加载。搜索操作将在下一节中报告。

使用 Elasticsearch 8.14.0,138M 向量的初始索引花费了不到 5 个小时,平均每秒 8,000 个文档。

请注意,瓶颈通常是嵌入的生成,这里没有报告。

等待合并最后完成只增加了 2 分钟:

总体索引性能(8.14.0 默认 int8 HNSW 配置)

相比之下,在 Elasticsearch 8.13.4 上进行的相同实验需要近 6 个小时进行提取,另外还需要 2 个小时等待合并:

总索引性能(8.13.4 默认 int8 HNSW 配置)

Elasticsearch 8.14.0 标志着首次利用原生代码进行向量搜索的版本。在合并期间使用原生 Elasticsearch 编解码器来加速 int8 向量之间的相似性,从而显著缩短总体索引时间。我们目前正在探索通过使用此自定义编解码器进行搜索的进一步优化,敬请期待更新!

积极的合并运行在不到 6 小时内完成,平均每秒 7,000 个文档。但是,需要等待近一个小时才能完成合并。与使用默认合并策略的运行相比,速度降低了 40%:

总体索引性能(8.14.0 积极合并 int8 HNSW 配置)

积极合并配置执行的额外工作可总结在下面的两个图表中。

积极合并配置合并了 2.7 倍的文档,以创建更大且更少的段。默认合并配置报告从索引的 1.38 亿个文档中合并了近 3 亿个文档。这意味着每个文档平均合并 2.2 次。

每个节点合并的文档总数(8.14.0 默认 int8 HNSW 配置)

每个节点合并的文档总数(8.14.0 积极合并 int8 HNSW 配置)

在下一节中,我们将分析这些配置对搜索性能的影响。

搜索评估

对于搜索操作,我们的目标是捕获两个关键指标:最大查询吞吐量近似最近邻搜索的准确度

为了实现这一点,standalone-search-knn-* 操作使用各种近似搜索参数组合来评估最大搜索吞吐量。此操作涉及使用 parallel_indexing_search_clients 尽可能快速地并行执行来自训练集的 10,000 个查询。这些操作旨在利用节点上所有可用的 CPU,并在所有索引和合并任务完成后执行。

为了评估每个组合的准确性,knn-recall-* 操作计算相关的召回率和标准化折扣累积收益 (Normalized Discounted Cumulative Gain - nDCG)。nDCG 是根据 msmarco-passage-v2/trec-dl-2022/judged 中发布的 76 个查询计算得出的,使用了 386,000 个 qrels 注释。所有 nDCG 值的范围从 0.0 到 1.0,其中 1.0 表示完美排名。

由于数据集的大小,生成真实结果来计算召回率的成本极高。因此,我们将召回率报告限制为测试集中的 76 个查询,我们使用强力方法离线计算了这些查询的真实结果。

搜索配置包含三个参数:

  • k:要返回的段落数(passages)。
  • num_candidates:用于限制在最近邻图上搜索的队列大小。
  • num_rescore:使用全保真向量重新评分的段落数。

使用自动量化,使用原始浮点向量重新评分略多于 k 个向量可以显著提高召回率。

操作根据这三个参数命名。例如,knn-10-100-20 表示 k=10、num_candidates=100 和 num_rescore=20。如果省略最后一个数字,如 knn-10-100,则 num_rescore 默认为 0。

有关我们如何创建搜索请求的更多信息,请参阅 track.py 文件。

下图说明了不同召回率水平下的预期每秒查询数 (Queries Per Second - QPS)。例如,默认配置(橙色系列)可以实现 50 QPS,预期召回率为 0.922。

每秒召回率与查询次数(Elasticsearch 8.14.0)

对于相同级别的召回率,激进合并配置的效率是后者的 2 到 3 倍。这种效率是意料之中的,因为搜索是在更大、更少的片段上进行的,如上一节所示。

默认配置的完整结果如下表所示:

每秒查询数、延迟(以毫秒为单位)、召回率和具有不同参数组合的 NDCG@10(8.14 默认 int8 HNSW 配置)

%best 列表示此配置的实际 NDCG@10 与最佳可能 NDCG@10 之间的差异,后者使用离线强力计算的地面实况最近邻确定。

例如,我们观察到,尽管 knn-10-20-20 配置的召回率为 67.4%,但它实现了此数据集最佳可能 NDCG 的 90%。请注意,这只是一个点结果,结果可能因其他模型和/或数据集而异。

下表显示了积极合并配置的完整结果:

每秒查询数、延迟(以毫秒为单位)、召回率和具有不同参数组合的 NDCG@10(8.14 积极合并 int8 HNSW 配置)

使用 knn-10-500-20 搜索配置,积极合并设置可以在 150 QPS 下实现 > 90% 的召回率。

结论

在这篇文章中,我们描述了一种新的 rally track,旨在对 Elasticsearch 上的大规模向量搜索进行基准测试。我们探讨了运行近似最近邻搜索所涉及的各种权衡,并展示了在 Elasticsearch 8.14 中,我们如何将成本降低 75%,同时将索引速度提高 50%,以实现真实的大规模向量搜索工作负载。

我们正在努力优化和寻找机会来增强我们的向量搜索功能。请继续关注本系列的下一篇文章,我们将在其中深入探讨向量搜索用例的成本和效率,特别是研究 int4 和二进制压缩技术的潜力。

通过不断改进我们的方法并发布用于大规模测试性能的工具,我们的目标是突破 Elasticsearch 的极限,确保它仍然是大规模向量搜索的强大且经济高效的解决方案。

准备好自己尝试一下了吗?开始免费试用。

Elasticsearch 集成了 LangChain、Cohere 等工具。加入我们的高级语义搜索网络研讨会,构建你的下一个 GenAI 应用程序!

原文:Elasticsearch vector search: Designing for large scale — Elastic Search Labs

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/704576.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深度学习长文|使用 JAX 进行 AI 模型训练

引言 在人工智能模型的开发旅程中&#xff0c;选择正确的机器学习开发框架是一项至关重要的决策。历史上&#xff0c;众多库都曾竞相争夺“人工智能开发者首选框架”这一令人垂涎的称号。&#xff08;你是否还记得 Caffe 和 Theano&#xff1f;&#xff09;在过去的几年里&…

负压式水帘风机和一体式水帘风机的特点

负压式水帘风机和一体式水帘风机各有其独特的特点&#xff0c;以下是它们的特点归纳&#xff1a; 负压式水帘风机特点&#xff1a; 高效节能&#xff1a; 通过水帘与负压风机的配合&#xff0c;模拟自然界的蒸发降温过程&#xff0c;耗电量仅为传统空调的十分之一&#xff0c…

写个代码扫描插件,再也不怕 log4j 等问题

引言 关于静态代码扫描&#xff0c;大家想必都非常熟悉了&#xff0c;比如 lint、detekt 等&#xff0c;这些也都是常用的扫描工具。但随着隐私合规在国内越来越趋于常态&#xff0c;我们经常需要考虑某些危险api的调用排查等等&#xff0c;此时上述的工具往往不容易实现现有的…

Python内存管理与垃圾回收机制

目录 一、引言 二、Python内存管理概述 三、引用计数机制 四、垃圾回收机制 标记-清除&#xff08;Mark-and-Sweep&#xff09; 分代收集&#xff08;Generational Collection&#xff09; 五、内存泄漏与优化 六、总结 一、引言 Python作为一门高级编程语言&#xff…

MySQL查询优化最佳实践15条(建议收藏)

目录 1 优化方法&#xff08;15条&#xff09; 2 总结 MySQL的数据库常规查询的过程中性能的优化非常重要&#xff0c;其中很多点是和开发习惯有关&#xff0c;能熟练掌握不只能提高工作的效率&#xff0c;同时也能提高个人的技能。有一些优化的技巧同样也适合于其他的数据库…

2024中国通信技术产业博览会:JUNO光缆与WaveLogic 6技术,海洋深处的数字脉搏

在数字化时代&#xff0c;通信技术是连接世界的桥梁。NTT DATA主导的JUNO海底光缆计划&#xff0c;通过部署Ciena的WaveLogic 6技术&#xff0c;标志着全球通信网络容量的一次重大飞跃。这一进步不仅加强了亚洲与北美之间的数据连接&#xff0c;更为即将到来的“2024中国军民两…

华为云EI生态

1、人工智能技术趋势 2、华为AI发展思路 3、华为云EI&#xff1a;让企业更智能 4、华为云服务全景图 5、基础平台类服务 6、MLS:解决特性到模型应用的完整过程 7.DLS 8.GES超大规模一体化图分析与查询 9、EI视觉认知 10、EI语音语义 11、OCR&#xff1a;提供高精度光学文字自动…

OpenCV特征匹配

1、OpenCV Brute-Force匹配器 Brute-Force匹配器的匹配方法非常简单&#xff0c;输入两张图像所分别对应的特征&#xff08;特征点坐标与特征点域对应的描述子&#xff09;&#xff0c;循环遍历两幅图像中的特征&#xff0c;计算第一幅图像与第二幅图像之间每个特征点之间的距…

49.Python-web框架-Django解决多语言redirect时把post改为get的问题

目录 1.背景 2.思路 3.寻找 Find and Replace 4.再次运行程序&#xff0c;POST来了 5.小结 1.背景 昨天在练习一个Django功能时&#xff0c;把form的method设置为POST&#xff0c;但是实际提交时&#xff0c;一直是GET方法。最后发现这是与多语言相关&#xff0c;django前面…

Linux - 复盘一次句柄数引发的故障

文章目录 Pre&#xff08;内核、用户、进程&#xff09;句柄数设置问题 shell修复 Pre Linux - 深入理解/proc虚拟文件系统&#xff1a;从基础到高级 &#xff08;内核、用户、进程&#xff09;句柄数设置 在Linux系统中&#xff0c;进程打开的最大句柄数可以通过多种方式配置…

计算机组成原理 期末复习笔记整理(上)(个人复习笔记/侵删/有不足之处欢迎斧正)

零、计算机的发展 冯.诺依曼计算机的特点: 1.计算机由五大部件组成 2.指令和数据以同等地位存于存储器&#xff0c;可按地址寻访 3.指令和数据用二进制表示 4.指令由操作码和地址码组成 5.存储程序&#xff08;首次提出存储结构&#xff09; 6.以运算器为中心&#xff08;现代…

大众点评全国美食POI采集780万家-2024年5月底

大众点评全国美食POI采集780万家-2024年5月底 店铺POI点位示例&#xff1a; 店铺id H8kTSRz3kLUQ2WtU 店铺名称 幸福西饼生日蛋糕(布心店) 十分制服务评分 8.2 十分制环境评分 8.4 十分制划算评分 8.3 人均价格 75 评价数量 119033 店铺地址 金稻田路1068号边防布心住…

Python文件操作与IO:从基础到高级技巧的完整指南

目录 一、引言 二、基础文件操作 打开文件 写入文件 读取和写入二进制文件 四、文件路径处理 五、文件操作的高级技巧 上下文管理器&#xff08;with 语句&#xff09; 文件锁 文件编码 使用内置模块处理文件 文件压缩与解压缩 六、案例&#xff1a;处理日志文件 …

支付卡产业最新发布PCI DSS v4.0.1

自2022年3月PCI DSS v4.0发布以来&#xff0c;受到全球支付产业高度关注&#xff0c;为了解决来自所有产业相关者的反馈和问题&#xff0c;PCI安全标准委员会&#xff08;PCI SSC&#xff09;发布了该标准的修订版PCI DSS v4.0.1。其中包括对格式和印刷错误的更正&#xff0c;也…

顶顶通呼叫中心中间件-限制最大通话时间(mod_cti基于FreeSWITCH)

顶顶通呼叫中心中间件-限制最大通话时间(mod_cti基于FreeSWITCH) 一、最大通话时间 1、配置拨号方案 1、点击拨号方案 ->2、在框中输入通话最大时长->3、点击添加->4、根据图中配置->5、勾选continue。修改拨号方案需要等待一分钟即可生效 action"sched…

基于Pytorch实现AI写藏头诗

网上你找了一圈发现开源的代码不是付费订阅就是代码有问题,基于Pytorch实现AI写藏头诗看我这篇就够了。 用到的工具:华为云ModelArts平台的notebook/Pycharm/Vscode都行。 镜像:pytorch1.8-cuda10.2-cudnn7-ubuntu18.04,有GPU优先使用GPU资源。 实验背景 在短时测试使用场…

变电站SF6-O2在线监控报警系统在电力行业的创新应用

一、六氟化硫是什么&#xff1f; 六氟化硫又称为SF6&#xff0c;这种气体在常温常压下为无色无臭无毒的气体。不燃烧。对热稳定&#xff0c;没有腐蚀性&#xff0c;可以作为通用材料。电绝缘性能和消弧性能好&#xff0c;绝缘性能为空气的2&#xff5e;3倍&#xff0c;而且气体…

外网如何访问公司内网服务器?

在现代商业环境中&#xff0c;随着信息技术的快速发展&#xff0c;越来越多的公司有需求让远程用户在外网环境下访问公司内网服务器。这在很大程度上提高了远程办公的灵活性和效率。由于安全和网络限制等问题&#xff0c;实现这一目标并不是一件容易的事情。 在处理这个问题时…

【Qt 学习笔记】Qt窗口 | 对话框 | 创建自定义对话框

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt窗口 | 对话框 | 创建自定义对话框 文章编号&#xff1a;Qt 学习笔记…

[人工智能]啥是大模型?一篇文章看懂火遍全网的“AI大模型”

美国商业科技界正在升起两位“新神”。 一位是“钢铁侠”埃隆马斯克&#xff0c;“带领人类走向火星”&#xff1b; 一位是“奥特曼”山姆阿尔特曼&#xff0c;“带领AI走向人类”。 大多数人对马斯克很熟悉了&#xff0c;特斯拉汽车在中国道路上疾驰&#xff0c;朋友圈也经…