赞
踩
Chroma是一款开源的向量数据库,它使用向量相似度搜索技术,可以快速有效地存储和检索大规模高维向量数据。它的应用场景包括推荐系统、图像和视频搜索、自然语言处理等领域,可以帮助用户快速地找到相似的数据和信息。
Chroma是一款应用嵌入式数据库,以包的形式嵌入到我们的代码,Chroma的优点就是简单,如果你在开发LLM应用需要一个向量数据库实现LLM记忆功能,需要支持文本相似语言搜索,又不想安装独立的向量数据库,Chroma是不错的选择。
pip install chromadb
import chromadb
chroma_client = chromadb.client()
合集(collection)在chroma数据库中的作用就类似表,存储向量数据(包括文档和其他源数据)的地方,下面创建一个集合:
# 创建集合
collection = chroma_client.create_collection(name="test")
Chroma会存储我们的数据,并根据文本数据的向量创建专门的向量索引方便后面查询。
# 假设这里是需要存储的文本
text1 = "This is a document"
text2 = "This is another document"
# 使用内置的嵌入模型计算向量
collection.add(
documents=[text1,text2],
metadatas=[{"source": "my_source"}, {"source": "my_source"}],
ids=["id1", "id2"]
)
- documents参数就是需要写入的文本数据数组,支持一次插入多条数据
- metadatas是每条写入的数据关联的一些属性
- ids 是每条写入数据的id
# 指定向量值
collection.add(
embeddings=[[1.2, 2.3, 4.5], [6.7, 8.2, 9.2]],
documents=[text1, text2],
metadatas=[{"source": "my_source"}, {"source": "my_source"}],
ids=["id1", "id2"]
)
results = collection.query(
query_texts=["This is a query document"],
n_results=2
)
其中n为n个最相似的结果。默认情况下,Chroma中的数据是存储在内存中,重启程序数据就丢了,当然你可以设置Chroma的数据持久化到硬盘,这样程序启动的时候会去加载磁盘中的数据。
client = chromadb.PersistentClient(path="/data/tizi365.db")
客户端对象一些常用的函数
client.reset() # 清空并完全重置数据库
前面提到过,chromadb中的集合类似mysql中的数据表,因此其命名本身也存在一些限制:
需要注意的是,如果你在创建时候指定了向量计算函数,则获取集合时也应该提供向量计算函数
。# 通过embedding_function参数指定向量计算函数,不指定则使用内置的函数
collection = client.create_collection(name="my_collection", embedding_function=emb_fn)
创建时候,还可以指定向量计算方法,类似如下:
collection = client.create_collection(
name="collection_name",
metadata={"hnsw:space": "cosine"} # l2 是默认的计算方法
)
# 如果创建集合的使用指定了向量计算函数,引用集合的时候也要指定向量计算函数
collection = client.get_collection(name="my_collection", embedding_function=emb_fn)
# 删除指定集合
client.delete_collection(name="my_collection")
collection.peek() # 返回集合中前 10 个数据的列表
collection.count() # 返回集合中的数据总数
collection.modify(name="new_name") # 重命名集合
使用.add
方法将数据添加到Chroma,类似如下:
collection.add(
documents=["lorem ipsum...", "doc2", "doc3", ...],
metadatas=[{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
ids=["id1", "id2", "id3", ...]
)
如果 Chroma 收到一个文档列表(documents),它会自动使用集合的嵌入函数对文档进行向量计算(如果创建集合时未提供嵌入函数,则使用默认值)。Chroma 还会存储文档本身。如果文档太大,无法使用所选的嵌入函数计算,则会出现异常。
每个文件都必须有一个唯一的ID(ids)。两次添加相同的 ID 会导致只存储初始值。可以为每个文档提供一个可选的元数据字典(metadatas)列表,以存储更多信息,用于支持查询的时候筛选数据。
或者,你也可以直接提供文档相关向量数据的列表,Chroma直接使用你填写的向量数据,而不会自动计算向量。(但是需要注意的是提供的向量维度(长度)与集合的维度不一致),则会出现异常。
你也可以将文档存储在其他地方,只需向 Chroma 提供向量数据和元数据列表即可。你可以使用 ids 将向量与存储在其他地方的文档关联起来。
collection.add(
embeddings=[[1.1, 2.3, 3.2], [4.5, 6.9, 4.4], [1.1, 2.3, 3.2], ...],
metadatas=[{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
ids=["id1", "id2", "id3", ...]
)
需要注意的是,向量数据库的核心功能是基于向量数据的语义搜索,为减小向量数据库的大小,提高效率,我们可以选择在向量数据库存储向量数据和一些需要筛选的属性条件就行,其他数据,例如文章内容等数据,存储到其他专门的数据库中,只要通过id关联起来就可以了。
collection.query(
query_embeddings=[[11.1, 12.1, 13.1],[1.1, 2.3, 3.2], ...],
n_results=10,
where={"metadata_field": "is_equal_to_this"},
where_document={"$contains":"search_string"}
)
查询将按顺序返回与每个查询向量(query_embedding)最匹配的 n_results 个结果。可以提供一个可选的 where 过滤字典,根据与每个文档相关的元数据过滤结果。此外,还可提供一个可选的 where_document 过滤字典,用于根据文档内容过滤结果。
如果提供的 query_embeddings 与集合的维度不一致,则会出现异常,为了确保向量维度一致,统一使用同一个文本嵌入模型计算向量就行。
你也可以通过一组查询文本进行查询。Chroma 会首先使用集合的嵌入函数计算每一个查询文本的向量,然后使用生成的文本向量执行查询。
# 直接通过文本查询,相似的内容,这里chroma会使用默认嵌入模型计算向量
collection.query(
query_texts=["doc10", "thus spake zarathustra", ...],
n_results=10,
where={"metadata_field": "is_equal_to_this"},
where_document={"$contains":"search_string"}
)
另外可以使用.get
从集合中按照id查询数据
collection.get(
ids=["id1", "id2", "id3", ...],
where={"style": "style1"}
)
.get 还支持 where 和 where_document 筛选器。如果没有提供 id,它将返回集合中符合 where 和 where_document 筛选器的所有项目。
# 根据id批量更新数据
collection.update(
ids=["id1", "id2", "id3", ...],
embeddings=[[1.1, 2.3, 3.2], [4.5, 6.9, 4.4], [1.1, 2.3, 3.2], ...],
metadatas=[{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
documents=["doc1", "doc2", "doc3", ...],
)
如果在集合中找不到 id,将记录错误并忽略更新。如果提供的文档没有相应的向量,将使用集合的嵌入函数计算向量。
Chroma 支持使用 .delete 按 id 从集合中删除数据。与每个数据相关的向量、文档和元数据都将被删除。
collection.delete(
ids=["id1", "id2", "id3",...],
where={"chapter": "20"}
)
默认情况下,Chroma 使用 Sentence Transformers的 all-MiniLM-L6-v2 模型计算向量。该嵌入模型可以创建句子和文档向量。该嵌入模型功能在本地计算机上运行,需要下载模型文件(这是自动完成的)。
前面的代码都是使用默认嵌入实现的,现在使用OpenAI提供的接口来完成嵌入并存入数据库中。
import chromadb
from chromadb.utils import embedding_functions
from chromadb.api.types import Documents, EmbeddingFunction, Embeddings
# 初始化客户端
chroma_client = chromadb.Client()
# 使用openai的嵌入接口
openai_ef = embedding_functions.OpenAIEmbeddingFunction(
api_key="REPLACE BY YOUR KEY",
model_name="text-embedding-ada-002"
)
class MyEmbeddingFunction(EmbeddingFunction):
def __call__(self, texts: Documents) -> Embeddings:
return openai_ef.embed_with_retries(texts)
# 创建集合
collection = chroma_client.create_collection(name="test", embedding_function=MyEmbeddingFunction())
Qdrant是一个开源向量数据库,专为下一代AI应用程序设计。它是面向云原生的,并提供RESTful和gRPC API以管理嵌入。Qdrant的特性强大,支持图像、语音和视频搜索,以及与AI引擎的集成。
向量数据库是一种专门设计用于高效存储和查询高维向量的数据库。在传统的OLTP和OLAP数据库中(如上图所示),数据以行和列的方式组织(这些被称为表),查询是基于这些列中的值进行的。然后,在某些应用中,如图像识别、自然语言处理和推荐系统,数据通常以高维空间中的向量表示,这些向量加上一个id和有效负载,就是我们存储在类似于Qdrant的向量数据库中的元素。
在这个背景下,向量是对象或数据点(point)的数学表示,向量的每个元素对于对象的某个特征或者属性。例如,在图像识别系统中,向量可以表示为一个图像,向量的每个元素代表像素值或该像素特征/描述符。在音乐推荐系统中,每个向量代表一首歌曲,向量的每个元素代表歌曲的每个特征,比如节奏、流派、歌词等。
向量数据库针对高维向量的高效存储和查询进行了优化,通常使用了专门的数据结构和索引技术,如层次式可导航小世界(HNSW,用于实现近似最近邻搜索)和乘积量化等。这些数据库能够在允许用户按照某个距离度量标准,找到与给定查询向量最接近的向量的同时,实现快速相似性和语义搜索。最常用的距离度量标准有欧式距离、余弦相似度和点积,在Qdrant中这三种度量标准得到了完全的支持。
以下是对这三种向量相似度算法的简要介绍:
使用向量数据库的其他好处包括:
docker pull qdrant/qdrant
docker run -p 6333:6333 -p 6334:6334 -v ~/data:/qdrant.storage:z qdrant/qdrant
PUT /collections/{collection_name}
{
"vectors": {
"size": 300,
"distance": "Cosine"
}
}
参数说明:
- collection_name 集合名字(必填)
- vectors 参数定义
- size:向量的长度(也叫维度)
- distance:向量相似度算法,主要有“Cosine”、“Euclid”、"Dot"三种算法。
id
、payload(关联数据)
、向量数据(vector)
三部分。PUT /collections/{collection_name}/points
{
"points": [
{
"id": "5c56c793-69f3-4fbf-87e6-c4bf54c28c26", // id
"payload": {"color": "red"}, // 关联的属性数据,通常业务这里可以关联业务的属性,例如:订单ID、商品ID、标题等等属性
"vector": [0.9, 0.1, 0.1] // 向量数据,代表当前业务数据的特征
}
]
}
POST /collections/{collection_name}/points/search
{
"vector": [0.2, 0.1, 0.9, 0.7], // 向量参数
"limit": 3 // 返回相似度最高的3条数据
}
需要将你搜索的内容,先转换为向量,然后再根据该向量在向量数量数据库中搜索。
// collection_name - 集合名字
POST /collections/{collection_name}/points/search
{
"filter": { // 这里主要用于过滤payload的关联属性,整体语法格式类似elasticsearch语法,这个参数是可选的
"must": [ //筛选color=red的point数据
{
"key": "color",
"match": {
"value": "red"
}
}
]
},
"vector": [0.2, 0.1, 0.9, 0.7], // 向量参数
"limit": 3
}
同一集合内每个点的向量都必须具有相同的维度,并通过单一度量进行比较。命名向量可用于在单个点中包含多个向量,每个向量都可以有自己的维度和度量要求。
距离度量用于衡量向量之间的相似性。度量的选择取决于向量获取的方式,特别是神经网络编码器训练的方法。
设置多租户
创建集合
PUT /collections/{collection_name}
{
"vectors": {
"size": 300,
"distance": "Cosine"
}
}
DELETE /collections/{collection_name}
PATCH /collections/{collection_name}
{
"optimizers_config": {
"indexing_threshold": 10000
}
}
GET /collections/{collection_name}
点(points)是Qdrant操作的核心实体。一个点是由向量(vector)和可选载荷(payload)组成的记录。
您可以根据向量(矢量)相似性搜索在一个集合中分组的点。更详细的过程描述在搜索和过滤部分中。
本节介绍如何创建和管理矢量(向量)。
任何点(point)的修改操作都是异步的,并且分为两个步骤。在第一阶段,操作将被写入预写日志中。
此刻开始,即使机器供电中断,服务也不会丢失数据。
PUT /collections/{collection_name}/points
{
"points": [
{
"id": "5c56c793-69f3-4fbf-87e6-c4bf54c28c26",
"payload": {"color": "red"},
"vector": [0.9, 0.1, 0.1]
}
]
}
Qdrant API支持两种批量创建方式 - 记录导向和列导向。在内部,这些选项没有区别,只是为了方便交互。
PUT /collections/{collection_name}/points
{
"points": [
{
"id": 1,
"payload": {"color": "red"},
"vector": [0.9, 0.1, 0.1]
},
{
"id": 2,
"payload": {"color": "green"},
"vector": [0.1, 0.9, 0.1]
},
{
"id": 3,
"payload": {"color": "blue"},
"vector": [0.1, 0.1, 0.9]
}
]
}
PUT /collections/{collection_name}/points/vectors
{
"points": [
{
"id": 1,
"vector": {
"image": [0.1, 0.2, 0.3, 0.4]
}
},
{
"id": 2,
"vector": {
"text": [0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2]
}
}
]
}
POST /collections/{collection_name}/points/vectors/delete
{
"points": [0, 3, 100],
"vectors": ["text", "image"]
}
Qdrant的一个重要特性之一是能够在向量之外存储附加信息(存储管理业务属性)。在Qdrant术语中,这些附加信息被称为“负载”。
Qdrant允许您存储任何可以使用JSON表示的信息。
在过滤过程中,Qdrant将检查那些符合过滤条件的值的条件。如果存储的值类型不符合过滤条件,则被认为是未满足条件的。
简单来说,你可以提前设想好,存放哪些数据到json格式的数据中,然后将这个数据设置为对应向量的payload
负载索引
为了更有效地进行过滤搜索,Qdrant允许您通过指定字段的名称和类型来为负载字段创建索引。
索引字段也会影响向量索引。
在实践中,我们建议在那些可能最多限制结果的字段上创建索引。例如,使用对象ID的索引将比使用颜色的索引更高效,因为对象ID对于每个记录是唯一的,而颜色只有几个可能的值。
在涉及多个字段的复合查询中,Qdrant将尝试首先使用最具限制性的索引。
要为字段创建索引,可以使用以下内容:
PUT /collections/{collection_name}/index
{
"field_name": "要创建索引的字段名称",
"field_schema": "keyword"
}
第二步是向量比较。在这种情况下,它等同于点积运算-由于SIMD的快速操作。
POST /collections/{collection_name}/points/search
{
"filter": {
"must": [
{
"key": "city",
"match": {
"value": "伦敦"
}
}
]
},
"params": {
"hnsw_ef": 128,
"exact": false
},
"vector": [0.2, 0.1, 0.9, 0.7],
"limit": 3
}
POST /collections/{collection_name}/points/search
{
"vector": [0.2, 0.1, 0.9, 0.7],
"with_vectors": true,
"with_payload": true,
"limit": 10,
"offset": 100
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。