faiss简介
Faiss is a library for efficient similarity search and clustering of dense vectors。
官方介绍: Faiss是一个用于高效相似性搜索和密集向量聚类的库。也就是用来实现高效的向量检索。
Faiss主要组件包括:
- 索引结构:Flat(暴力搜索) 、IVF(Inverted File)、IVFPQ(Inverted File with Product Quantization)、HNSW(Hierarchical Navigable Small World),索引结构可以加速相似性搜索,降低查询时间。
- 向量编码:PQ(Product Quantization)、OPQ(Optimized Product Quantization)。编码可以将高维向量映射到低维空间中,同时保持距离的相似性,有助于减少内存占用和计算量。
- 相似性度量:欧氏距离、内积、Jaccard 相似度等。
Faiss的核心API有:
IndexFactory(d int, description string, metric int):用来创建索引,通过维度,索引方法描述,相似性度量来创建索引。
Ntotal() 索引向量的数量。
Train(x []float32) 用一组具有代表性的向量训练索引。
Add(x []float32),用于创建向量检索集。
Search(x []float32, k int64) (distances []float32, labels []int64, err error),x向量在k紧邻进行检索,返回每个查询向量的 k 个最近邻的 ID 以及相应的距离。
如何理解Add和Search方法呢?Add是添加向量,Search从向量中检索。比如一篇文章拆分成5个片段,此时调用Add方法生成了5个向量,查询的内容会生成一个查询向量,那么Search中k=2会返回最近的两个近邻,也就是返回5个向量中的2个向量,那么返回值distances是查询向量到返回2个向量的距离,返回值labels是返回的向量在5个片段中的位置,此时就可以知道返回了那些段。
Faiss的主要流程是:
- 初始化索引结构,指定相似性度量方法(metric)和编码方法(description)。使用IndexFactory。
- 将原始向量数据添加到索引中。使用Add。
- 对查询向量进行编码,并在索引中搜索与查询向量相似的向量。使用Search。
- 获取搜索结果,并根据需要进行后处理。
文档向量化检索设计
如果我们要实现一篇文档的向量化检索该如何设计呢?可以使用mysql和内存缓存作为文档的向量存储,方案可以先将文档拆分,然后存储到数据库中,表设计如下:
mysql存储拆分后的文档—— primary_id,edoc_part_content,project_id,embedding
内存缓存存储向量位置到文档主键ID——键:project_id+Ntotal() 值:primary_id
服务启动初始化时候从mysql加载doc表,获取到所有的文档,然后通过Add方法加载到检索集中,每加一次,调用Ntotal方法获取当前向量总数,也就是当前向量数组的位置下标,存入内存缓存中,
查询时候,生成查询向量后,调用Search方法,获取到检索集位置,然后获取从内存缓存中获取mysql中的主键id,去mysql查询到文档的内容。
Faiss配置指南
相似性计算方法
相似性计算主要有余弦,L1,L2等计算方法。
InnerProduct
内积/余弦相似度
L1
曼哈顿距离
L2
欧氏距离
Linf
无穷范数
Lp
p范数
Canberra
BC相异度
BrayCurtis
兰氏距离/堪培拉距离
JensenShannon
JS散度
索引方法
索引描述主要是向量检索算法。主要有以下几个:
Flat:最基础的索引结构,比较精确
IVF:Inverted File 倒排文件
PQ:Product Quantization 乘积量化
PCA:Principal Component Analysis 主成分分析
HNSW:Hierarchical Navigable Small World 分层的可导航小世界
相似性计算方法 | 索引描述 | 说明 |
---|---|---|
InnerProduct | Flat | 余弦相似度 暴力检索 |
InnerProduct | IVF100,Flat | 余弦相似度 k-means聚类中心为100倒排(IVFx)暴力检索 |
L2 | Flat | 欧式距离 暴力检索 |
InnerProduct | PQ16 | 余弦相似度 乘积量化 利用乘积量化的方法,改进了普通检索,将一个向量的维度切成x段,每段分别进行检索,每段向量的检索结果取交集后得出最后的TopK。因此速度很快,而且占用内存较小,召回率也相对较高 |
L2 | PCA32,IVF100,PQ16 | 欧式距离 将向量先降维成32维,再用IVF100 PQ16的方法构建索引 |
L2 | PCA32,HNSW32 | 欧式距离 处理HNSW内存占用过大的问题 |
L2 | IVF100,PQ16 |
欧式距离 倒排乘积量化:工业界大量使用此方法,各项指标都均可以接受,利用乘积量化的方法,改进了IVF的k-means,将一个向量的维度切成x段,每段分别进行k-means再检索 |
其他 | 其他 | 大家自己枚举调优吧,采用下文测试方法测试是否成功 |
GoLang代码例子
faiss本身用C++实现,这里使用go-faiss来实现例子,embeding获取通过openai的接口实现。
1 | package services |
参考
https://github.com/facebookresearch/faiss
https://github.com/DataIntelligenceCrew/go-faiss
https://zhuanlan.zhihu.com/p/357414033
https://guangzhengli.com/blog/zh/vector-database/
https://github.com/sashabaranov/go-openai/blob/master/embeddings.go