1. 为什么需要向量数据库
1.1 “猫”与向量的关系与衍生
这里我们以 猫 引出 词向量,再引出 向量数据库 的概念,通过这一个小小的演示,大家就能快速掌握词向量与向量数据库。
平时有养猫或者熟悉猫的小伙伴对于下面这一张猫的品类图,很快就能区分出它们的品种,之所以能做到这点,是因为我们会从不同的角度来观察这些猫的特征,如下
如果我们使用一个水平轴来表示 体型大小 这个特征,这些不同品种的猫将落在不同的坐标点上,这样就可以通过体型的大小区分出一些品种,如下
然而,如果仅仅靠体型一个特征,依旧会有很多品种的猫特征相近,比如 缅英猫、奶牛猫 和 折耳猫 就非常接近,所以我们继续添加多一个特征,比如毛发的长短,继续建立一个毛发的垂直轴,这样子就可以区分出更多品种
现在每个品种的猫就可以表示为一个二维的坐标点,但是哪怕有两个特征,仍然会有一些品种无法区分。
所以我们需要从更多的角度来观察,例如 腿的长短,这个时候在建立一个 腿的长短 的 z轴,又有更多的品种被区分出来,现在每个品种的猫就可以表示为一个三维的坐标点,如下:
如果这个时候还想引入更多的特征进行区分,比如:眼睛大小、尾巴长短、毛发颜色、声音大小、耳朵形状 等等,虽然在坐标图上没法展示出来,但是我们却可以很轻松地将这些特征使用数值的方式展示出来,例如下方:
1. 暹罗猫: (0.4, 0.3, 0.4, 0.5, 0.3, 0.4, 0.5, ...)
2. 英国短毛猫: (0.7, 0.2, 0.5, 0.5, 0.5, 0.5, 0.5, ...)
3. 缅甸猫: (0.5, 0.3, 0.4, 0.5, 0.3, 0.4, 0.5, ...)
4. 波斯猫: (0.8, 0.8, 0.4, 0.8, 0.7, 0.4, 0.6, ...)
5. 布偶猫: (0.7, 0.6, 0.5, 0.8, 0.5, 0.4, 0.5, ...)
6. 无毛猫: (0.6, 0.1, 0.4, 0.5, 0.3, 0.4, 0.5, ...)
7. 中华田园猫: (0.5, 0.3, 0.5, 0.5, 0.5, 0.4, 0.5, ...)
8. 折耳猫: (0.6, 0.3, 0.4, 0.5, 0.3, 0.4, 0.7, ...)
9. 三花猫: (0.5, 0.3, 0.5, 0.5, 0.5, 0.5, 0.5, ...)
10. 美国短毛猫: (0.7, 0.2, 0.5, 0.5, 0.5, 0.5, 0.5, ...)
11. 狮子猫: (0.9, 0.7, 0.7, 0.8, 0.7, 0.8, 0.5, ...)
12. 奶牛猫: (0.6, 0.3, 0.5, 0.5, 0.5, 0.4, 0.5, ...)
当记录的特征足够大,维度足够大时,区分的程度也会越高,当看到一只猫,只需要将它转换成对应的 多维坐标数据/向量,就可以很轻松地找到这只猫的分类归属,而且不仅仅是猫,几乎所有的事物都可以使用这一套方式进行表达。
所以一个字、一个词、一句话、一篇文本、甚至一张图片都可以用这样一个 多维坐标数据,亦或者说 向量 记录对应的特征,而将文本转换为记录特征的向量就可以被称为词向量。
1.2 向量数据库概念与用途
向量数据库就是一种专门用于存储和处理向量数据的数据库系统,传统的关系型数据库通常不擅长处理向量数据,因为它们需要将数据映射为结构化的表格形式,而向量数据的维度较高、结构复杂,导致传统数据库存储和查询效率低下,所以向量数据库应运而生。
由于高维的向量我们在三维空间没法绘图,这里我们以二维向量的形式扩展到多维,来一起看下向量的神通广大之处!
例如下图,在二维坐标上,概念上更接近的点,在图表上也更聚集,而那些概念上不同的点则一般距离比较远。
如果将两个点之间作差,得到一条新的向量,甚至我们可以使用这条 结果向量 来表示两个点之间的关联(越短表示关联越大),相比传统的数据库,向量数据库针对向量距离/相似度计算进行了特定的优化,如下
所以最常见的应用就是人脸识别,将不同的人脸归一化(固定大小)后生成对应的向量,然后将千千万万张人脸的向量进行存储。
进行人脸识别时,只需要将这张人脸按照统一的标准归一化并转换成向量,接下来在向量数据库中搜索与这个向量最接近的向量,就可以巧妙实现人脸识别
这也是向量数据库的最常使用场景:人脸识别、图像搜索、音频识别、智能推荐系统等。
而在 RAG 中,我们将对应的知识文档按照特定的规则拆分成合适的大小,再转换成向量存储到向量数据库中,当人类提问时,将人类提问 query 转换成向量并进行搜索,找到在特征上更接近的文本块,这些文本块就可以看成和 query 具有强关联或者说有因果关系。这样就可以将这些 文本块 作为这次提问的额外补充知识,让 LLM 基于补充知识+提问生成对应的内容,从而实现知识库问答.
2. 传统该数据库与向量数据库
2.1 两种数据库差异
2.1.1 搜索方式差异
传统数据库,比如关系型数据库,擅长处理结构化数据,如存储在表格中的文本和数字等。它们通过预定义的查询语言(如SQL)来进行精确匹配或条件搜索。这种方式在处理银行交易、客户信息等数据时效果显著,但在处理复杂的模式识别问题时就显得力不从心。
例如,通过 SELECT + WHERE 可以精准查询到 id 为 e0d13c78-870b-46df-b2f5-693ae9d5d727 的用户。
SELECT * FROM account WHERE id='e0d13c78-870b-46df-b2f5-693ae9d5d727'
但是想通过 SQL 来查询和 我喜欢打篮球游泳与编程 这句话语义相近的内容,就无能力为了。
相比之下,向量数据库不是通过匹配确切的数值,而是通过一种称为 相似性搜索 的方法来工作。它们可以快速找到与查询向量最相似的数据点(目前绝大部分向量数据库都支持在 相似性搜索 的基础上添加筛选条件),即使这些数据点在数值上并不完全相同。
例如,在一个向量数据库中,即使没有完全相同的照片,我们仍然可以找到风格相似的图片。通过这种方式,向量数据库打破了传统数据库的局限,为处理和分析大规模、复杂的数据提供了更灵活和强大的解决方案。
2.1.2 数据处理与存储差异
传统数据库采用基于行的存储方式
,传统数据库将数据存储为行记录,每一行包含多个字段,并且每个字段都有固定的列。传统数据库通常使用索引来提高查询性能,例如下方就是一个典型的传统数据库表格
这种方式在处理结构化数据时非常高效,但在处理非结构化或半结构化数据时效率低下。
向量数据库将数据以列形式存储
,即每个列都有一个独立的存储空间,这使得向量数据库可以更加灵活地处理复杂的数据结构。向量数据库还可以进行列压缩(稀疏矩阵),以减少存储空间和提高数据的访问速度。
并且在向量数据库中,将数据表示为高维向量,其中每个向量对应于数据点。这些向量之间的距离表示它们之间的相似性。这种方式使得非结构化或半结构化数据的存储和检索变得更加高效。
以电影数据库为例,我们可以将每部电影表示为一个特征向量。假设我们使用四个特征来描述每部电影:动作、冒险、爱情、科幻。每个特征都可以在0到1的范围内进行标准化,表示该电影在该特征上的强度。
例如,电影"阿凡达"的向量表示可以是 [0.9, 0.8, 0.2, 0.9]
,其中数字分别表示动作、冒险、爱情、科幻的特征强度。其他电影也可以用类似的方式表示。这些向量可以存储在向量数据库中,如下所示
现在,如果我们想要查找与电影"阿凡达"相似的电影,我们可以计算向量之间的距离,找到最接近的向量,从而实现相似性匹配,而无需复杂的SQL查询。这就像使用地图找到两个地点之间的最短路径一样简单。
2.1.3 优缺点横向对比
尽管向量数据库在处理高维数据和实现快速检索方面有着显著优势,但它并不是一种“一刀切”的解决方案。在某些应用场景中,其他类型的数据库可能更合适,而且向量数据库与传统关系数据库协同发展、相互补充。
3. 相似性搜索算法
3.1 余弦相似度与欧式距离
在向量数据库中,支持通过多种方式来计算两个向量的相似度,例如:余弦相似度、欧式距离、曼哈顿距离、闵可夫斯基距离、汉明距离、Jaccard相似度等多种。其中最常见的就是 余弦相似度 和 欧式距离。
例如下图,左侧就是 欧式距离,右侧就是 余弦相似度
① 余弦相似度主要用于衡量向量在方向上的相似性,特别适用于文本、图像和高维空间中的向量。它不受向量长度的影响,只考虑方向的相似程度,余弦相似度的计算公式如下(计算两个向量夹角的余弦值,取值范围为[-1, 1]):
similarity(A,B)=A⋅B∥A∥∥B∥=∑i=1nAi⋅Bi∑i=1nAi2⋅∑i=1nBi2\operatorname{similarity}(\mathbf{A}, \mathbf{B})=\frac{\mathbf{A} \cdot \mathbf{B}}{\|\mathbf{A}\|\|\mathbf{B}\|}=\frac{\sum_{i=1}^n A_i \cdot B_i}{\sqrt{\sum_{i=1}^n A_i^2} \cdot \sqrt{\sum_{i=1}^n B_i^2}}similarity(A,B)=∥A∥∥B∥A⋅B=∑i=1nAi2⋅∑i=1nBi2∑i=1nAi⋅Bi
② 欧式距离衡量向量之间的直线距离,得到的值可能很大,最小为 0,通常用于低维空间或需要考虑向量各个维度之间差异的情况。欧氏距离较小的向量被认为更相似,欧式距离的计算公式如下:
distance(A,B)=∑i=1n(Ai−Bi)2
\operatorname{distance}(\mathbf{A}, \mathbf{B})=\sqrt{\sum_{i=1}^n\left(A_i-B_i\right)^2}
distance(A,B)=i=1∑n(Ai−Bi)2
3…2 相似性搜索加速计算
在向量数据库中,数据按列进行存储,通常会将多个向量组织成一个 M×N 的矩阵,其中 M 是向量的维度(特征数),N 是向量的数量(数据库中的条目数),这个矩阵可以是稠密或者稀疏的,取决于向量的稀疏性和具体的存储优化策略。
这样计算相似性搜索时,本质上就变成了向量与 M×N 矩阵的每一行进行相似度计算,这里可以用到大量成熟的加速算法:
- 矩阵分解方法:
- SVD(奇异值分解):可以通过奇异值分解将原始矩阵转换为更低秩的矩阵表示,从而减少计算量。
- PCA(主成分分析):类似地,可以通过主成分分析将高维矩阵映射到低维空间,减少计算复杂度。
- 索引结构和近似算法:
- LSH(局部敏感哈希):LSH 可以在近似相似度匹配中加速计算,特别适用于高维稀疏向量的情况。
- ANN(近似最近邻)算法:ANN 算法如KD-Tree、Ball-Tree等可以用来加速对最近邻搜索的计算,虽然主要用于向量空间,但也可以部分应用于相似度计算中。
- GPU 加速:使用图形处理单元(GPU)进行并行计算可以显著提高相似度计算的速度,尤其是对于大规模数据和高维度向量。
- 分布式计算:由于行与行之间独立,所以可以很便捷地支持分布式计算每行与向量的相似度,从而加速整体计算过程。
向量数据库底层除了在算法层面上针对相似性搜索做了大量优化,在存储结构、索引机制等方面均做了大量的优化,这才使得向量数据库在处理高维数据和实现快速相似性搜索上展示出巨大的优势。