目录
· 1. 简介
· 2. 矢量数据库 Vs. 其他数据库
· 3. 矢量数据库 Vs. 矢量索引
· 4. 流行的矢量数据库
∘ 4.1. 矢量数据库如何工作?
· 5. 索引技术
· 6. 精确匹配
∘ 6.1. 平面索引
· 7. 近似匹配
∘ 7.1. Annoy近似最近邻
∘ 7.2. 倒排文件(IVF)索引
∘ 7.3. 随机投影(RP)
∘ 7.4. 乘积量化(PQ)
∘ 7.5. 局部敏感哈希(LSH)
∘ 7.6. 分层可导航小世界(HNSW)
∘ 7.7.基于密度的噪声空间聚类 (DBSCAN)
· 8. 相似性度量:距离度量
∘ 8.1. 如何选择相似性度量
· 9. 过滤
· 10. 选择矢量数据库
∘ 10.1. 比较参数
·结论
1. 简介
在之前的博客中,我们已经介绍了如何将原始数据嵌入到向量中。为了重复使用嵌入的信息,我们需要存储嵌入,以便可以按需访问它们。为此,我们使用一种特殊的数据库,称为矢量数据库。
对于使用检索增强生成 (RAG) 的大规模应用程序而言,高效存储和检索嵌入(具有 CRUD 操作、元数据过滤和水平扩展等功能)至关重要。ChromaDB、Pinecone 和 Weaviate 等矢量数据库专门从事此工作,可提供快速检索和相似性搜索。
集成正确的矢量数据库对于最大限度地提高 RAG 性能至关重要。考虑到用例的复杂性,经过深思熟虑的选择可确保无缝存储和检索,从而优化检索增强生成模型的功能。
在这篇博客中,我们将深入研究矢量数据库和索引方法。
2. 矢量数据库与其他数据库
3. 矢量数据库与矢量索引
在科技行业,一种普遍的误解认为矢量数据库只是近似最近邻 (ANN) 搜索算法的包装器。
从本质上讲,向量数据库是非结构化数据的综合解决方案。与这种误解相反,它包含了当今结构化/半结构化数据库管理系统中发现的用户友好功能,包括云原生、多租户和可扩展性。它解决了独立向量索引的局限性,解决了可扩展性挑战、集成复杂性以及缺乏实时更新和内置安全措施的问题。随着我们深入研究本教程,这一点变得显而易见。
另一方面,轻量级 ANN 库(如FAISS和ScaNN)可用作构建向量索引的工具。这些库旨在加速多维向量的最近邻搜索。虽然适用于生产系统中的小型数据集,但随着数据集的增长,可扩展性成为一项挑战。
4. 流行的矢量数据库
4.1. 矢量数据库如何工作?
我们知道传统数据库是以行和列的形式存储字符串、数字等标量数据,而向量数据库是针对向量进行操作的,因此优化和查询的方式有很大不同。
在传统数据库中,我们通常会查询数据库中的值与查询完全匹配的行。在向量数据库中,我们应用相似度度量来查找与查询最相似的向量。
矢量数据库使用多种算法的组合,这些算法均参与近似最近邻 (ANN) 搜索。这些算法通过各种索引技术优化搜索。
这些算法被组装成一个管道,可以快速准确地检索查询向量的邻居。由于向量数据库提供近似结果,因此我们考虑的主要权衡是准确性和速度。结果越准确,查询速度就越慢。但是,一个好的系统可以提供超快的搜索和近乎完美的准确性。
以下是矢量数据库的常见流程:
- 索引:向量数据库使用 PQ、LSH 或 HNSW 等算法对向量进行索引(更多信息见下文)。此步骤将向量映射到可实现更快搜索的数据结构。
- 查询:向量数据库将索引查询向量与数据集中的索引向量进行比较,以找到最近的邻居(应用该索引使用的相似度度量)
- 后处理:在某些情况下,矢量数据库从数据集中检索最终的最近邻居,并对其进行后处理以返回最终结果。此步骤可以包括使用不同的相似性度量对最近邻居重新排序。
在以下章节中,我们将更详细地讨论每种算法,并解释它们如何有助于提高矢量数据库的整体性能。
5.索引技术
基于树的方法对于低维数据非常有效,并且提供精确的最近邻搜索。然而,由于“维数灾难”,它们的性能在高维空间中通常会下降。它们还需要大量内存,并且对于大型数据集效率较低,从而导致更长的构建时间和更高的延迟。
量化方法节省内存,并且通过将向量压缩为紧凑代码来缩短搜索时间。但是,这种压缩可能会导致信息丢失,从而可能降低搜索准确性。此外,这些方法在训练阶段的计算成本可能很高,从而增加构建时间。
哈希方法速度快,内存效率相对较高,可将相似的向量映射到相同的哈希桶。它们在处理高维数据和大规模数据集时表现良好,可提供高吞吐量;但是,由于哈希冲突会导致误报和漏报,搜索结果的质量可能会降低。选择正确数量的哈希函数和哈希表数量至关重要,因为它们会显著影响性能。
聚类方法可以通过将搜索空间缩小到特定聚类来加快搜索操作,但搜索结果的准确性可能会受到聚类质量的影响。聚类通常是一个批处理过程,这意味着它不太适合动态数据,因为动态数据会不断添加新向量,从而导致频繁重新索引。
图方法在准确性和速度之间实现了良好的平衡。它们对于高维数据非常有效,可以提供高质量的搜索结果。然而,它们可能占用大量内存,因为它们需要存储图结构,而且图的构建也需要耗费大量的计算资源。
矢量数据库中算法的选择取决于任务的具体要求,包括数据集的大小和维数、可用的计算资源以及准确度和效率之间可接受的权衡。还值得注意的是,许多现代矢量数据库使用混合方法,结合不同方法的优势来实现高速度和高准确度。对于任何希望从矢量数据库中获得最佳性能的人来说,了解这些算法及其权衡至关重要。现在让我们来看看每个类别中的所有流行算法。
6. 精确匹配
6.1. 平面索引(强力)
我们应该看的第一个指数是最简单的——平面指数。
平面索引之所以“平面”,是因为我们不会修改输入到其中的向量。
由于我们的向量没有近似或聚类——这些索引产生最准确的结果。我们拥有完美的搜索质量,但这是以大量的搜索时间为代价的。
使用平面索引,我们引入查询向量xq,并将其与索引中的每个其他全尺寸向量进行比较 – 计算到每个向量的距离。
计算完所有这些距离后,我们将返回其中最近的 k 个作为最近匹配。k 最近邻 (kNN) 搜索。
6.2. 平衡搜索时间
平面索引非常准确,但速度非常慢。在相似性搜索中,搜索速度和搜索质量(准确度)之间总是存在权衡。
我们必须要做的是确定用例的最佳点在哪里。有了平坦的索引,我们就可以做到:
这里我们的搜索速度完全没有经过优化,适合许多较小的索引用例,或者搜索时间无关紧要的场景。但是,其他用例需要更好地平衡速度和质量。
那么,我们如何才能加快搜索速度呢?主要有两种方法:
- 减少向量大小——通过降维或减少表示向量值的位数。
- 减少搜索范围——我们可以通过根据某些属性、相似性或距离将向量聚类或组织成树结构来实现这一点——并将搜索限制在最近的聚类或通过最相似的分支进行过滤。
使用其中任何一种方法意味着我们不再执行详尽的最近邻搜索,而是执行近似最近邻 (ANN) 搜索 – 因为我们不再搜索整个全分辨率数据集。
因此,我们提供的是更加均衡的组合,优先考虑搜索速度和搜索时间:
通常,我们希望搜索速度和搜索质量更加均衡。
7. 近似匹配
7.1. Annoy(近似最近邻 Oh Yeah)
在向量数据库中使用的基于树的算法中,有一种算法因其效率和简单性而脱颖而出:Annoy,即“近似最近邻 Oh Yeah”。Annoy是一个具有 Python 绑定的 C++ 库,由 Spotify 设计,用于搜索空间中靠近给定查询点的点(近似匹配)。它创建大型只读、基于文件的数据结构,这些数据结构被映射到内存中,从而允许多个进程共享相同的数据。
Annoy 通过使用随机投影树组成的森林来执行有效的 ANN 搜索。该算法将点投影到随机超平面上,并根据点落在超平面的哪一侧对空间进行分区。此过程以递归方式重复,从而产生分区的二叉树。创建一个森林,每棵树都有不同的随机种子。当收到查询点时,算法会遍历森林中的每棵树,以找到该点所属的叶节点。然后通过收集所有树中找到的叶节点中的点列表并返回此列表中最接近查询点的前 k 个点来近似最近邻居。
Annoy特别适合高维数据,因为精确的最近邻搜索成本可能非常高昂。它在 Spotify 的音乐推荐生产中被使用,它根据音频特征帮助找到类似的歌曲。因此,准确度可能受到森林中树木的数量和搜索期间检查的点数的影响,这两者都可以根据任务的具体要求进行调整。
Annoy 的效率和内存效率使其成为处理高维数据和大型数据库的不二之选。需要考虑一些权衡。构建索引可能需要大量时间,尤其是对于大型数据集。由于 Annoy 使用随机森林分区算法,因此索引无法使用新数据更新,必须从头开始重建。根据数据集的大小或数据更改的频率,重新训练索引的成本可能非常高昂。
7.2. 倒排文件(IVF)索引
倒排文件索引 (IVF) 索引通过聚类缩小搜索范围。它是一种非常流行的索引,因为它易于使用、搜索质量高且搜索速度合理。
它基于 Voronoi 图的概念——也称为 Dirichlet 镶嵌(一个更酷的名字)。
要理解 Voronoi 图,我们需要想象将高维向量放入二维空间。然后,我们在二维空间中放置一些额外的点,这些点将成为我们的“簇”(在我们的例子中是 Voronoi 单元)质心。
然后我们从每个质心向外延伸相等的半径。在某个时刻,每个细胞圆的圆周将与另一个细胞圆相撞——形成我们的细胞边缘:
现在,每个数据点都将包含在一个单元格内 — — 并分配给相应的质心。
与我们的其他索引一样,我们引入了一个查询向量xq —— 该查询向量必须落在我们的一个单元格内,此时我们将搜索范围限制在该单个单元格内。
但是,如果我们的查询向量落在单元格的边缘附近,就会出现问题——很有可能其最近的其他数据点包含在相邻单元格内。我们称之为边缘问题:
现在,我们可以采取以下措施来缓解此问题并提高搜索质量:增加一个称为nprobe值的索引参数。使用nprobe,我们可以设置要搜索的单元格数量。
7.3. 随机投影(RP)
随机投影的基本思想是使用随机投影矩阵将高维向量投影到低维空间。我们创建一个随机数矩阵。矩阵的大小将是我们想要的目标低维值。然后,我们计算输入向量和矩阵的点积,从而得到一个投影矩阵,该矩阵的维度比原始向量少,但仍保留其相似性。
当我们查询时,我们使用相同的投影矩阵将查询向量投影到较低维空间上。然后,我们将投影后的查询向量与数据库中的投影向量进行比较,以找到最近邻居。由于数据的维数降低了,因此搜索过程比搜索整个高维空间要快得多。
请记住,随机投影是一种近似方法,投影质量取决于投影矩阵的属性。一般来说,投影矩阵越随机,投影质量就越好。然而,生成真正随机的投影矩阵在计算上可能很昂贵,尤其是对于大型数据集。
7.4. 乘积量化(PQ)
构建索引的另一种方法是乘积量化 (PQ),这是一种针对高维向量(如向量嵌入)的有损压缩技术。它获取原始向量,将其分解为较小的块,通过为每个块创建代表性“代码”来简化每个块的表示,然后将所有块重新组合在一起 — 而不会丢失对相似性操作至关重要的信息。PQ 的过程可以分为四个步骤:拆分、训练、编码和查询。
- 分裂——将向量分解成若干段。
- 训练— 我们为每个片段建立一个“代码本”。简而言之 — 算法会生成一个可以分配给向量的潜在“代码”池。实际上 — 这个“代码本”由对向量的每个片段执行 k 均值聚类所创建的聚类中心点组成。片段代码本中的值数量与我们用于 k 均值聚类的值数量相同。
- 编码— 算法为每个片段分配一个特定的代码。实际上,我们在训练完成后,在码本中找到与每个矢量片段最接近的值。我们为该片段提供的 PQ 代码将是码本中相应值的标识符。我们可以使用任意数量的 PQ 代码,这意味着我们可以从码本中选择多个值来表示每个片段。
- 查询— 当我们查询时,算法将向量分解为子向量,并使用相同的码本对其进行量化。然后,它使用索引代码来查找与查询向量最接近的向量。
码本中的代表性向量数量是表征的准确性和搜索码本的计算成本之间的权衡。码本中的代表性向量越多,子空间中向量的表征就越准确,但搜索码本的计算成本就越高。相反,码本中的代表性向量越少,表征的准确性就越低,但计算成本就越低。了解有关 PQ 的更多信息。
7.5. 局部敏感哈希(LSH)
局部敏感哈希 (LSH) 的工作原理是将向量分组到存储桶中,通过哈希函数处理每个向量,从而最大化哈希冲突 – 而不是像哈希函数通常那样最小化。
这是什么意思?假设我们有一本 Python 字典。当我们在字典中创建新的键值对时,我们使用哈希函数对键进行哈希处理。键的哈希值决定了我们存储其相应值的“存储桶”:
类似字典的对象的典型哈希函数将尝试最小化哈希冲突,旨在为每个存储桶仅分配一个值。
Python 字典是哈希表的一个示例,它使用典型的哈希函数来最小化哈希冲突,即两个不同的对象(键)产生相同的哈希的哈希冲突。
在我们的字典中,我们希望避免这些冲突,因为这意味着我们将有多个对象映射到一个键 – 但对于 LSH,我们希望最大化散列冲突。
为什么我们要最大化碰撞?好吧,对于搜索,我们使用 LSH 将相似的对象分组在一起。当我们引入新的查询对象(或向量)时,我们的 LSH 算法可用于查找最接近的匹配组:
我们的 LSH 哈希函数尝试最大化哈希碰撞,从而产生向量分组。
7.6. 分层可导航小世界(HNSW)
HNSW — 搜索质量高,搜索速度快,但索引大小较大。条形图中“半满”的部分表示修改索引参数时遇到的性能范围。
HNSW 创建了一个分层的树状结构,其中树的每个节点代表一组向量。节点之间的边缘表示向量之间的相似性。该算法首先创建一组节点,每个节点包含少量向量。这可以随机完成,也可以通过使用 k-means 等算法对向量进行聚类来完成,其中每个聚类都成为一个节点。
解释分配给每个顶点的链接数以及 M、M_max 和 M_max0 的影响。
然后,该算法检查每个节点的向量,并在该节点和具有与其向量最相似向量的节点之间画一条边。
当我们查询 HNSW 索引时,它会使用此图浏览树,访问最有可能包含与查询向量最接近的向量的节点。。
7.7. 基于密度的噪声应用空间聚类(DBSCAN)
DBSCAN 以密度可达性和密度连通性为理念。它从数据集中的任意点开始,如果在距离该点给定半径“eps”内至少有“minPts”,则创建一个新集群。Eps 代表 epsilon,这是一个用户定义的输入,表示集群中要考虑的两个点之间的最大距离,而 minPts 是指形成集群所需的最小数据点数。然后,该算法迭代地将“eps”半径内所有可直接到达的点添加到集群中。此过程持续到无法再将其他点添加到集群为止。然后,算法继续到数据集中的下一个未访问点,并重复该过程,直到所有点都已被访问。DBSCAN 中的关键参数是“eps”和“minPts”,它们分别定义点的集群和形成集群所需的最小点密度。
8.相似性测量:距离度量
相似度度量是一种数学方法,用于确定向量空间中两个向量的相似度。相似度度量用于向量数据库,以比较数据库中存储的向量并找出与给定查询向量最相似的向量。
可以使用多种相似性度量,包括:
- 余弦相似度:测量向量空间中两个向量之间角度的余弦。其范围从 -1 到 1,其中 1 表示相同向量,0 表示正交向量,-1 表示完全相反的向量。
- 欧氏距离:测量向量空间中两个向量之间的直线距离。其范围从 0 到无穷大,其中 0 表示相同的向量,值越大表示向量越不相似。
- 点积:测量两个向量的幅值与它们之间角度的余弦的乘积。其范围从 -∞ 到 ∞,其中正值表示指向同一方向的向量,0 表示正交向量,负值表示指向相反方向的向量。
8.1. 如何选择相似度度量
一般最佳做法是使用与训练嵌入时相同的相似度度量进行搜索;但是,相似度度量的选择还取决于数据的具体特征以及您要解决的问题的背景。以下是针对每个讨论的相似度度量的一些主要应用:
欧几里德距离
- 聚类分析:聚类,如 k 均值,根据数据点在向量空间中的接近度对数据点进行分组。
- 异常和欺诈检测:在这些用例中,可以通过与正常交易质心异常大的距离检测到异常数据点。
点积
- 图像检索和匹配:具有相似视觉内容的图像将具有紧密对齐的向量,从而产生更高的点积值。当您想要查找与给定查询图像相似的图像时,点积是一个不错的选择。
- 神经网络和深度学习:在神经网络中,全连接层使用点积将输入特征与可学习权重相结合。这可以捕捉特征之间的关系,对分类和回归等任务很有帮助。
- 音乐推荐:点积相似度有助于识别具有相似音频特征的曲目,这使其对于音乐推荐系统很有价值。
余弦相似度
- 主题建模:在文档嵌入中,每个维度可以表示一个词的频率或 TF-IDF 权重。但是,两个不同长度的文档可能具有截然不同的词频,但词分布相同。由于这将它们置于向量空间中的相似方向,但不具有相似的距离,因此余弦相似度是一个很好的选择。
- 文档相似性:主题建模的另一个应用。相似的文档嵌入具有相似的方向,但距离可以不同。
- 协同过滤:推荐系统中的这种方法利用用户(或物品)的集体偏好和行为来提供个性化推荐。用户(或物品)根据其交互表示为向量。由于总体评分和受欢迎程度会产生不同的距离,但相似向量的方向仍然很接近,因此通常使用余弦相似度。
9.过滤
数据库中存储的每个向量也包含元数据。除了能够查询相似向量之外,向量数据库还可以根据元数据查询筛选结果。为此,向量数据库通常维护两个索引:向量索引和元数据索引。然后,它会在向量搜索本身之前或之后执行元数据筛选,但无论哪种情况,都会存在导致查询过程变慢的困难。
过滤过程可以在向量搜索之前或之后执行,但每种方法都有可能影响查询性能的挑战:
- 预过滤:在这种方法中,元数据过滤是在向量搜索之前完成的。虽然这可以帮助减少搜索空间,但也可能导致系统忽略与元数据过滤条件不匹配的相关结果。此外,由于增加了计算开销,广泛的元数据过滤可能会减慢查询过程。
- 后过滤:在这种方法中,元数据过滤是在向量搜索之后进行的。这可以帮助确保考虑所有相关结果,但它也可能带来额外的开销并减慢查询过程,因为在搜索完成后需要过滤掉不相关的结果。
为了优化过滤过程,矢量数据库使用了各种技术,例如利用高级元数据索引方法或使用并行处理来加速过滤任务。平衡搜索性能和过滤准确性之间的权衡对于在矢量数据库中提供高效且相关的查询结果至关重要。。
10. 选择矢量数据库
以下是一个简洁的摘要,可以帮助您做出决定:
- 开源和托管云:如果您倾向于开源解决方案,Weaviate、Milvus和Chroma将成为主要竞争者。Pinecone虽然不是开源的,但其开发人员经验和强大的完全托管解决方案却非常出色。
- 性能:就每秒查询次数的原始性能而言,Milvus处于领先地位,紧随其后的是Weaviate和Qdrant。然而,就延迟而言,Pinecone和Milvus都提供了令人印象深刻的 2ms 以下结果。如果为Pinecone添加多个 pod ,则可以达到更高的 QPS。
- 社区实力:Milvus拥有最大的社区影响力,其次是Weaviate和Elasticsearch。强大的社区通常意味着更好的支持、增强功能和错误修复。
- 可扩展性、高级功能和安全性:基于角色的访问控制是许多企业应用程序的关键功能,可在Pinecone、Milvus和Elasticsearch中找到。在扩展方面, Milvus和Chroma提供动态段放置功能,使其适用于不断发展的数据集。如果您需要一个具有多种索引类型的数据库,Milvus对 11 种不同类型的支持是无与伦比的。虽然混合搜索得到了全面支持,但Elasticsearch在磁盘索引支持方面确实有所欠缺。
- 定价:对于初创公司或预算有限的项目,Qdrant 的50k 向量定价估计为 9 美元,很难被击败。另一方面,对于需要高性能的大型项目,Pinecone和Milvus提供了有竞争力的定价层。
总之,矢量数据库没有万能的解决方案。理想的选择取决于具体项目需求、预算限制和个人偏好。
10.1. 比较参数
- 是否开源:表示软件的源代码是否可供公众免费使用,允许开发人员审查、修改和分发该软件。
- 自托管:指定数据库是否可以托管在用户自己的基础架构上,而不是依赖于第三方云服务。
- 云管理:提供数据库云管理的界面
- 专为向量构建:这意味着数据库是专门为向量存储和检索而设计的,而不是具有附加向量功能的通用数据库。
- 开发人员体验:评估开发人员使用数据库的用户友好性和直观性,考虑文档、SDK 和 API 设计等方面。
- 社区:评估数据库周边开发者社区的规模和活跃度。强大的社区通常意味着良好的支持、贡献和持续发展的潜力。
- 每秒查询数:使用特定数据集进行基准测试(在本例中为 nytimes-256-angular 数据集)时数据库每秒可以处理多少个查询
- 延迟:发起请求和接收响应之间的延迟(以毫秒为单位)。95%的查询延迟都在 nytimes-256-angular 数据集指定的时间内。
- 支持的索引类型:指数据库支持的各种索引技术,这会影响搜索速度和准确性。一些矢量数据库可能支持多种索引类型,如 HNSW、IVF 等。
- 混合搜索:确定数据库是否允许将传统(标量)查询与矢量查询相结合。这对于需要根据非矢量标准过滤结果的应用程序至关重要。
- 磁盘索引支持:指示数据库是否支持在磁盘上存储索引。这对于处理无法放入内存的大型数据集至关重要。
- 基于角色的访问控制:检查数据库是否具有允许向特定角色或用户授予权限的安全机制,从而增强数据安全性。
- 动态段放置与静态数据分片:指数据库如何管理数据分布和扩展。动态段放置允许根据实时需求更灵活地分配数据,而静态数据分片将数据划分为预定的段。
- 免费托管层:指定数据库提供商是否提供免费的云托管版本,允许用户无需初始投资即可测试或使用数据库。
- 定价(50k 个向量@1536)和定价(20M 个向量,20M 个要求@768):提供与存储和查询特定量数据相关的成本信息,深入了解数据库在小型和大型用例中的成本效益。
结论
本博客简要介绍了矢量数据库,重点介绍了它们在检索增强生成 (RAG) 应用中的关键作用。作者重点介绍了 ChromaDB、Pinecone 和 Weaviate 等热门数据库,强调了高效存储和检索对于实现最佳 RAG 性能的重要性。
该博客深入探讨了各种索引技术和算法,并深入介绍了 Annoy、倒排文件 (IVF) 索引、随机投影、乘积量化、局部敏感哈希 (LSH)、HNSW 和 DBSCAN。它进一步解释了相似度度量,如余弦相似度、欧几里德距离和点积,以及在文档相似度、图像检索和协同过滤中的实际应用。
很大一部分内容致力于帮助读者选择正确的矢量数据库。考虑了开源可用性、性能、社区实力、可扩展性、高级功能、安全性和定价等关键因素。比较参数提供了快速摘要,使读者能够根据自己的特定需求和偏好做出明智的决定。
总之,该博客为浏览矢量数据库的人提供了快速指南,为 RAG 模型的无缝集成和优化提供了必要的知识。
RA/SD 衍生者AI训练营。发布者:chris,转载请注明出处:https://www.shxcj.com/archives/4051