在本系列的上一篇文章中,我们介绍了向量数据库中通常使用的不同类型的索引。然而,索引只是向量数据库中更大问题中的一小部分。回想一下,在第二部分中,我们描述了什么是向量数据库。为了区分目前市场上的各种向量数据库产品,我们需要了解以下组件之间的关系:
-
应用层,以及它所处的位置
-
数据层,以及它在数据库和应用层之间的位置
-
索引策略,以及它如何与内存和CPU使用相关联
-
存储层设计
-
在所有这些方面与可扩展性和成本考虑相关的问题
每个组件都涉及自己的权衡。我将它们分成了以下几个类别 - 我相信还有一些我忽略了的,但这是一个开始。🤓话不多说,让我们深入探讨一下。
1.本地部署 vs. 云托管
很多供应商都强调他们的“云原生”特性,好像这是自面包切片以来最好的事情,从可扩展性的角度来看。然而,在从成本的角度决定哪种解决方案最好时,重要的是首先考虑托管选项是如何分解的。嵌入式数据库架构现在也是选项之一!🎉 考虑以下组合:
-
云原生(托管)+ 客户端-服务器模式
-
本地部署(自托管)+ 嵌入式
-
云原生(托管)+ 嵌入式
直观地比较这些组合更容易。
很明显,最常见的数据库体系结构类型是客户机-服务器体系结构,这是因为它已经经过了多年来各种其他数据库的实战测试。下面将描述嵌入式/无服务器托管模型,由于下面描述的原因,它特别有趣。
客户端-服务器架构 vs. 嵌入式架构****
自从DuckDB通过MotherDuck1对其开源嵌入式SQL数据库进行了商业化,它一直是其他新兴数据库供应商的灵感来源。在向量数据库领域,有一个供应商在这方面脱颖而出:LanceDB2,一个相对较新的参与者 - 它采用了嵌入式、无服务器的设计,其开源版本可以立即使用,并且具备可扩展性。
另一个知名的产品Chroma也提供了嵌入式选项,但它纯粹是基于内存的,并且仅在单台机器上运行,因此他们似乎更倾向于采用经过验证的客户端-服务器模型,将其托管在云上。Zilliz是一个将Milvus封装为无服务器版本的产品,它在云上的免费版本也提供了嵌入式数据库。然而,LanceDB是唯一一个默认构建为嵌入式的产品。 对于那些在本地和云存储中分布着大量数据的组织来说,嵌入式/无服务器的向量数据库在将数据层连接到应用层(用户与数据交互的层)时为开发人员提供了很大的自由和灵活性,特别是在涉及隐私和安全性的情况下。尽管许多供应商提供了完全托管的、在虚拟私有云(VPC)中部署的具有安全端点的云托管解决方案,但组织可能不愿将所有数据和向量计算迁移到云上。这对于那些拥有高度敏感数据并需要与非云原生的传统系统进行接口的大型组织来说尤为真实。在这些情况下,部署一个像LanceDB这样的嵌入式向量数据库在本地更容易,并且可以非常容易地将其连接到应用层。
成本考虑
提供云原生、托管解决方案的数据库通常根据存储的数据量和查询次数收费。对于拥有大量数据但不想支付传输和存储基础设施费用的组织来说,这是一个很好的模型。然而,对于已经拥有大型内部数据基础设施团队准备支持本地或嵌入式托管的组织来说,将数据发送到云上进行索引和查询几乎没有意义。 虽然很难定义一个组织规模的“临界点”,在这个点上可以做出这种区分,但重要的是要知道,标准的客户端-服务器数据库架构部署在云上,这是我们多年来一直使用的方式,并不是2023年的唯一选择。需要提出的问题:
-
我的数据集增长得足够快,需要在云上按需弹性扩展吗?
-
我是否有足够大的数据基础设施团队来支持本地或嵌入式托管?
-
我的数据集是否足够敏感,需要将其保留在本地?
-
对于完全托管的云托管解决方案,按查询和存储的数据量付费可能会有哪些成本考虑?
2. 专业供应商 vs. 传统供应商
许多组织已经投资于传统解决方案(如Elasticsearch、Meilisearch、MongoDB等)。这些解决方案并非专为向量搜索而构建,但它们在现有功能基础上添加了一些向量搜索能力。如果您希望在现有应用程序上添加向量/语义搜索功能,首先尝试使用现有数据库的向量搜索功能,并考虑这些解决方案的成本影响,然后再考虑其他选择是有意义的。 然而,传统供应商提供的向量搜索功能有一些限制。例如,Elasticsearch对可以使用其向量搜索功能的客户端有很多额外限制,并且可能需要专门的部署和许可条款才能访问其完整的工具套件。MongoDB仅为其Atlas云部署提供向量搜索,而不支持自托管解决方案。这些都是重要的考虑因素! 另一个需要记住的关键事实是:像Qdrant、Weaviate、LanceDB等专为向量数据库供应商已经花费了数千小时来优化其存储、索引和查询策略,以适应向量搜索。它们还有幸从头开始构建系统,通常使用现代编程语言如Go或Rust,因此设计用于大规模可扩展性和性能。几乎每个专为向量数据库的解决方案都提供Python或JavaScript客户端,因此很容易至少开始在自己的数据上进行测试,以做出更明智的决策。需要提出的问题:
-
我是否已经拥有现有的数据库可以用于向量搜索?
-
我是否可以在自己的数据上运行简单的基准测试,以比较传统解决方案和专为向量搜索构建的解决方案的性能?
-
这个解决方案是否能够随着数据的增长而扩展?
在许多情况下,现有的解决方案添加向量搜索功能的性能不会像专为向量数据库那样高效。这可以在比较pgvector/PostgreSQL和Qdrant的基准测试研究中清楚地看到。结果显示,pgvector在所有方面都比Qdrant慢得多,并且在底层提供的优化功能远远不如Qdrant。
3. 插入速度 vs. 查询速度
某些供应商(如Milvus/Zilliz)已经存在了相当长的时间,他们正在研究需要向量的大规模流式应用案例。在实时场景(如视频监控或金融交易跟踪)中,一次性插入和索引大量向量可能是至关重要的,而Milvus/Zilliz能够应对这个问题。 然而,对于大多数使用案例来说,插入速度真的那么重要吗?对于大多数组织来说,查询速度更为重要。这是因为插入和索引通常是不频繁进行的,但数据可能会被频繁查询,通常通过用户界面以实时的方式进行大规模查询。Qdrant是一个开源的、专为向量数据库的解决方案,使用Rust编写,专门针对这种使用案例进行了优化。由于它是用Rust编写的,它在索引方面表现出色,但正如在Qdrant自己的文档页面上展示的Qdrant演示所示,实际上可以在实时环境中实现语义搜索-随输入即时返回向量搜索结果,仅需几毫秒即可产生相关结果。需要提出的问题:
-
我将多频繁地插入(和索引)大量向量?
-
在查询时,我是否满足应用程序的延迟要求?
4. 召回率 vs. 延迟
召回率是查询返回的相关结果的百分比,而延迟是返回结果所花费的时间。不同的数据库供应商在优化召回率和延迟方面做出不同的权衡。正如在本系列的第三部分总结的那样:
-
一种索引是以原始形式存储向量,并用于精确的k最近邻搜索。它是最准确的,但也是最慢的。
-
IVF-Flat索引使用倒排文件索引来快速缩小搜索空间,比暴力搜索要快得多,但在召回率方面会牺牲一些准确性。
-
IVF-PQ将IVF与Product Quantization结合使用,对向量进行压缩,减少内存占用并加快搜索速度,同时在召回率方面比纯索引更好。
-
HNSW是目前最流行的索引方法,可以与Product Quantization结合使用,以提高召回率,同时相对于HNSW-PQIVF-PQ在内存效率上有所改进。
-
Vamana是一个相对较新的索引方法,专为磁盘性能进行了设计和优化-它承诺可以存储大于内存的向量数据,并且在性能上与HNSW相当快。
然而,由于磁盘性能的挑战,目前还没有很多数据库采用这种索引方法。在考虑所有这些权衡的同时,我们可以参考本系列早期的图片。
对于早期阶段的使用案例和概念验证(POCs),VF-PQ是有意义的,其中完美的相关性对应用程序的成功并不是至关重要的。然而,为了获得更好的质量和相关性,大多数专门的供应商使用HNSW索引。最近,像Weaviate和Qdrant这样的供应商已经开始将产品量化(PQ)与HNSW相结合,以提高处理非常大型数据集时的内存效率。需要提出的问题:
-
对于我的使用案例,搜索召回率有多重要?通常,通过对自己的数据和查询进行基准测试研究,可以帮助回答这个问题。
-
在我的使用案例中,延迟有多重要?如果数据集非常大,那么使用产品量化索引(如IVF-PQ或HNSW-PQ)来减少内存占用可能是有意义的。
5. 内存中 vs. 磁盘上的索引和向量存储
像Redis这样的数据库完全基于内存,速度非常快。然而,很可能您的使用案例需要存储大量大于内存的向量。为了在保持ANN搜索速度的同时扩展向量存储到非常大的数据,需要结合一些技巧。像Qdrant和Weaviate这样的数据库提供了使用内存映射文件存储向量的选项,利用页面缓存在磁盘上的虚拟地址空间,避免将整个数据加载到内存中。这有助于保持几乎与内存数据库相同的速度,而实际上并不将数据持久化到磁盘上。 从索引的角度来看,HNSW因其对内存需求较高而闻名。随着向量数据集越来越大,自然而然的问题是,它在超出内存的索引上的扩展性如何?如前一节所述,通过将PQ与HNSW结合使用,可以减少内存需求。Vamana是一种相对较新的索引方法,它是DiskANN算法的一部分,被认为是最有前景的方法之一(目前仅在LanceDB7和Milvus8中可用),据称在纯粹的磁盘上扩展到大于内存的索引时性能与HNSW相当。注意:在所有的数据库供应商中,LanceDB在这方面脱颖而出,因为它是唯一一个所有支持的索引都是基于磁盘的数据库。在响应向量查询时,只有来自索引文件的相关页面会从磁盘加载并缓存在内存中。这主要得益于LanceDB构建在Lance之上,Lance是一个新的开源列式向量存储,专为快速的磁盘向量检索进行了优化。 需要提出的问题:
-
如果我的数据集非常大,如何减少内存消耗?在这种情况下,减少存储的向量的维度、调整图连接的最大数量(如果使用HNSW),或者添加产品量化(如果您的数据库支持)都可以帮助减少内存消耗。
-
我的数据库是否有将向量存储在磁盘上的选项,如果有,它会如何影响查询速度?像往常一样,需要在自己的数据和使用案例上进行测试!
6. 稀疏向量存储 vs. 密集向量存储
由诸如BERT等模型生成的向量嵌入是密集的,意味着它们完全由非零浮点数组成。然而,也可以使用稀疏向量,计算每个文档的相对词频,其中大部分向量值为零。稀疏向量通常由BM25和SPLADE(Sparse Lexical AnD Expansion)等算法生成。Elasticsearch提供了自己的专有预训练稀疏模型,用于英语,称为ELSER(Elasticsearch Learned Sparse Encoder),大约有30,000个维度,但由于它是稀疏的,计算和存储成本比等长度的密集向量要低得多。 随着Transformer模型和许多其他模型的出现,从文档中生成密集向量变得更加容易(也更经济)。密集向量的主要优点是,由于来自Transformer的底层嵌入,它们比稀疏向量更好地压缩了语言的语义。然而,在索引时间上,它们的成本更高,这在处理非常大的数据集时是需要考虑的因素。需要提出的问题:
-
在我的使用案例中,语义搜索有多重要?如果非常重要,那么密集向量绝对是首选。
-
延迟和索引速度有多重要?如果这些是非常重要的约束条件,那么可能值得考虑稀疏向量(尽管从语义搜索的角度来看,它们永远无法与密集向量表现得一样好)。
7. 全文搜索 vs. 向量搜索混合策略
众所周知,向量搜索并非万能解决方案。我再次引用Colin Harman的博客文章9,他在其中指出了这个关键事实:不幸的是,对于企业级应用程序来说,纯向量搜索往往不是正确的解决方案。许多从业者都理解这一点,并经常将向量搜索作为信息检索系统的一部分使用。 这主要是因为向量搜索可能会将语义上相似的结果排在精确匹配之上,在许多使用情况下,我们可能希望精确匹配的得分高于语义上相似的匹配。此外,随着语言和术语的演变,“某些术语的含义”可能会发生变化,而这些变化可能无法很好地被底层嵌入所捕捉到。重新对向量搜索的结果进行排序,通常使用基于全文关键词的搜索得分,或通过组合索引策略(例如使用倒排索引和向量索引的组合)可以帮助提高结果的质量。Vespa是一个混合搜索引擎的良好示例,它提供了一个索引HNSW-IVF10。 选择全文搜索还是向量搜索混合策略取决于应用程序的需求和数据的特点。如果需要同时考虑关键词匹配和语义匹配,那么混合策略可能是更好的选择。通过重新排序来处理这种权衡的几种技术如下所述。
-
简单回退方法:这种方法使用“回退”策略,首先使用实现了BM25的解决方案(如Meilisearch或Elasticsearch)进行关键词搜索,然后将高延迟的向量搜索与关键词搜索结果进行线性组合。这是最简单的方法,但在相关性方面并不总是产生最佳结果。
-
倒数秩融合(RRF):这种方法将稀疏向量和密集向量获得的倒数秩相加,提供一个融合的排序分数。Elasticsearch和Weaviate11等数据库提供了使用多种RRF方法的混合搜索。
-
交叉编码器重新排序:这是用于混合分数重新排序的最先进的方法。它使用具有交叉编码损失函数的神经双编码器来融合稀疏/密集排序分数,通常产生最佳结果,但由于通过更昂贵的方法进行重新排序,会导致更高的延迟。这些解决方案通常不直接在向量数据库中提供,需要在向量数据库的下游构建自定义搜索引擎来执行重新排序。Nils Reimers是该库的创建者,现在在Cohere.ai工作,他在下面链接的Weaviate播客中详细描述了这些解决方案。
需要提出的问题:
-
我选择的数据库是否实现了可靠的混合搜索策略?还是我需要在向量数据库的下游手动构建一个解决方案?
-
重新排序策略对搜索延迟有何影响?
-
通过提高准确性(例如通过交叉编码器重新排序)来改进搜索结果时,我能够接受增加多少延迟?
8. 过滤策略
在搜索中,真实世界的查询很少是简单的文本查询,只要求特定的关键词。它们通常涉及对其他元数据属性进行过滤。以零售为例,考虑一个关于服装搜索(裤子、牛仔裤等)的例子,特定尺寸的过滤器如何应用于搜索结果可以对结果的质量产生巨大影响。 预过滤搜索:这种方法在执行向量搜索之前,天真地应用尺寸过滤器。虽然这听起来像是一种自然的尝试,但这可能导致HSNW图分解为不相交的连通分量(根据渗透理论12,定义了这种情况发生的阈值)。例如,如果用户正在寻找不在搜索目录中的尺码为28的“牛仔裤”,正确的做法至少是显示相似尺码的相关物品(如“裤子”)。但是,由于预过滤会强制删除所有不符合尺寸条件的术语,因此无法遍历完整的图形,从而错过相关结果。 后过滤搜索:这种方法返回与查询向量(“牛仔裤”)最近的邻居,并根据匹配的尺码对它们进行过滤,此操作在检索到所有“牛仔裤”结果之后进行。然而,这也存在一个问题 - 我们并不总是为每个查询获得相同数量的结果,如果过滤属性(即尺码28)在整个数据集中只占很小一部分,我们可能几乎没有获得任何结果! 自定义过滤搜索:许多数据库在预过滤和后过滤之间应用介于两者之间的方法 - 例如,Weaviate在HNSW索引分片旁边存储倒排索引分片,并使用倒排索引更有效地进行预过滤 - 从倒排索引中获取的“允许列表”是一个相当大的列表,然后通过考虑语义的HNSW索引更有效地搜索。Qdrant在预过滤和后过滤之间使用自己的过滤方法,在索引时通过在类别之间建立边缘来确保广泛条件下的连通HNSW图。注意:在向量搜索中,没有一种“一刀切”的过滤结果的解决方案。存在多种缓解策略,例如构建额外的IVF索引以使用关键词辅助搜索(如Weaviate),或在类别之间创建额外的HNSW图连接,在过滤过程中考虑搜索中的所有桶(如Qdrant)。这个领域在不断发展,高度相关的搜索和检索是一个极其困难的问题,因为需要在众多权衡之间进行选择。 需要提出的问题:
-
我选择的数据库如何处理预过滤和后过滤?
-
对于我将执行的查询类别,预过滤和后过滤策略在我的数据上的效果如何?请注意,以上内容是基于虚构的情景和名称,仅用于说明目的。
结论
哇!这段时间以来,我一直在深入思考向量数据库的内部工作原理。我在2023年的大部分时间里都在思考这个话题,并且经历了许多有趣的对话,与开发人员、首席执行官和其他正在尝试这些工具和技术的人交流过。 随着向量数据库在这个快速变化的领域不断发展,我认为这个系列的关键要点,至少对我来说,是没有一种“一刀切”的解决方案。选择向量数据库堆栈的最佳方法是首先了解您的用例的需求和约束,然后在自己的数据上测试不同的解决方案。根据我的经验,专为特定目的构建的解决方案是更优选的选择,因为它们具有更广泛的功能套件,能够实施最先进的解决方案,因为它们从零开始,并且它们还包含了许多现有供应商无法优先考虑的优化。展望未来,我对两个使用Rust构建的数据库特别感兴趣,它们分别是Qdrant和LanceDB,它们将成为我进行任何概念验证和实验的首选解决方案。它们以非常不同的方式进行创新,并且最重要的是,它们都以开发人员为中心的理念,拥有快速增长的社区。无论您喜欢哪个供应商,我都敦促您与我和其他人一起深入探索这些工具!🤓
作者:Prashanth Rao
更多技术干货请关注公众号“云原生数据库”
squids.cn,目前可体验全网zui低价RDS,免费的迁移工具DBMotion、SQL开发工具等。