向量数据库简单理解

背景

传统的数据库并不适合用来存储和检索向量数据

因此需要一种专门设计的数据库,用来存储和检索向量数据

应用场景

给定一个查询向量,然后从众多向量中,找到最为相似的一些向量,这就是“最近邻“问题

相似性检测

通过计算两个向量的余弦值来判断

夹角越小,余弦值越大

计算两个向量的欧式距离来判断

距离越近越相似

检索-最近邻搜索算法

暴力搜索(平坦搜索)

依次比较所有向量和查询向量的相似度,挑选出相似度最高的几个

优点:它的搜索质量是完美的,因为它真的比较了每一个向量

缺点:如果库中的向量过多,将导致极高的搜索时间

应用场景:数据规模较小的向量库

k-means聚类算法

聚类

①先选定一个想要分类的数量,比如4类

②随机生成4个聚类中心点

③这些向量和哪一个中心点最近,就被分为哪一类

④用当前被分为一类的向量计算出一个平均向量点

⑤把对应的中心点的位置更新为这个平均点

⑥再判断每个向量点和哪一个中心点最近,重新分类

⑦继续用同一类的向量点,计算出一个平均点,把中心点更新过去

⑧一直重复第6步和第7步,直到中心点趋于稳定(或者说收敛)

⑨最终,将这些向量分成了4类

搜索

在搜索的时候,只需要找出和查询向量最近的那个聚类中心,搜索这个分类中的向量即可,也就实现了缩小搜索范围的目的

问题:聚类的方法不能保证不会出现遗漏的问题

例如,当我们查找和A最相似的向量时,由于在所有的中心点中,A离蓝色块的中心点C最近,所以接下来会去蓝色块中去查对应的相似向量,而实际上,与A相似度最高的向量(也就是离A最近的向量),是B,在紫色块内,所以,无论在蓝色块中怎么查,都无法查到相似度最高的向量,就出现了遗漏的问题

解决

可以指定同时搜索多个最近区域来减少遗漏

PQ乘积量化Product Quantization算法

数据结构
背景

如果向量的维度是128,每个维度值是一个32位的浮点数,那么一个向量占用的内存大小为128 x 4为512字节

如果库里面一共有一千万个向量,那么占用存储空间大概有4.77G

而,在真实的应用场景中,上千的向量维度和上亿的向量数量都是很常见的,所以,这样存储,会存在很严重的问题

解决方案

在k-means聚类算法的基础上,直接用聚类中心(质心)来代替这个聚类中所有的向量

注意:这是一种有损压缩的方法

使用编码+码本来存储向量

每次使用某个向量时,用它的编码值,从码本中找到对应的质心,再复原出质心向量的具体值

维度灾难
背景

如果数据库的向量比较稀疏,可能需要聚很多类,才能保证量化效果

而维度的增加,将导致空间爆炸式的扩张,从而迅速的导致向量的分布变得越来越稀疏

例如,128维的向量,可能需要2 ^ 64个聚类中心,这会导致用来记录质心编码,和向量值的码本变得非常巨大,而为了保存这个巨大的码本所消耗的内存,已经超越乃至远远超越了量化本身所节省下来的内存(质心数量比源数据向量要多很多)

而实际应用中,几百上千维的向量都是很常见的,采用这种方法,显然是不可取的

解决方案

先把高维的向量分割成若干个低维的子向量,然后在这些子向量上独立进行量化

例如,

①把128维的向量,分成8个16维的子向量

②在8个16维的子空间中,分别独立的对子向量进行k-means聚类训练,于是每个向量便可以使用8个子空间的训练结果,对自己8个对应的子向量进行量化

而且,由于每个子向量的维度,是16,不是很高,因此每个16维的子空间只需要大约256个聚类数量,就能得到不错的量化效果

所以,每个子向量的量化编码值的范围是0~255

③把8个子向量的量化编码值,合并在一起,就得到了原始向量最终的量化编码值

也就是说,现在一个向量被量化为8个编码值,

同样,每个子空间,也会构建自己的子码本

在使用的时候,用8个编码值,分别从对应的子码本中,查询出8个16维的子向量,再拼起来,复原出一个128维的向量

④由于每个子空间的聚类数量只有256,所以每个子码本将变得很小,小到和数据本身相比,忽略不计

而8个子空间的“小码本“,放到一起得到的”大码本“,也仍然足够小

搜索

和k-means算法一样

LSH位置敏感哈希(Locality Sensitive Hashing)算法

分组

①确定一个hash函数(也就是LSH函数),使得,在计算向量的hash值时,位置越相近,越有可能产生相同的hash值

②对数据库中所有的向量,用①中的hash函数做运算,得到对应的hash值

③把hash值一样的向量分到同一组(同一个桶中),hash值不一样的向量分到不同的组

搜索

①计算查询向量的hash值

②找到其所在的桶,再遍历桶中的向量来搜索,因为和查询向量最相似的一些向量,大概率都在这个桶中

LSH的实现-随机超平面(随机投影)

以A,B,C三个二维向量为例

①随机生成一条直线,且这条直线区分正反两侧

②如果一个向量,在这条线的正的一侧,他就是1,如果在反的一侧,那么就是0

③再随机生成一条直线,同样正侧的向量是1,反侧的向量是0

④重复上述步骤,我们随机生成若干个这样的直线,每次都根据向量所在的正反侧,得到1或者0

⑤如果一共使用4条随机的直线,如此就为每个向量算出来4个0或1,各自得到一个四位的二进制编码

⑥A,C这两个向量更为相似,因为它们只有第三位不同,相似度为3/4,计算方式为汉明距离/编码位数,而B和AC的相似度都很低

⑦这串二进制的编码,即位向量的hash值

对于更高维度的向量,道理也是一样的,比如三维向量,我们可以使用三维空间中的一个随机平面来做hash函数的计算,这个面,也有正反,正面的向量得到1,反面的得到0,若干个随机平面,也就得到了一串二进制编码的hash值

如果是更高的维度,在这些更高维度中,也存在着高维的“超平面“,也可以完成相应的hash值生成

NSW(导航小世界)算法

基于图结构的搜索

图结构的建立

要求:

建立步骤:

①先把向量点拿出来

②再随机的一个个的放回向量空间中

③在每次放回点的时候,找到最近的几个点建立连接,比如3个点

④如此进行下去,直到把所有的点都放回去

⑤这个图结构就建好了

搜索

在这个图中,先通过长的连接快速导航,找目标点附近的节点,再通过短的连接精细化搜索,找到目标节点(最相似的节点)

HNSW(分层的导航小世界)算法

背景

NSW算法在搜索时,不是很稳定,并不是每一次导航时,都会快速找到目标点附近的节点,再通过短的连接找到目标节点

特别是当数据量很大时,它可能变得很不稳定,进而在很大的程度上会影响性能

解决方案

为了解决这个问题,可以使用HNSW算法

整个算法思路,和Redis里面的跳表很类似

构建多层结构时,按照自顶向下,连接平均的长度逐渐变短来设计的,所以从顶部作为入口,就可以保证,先粗快,后细慢的过程平稳的发生

参考文章&视频

【上集】向量数据库技术鉴赏_哔哩哔哩_bilibili

【下集】向量数据库技术鉴赏_哔哩哔哩_bilibili

向量数据库|一文全面了解向量数据库的基本概念、原理、算法、选型-腾讯云开发者社区-腾讯云 (tencent.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值