Faiss向量数据库的配置与使用!
Faiss向量数据库的配置与使用!
月伴飞鱼目前关于向量数据库的技术进展非常迅速,所以不同服务商提供的向量数据库使用差异非常大。
数据的存储结构、支持的相似性检索方式、集合、条件筛选等功能差异也比较大。
在 LangChain 中对于向量数据库基类只做了通用性的封装,减轻了部分迁移成本。
在使用向量数据库时一定要综合衡量下各个向量数据库的差异。
按照部署方式和提供的服务类型进行划分,向量数据库可以划分成几种。
本地文件向量数据库:
用户将向量数据存储到本地文件系统中,通过数据库查询的接口来检索向量数据,例如:Faiss。
本地部署 API 向量数据库:
这类数据库不仅允许本地部署,而且提供了方便的 API 接口,使用户可以通过网络请求来访问和查询向量数据。
这类数据库通常提供了更复杂的功能和管理选项,例如:Milvus、Annoy、Weaviate 等。
云端 API 向量数据库:
将向量数据存储在云端,通过 API 提供向量数据的访问和管理功能,例如:TCVectorDB、Pinecone 等。
要想快速上手向量数据库的使用,只需要把向量数据库看成是 Excel电子表格 使用即可,按照使用办公软件的流程:
安装、写入数据、查找数据、删除数据、更新数据、保存数据等相同的流程去学习+使用向量数据库即可。
而且向量数据库没有 SQL 数据库这么多复杂的查询功能,也没有事务,学习起来其实比绝大部分传统数据库都要容易上手。
Faiss向量数据库简介
Faiss 是 Facebook 团队开源的向量检索工具。
针对高维空间的海量数据,提供高效可靠的相似性检索方式,被广泛用于推荐系统、图片和视频搜索等业务。
在百万级向量的相似性检索表现中,Faiss 能实现 < 10ms 的响应(需牺牲搜索准确度)。
Faiss 官网:https://faiss.ai/
Faiss 使用 C++ 开发,提供了 Python 接口,可以通过 PIP 安装 Faiss 库。
1 | pip install faiss-cpu |
GPU环境下使用并且已经安装了CUDA,则可以使用GPU版本。
1 | pip install faiss-gpu |
目前绝大部分向量数据库都支持多种对数据的操作方法:
新增数据、检索数据、带得分的数据检索、带筛选条件的数据检索、删除数据等,但是几乎都不支持修改数据。
这是因为向量数据库通常使用特定的索引结构(如向量索引树或近似最临搜索算法),这些结构结构需要再数据插入后进行构建和优化。
如果允许修改数据,索引结构可能需要频繁更新,这会显著增加系统的复杂性和开销,所以一般是删除后再新增。
Faiss 也类似,不过由于 Faiss 是本地文件向量数据库,还额外支持了将向量数据持久化到本地、从本地文件夹加载向量数据库等操作。
Faiss 向量数据库使用技巧
数据的导入与相似性搜索:
在 LangChain 中,提供了
from_texts
和from_documents
两个通用方法。这两个方法可以快捷从 文本和 文档 中导入数据到向量数据库中。
由于向量数据库存储的向量,所以需要传入文本嵌入模型,让向量数据库自动将传入的文本转换成向量。
1 | import dotenv |
完成数据的填充后,即可在向量数据库中进行对应的检索,LangChain 为所有的向量数据库都设计封装了一致的搜索接口。
最常用的有以下 4 种:
similarity_search()
:
- 基础相似度搜索,传递 query(搜索语句)、k(返回条数)、filter(过滤器)、fetch_k(富余条数) 等。
similarity_search_with_score()
:
- 携带得分的相似性搜索,参数和
similarity_search()
函数保持一致,只是会返回得分。- 这里的得分并不是相似性得分,而是欧几里得距离。
similarity_search_with_relevance_scores()
:
- 携带相关性得分的相似性搜索,得分范围是 0-1。
as_retriever()
:
- 将向量数据库转换成检索器,检索器是 Runnable 可运行组件。
在向量数据库中进行检索并携带得分(这里的得分并不是相似性得分,默认是欧几里得距离),效果如下:
1 | print(db.similarity_search_with_score("我养了一只猫,叫笨笨")) |
输出内容:
1 | [(Document(page_content='我养了一只猫,叫大笨'), 0.11375141), (Document(page_content='猫咪在窗台上打盹,看起来非常可爱。'), 1.0895041), (Document(page_content='我的狗喜欢追逐球,看起来非常开心。'), 1.3836973), (Document(page_content='我的手机突然关机了,让我有些焦虑。'), 1.5533546)] |
由于不同文本嵌入模型生成向量的范围不一致。
LangChain 封装的 Faiss 计算相关性得分的时候,可能会出现 Bug(比如出现负数)。
在使用 LangChain 封装的向量数据库时,一定要注意测试和校验下文本嵌入模型生成向量的数值范围,避免出现明显的错误。
由于向量数据库目前更新太快,而且 LangChain 封装了太多的第三方组件(数百个)。
在很多场合下,LangChain 可能没有对每一种情况进行测试,有可能会出现一些莫名其妙的计算结果。
带过滤的相似性搜索
在绝大部分向量数据库中,除了存储向量数据,还支持存储对应的元数据。
这里的元数据可以是文本原文、扩展信息、页码、归属文档ID、作者、创建时间等等任何自定义信息。
一般在向量数据库中,会通过元数据来实现对数据的检索。
比较遗憾的是 Faiss 原生并不支持过滤,所以在 LangChain 封装的 FAISS 中对过滤功能进行了相应的处理。
首先获取比 K 更多的结果 Fetch_K(默认为 20 条),然后先进行搜索。
接下来再搜索得到的 Fetch_K 条结果上进行过滤,得到 K 条结果,从而实现带过滤的相似性搜索。
而且 Faiss 的搜索都是针对 元数据 的,在 Faiss 中执行带过滤的相似性搜索非常简单,只需要在搜索时传递 Filter 参数即可。
Filter 可以传递一个元数据字典,也可以接收一个函数(函数的参数为元数据字典,返回值为布尔值)。
例如下方的代码只会对 Page>5 的文档进行检索,代码如下:
1 | import dotenv |
删除指定数据
在 Faiss 中,支持删除向量数据库中特定的数据,目前仅支持传入数据条目 ID 进行删除,并不支持条件筛选。
但是可以通过条件筛选找到符合的数据,然后提取 ID 列表,然后批量删除。
1 | db.delete([db.index_to_docstore_id[0]]) |
保存和加载本地数据
除了从文本和文档列表中加载数据到向量数据库,Faiss 还支持将整个数据库持久化到本地文件。
亦或者从本地文件一键加载数据,这样就不需要在每次使用向量数据库的时候重新创建。
可以极大提升向量数据库的使用效率,两个方法如下:
save_local()
:
- 将向量数据库持久化到本地,传递
folder_path
和index
分别代表文件夹路径与索引名字。
load_local()
:
- 将本地的数据加载到向量数据库,传递
folder_path
、embeddings
和index
分别代表文件夹路径、嵌入模型、索引名字。
1 | db.save_local("./vector-store/") |
输出结果:
1 | [Document(page_content='笨笨是一只很喜欢睡觉的猫咪', metadata={'page': 1}), Document(page_content='猫咪在窗台上打盹,看起来非常可爱。', metadata={'page': 3}), Document(page_content='我的狗喜欢追逐球,看起来非常开心。', metadata={'page': 10}), Document(page_content='我的手机突然关机了,让我有些焦虑。', metadata={'page': 7})] |