向量数据库相关知识(搬运学习,建议还是看原文,这个只是我自己的学习记录)

参考:https://cloud.tencent.com/developer/article/2312534


Vector Embeddings

Vector Embedding 是由 AI 模型(例如大型语言模型 LLM)生成的,它会根据不同的算法生成高维度的向量数据,代表着数据的不同特征,这些特征代表了数据的不同维度。例如,对于文本,这些特征可能包括词汇、语法、语义、情感、情绪、主题、上下文等。对于音频,这些特征可能包括音调、节奏、音高、音色、音量、语音、音乐等。

例如对于目前来说,文本向量可以通过 OpenAI 的 text-embedding-ada-002 模型生成,图像向量可以通过 clip-vit-base-patch32 模型生成,而音频向量可以通过 wav2vec2-base-960h 模型生成。这些向量都是通过 AI 模型生成的,所以它们都是具有语义信息的。


特征和向量:

只要特征足够多,就能够将事务都区分分开来,最后就能得到一个高维的坐标系,虽然我们想象不出高维坐标系长什么样,但是在数组中,我们只需要一直向数组中追加数字就可以了。

实际上,只要维度够多,我们就能够将所有的事物区分开来,世间万物都可以用一个多维坐标系来表示,它们都在一个高维的特征空间中对应着一个坐标点。

那这和相似性搜索 (Similarity Search) 有什么关系呢?你会发现在上面的二维坐标中,德牧和罗威纳犬的坐标就非常接近,这就意味着它们的特征也非常接近。我们都知道向量是具有大小和方向的数学结构,所以可以将这些特征用向量来表示,这样就能够通过计算向量之间的距离来判断它们的相似度,这就是相似性搜索


相似性搜索 (Similarity Search):

如果想要在一个海量的数据中找到和某个向量最相似的向量,我们需要对数据库中的每个向量进行一次比较计算,但这样的计算量是非常巨大的,所以我们需要一种高效的算法来解决这个问题。

高效的搜索算法有很多,其主要思想是通过两种方式提高搜索效率:

  1. 减少向量大小——通过降维或减少表示向量值的长度。
  2. 缩小搜索范围——可以通过聚类或将向量组织成基于树形、图形结构来实现,并限制搜索范围仅在最接近的簇中进行,或者通过最相似的分支进行过滤。

1:聚类

(1):K-Means2

我们可以在保存向量数据后,先对向量数据先进行聚类。例如下图在二维坐标系中,划定了 4 个聚类中心,然后将每个向量分配到最近的聚类中心,经过聚类算法不断调整聚类中心位置,这样就可以将向量数据分成 4 个簇。每次搜索时,只需要先判断搜索向量属于哪个簇,然后再在这一个簇中进行搜索,这样就从 4 个簇的搜索范围减少到了 1 个簇,大大减少了搜索的范围。

但是这种K-Means搜索方式也有一些缺点,例如在搜索的时候,如果搜索的内容正好处于两个分类区域的中间,就很有可能遗漏掉最相似的向量。

(2):Faiss

现实情况中,向量的分布也不会像图中一样区分的那么明显,往往区域的边界是相邻的,就像下图 Faiss 算法 一样。

那么为了解决搜索时可能存在的遗漏问题,可以将搜索范围动态调整,例如当 nprobe = 1 时,只搜索最近的一个聚类中心,当 nprobe = 2 时,搜索最近的两个聚类中心,根据实际业务的需求调整 nprobe 的值。

实际上,除了暴力搜索能完美的搜索出最相邻,所有的搜索算法只能在速度和质量还有内存上做一个权衡,这些算法也被称为近似最相邻(Approximate Nearest Neighbor)。

解决聚类内存太大问题的方法:Product Quantization (PQ)

聚类算法最大的问题在于内存占用太大。这主要体现在两个方面,

问题:首先因为需要保存每个向量的坐标,而每个坐标都是一个浮点数,占用的内存就已经非常大了。

解决:量化

问题:除此之外,还需要维护聚类中心和每个向量的聚类中心索引,这也会占用大量的内存。

解决:将向量分解为多个子向量,然后对每个子向量独立进行量化,例如一个 128 维的向量,需要维护 2^64 个聚类中心才能维持不错的量化结果,但这样的码本存储大小已经超过维护原始向量的内存大小了。将 128 维的向量分为 8 个 16 维的向量,然后在 8 个 16 维的子向量上分别进行聚类,因为 16 维的子向量大概只需要 256 个聚类中心就能得到还不错的量化结果,所以就可以将码本的大小从 2^64 降低到 8 * 256 = 2048 个聚类中心,从而降低内存开销。

而将向量进行编码后,也将得到 8 个编码值,将它们拼起来就是该向量的最终编码值。等到使用的时候,只需要将这 8 个编码值,然后分别在 8 个子码本中搜索出对应的 16 维的向量,就能将它们使用笛卡尔积的方式组合成一个 128 维的向量,从而得到最终的搜索结果。这也就是乘积量化(Product Quantization)的原理。

2:近似最近邻搜索

(1):Hierarchical Navigable Small Worlds (HNSW)

除了聚类以外,也可以通过构建树或者构建图的方式来实现近似最近邻搜索。这种方法的基本思想是每次将向量加到数据库中的时候,就先找到与它最相邻的向量,然后将它们连接起来,这样就构成了一个图。当需要搜索的时候,就可以从图中的某个节点开始,不断的进行最相邻搜索和最短路径计算,直到找到最相似的向量。

解决这个问题的思路与常见的跳表算法相似,如下图要搜索跳表,从最高层开始,沿着具有最长“跳过”的边向右移动。如果发现当前节点的值大于要搜索的值-我们知道已经超过了目标,因此我们会在下一级中向前一个节点。(不知道跳表的看这个:跳表的原理与实现 [图解]_跳表实现-CSDN博客

(2):Locality Sensitive Hashing (LSH)局部敏感哈希

LSH 使用一组哈希函数将相似向量映射到“桶”中,从而使相似向量具有相同的哈希值。这样,就可以通过比较哈希值来判断向量之间的相似度。

一般的哈希函数为了查找方便我们需要减少碰撞次数,但是在向量搜索中,我们的目的是为了找到相似的向量,所以可以专门设计一种哈希函数,使得哈希碰撞的概率尽可能高,并且位置越近或者越相似的向量越容易碰撞,这样相似的向量就会被映射到同一个桶中。

等搜索特定向量时,为了找到给定查询向量的最近邻居,使用相同的哈希函数将类似向量“分桶”到哈希表中。查询向量被散列到特定表中,然后与该表中的其他向量进行比较以找到最接近的匹配项。这种方法比搜索整个数据集要快得多,因为每个哈希表桶中的向量远少于整个空间中的向量数。

(3):Random Projection for LSH 随机投影

如果在二维坐标系可以通过随机生成的直线区分相似性,那么同理,在三维坐标系中,就可以通过随机生成一个平面,将三维坐标系划分为两个区域。在多维坐标系中,同样可以通过随机生成一个超平面,将多维坐标系划分为两个区域,从而区分相似性。

但是在高维空间中,数据点之间的距离往往非常稀疏,数据点之间的距离会随着维度的增加呈指数级增长。导致计算出来的桶非常多,最极端的情况是每个桶中就一个向量,并且计算速度非常慢。所以实际上在实现 LSH 算法的时候,会考虑使用随机投影的方式,将高维空间的数据点投影到低维空间,从而减少计算的时间和提高查询的质量。

随机投影背后的基本思想是使用随机投影矩阵将高维向量投影到低维空间中。创建一个由随机数构成的矩阵,其大小将是所需的目标低维值。然后,计算输入向量和矩阵之间的点积,得到一个被投影的矩阵,它比原始向量具有更少的维度但仍保留了它们之间的相似性。

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

其基本步骤是:

  1. 从高维空间中随机选择一个超平面,将数据点投影到该超平面上。
  2. 重复步骤 1,选择多个超平面,将数据点投影到多个超平面上。
  3. 将多个超平面的投影结果组合成一个向量,作为低维空间中的表示。
  4. 使用哈希函数将低维空间中的向量映射到哈希桶中。

同样,随机投影也是一种近似方法,并且投影质量取决于投影矩阵。通常情况下,随机性越大的投影矩阵,其映射质量就越好。但是生成真正随机的投影矩阵可能会计算成本很高,特别是对于大型数据集来说。关于更多 RP for LSH 算法的细节,可以参考这篇博客

相似性测量 (Similarity Measurement)

上面我们讨论了向量数据库的不同搜索算法,但是还没有讨论如何衡量相似性。在相似性搜索中,需要计算两个向量之间的距离,然后根据距离来判断它们的相似度。

而如何计算向量在高维空间的距离呢?有三种常见的向量相似度算法:欧几里德距离、余弦相似度和点积相似度。

一些小的数学知识可以去看:机器学习中的数学——距离定义(一):欧几里得距离(Euclidean Distance)-CSDN博客

(1):欧几里得距离(点距)

欧几里得距离算法的优点是可以反映向量的绝对距离,适用于需要考虑向量长度的相似性计算。例如推荐系统中,需要根据用户的历史行为来推荐相似的商品,这时就需要考虑用户的历史行为的数量,而不仅仅是用户的历史行为的相似度。

欧几里得距离是指两个向量之间的距离:

(2)余弦相似度(Cosine Similarity)(夹角距)

余弦相似度对向量的长度不敏感,只关注向量的方向,因此适用于高维向量的相似性计算。例如语义搜索和文档分类。

余弦相似度是指两个向量之间的夹角余弦值


(3)点积相似度 (Dot product Similarity)(点到直线距离)

点积相似度算法的优点在于它简单易懂,计算速度快,并且兼顾了向量的长度和方向。它适用于许多实际场景,例如图像识别、语义搜索和文档分类等。但点积相似度算法对向量的长度敏感,因此在计算高维向量的相似性时可能会出现问题。

向量的点积相似度是指两个向量之间的点积值


过滤

存储在数据库的向量往往还需要包含元数据,例如用户 ID、文档 ID 等信息。这样就可以在搜索的时候,根据元数据来过滤搜索结果,从而得到最终的结果。

为此,向量数据库通常维护两个索引:一个是向量索引,另一个是元数据索引。然后,在进行相似性搜索本身之前或之后执行元数据过滤,但无论哪种情况下,都存在导致查询过程变慢的困难。

  • Pre-filtering:在向量搜索之前进行元数据过滤。虽然这可以帮助减少搜索空间,但也可能导致系统忽略与元数据筛选标准不匹配的相关结果。
  • Post-filtering:在向量搜索完成后进行元数据过滤。这可以确保考虑所有相关结果,在搜索完成后将不相关的结果进行筛选。

    向量数据库选型


向量数据库比较原理上(后面会实践部署来比较一下):

1:Chroma

2:Milvus

3:Faiss

4:Weaviate

总结:

Chroma在易用性上占优,特别适合在Jupyter Notebook上进行开发、测试和生产,是处理多媒体数据,尤其是音频和视频搜索的理想选择。

Milvus强调在存储效率和数据查询性能上的平衡,支持内存和持久存储,适用于各种数据类型和格式。它在电子商务、自然语言处理以及图像和视频分析等多个方面有广泛应用,特别是在数据分区、负载均衡和容错方面提供了强大的支持。

Faiss可以进行GPU加速的高速检索,特别擅长处理庞大数据集的快速最近邻搜索,适用于不同技术需求和数据环境,能够与多种技术风格相协调。

Weaviate则提供了GraphQL-based API,强调与知识图的灵活高效交互。支持实时数据更新,确保数据的时效性,以及通过模式推断功能,自动化了数据结构定义的过程,适合于需要数据分类和企业资源规划的场合

  • 18
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值