今年AI大模型应用呈井喷式发展,其中,LangChain、Haystack等端到端大语言模型应用框架更是将向量数据库推出了新热点。
向量数据库(vector database,也有人称矢量数据库),简单地说,它们是以向量格式管理、存储和检索数据的数据库。
为什么向量数据库对AI如此重要?
因为它在处理高维数据方面具有先天优势,从图像处理到推荐系统,向量数据库无疑是幕后的英雄。它的主要功能包括:
- 管理:向量数据库以原始数据形式处理数据,能够有效地组织和管理数据,便于AI模型应用。
- 存储:能够存储向量数据,包括各种AI模型需要使用到的高维数据。
- 检索:向量数据库特别擅长高效地检索数据,这一个特点能够确保AI模型在需要的时候快速获得所需的数据。这也是向量数据库能够在一些推荐系统或者检索系统中得到应用的重要原因。
因此,我们说向量数据库让AI有了记忆,这个记忆不仅仅是记录存储、也包括检索和管理。就像人类的记忆一样,我们通过同学的毕业照总是能够认得这个人是谁;我们在和朋友聊天的时候也常常会一起回忆过去。
那么向量数据库是如何工作的?
向量数据库的核心是通过使用数学模型来管理向量数据。
那么什么又是向量?简单地说,向量是一个既有方向又有大小的数字对象。在向量数据库中,向量可以用于表示复杂的数据,例如:图像、文本。
每个数据片段都被转换成高维空间中的向量管理起来。当我们需要查找相似的数据片段时,数据库不需要遍历筛选选每个条目。而是通过计算向量之间的距离来匹配,向量越接近,数据就越相似。这种方式非常高效,通过这种方式检索数据可以比传统关系型数据库更快地处理大批量数据。
下面是个文本向量存储的示例图:
下面是图片向量化存储与检索的示例图:
大家都知道,通用大模型的运行涉及巨大的计算资源,因此许多大模型都基于MaaS,私有化成本很高。与之相矛盾的是在具体行业大模型应用中往往对数据安全要求高,并且需要与相关业务或领域知识深入融合,才能做到安全、专业。LangChain等大模型应用框架为行业大模型应用提供了一个经典解决方案,而开源的向量数据库又为LangChain等大模型应用解决方案提供了基础支撑,其实向量数据库在许多应用场景(如:企业知识库、推荐系统、档案管理等)也非常有用。因此,向量数据库也成为大模型应用发展的一个热门技术。
八个优秀的开源向量数据库项目
开源社区对向量数据库的发展功不可没,许多开源向量数据库项目在性能、灵活性和鲁棒性方面表现都非常优秀,下面列举8个目前最佳的开源向量数据库项目,这些开业项目应该能够为你的AI解决方案提供最佳技术选型。
1.Milvus
https://github.com/milvus-io/milvus
Milvus是由Zilliz提供的一个高度可定制的开源向量数据库,旨在为嵌入式相似性搜索等AI应用提供支持。目前Milvus已经发布了 2.0 ,Milvus 2.0是一个云原生向量数据库,设计上采用存储、计算分离。Milvus2.0中的所有组件都支持无状态,这样做就使得整个的应用更加灵活而有弹性。
Milvus建立在Faiss、Annoy、HNSW等主流向量搜索库之上,旨在对包含数百万、数十亿甚至数万亿个向量的密集向量数据集进行相似性搜索。
Milvus还支持数据分片、数据持久化、流数据摄取、向量和标量数据之间的混合搜索以及许多其他高级功能。建议使用Kubernetes部署Milvus,以获得最佳可用性和弹性。
Milvus采用共享存储架构,存储、计算分离,具备计算节点的水平可扩展性。遵循数据平面和控制平面分解原则,Milvus包括四层:接入层、协调服务、工作节点和存储。在扩展或灾难恢复方面,这些层可以做到相互独立。
下面是Milvus的架构图。
Milvus的主要特性包括:
- 支持万亿向量数据集上的毫秒级搜索:在万亿向量数据集上测试平均延迟(毫秒级)。
- 简化的非结构化数据管理:丰富API、跨客户端一致的用户体验。
- 始终保持高可靠性:Milvus的内置复制和故障转移/回切功能可确保数据和应用程序在发生中断时保持业务连续性。
- 高度可扩展和弹性性能:组件级的可伸缩性使其可以按需伸缩。Milvus可以根据负载类型在组件级别自动缩放,使资源调度更加高效。
- 混合搜索能力:除了向量,Milvus还支持“布尔类型”、“整数”、“浮点数”等数据类型。
- 统一Lambda结构:Milvus将流和批处理结合起来进行数据存储,以平衡及时性和效率。它的统一界面使向量相似性搜索变得轻而易举。强大的社区支持和行业的认可:拥有超过1000个企业用户,GitHub超23K Star,以及活跃的开源社区。
更多内容可以参考官网:https://milvus.io
Demo:https://milvus.io/milvus-demos/
文档: https://milvus.io/docs
2.Faiss
https://github.com/facebookresearch/faiss
Faiss由Facebook的AI Research团队开发的向量数据库,在高维矢量搜索方面表现出色。是一个搜索效率非常突出的向量库,这也使其成为一些实时性要求高的应用程序的绝佳选择。Faiss是一个高效的相似性搜索和密集向量聚类库。它包含的算法可以搜索任何大小的向量集,甚至多达超过RAM的向量大小。它还包含用于评估和参数调整的支持代码。Faiss是用C++编写的,带有Python/numpy的完整包装,一些常用的算法是在GPU上实现的。
Faiss是通过存储一组向量的索引,并提供了一个函数在它们当中进行比较,从而实现搜索。
目前Faiss在GitHub上的Star已经超过24K。
基于CPU、GPU的python安装方法如下:
$ conda install -c pytorch faiss-cpu
$ conda install -c pytorch faiss-gpu
以上只能安装一个,不能同时安装两个,因为后者是前者的超集。
3.Annoy
https://github.com/spotify/annoy
Annoy (Approximate Nearest Neighbors Oh Yeah)是由Spotify创建的一个轻量级且功能强大的向量数据库。它专为快速搜索大型数据集而设计,非常适合需要快速响应的应用。它是一个C++库,但支持在Python中使用。
它通过创建大型的只读文件数据结构,并将这些数据结构映射到内存中,以便许多进程可以共享相同的数据。
ANNOY的核心是一种基于随机投影和树的算法。它由Erik Bernhardsson于2015年在Spotify工作时开发。ANNOY设计目标是实现在100到1000个密集维度的数据集中进行搜索。为了计算最近的邻居,它将点集分成两半,并递归地进行,直到每个集合都有k个项目。通常k应该在100左右(见下图)。
关于Annoy的主要特征官方介绍如下:
- 支持多种相似算法:欧氏距离、曼哈顿距离、余弦距离、汉明距离、内积距离。余弦距离等价于归一化向量的欧几里得距离= sqrt(2-2*cos(u,v))
- 如果你没有太多的维度(比如<=100),效果会更好,但即使是1000维的维度,它的表现也还是非常优秀。
- 内存占用小
- 允许在多个进程之间共享内存
- 索引创建与查找是分开的(特别是,一旦创建了树,就不能添加更多的项)
- 原生Python支持,已在2.7、3.6和3.7中测试。
- 在磁盘上构建索引,以便索引无法放入内存的大数据集
python语言下的安装annoy:
pip install annoy
python语言下的使用annoy:
from annoy import AnnoyIndex
import random
f = 40 # Length of item vector that will be indexed
t = AnnoyIndex(f, 'angular')
for i in range(1000):
v = [random.gauss(0, 1) for z in range(f)]
t.add_item(i, v)
t.build(10) # 10 trees
t.save('test.ann')
# ...
u = AnnoyIndex(f, 'angular')
u.load('test.ann') # super fast, will just mmap the file
print(u.get_nns_by_item(0, 1000)) # will find the 1000 nearest neighbors
4.Nmslib
https://github.com/nmslib/nmslib
Nmslib (Non-Metric Space Library)是一个于非度量空间的开源向量数据库。是一个高效的跨平台相似性搜索库,也是一个评估相似性搜索方法的工具包,并且它的核心库没有任何第三方依赖项。
该项目的目标是创建一个用于能够在通用以及非度量空间中进行搜索的全面工具包,包括:通用搜索方法、近似搜索方法、各种度量空间访问方法以及非度量空间的方法。
Nmslib是一个可扩展的库,可以添加新的搜索方法和距离函数。支持在C++和Python、Java中使用,例如:可以使用Java等语言构建一个查询服务器。
5.Qdrant
https://github.com/qdrant/qdrant
Qdrant是一个包含向量数据库和向量相似度搜索引擎的开源项目。它提供了一组便捷的API来执行存储、搜索和管理向量数据,并且能够同时存储payload数据,这就有利于自定义的数据过滤,这个方面在各种神经网络、基于语义的匹配、分面搜索、精准推荐等应用程序非常有用。
Qdrant是用Rust语言开发的,因此它能在高负载下也具备高效、可靠特性。Qdrant的使用非常简单:
(1)使用Docker启动
docker run -p 6333:6333 qdrant/qdrant
br
(2)在python中使用
安装:
pip install qdrant-client
连接:
from qdrant_client import QdrantClient
qdrant = QdrantClient("http://localhost:6333") # Connect to existing Qdrant instance, for production
qdrant的特点如下:
- 过滤和有效数据:Qdrant使JSON格式存储Payload(有效数据)与向量相关联,支持should、must和must_not条件的各种组合检索方式,确保能够检索所有向量,这点与ElasticSearch的后过滤不同。
- 支持丰富的数据类型:Payload适应不同的数据类型和查询条件,包括字符串匹配、数值范围、地理位置等。这些筛选条件使您能够在相似性匹配的基础上创建自定义业务逻辑。
- 查询计划和Payload索引:查询规划器利用存储的Payload信息来优化查询。
- 硬件加速:利用现代CPU x86-x64架构,Qdrant在现代硬件上提供更快的搜索性能。
- 写入前记录日志:Qdrant通过更新确认确保数据的持久性,即使在停电期间也是如此。更新日志存储所有操作,从而可以轻松地重建最新的数据库状态。
- 分布式部署:从v0.8.0开始,Qdrant支持分布式部署。多个Qdrant机器形成一个集群,通过Raft协议进行协调,以进行水平扩展。
- 独立运行:Qdrant支持独立运行,不依赖外部数据库或编排控制器,简化了配置。
6.Chroma
https://github.com/chroma-core/chroma
Chroma是一个开源嵌入式向量数据库。基于Chroma可以轻松构建LLM应用程序。Chroma的设计非常简单、易用、灵活,可以满足各种场景下的应用。它支持使用第三方的embedding模型执行查询和元数据过滤。
下面是Chroma与OpenAI embedding搭配使用的架构示意图:
基于Docker的Chromadb可以参考:
- docker-compose:https://github.com/chroma-core/chroma/blob/main/docker-compose.yml
- dockerFile: https://github.com/chroma-core/chroma/blob/main/Dockerfile
在具体应用开发上,Python下使用Chroma也非常简单。
安装:
pip install chromadb
四个核心API的使用:
import chromadb
# setup Chroma in-memory, for easy prototyping. Can add persistence easily!
client = chromadb.Client()
# Create collection. get_collection, get_or_create_collection, delete_collection also available!
collection = client.create_collection("all-my-documents")
# Add docs to the collection. Can also update and delete. Row-based API coming soon!
collection.add(
documents=["This is document1", "This is document2"], # we handle tokenization, embedding, and indexing automatically. You can skip that and add your own embeddings as well
metadatas=[{"source": "notion"}, {"source": "google-docs"}], # filter on these!
ids=["doc1", "doc2"], # unique for each doc
)
# Query/search 2 most similar results. You can also .get by id
results = collection.query(
query_texts=["This is a query document"],
n_results=2,
# where={"metadata_field": "is_equal_to_this"}, # optional filter
# where_document={"$contains":"search_string"} # optional filter
)
Chroma的主要特点包括:
- 简单:类型完整、测试全面、文档完整
- 整合:支持LangChain(python和js)、LlamaIndex等等。
- 开发、测试、生产过程:在python notebook中运行的API可直接应用到集群环境。
- 功能丰富:查询、过滤、密度估计等
- 免费、开源
7.LanceDB
https://github.com/lancedb/lancedb
LanceDB是一个开源的支持持久存储的向量搜索数据库,这个开源项目可以大大简化embeddings的检索、过滤和管理。
LanceDB的内核是用Rust开发的,并使用Lance构建(Lance是一种为高性能ML工作负载设计的开源列格式)。Python和JavaScript等语言可以使用API操作LanceDB。
Python的使用方式如下:
安装:
pip install lancedb
检索:
import lancedb
uri = "data/sample-lancedb"
db = lancedb.connect(uri)
table = db.create_table("my_table",
data=[{"vector": [3.1, 4.1], "item": "foo", "price": 10.0},
{"vector": [5.9, 26.5], "item": "bar", "price": 20.0}])
result = table.search([100, 100]).limit(2).to_df()
LanceDB的主要功能特点如下:
- 无需管理服务器的生产规模向量搜索。
- 支持存储、查询以及过滤向量、元数据和多模态数据(文本、图像、视频、点云等)。
- 支持向量相似度搜索、全文检索和SQL语法。
- 支持Python和JavaScript/Typescript。
- 零拷贝、自动版本控制,无需额外基础架构即可管理数据版本。
- 支持基于GPU构建向量索引。
- 支持与LangChain️、LlamaIndex、Apache-Arrow、Pandas、Polars、DuckDB等生态集成。
8.Vectra
https://github.com/Stevenic/vectra
Vectra是一个Node.js的本地向量数据库,其功能类似于Pinecone或Qdrant,但区别是Vectra使用本地文件构建。每个Vectra索引都对应磁盘上的一个文件夹。文件夹中包含一个index.json文件,文件内容包含索引的所有向量以及这些索引的元数据。创建索引时,可以指定索引的元数据属性,只有这些字段才会存储在index.json文件中。而项目的其他元数据将会被保存到一个有GUID指定的文件中。
运行时,整个Vectra索引都被加载到内存中,因此它的检索效率非常高,甚至是实时的,但是它不适合用于类似需要保留长上下文的聊天机器人场景。Vectra更适合用于一些小的语料库、静态数据或者一些问答文档的检索等应用场景。
在Node.js中的使用如下:
安装:
$ npm install vectra
创建实例:
if (!await index.isIndexCreated()) {
await index.createIndex();
}
创建索引:
import { LocalIndex } from 'vectra';
const index = new LocalIndex(path.join(__dirname, '..', 'index'));
添加数据到索引:
import { OpenAIApi, Configuration } from 'openai';
const configuration = new Configuration({
apiKey: `<YOUR_KEY>`,
});
const api = new OpenAIApi(configuration);
async function getVector(text: string) {
const response = await api.createEmbedding({
'model': 'text-embedding-ada-002',
'input': text,
});
return response.data.data[0].embedding;
}
async function addItem(text: string) {
await index.insertItem({
vector: await getVector(text),
metadata: { text }
});
}
// Add items
await addItem('apple');
await addItem('oranges');
await addItem('red');
await addItem('blue');
检索数据:
async function query(text: string) {
const vector = await getVector(input);
const results = await index.queryItems(vector, 3);
if (results.length > 0) {
for (const result of results) {
console.log(`[${result.score}] ${result.item.metadata.text}`);
}
} else {
console.log(`No results found.`);
}
}
await query('green');
/*
[0.9036569942401076] blue
[0.8758153664568566] red
[0.8323828606103998] apple
*/
await query('banana');
/*
[0.9033128691220631] apple
[0.8493374123092652] oranges
[0.8415324469533297] blue
*/
总之
以上这些开源向量数据库每一个都有自己独特的一面。选择使用哪一款取决于项目的具体需求。如果您正在处理一个需要高速数据检索的项目,那么Annoy可能是最合适的。但如果项目涉及非度量空间,那么Nmslib可能才是首选的。一个合适的向量数据库可以成为AI解决方案当中的记忆海绵体,让AI不仅能推理还能记忆、检索,提升AI应用的效果。