文章指出pgvector基准测试常误导人,成功使用需关注规模、索引策略、混合检索、智能分区和预热。强调将其视为严肃的Postgres工作负载。
译自:The reason your pgvector benchmark is lying to you
作者:Naina Ananthaswamy
作为一个开源Postgres扩展,pgvector允许您在现有的表、事务和工具中存储和查询向量嵌入以及关系数据。去年十月,Alex Jacobs发表了一篇名为“反对pgvector的案例”的帖子,该文章在工程界广为流传。他的论点是,那些将pgvector吹捧为专用向量数据库的即插即用替代品的博客文章,都忽略了在大规模运行时所面临的实际操作问题(我在此不作深入探讨,但那篇博客文章绝对值得一读)。
他没错。他所描述的大部分内容对于当时原生的pgvector来说是准确的,并且突出了博客文章所承诺的与团队从本地Postgres实例转向生产工作负载时所遇到的情况之间的差距。但在过去的几个月里,pgvector的故事已经发生了很大的变化。
HNSW索引,v0.5.0中引入,相比IVFFlat基于集群的方法,提高了召回率和查询一致性。增量索引构建变得更加强大,在托管环境中运行pgvector的团队已经开发出操作模式,解决了Jacobs描述的许多故障模式。
本文旨在探讨在您决定采用pgvector之后如何成功地使用它。Jacobs的观点对团队将pgvector视为开箱即用技术时所发生的情况进行了公正的描述,但接下来将说明如何避免这种结果。
笔记本电脑 vs. 生产环境
pgvector中“演示可行,生产环境崩溃”的模式可能是规模变化的结果,这会改变哪些问题变得重要。对128维的10,000个向量进行基准测试看起来很顺利,查询速度快,索引构建也快。然而,该基准测试几乎无法告诉您相同的设置在500万个向量和1,536维下将如何运行。在那种规模下,索引本身就成为一个基础设施问题。
一个跨越数百万高维向量的HNSW索引在构建时需要比查询时更多的RAM,并且这些内存是从您的实时生产数据库中提取的。索引构建可能运行数小时,查询计划器对过滤向量查询的成本估算可能变化巨大,并且在任何部署(或故障转移)之后,第一批用户将付出冷缓存的代价,而ANN算法则在努力稳定下来。
“对128维的10,000个向量进行基准测试看起来很顺利……然而,该基准测试几乎无法告诉您相同的设置在500万个向量和1,536维下将如何运行。”
将这些视为有已知解决方案的工程问题,而非阻碍。是的,它们需要与标准关系型SQL不同的操作思维,并且只有在工作负载规模下才会显现。但那些措手不及的团队,是因为他们只对代表性数据进行基准测试,而没有考虑代表性规模。
在投入之前进行基准测试!
我坚信这是pgvector实现中最被忽视的步骤。跳过它,风险自负,因为它可能比任何其他失误带来更多的痛苦。
社区基准测试可以为您提供一个大致的预期,但您实际应用程序的性能会因向量维度、数据分布和数据集大小而异(通常差异很大)。对10k个128维向量运行的基准测试,几乎无法告诉您 您的 系统在500万个1536维向量下将如何表现。
因此,在您确定索引类型或数据库配置之前,请在代表性数据集上运行您自己的基准测试。在您预期达到的相同工作负载规模下,测量查询延迟、索引构建时间和搜索召回率。您现在花费的基准测试时间,将使您免于日后不那么有趣、耗时更长的重新架构。
选择和调整您的索引策略
IVFFlat与HNSW的选择是一个工作负载匹配的问题。我们从IVFFlat开始。它构建速度更快,并生成更紧凑的索引,使其成为周期性批量更新或相对适度数据集的可靠选择。您可以通过调整lists(要创建多少个分区)和probes(每次查询扫描多少个分区)来控制速度/召回率的权衡。然而,一个关键的注意事项是,IVFFlat索引需要训练数据来创建有效分区(这应该在数据加载后构建,而不是之前)。
然而,当您在频繁的向量查询下需要低查询延迟和高召回率时,HNSW更胜一筹。它的图结构可以实现更快的遍历,但索引创建时间更长,并且占用更多内存。这里的关键参数是ef_search(算法在查询期间探索的广度)和M(每个节点维护的连接数)。
但是,无论您选择哪种,都要根据您实际的查询模式和召回目标对这些参数进行 基准测试 。默认值和优化值之间的差距可能很大……然后,当您确定了有效的参数值后,将其与索引定义一起存储。当您的团队在六个月后更新嵌入模型时,向量的维度和分布将发生变化,因此需要相应地调整调优参数。
设计混合检索
在Postgres内部运行向量搜索的一个被低估的能力是将其与结构化SQL操作结合。
太多团队将pgvector视为一个独立的向量存储,只是恰好位于Postgres中。这样做的人们错过了显著的性能改进。
与其在 整个 数据集上运行向量相似性搜索,不如先使用SQL WHERE子句缩小候选集。您可以按租户ID、语言、内容类型或日期范围进行过滤。然后让ANN索引发挥作用,扫描缩小后的集合,而不是整个表。特别是在多租户应用程序中,这种方法通常能将查询性能提高一个数量级。
您甚至可以通过两阶段检索管道更进一步。首先运行一个快速ANN查询以提取top-N候选者。然后使用精确距离计算结合业务逻辑(新鲜度、用户权限、流行度加权等)对这些候选者进行重新排序。通过在SQL中进行重新排序,您可以将整个操作保持在一个事务中。
这种混合方法是pgvector与Postgres集成带来最大收益的地方。虽然专用向量数据库能很好地处理相似性搜索,但将其与任意SQL过滤器和事务业务逻辑结合通常需要编排层。但使用开源pgvector,您只需编写SQL。
智能分区并有意识地预热
您构建表的方式会影响向量查询性能,任何 纯粹 按照数据量进行分区的直觉都会偏离要点。
目标是根据与您实际查询过滤器相关的字段进行分区。因此,如果您的应用程序总是按租户过滤,就按租户分区。然后构建每个分区的向量索引,这样查询计划器可以在计划时修剪整个分区,这意味着向量索引对于任何给定查询只覆盖您总数据集的一小部分。
“任何纯粹根据数据量进行分区的直觉都会偏离要点。目标是根据与实际查询过滤器相关的字段进行分区。”
另一个让团队在生产环境中吃亏的地方是冷缓存性能。在部署或故障转移后,支持向量索引的页面不会在内存中。第一批访问系统的用户将承担从磁盘加载这些页面的成本,而ANN算法则在遍历图。使用像pg_prewarm这样的工具,您可以在流量到来 之前 将热页面加载到共享缓冲区中。您可以将其构建到您的部署过程中,以便从部署到服务的过渡不会降低性能。
了解其局限性
每个工具都有局限性,pgvector也不例外。关键在于理解它们。pgvector正在积极开发中,版本兼容性是一个考虑因素,因为该工具支持某些Postgres版本而非所有版本。扩展需要与您应对任何Postgres性能挑战时相同的手动调优,没有自动调优层来处理内存分配、查询优化或索引配置。
对于需要跨数千万向量实现20毫秒以下延迟的应用程序,pgvector可能是一个强大的起点,最终可以发展为专用解决方案。从这里开始,您可以验证您的用例并了解您的查询模式(无需在单独的基础设施上进行大量前期投资)。即使您超出了它的能力范围,您在迁移时也会对实际需求有更好的了解。
成功使用pgvector的团队与众不同之处
一个贯穿始终的特点是,那些从pgvector中获得最大收益的团队将其视为任何其他重要的Postgres工作负载来对待。他们在进行重大架构更改之前,会基于代表性数据进行基准测试,并有意识地调整索引参数,而不是盲目接受默认值。他们还设计利用完整SQL工具包的查询,并对pgvector的适用场景和不适用场景有透彻的理解。
如果您的团队已经运行Postgres并需要向量搜索,pgvector将大大减少架构的复杂性。关键在于投入运营工作以使其良好运行。Jacobs说博客文章跳过了难点是正确的……但只要采用正确的运营方法,这些难点 是 可以管理的。