引言
向量检索,即根据一个向量Q从海量的向量库中寻找TopK个与Q最相似或者距离最近的向量,其在工业中有着广泛的应用场景,比如图像检索、文本语义检索以及推荐系统中基于User与Item的Embedding向量召回等。
向量嵌入
- Vector Embedding 是由 AI 模型(例如大型语言模型 LLM)生成的,它会根据不同的算法生成高维度的向量数据,代表着数据的不同特征,这些特征代表了数据的不同维度。例如,对于文本,这些特征可能包括词汇、语法、语义、情感、情绪、主题、上下文等。对于音频,这些特征可能包括音调、节奏、音高、音色、音量、语音、音乐等。实际上,只要维度够多,我们就能够将所有的事物区分开来,世间万物都可以用一个多维坐标系来表示,它们都在一个高维的特征空间中对应着一个坐标点。
- 例如对于目前来说,文本向量可以通过 OpenAI 的 text-embedding-ada-002 模型生成,图像向量可以通过 clip-vit-base-patch32 模型生成,而音频向量可以通过 wav2vec2-base-960h 模型生成。这些向量都是通过 AI 模型生成的,所以它们都是具有语义信息的。
过滤 (Filtering)
- 在实际的业务场景中,往往不需要在整个向量数据库中进行相似性搜索,而是通过部分的业务字段进行过滤再进行查询。所以存储在数据库的向量往往还需要包含元数据,例如用户 ID、文档 ID 等信息。这样就可以在搜索的时候,根据元数据来过滤搜索结果,从而得到最终的结果。
- 向量数据库维护两个索引:一个是向量索引,另一个是元数据索引。过滤过程可以在向量搜索本身之前或之后执行,但每种方法都有自己的挑战,可能会影响查询性能:
- Pre-filtering:在向量搜索之前进行元数据过滤。虽然这可以帮助减少搜索空间,但也可能导致系统忽略与元数据筛选标准不匹配的相关结果。
- Post-filtering:在向量搜索完成后进行元数据过滤。这可以确保考虑所有相关结果,在搜索完成后将不相关的结果进行筛选。
相似性测量 (Similarity Measurement)
计算向量在高维空间的距离有三种常见的向量相似度算法:欧几里德距离、余弦相似度和点积相似度。
向量索引
- 在向量数据库中进行相似度匹配时,不能完全按照公式计算,因为向量数据库的数据量通常很大,维度也很高,时间和计算成本都会更加高。
- 向量索引(vector index):是指通过某种数学模型,对向量构建的一种时间和空间上比较高效的数据结构。借助向量索引,我们能够高效地查询与目标向量相似的若干个向量
近似算法
- 如果想要在一个海量的数据中找到和某个向量最相似的向量,我们需要对数据库中的每个向量进行一次比较计算,但这样的计算量是非常巨大的,所以我们需要一种高效的算法来解决这个问题。所有算法都是在内存、速度和质量上做一个权衡。
- 减少向量大小——通过降维或减少表示向量值的长度。
- 缩小搜索范围——可以通过聚类或将向量组织成基于树形、图形结构来实现,并限制搜索范围仅在最接近的簇中进行,或者通过最相似的分支进行过滤。
- 近似最近邻搜索(Approximate Nearest Neighbor Search)可以解决精度和效率的问题
基于树的方法
基于树的方法有很多种,比较典型的有KDTree、BallTree、VPTree,类比传统的二叉树,树结构无非是在建树的时候是决定往左还是往右扩展,不同的向量树索引在于按照什么标准去决策,KDTree 会选取向量中某个方差最大的维度取中值作为判定标准,也就是以超平面去划分空间,而BallTree则以球面去划分空间,VPTree会先选取一个制高点,然后计算每个点和制高点的距离,取距离中值作为判定标准。通常这些方法在检索的时候都会利用三角形不等式来去除不必要的探索。
哈希方法
向量量化
乘积量化(Product Quantization)
将原始向量分解成若干个低维向量的笛卡尔积,并对分解得到的低维向量空间做量化,这样原始向量便能通过低维向量的量化code表示,可以显著的减少内存的开销,同时加快搜索的速度,它唯一的问题是搜索的质量会有所下降。
基于图的方法
Hierarchical Navigable Small Worlds (HNSW)
- 这种方法的基本思想是每次将向量加到数据库中的时候,就先找到与它最相邻的向量,然后将它们连接起来,这样就构成了一个图。当需要搜索的时候,就可以从图中的某个节点开始,不断的进行最相邻搜索和最短路径计算,直到找到最相似的向量。
- HNSW 算法是一种经典的空间换时间的算法,它的搜索质量和搜索速度都比较高,但是它的内存开销也比较大,因为不仅需要将所有的向量都存储在内存中。还需要维护一个图的结构,也同样需要存储。
聚类
K-Means
- 常见的聚类算法有 K-Means,它可以将数据分成 k 个类别,其中 k 是预先指定的。k-means 算法的基本步骤:
- 选择 k 个初始聚类中心。
- 将每个数据点分配到最近的聚类中心。
- 计算每个聚类的新中心。
- 重复步骤 2 和 3,直到聚类中心不再改变或达到最大迭代次数。
- K-Means 在搜索的时候,如果搜索的内容正好处于两个分类区域的中间,就很有可能遗漏掉最相似的向量。现实情况中,向量的分布也不会像图中一样区分的那么明显,往往区域的边界是相邻的,Faiss 算法将向量想象为包含在 Voronoi 单元格中,当引入一个新的查询向量时,首先测量其与质心之间的距离,然后将搜索范围限制在该质心所在的单元格内。
开源方案
faiss
Faiss 作为一个强大的向量索引库,集成了大部分的ANN算法,包括乘积向量,暴力搜索,hnswlib等,也是大部分向量检索的核心引擎。
基于ES
大规模索引可以通过分布式分片解决单机容量问题。在倒排检索领域,ES有非常成熟的分片机制,每个shard是一个lucene索引,基于段合并的机制也能实现近实时搜索。
向量数据库
什么是 Milvus
- Milvus 是一款云原生向量数据库,它具备高可用、高性能、易拓展的特点,用于海量向量数据的实时召回。
- Milvus 基于 FAISS、Annoy、HNSW 等向量搜索库构建,核心是解决稠密向量相似度检索的问题。在向量检索库的基础上,Milvus 支持数据分区分片、数据持久化、增量数据摄取、标量向量混合查询、time travel 等功能,同时大幅优化了向量检索的性能,可满足任何向量检索场景的应用需求。
- Milvus 采用共享存储架构,存储计算完全分离,计算节点支持横向扩展。从架构上来看,Milvus 遵循数据流和控制流分离,整体分为了四个层次,分别为接入层(access layer)、协调服务(coordinator service)、执行节点(worker node)和存储层(storage)。各个层次相互独立,独立扩展和容灾。
为什么需要 Milvus
- 需要使用 embedding 技术将文本、图片、语音、视频等数据转化为向量。随后,Milvus 会存储这些向量,并为其建立索引。Milvus 能够根据两个向量之间的距离来分析他们的相关性。如果两个向量十分相似,这说明向量所代表的源数据也十分相似。
- Milvus 向量数据库专为向量查询与检索设计,能够为万亿级向量数据建立索引。
- 与现有的主要用作处理结构化数据的关系型数据库不同,Milvus 在底层设计上就是为了处理由各种非结构化数据转换而来的 Embedding 向量而生。
为什么选择使用 Milvus
- 高性能:性能高超,可对海量数据集进行向量相似度检索。
- 高可用、高可靠:Milvus 支持在云上扩展,其容灾能力能够保证服务高可用。
- 混合查询:Milvus 支持在向量相似度检索过程中进行标量字段过滤,实现混合查询。
- 开发者友好:支持多语言、多工具的 Milvus 生态系统。