什么是AI矢量数据库?

对于涉及大型语言模型、生成式人工智能和语义搜索的应用程序来说,高效的数据处理变得比以往任何时候都更加重要。

所有这些新应用程序都依赖于矢量嵌入(vector embeddings),这是一种数据表示形式,其中包含语义信息,这对于人工智能获得理解并维持在执行复杂任务时可以利用的长期记忆至关重要。

嵌入是由人工智能模型(如大型语言模型)产生的,有大量的属性或特征,使得它们的表示方法在管理上具有挑战性。在人工智能和机器学习的背景下,这些特征代表了数据的不同维度,对于理解模式、关系和基本结构至关重要。

这就是为什么我们需要一个专门为处理这种类型的数据而设计的专门数据库。

矢量数据库(Vector databases )通过为嵌入提供优化的存储和查询能力来满足这一要求。
矢量数据库具有传统数据库所没有的独立矢量/向量索引的能力,以及处理矢量/向量嵌入的专业性,而传统的基于标量的数据库缺乏这种能力。

处理矢量嵌入的挑战是,传统的基于标量的数据库无法跟上此类数据的复杂性和规模,从而难以提取洞察力和进行实时分析。这就是矢量数据库发挥作用的地方--它们被有意设计为处理这种类型的数据,并提供你需要的性能、可扩展性和灵活性,以充分利用你的数据。

有了矢量数据库,我们可以为我们的人工智能添加高级功能,如语义信息检索、长期记忆等。

矢量索引和矢量数据库之间有什么区别?
像FAISS(Facebook AI Similarity Search)这样的独立矢量索引可以大大改善矢量嵌入的搜索和检索,但它们缺乏任何数据库中存在的能力。另一方面,矢量数据库是专门为管理矢量嵌入而建立的,与使用独立的矢量索引相比,有几个优势:

  • 数据管理:矢量数据库为数据存储提供了众所周知且易于使用的功能,如插入、删除和更新数据。这使得管理和维护矢量数据比使用独立的矢量索引(如FAISS)更容易,后者需要额外的工作来与存储解决方案集成。
  • 元数据存储和过滤:矢量数据库可以存储与每个矢量条目相关的元数据。然后,用户可以使用额外的元数据过滤器查询数据库,以进行更细粒度的查询。
  • 可扩展性:矢量数据库的设计可以随着数据量和用户需求的增长而扩展,为分布式和并行处理提供更好的支持。独立的矢量索引可能需要定制解决方案,以实现类似的可扩展性水平(如在Kubernetes集群或其他类似系统上部署和管理它们)。
  • 实时更新:矢量数据库通常支持实时数据更新,允许数据的动态变化,而独立的矢量索引可能需要一个完整的重新索引过程,以纳入新的数据,这可能是耗时和计算成本。
  • 备份和收集:矢量数据库处理备份数据库中存储的所有数据的常规操作。
  • 生态系统整合:矢量数据库可以更容易地与数据处理生态系统的其他组件集成,如ETL管道(如Spark)、分析工具(如Tableau和Segment)和可视化平台(如Grafana)--简化数据管理工作流程。它还能与其他人工智能相关工具轻松整合,如LangChain、LlamaIndex和ChatGPT的插件。
  • 数据安全和访问控制:矢量数据库通常提供内置的数据安全功能和访问控制机制,以保护敏感信息,这可能是独立的矢量索引解决方案所不具备的。

简而言之,矢量数据库为处理矢量嵌入提供了一个卓越的解决方案,它解决了独立的矢量索引的局限性,如可扩展性挑战、繁琐的整合过程,以及缺乏实时更新和内置安全措施,确保了更有效和简化的数据管理体验。

矢量数据库是如何工作的?
我们都知道传统数据库是如何工作的(或多或少)--它们在行和列中存储字符串、数字和其他类型的标量数据。另一方面,矢量数据库对矢量进行操作,所以它的优化和查询方式有很大不同。

在传统数据库中,我们通常是查询数据库中的行,其中的值通常与我们的查询完全匹配。在矢量数据库中,我们应用一个相似度指标来找到与我们的查询最相似的矢量。

矢量数据库使用不同算法的组合,这些算法都参与了近似近邻(ANN)搜索。这些算法通过散列、量化或基于图形的搜索来优化搜索。

这些算法被组装成一个管道,提供快速和准确地检索被查询矢量的邻居。由于矢量数据库提供了近似的结果,我们考虑的主要权衡是准确性和速度之间的关系。结果越准确,查询的速度就越慢。

然而,一个好的系统可以提供超快的搜索和近乎完美的准确性。

下面是一个矢量数据库的常见部件:

  • 编制索引:矢量数据库使用PQ、LSH或HNSW等算法对矢量进行索引(下文有更多介绍)。这一步将矢量映射到一个数据结构中,以实现更快的搜索。
  • 查询:矢量数据库将索引的查询矢量与数据集中的索引矢量进行比较,以找到最近的邻居(应用该索引所使用的相似度量)。
  • 后期处理:在某些情况下,矢量数据库从数据集中检索出最终的近邻,并对其进行后处理以返回最终结果。这一步可以包括使用不同的相似性度量对最近的邻居进行重新排序。


算法
有几种算法可以促进矢量索引的创建。它们的共同目标是通过创建一个可以快速遍历的数据结构来实现快速查询。它们通常会将原始矢量的表示方法转化为压缩的形式,以优化查询过程。

下面的章节将探讨几种算法及其处理矢量嵌入的独特方法。

随机投影
随机投影的基本思想是使用随机投影矩阵将高维矢量投影到低维空间。我们创建一个随机数的矩阵。矩阵的大小将是我们想要的目标低维值。然后,我们计算输入矢量和矩阵的点积,这将产生一个投影矩阵,其维数比我们的原始矢量少,但仍然保留了它们的相似性。

当我们查询时,我们使用相同的投影矩阵将查询矢量投影到低维空间。然后,我们将投影的查询矢量与数据库中的投影矢量进行比较,找到最近的邻居。由于数据的维度降低了,搜索过程明显比搜索整个高维空间要快。

只要记住,随机投影是一种近似的方法,投影的质量取决于投影矩阵的属性。一般来说,投影矩阵的随机性越大,投影的质量就越好。但是,生成一个真正的随机投影矩阵在计算上是很昂贵的,特别是对于大型数据集。

产品量化
另一种建立索引的方法是乘积量化(PQ),这是一种针对高维矢量(如矢量嵌入)的有损压缩技术。它将原始矢量分解成更小的块,通过为每个块创建一个有代表性的 "代码 "来简化每个块的表示,然后将所有的块重新放在一起--而不会丢失对相似性操作至关重要的信息。PQ的过程可以分解为四个步骤:分割、训练、编码和查询。

  • 分割--矢量被分割成段。
  • 训练--我们为每个分段建立一个 "编码本"。简单地说--该算法产生了一个潜在的 "编码 "库,可以分配给一个矢量。在实践中--这个 "编码本 "是由通过对矢量的每个分段进行k-means聚类而产生的聚类中心点组成的。我们将在段编码簿中拥有与我们用于k-means聚类的值相同的数量。
  • 编码--该算法为每个段分配了一个特定的编码。在实践中,我们在训练完成后,在编码簿中找到与每个矢量段最接近的值。我们对该段的PQ代码将是编码库中相应数值的标识符。我们可以使用任意多的PQ代码,这意味着我们可以从编码库中挑选多个值来代表每个段。
  • 查询--当我们查询时,算法将矢量分解为子矢量,并使用相同的编码本对其进行量化。然后,它使用索引编码来寻找与查询矢量最近的矢量。

位置敏感散列
位置敏感散列(LSH)是一种在近似近邻搜索的背景下进行索引的技术。它对速度进行了优化,同时仍然提供一个近似的、非穷举的结果。LSH使用一组散列函数将相似的向量映射到 "桶 "中。

为了找到一个给定查询矢量的最近邻居,我们使用相同的散列函数,用于将类似的矢量 "打包 "到散列表中。查询矢量被散列到一个特定的表中,然后与同一表中的其他矢量进行比较,找出最接近的匹配。这种方法比搜索整个数据集要快得多,因为每个哈希表中的矢量远远少于整个空间中的矢量。

重要的是要记住,LSH是一种近似的方法,而近似的质量取决于哈希函数的属性。一般来说,使用的哈希函数越多,近似的质量就越好。然而,使用大量的哈希函数在计算上是很昂贵的,对于大型数据集来说可能不可行。

分层可导航小世界(HNSW)
HNSW创建了一个分层的树状结构,树上的每个节点代表一组矢量。节点之间的边代表矢量之间的相似性。该算法首先创建一组节点,每个节点有少量的矢量。这可以随机进行,也可以通过k-means等算法对矢量进行聚类,其中每个聚类成为一个节点。


相似性措施
在前面讨论的算法的基础上,我们需要了解相似性措施在矢量数据库中的作用。这些措施是矢量数据库如何比较和识别与给定查询最相关的结果的基础。

相似性度量是确定两个矢量在一个矢量空间中的相似程度的数学方法。相似性度量在矢量数据库中被用来比较存储在数据库中的矢量,并找到与给定查询矢量最相似的矢量。

可以使用几种相似性度量,包括:

  • 余弦相似度:测量矢量空间中两个矢量之间的角度的余弦。它的范围是-1到1,其中1代表相同的矢量,0代表正交的矢量,而-1代表截然相反的矢量。
  • 欧几里得距离:测量矢量空间中两个矢量之间的直线距离。它的范围从0到无穷大,其中0代表相同的矢量,较大的数值代表越来越不相似的矢量。
  • 点积:测量两个矢量的大小与它们之间角度的余弦的乘积。它的范围从-∞到∞,正值代表指向同一方向的矢量,0代表正交矢量,负值代表指向相反方向的矢量。

筛选
存储在数据库中的每个矢量也包括元数据。除了能够查询类似的矢量外,矢量数据库还可以根据元数据查询来过滤结果。为了做到这一点,矢量数据库通常维护两个索引:一个矢量索引和一个元数据索引。然后,它在矢量搜索本身之前或之后执行元数据过滤

过滤过程可以在矢量搜索本身之前或之后进行,但每种方法都有其自身的挑战,可能会影响查询性能:

  • 预过滤:在这种方法中,元数据过滤是在矢量搜索之前进行的。虽然这有助于减少搜索空间,但它也可能导致系统忽略那些不符合元数据过滤标准的相关结果。此外,由于增加了计算开销,大量的元数据过滤可能会减慢查询过程。
  • 后期过滤:在这种方法中,元数据过滤是在矢量搜索之后进行的。这有助于确保所有相关的结果都被考虑在内,但是它也可能引入额外的开销并减慢查询过程,因为不相关的结果需要在搜索完成后被过滤掉。


数据库操作
与矢量索引不同,矢量数据库配备了一系列能力,使其更有资格用于大规模的生产环境中。让我们来看看操作数据库所涉及的组件的总体概况。

性能和容错性
性能和容错性是紧密相连的。我们拥有的数据越多,需要的节点就越多--出现错误和故障的机会也就越大。就像其他类型的数据库一样,我们要确保即使一些底层节点发生故障,也能尽快执行查询。这可能是由于硬件故障、网络故障或其他类型的技术错误。这种故障可能导致停机,甚至是不正确的查询结果。

为了确保高性能和容错性,矢量数据库使用分片和复制的方式适用于以下情况:

分片--将数据分割到多个节点上。有不同的方法对数据进行分区--例如,可以通过不同数据簇的相似性进行分区,以便将相似的矢量存储在同一个分区中。当进行查询时,它被发送到所有的分片上,结果被检索和合并。这被称为 "分散收集 "模式。

复制 - 在不同的节点上创建数据的多个副本。这确保了即使某个节点发生故障,其他节点也能替代它。有两种主要的一致性模式:最终一致性和强

一致性。最终一致性允许数据的不同副本之间存在暂时的不一致,这将提高可用性并减少延迟,但可能导致冲突甚至数据丢失。另一方面,强一致性要求所有的数据副本在写操作被认为完成之前都要更新。这种方法提供了更强的一致性,但可能会导致更高的延迟。
监测

为了有效地管理和维护一个矢量数据库,我们需要一个强大的监控系统来跟踪数据库的性能、健康和整体状态等重要方面。监控对于检测潜在的问题、优化性能和确保顺利的生产运营至关重要。监测矢量数据库的一些方面包括以下内容:

资源使用情况 - 监测资源使用情况,如CPU、内存、磁盘空间和网络活动,能够识别可能影响数据库性能的潜在问题或资源限制。
查询性能--查询延迟、吞吐量和错误率可能表明需要解决的潜在系统性问题。

系统健康 - 整体系统健康监测包括单个节点、复制过程和其他关键组件的状态。

访问控制
访问控制是管理和调节用户访问数据和资源的过程。它是数据安全的一个重要组成部分,确保只有授权用户才有能力查看、修改或与存储在矢量数据库中的敏感数据互动。

访问控制之所以重要,有几个原因:

  • 数据保护:由于人工智能应用程序经常处理敏感和机密信息,实施严格的访问控制机制有助于保护数据免受未经授权的访问和潜在的破坏。
  • 合规性:许多行业,如医疗保健和金融,都受到严格的数据隐私法规的约束。实施适当的访问控制有助于组织遵守这些法规,保护他们免受法律和财务影响。
  • 问责制和审计:访问控制机制使企业能够保持矢量数据库内用户活动的记录。这些信息对于审计来说是至关重要的,当安全漏洞发生时,它有助于追溯任何未经授权的访问或修改。
  • 可扩展性和灵活性:随着组织的成长和发展,他们的访问控制需求可能会改变。一个强大的访问控制系统允许无缝修改和扩展用户权限,确保数据安全在整个组织的增长中保持不变。

备份和收集
当其他一切都失败时,矢量数据库提供了依靠定期创建的备份的能力。这些备份可以存储在外部存储系统或基于云的存储服务中,确保数据的安全性和可恢复性。在数据丢失或损坏的情况下,这些备份可以用来将数据库恢复到以前的状态,最大限度地减少停机时间和对整个系统的影响。

API和SDK
这就是橡胶与道路的结合点:与数据库互动的开发者希望通过一个易于使用的API,使用一个熟悉和舒适的工具集。通过提供一个用户友好的界面,矢量数据库API层简化了高性能矢量搜索应用程序的开发。

除了API之外,矢量数据库通常会提供包裹API的特定编程语言的SDK。这些SDK使开发者更容易获得更多的信息。