什么是向量数据库及其工作原理和使用场景
推荐超级课程:
@TOC
什么是向量数据库?
向量数据库用于索引和存储向量嵌入,以便快速检索和相似性搜索,具备CRUD操作、元数据过滤、水平扩展和无服务器等能力。
我们正处于AI革命之中。它正在颠覆其所触及的任何行业,带来巨大的创新——但同时也带来了新的挑战。对于涉及大型语言模型、生成型AI和语义搜索的应用程序而言,高效的数据处理比以往任何时候都更为关键。
所有这些新应用程序都依赖于[向量嵌入],这是一种向量数据表示形式,其中包含了AI获得理解并维持长期记忆以在执行复杂任务时参考的语义信息。
嵌入向量由AI模型(如大型语言模型)生成,具有许多属性或特征,使得其表示形式难以管理。在AI和机器学习的背景下,这些特征代表了数据的不同维度,对于理解模式、关系和底层结构至关重要。
因此,我们需要专门为处理这种数据类型设计的数据库。向量数据库具有传统数据库的功能,这些功能在独立的向量索引中是不存在的,并且它们专门处理向量嵌入,这是传统基于标量的数据库所缺乏的。
处理向量数据的挑战在于,传统的基于标量的数据库无法跟上这种数据的复杂性和规模,使得提取洞察和执行实时分析变得困难。这时,向量数据库就派上用场了——它们是专门设计来处理这类数据的,并提供了所需的性能、可扩展性和灵活性,以充分利用您的数据。
我们正在看到下一代向量数据库引入更复杂的架构来高效地处理智能的成本和扩展。这种能力由无服务器向量数据库处理,可以将存储和计算的成本分开,以实现AI的低成本知识支持。
使用向量数据库,我们可以向AI添加知识,如语义信息检索、长期记忆等。下图更清楚地展示了向量数据库在此类应用中的作用:
让我们来分解一下:
- 首先,我们使用[嵌入模型]为我们想要索引的内容创建向量嵌入。
- 向量嵌入被插入到向量数据库中,其中包含一些对原始内容的引用,嵌入就是从这些原始内容创建的。
- 当应用程序发出查询时,我们使用相同的嵌入模型为查询创建嵌入,并使用这些嵌入来查询数据库中相似的向量嵌入。如前所述,这些相似的嵌入与用于创建它们的原始内容相关联。
向量索引和向量数据库之间的区别是什么?
向量数据库是专门为管理向量嵌入而构建的,与使用独立向量索引相比具有以下优势:
- 数据管理:向量数据库为数据存储提供了众所周知且易于使用的功能,如插入、删除和更新数据。
- 元数据存储和过滤:向量数据库可以存储与每个向量条目关联的元数据。用户可以使用额外的元数据过滤器进行更精细的查询。
- 可扩展性:向量数据库旨在随数据量和用户需求的增长而扩展,为分布式和并行处理提供更好的支持。独立的向量索引可能需要定制解决方案以达到相似的可扩展性(例如,在Kubernetes集群或其他类似系统上部署和管理它们)。现代向量数据库还使用无服务器架构来优化大规模的成本。
- 实时更新:向量数据库通常支持实时数据更新,允许对数据进行动态更改以保持结果的新鲜度,而独立的向量索引可能需要通过完整的重新索引过程来整合新数据,这可能既耗时又计算成本高昂。高级向量数据库可以在保持新鲜度的同时,通过索引重建来使用性能升级。
- 备份和集合:向量数据库负责备份存储在数据库中的所有数据的常规操作。
- 生态系统集成:向量数据库可以更容易地与数据处理生态系统的其他组件集成,如ETL管道(如Spark)、分析工具(如Tableau 和Segment )以及可视化平台(如Grafana )——简化数据管理流程。它还使得与其他AI相关工具如LangChain 、LlamaIndex 、Cohere 等轻松集成。
- 数据安全和访问控制:向量数据库通常提供内置的数据安全功能和访问控制机制来保护敏感信息,这在独立的向量索引解决方案中可能不可用。通过命名空间的多租户允许用户完全划分他们的索引,甚至在自己的索引中创建完全隔离的分区。
简而言之,向量数据库通过解决独立向量索引的局限性,如可扩展性挑战、笨重的集成过程以及缺乏实时更新和内置安全措施,为处理向量嵌入提供了优越的解决方案,确保了更有效和流畅的数据管理体验。
向量数据库是如何工作的?
我们都知道传统数据库是如何工作的(或多或少)——它们将字符串、数字和其他类型的标量数据存储在行和列中。另一方面,向量数据库操作的是向量,因此它的优化和查询方式大不相同。
在传统数据库中,我们通常查询数据库中的行,其中的值通常与我们的查询完全匹配。在向量数据库中,我们应用相似度度量来找到与我们的查询最相似的向量。
向量数据库使用不同的算法组合来进行近似最近邻(ANN)搜索。这些算法通过散列、量化和基于图的搜索来优化搜索过程。
这些算法被组装成一个管道,提供对查询向量的邻居的快速和准确检索。由于向量数据库提供近似结果,我们主要考虑的是准确性和速度之间的权衡。结果越准确,查询速度就越慢。然而,一个好的系统可以提供近乎完美的准确性的超快速搜索。
以下是向量数据库的常见管道:
- 索引:向量数据库使用诸如PQ、LSH或HNSW之类的算法对向量进行索引(下面将详细介绍这些算法)。这一步将向量映射到一种数据结构,以实现更快的搜索。
- 查询:向量数据库将索引的查询向量与数据集中的索引向量进行比较,以找到最近的邻居(应用该索引使用的相似度度量)
- 后处理:在某些情况下,向量数据库从数据集中检索最终的最近邻居,并对其进行后处理以返回最终结果。这一步骤可以包括使用不同的相似度度量重新排名最近邻居。
无服务器向量数据库
无服务器代表了向量数据库的下一代进化。上述架构使我们得到了一个准确、快速、可扩展的向量数据库架构,但成本高昂。这就是我们在第一代向量数据库中看到的情况。随着AI用例的增加,成本和弹性变得越来越重要,因此需要第二代无服务器向量数据库。
第一代向量数据库有三个关键痛点,无服务器向量数据库可以解决这些问题:
- 存储与计算的分离:为了优化成本,应在需要时才使用计算资源。这意味着将索引存储与查询解耦,并且只搜索所需的内容——当涉及延迟时,这变得愈发困难。
- 多租户:处理索引中的命名空间,以确保不经常查询的命名空间不会增加成本。
- 新鲜度:向量数据库需要提供新鲜数据,即在新数据插入几秒钟内,数据即可被查询。注意,对于Pinecone的无服务器架构,在插入大量数据时,新鲜度可能会延迟。
为了实现存储与计算的分离,高度复杂的几何分区算法可以将索引分解为子索引,使我们能够专注于特定分区的搜索:
搜索空间的分区
通过这些分区,查询的搜索空间可以仅关注向量索引的几个部分,而不是整个搜索空间。典型的搜索行为将显示某些分区比其他分区更频繁地被访问,这使我们能够在计算成本和冷启动时间之间进行调整,以找到成本和延迟之间的最佳平衡。
当我们进行这种分区时,我们解决了计算与存储分离的问题。然而,几何分区在索引构建时是一个较慢的过程。这意味着我们必须等待新数据正确存储在索引中,这可能会导致新鲜度问题。
为了解决这个问题,向量数据库需要另一个独立的层,称为新鲜度层。新鲜度层充当可以查询的向量的临时“缓存”。同时,我们等待索引构建器将新向量放入几何分区索引中。
在这个过程中,查询路由器可以将查询发送到索引和新鲜度层。然而,值得注意的是,新鲜度层存在于计算实例中,所以我们不能在那里存储完整的索引。相反,我们等待新向量被插入索引中——一旦完成,它们就会从新鲜度层中移除。
最后,还有多租户问题。许多第一代向量数据库已经处理了多租户问题,并且长期以来都是如此。然而,在无服务器架构中,多租户更为复杂。
我们必须避免将不同类型的用户放在同一硬件上,以保持低成本和低延迟。如果我们有用户A,几乎每天在相同硬件上每秒进行20次查询,而用户B每月进行20次查询,用户B将被迫在计算硬件上24/7,因为这是用户A所需的持续低延迟所必需的。
为了解决这个问题,向量数据库必须能够识别使用习惯相似的用户,并在保持他们之间完全分离的同时将他们放置在一起。这可以基于用户使用指标和基于使用的热/冷基础设施的自动分配来完成。
将第一代向量数据库与存储与计算分离、多租户和新鲜度相结合,我们得到了新一代的现代向量数据库。这种架构(与向量数据库基础相结合)是现代AI堆栈的首选。
在以下部分,我们将讨论一些向量数据库基础背后的算法,并解释它们如何为我们的数据库的整体性能做出贡献。
算法
几种算法可以促进向量索引的创建。它们的共同目标是创建一个可以快速遍历的数据结构,以实现快速查询。它们通常会将以原始向量的表示转换为压缩形式,以优化查询过程。
随机投影
随机投影的基本思想是使用随机投影矩阵将高维向量投影到低维空间。我们创建一个随机数矩阵。矩阵的大小将是我们想要的低维目标值。然后我们计算输入向量和该矩阵的点积,得到一个投影矩阵,其维度比原始向量少,但仍然保留了它们的相似性。
当我们进行查询时,我们使用相同的投影矩阵将查询向量投影到低维空间。然后,我们将投影的查询向量与数据库中的投影向量进行比较,以找到最近的邻居。由于数据的维度降低,搜索过程比在整个高维空间中搜索要快得多。
请记住,随机投影是一种近似方法,投影质量取决于投影矩阵的性质。一般来说,投影矩阵越随机,投影的质量就越好。但是,生成一个真正的随机投影矩阵在计算上可能是昂贵的,特别是对于大型数据集。
产品量化
建立索引的另一种方法是产品量化(PQ),这是一种针对高维向量(如向量嵌入)的有损压缩技术。它将原始向量分割成更小的块,通过为每个块创建一个代表性的“代码”来简化每个块的表现形式,然后将所有块重新组合在一起——在此过程中不丢失对相似性操作至关重要的信息。PQ的过程可以分为四个步骤:分割、训练、编码和查询。
- 分割 - 将向量分解为多个段。
- 训练 - 为每个段构建一个“代码本”。简单来说,算法生成一组可能的“代码”,可以分配给一个向量。实际上,这个“代码本”是由执行k-means聚类在每个向量段上创建的簇的中心点组成的。我们在段代码本中的值数量将与用于k-means聚类的值数量相同。
- 编码 - 算法为每个段分配一个特定的代码。实际上,我们在训练完成后找到每个向量段在代码本中的最近值。我们的PQ代码段将是代码本中相应值的标识符。我们可以使用尽可能多的PQ代码,这意味着我们可以从代码本中选择多个值来表示每个段。
- 查询 - 当我们查询时,算法将向量分解为子向量,并使用相同的代码本进行量化。然后,它使用索引代码找到查询向量的最近向量。
代码本中的代表性向量数量是表征准确性和搜索代码本的计算成本之间的权衡。代码本中的代表性向量越多,向量在子空间中的表示就越准确,但搜索代码本的计算成本就越高。相反,代码本中的代表性向量越少,表征的准确性就越低,但搜索代码本的计算成本就越低。
局部敏感哈希
局部敏感哈希(LSH)是一种在近似最近邻搜索上下文中进行索引的技术。它优化了速度,同时仍然提供近似、非穷尽的搜索结果。LSH使用一组哈希函数将相似向量映射到“桶”中,如下所示:
重要的是要记住,局部敏感哈希(LSH)是一种近似方法,其近似质量取决于哈希函数的性质。通常,使用的哈希函数越多,近似质量就越好。然而,使用大量哈希函数在计算上可能非常昂贵,并且对于大型数据集可能不可行。
分层可导航小世界(HNSW)
HNSW创建了一个分层的、树状的结构,其中树的每个节点代表一组向量。节点之间的边表示向量之间的相似性。算法首先创建一组节点,每个节点包含少量向量。这可以通过随机方式完成,或者使用像k-means这样的算法对向量进行聚类,每个簇成为一个节点。
然后算法检查每个节点的向量,并在该节点与其具有最相似向量的节点之间画一条边。
当我们查询HNSW索引时,它使用这个图通过树进行导航,访问最有可能包含与查询向量最接近的向量的节点。
相似性度量
在之前讨论的算法基础上,我们需要了解相似性度量在向量数据库中的作用。这些度量是向量数据库比较和识别给定查询最相关结果的基础。
相似性度量是在向量空间中确定两个向量相似性的数学方法。在向量数据库中,相似性度量用于比较数据库中存储的向量,并找到与给定查询向量最相似的向量。
可以使用几种相似性度量,包括:
- **余弦相似性:**测量向量空间中两个向量之间的角度的余弦值。它的范围从-1到1,其中1表示相同的向量,0表示正交的向量,而-1表示完全相反的向量。
- **欧几里得距离:**测量向量空间中两个向量之间的直线距离。它的范围从0到无穷大,其中0表示相同的向量,而更大的值表示越来越不相似的向量。
- **点积:**测量两个向量的大小和它们之间角度的余弦的乘积。它的范围从-∞到∞,其中正值表示指向同一方向的向量,0表示正交向量,而负值表示指向相反方向的向量。
相似性度量的选择将影响从向量数据库获得的结果。还值得注意的是,每种相似性度量都有其自身的优缺点,根据用例和要求选择正确的一种非常重要。
过滤
数据库中存储的每个向量都包含元数据。除了查询相似向量的能力外,向量数据库还可以基于元数据查询对结果进行过滤。为此,向量数据库通常维护两个索引:一个向量索引和一个元数据索引。然后它可以在向量搜索之前或之后执行元数据过滤,但无论哪种情况,都有一些困难会导致查询过程变慢。
过滤过程可以在向量搜索本身之前或之后执行,但每种方法都有其自身的挑战,可能会影响查询性能:
- **预过滤:**在这种方法中,元数据过滤在向量搜索之前进行。虽然这有助于减少搜索空间,但也可能导致系统忽略不符合元数据过滤条件的相关结果。此外,广泛的元数据过滤可能会由于增加的计算开销而减慢查询过程。
- **后过滤:**在这种方法中,元数据过滤在向量搜索之后进行。这有助于确保所有相关结果都被考虑,但这也可能引入额外的开销并减慢查询过程,因为需要在搜索完成后过滤掉不相关结果。
为了优化过滤过程,向量数据库使用了各种技术,例如利用高级索引方法对元数据进行处理,或者使用并行处理来加速过滤任务。在向量数据库中,平衡搜索性能和过滤准确性的权衡对于提供高效且相关的查询结果至关重要。
数据库操作
与向量索引不同,向量数据库具备一系列功能,使其更适合用于大规模生产环境。
性能和容错性
性能和容错性紧密相关。数据越多,所需的节点就越多,出现错误和故障的概率也就越大。与其他类型的数据库一样,我们希望即使部分底层节点失败,查询也能尽可能快地执行。这可能是由于硬件故障、网络故障或其他类型的技术问题。这种故障可能导致停机甚至查询结果不正确。
为了确保高性能和容错性,向量数据库使用分片和复制,具体如下:
- 分片 - 将数据跨多个节点分区。数据分区有不同的方法,例如可以按照数据不同簇的相似性进行分区,使得相似向量存储在同一分区中。当进行查询时,查询会被发送到所有分片,然后检索并合并结果。这被称为“分散-聚集”模式。
- 复制 - 在不同节点上创建数据的多个副本。这确保了即使特定节点失败,其他节点也能够替代它。主要有两种一致性模型:最终一致性和强一致性。最终一致性允许不同数据副本之间暂时存在不一致,这将提高可用性并减少延迟,但可能导致冲突甚至数据丢失。另一方面,强一致性要求在写入操作被认为完成之前更新所有数据副本。这种方法提供更强的一致性,但可能导致更高的延迟。
监控
为了有效管理和维护向量数据库,我们需要一个健壮的监控系统,跟踪数据库性能、健康和整体状态的重要方面。监控对于检测潜在问题、优化性能和确保平稳生产操作至关重要。监控向量数据库的一些方面包括以下内容:
- 资源使用 - 监控资源使用情况,如CPU、内存、磁盘空间和网络活动,有助于识别可能影响数据库性能的潜在问题或资源限制。
- 查询性能 - 查询延迟、吞吐量和错误率可能表明需要解决的潜在系统问题。
- 系统健康 - 整体系统健康监控包括单个节点的状态、复制过程和其他关键组件。
访问控制
访问控制是管理和规范用户对数据和资源访问的过程。它是数据安全的重要组成部分,确保只有授权用户能够查看、修改或与存储在向量数据库中的敏感数据进行交互。
访问控制的重要性体现在以下几个方面:
- **数据保护:**由于AI应用程序经常处理敏感和机密信息,实施严格的访问控制机制有助于保护数据免受未授权访问和潜在的数据泄露。
- **合规性:**许多行业,如医疗保健和金融行业,都受到严格的数据隐私法规的约束。实施适当的访问控制有助于组织遵守这些法规,保护它们免受法律和财务上的后果。
- **责任与审计:**访问控制机制使组织能够记录用户在向量数据库中的活动。这些信息对于审计目的至关重要,在发生安全漏洞时,有助于追溯任何未经授权的访问或修改。
- **可扩展性与灵活性:**随着组织的成长和演变,它们的访问控制需求可能会发生变化。一个健壮的访问控制系统允许无缝修改和扩展用户权限,确保在整个组织成长过程中数据安全得以保持。
备份与集合
当其他一切手段失效时,向量数据库提供了依赖定期创建的备份的能力。这些备份可以存储在外部存储系统或基于云的存储服务上,确保数据的安全性和可恢复性。在数据丢失或损坏的情况下,可以使用这些备份将数据库恢复到之前的状态,从而最小化停机时间和对整个系统的影响。使用Pinecone,用户可以选择备份特定的索引,并将它们保存为“集合”,这些集合后来可以用来填充新的索引。
API和SDK
这是真正考验实力的地方:与数据库交互的开发者希望使用易于使用的API,使用熟悉的工具集。通过提供用户友好的界面,向量数据库API层简化了高性能向量搜索应用程序的开发。
除了API,向量数据库通常会提供特定编程语言的SDK,这些SDK封装了API。SDK使开发者更容易在他们的应用程序中与数据库交互。这允许开发者专注于他们的特定用例,例如语义文本搜索、生成式问答、混合搜索、图像相似性搜索或产品推荐,而无需担心底层基础设施的复杂性。
总结
在NLP、计算机视觉和其他AI应用领域,向量嵌入的指数级增长导致了向量数据库的出现,作为计算引擎,它允许我们有效地在应用程序中与向量嵌入交互。
向量数据库是专门构建的数据库,专门用于解决在生产场景中管理向量嵌入时出现的问题。因此,它们相较于传统的基于标量的数据库和独立的向量索引具有显著优势。
在这篇文章中,我们回顾了向量数据库的关键方面,包括它的工作原理、使用的算法以及使其在生产场景中操作就绪的附加功能。希望这能帮助您理解向量数据库的内部运作。