初始化持久化Chroma数据
import { ChromaClient } from 'chromadb'
初始化客户端
const client = new ChromaClient();
客户常用操作
await client.reset() # 清空数据库
使用集合
Chromadb使用collection
概念来管理向量数据的集合,可以简单的把集合类比成MYSQL的表。
创建、查看和删除Collections
Chroma在URL中使用集合名称,因此对其进行了一些命名限制:
- 名称长度必须介于3到63个字符之间。
- 名称必须以小写字母或数字开头和结尾,中间可以包含点、破折号和下划线。
- 名称不能包含两个连续的点。
- 名称不能是有效的IP地址。
创建集合,需要指定集合名称和一个可选的向量计算函数(也叫embedding嵌入函数)。如果提供了嵌入函数,则必须在每次获取集合时提供它。
说明:向量计算函数(embedding嵌入函数)的作用是用于计算文本向量。
import { ChromaClient } from 'chromadb'
下面创建和引用集合
# 创建集合,名字为my_collection,可以通过embeddingFunction参数指定文本嵌入模型,用于计算向量,也可以不设置,使用默认的
let collection = await client.createCollection({name:"my_collection", embeddingFunction: emb_fn})
# 引用指定名称的集合
let collection2 = await client.getCollection({name:"my_collection", embeddingFunction: emb_fn})
embedding函数以文本作为输入然后返回一个计算的向量数据。
说明:新手可以了解文本嵌入模型教程。
可以使用 .getCollection
按名称引用现有集合,也可以使用 .deleteCollection
删除现有集合。
const collection = await client.getCollection({name: "tizi365"}) # 引用集合tizi365
await client.deleteCollection({name: "my_collection"}) # 删除集合
集合常用函数
await collection.peek() // 返回集合前10条数据
await collection.count() // 返回集合数据总数
调整向量距离计算方法
createCollection
还包含一个可选的metadata
参数,通过设置 hnsw:space 的值,可以自定义向量空间的距离计算方法。
说明:向量数据是通过计算向量之间的空间距离表示向量之间的相似度,距离越近相似度越高,反而相似度越低。
let collection = client.createCollection("collection_name", undefined, metadata={ "hnsw:space": "cosine" })
hnsw:space 的有效选项为 “l2”、”ip “或 “cosine”。默认为 “l2”。
向集合添加数据
使用 .add
将数据添加到 Chroma集合。
不指定文档向量,直接添加数据:
await collection.add({
ids: ["id1", "id2", "id3", ...],
metadatas: [{"chapter": "3", "verse": "16"}, {"chapter": "3", "verse": "5"}, {"chapter": "29", "verse": "11"}, ...],
documents: ["lorem ipsum...", "doc2", "doc3", ...],
})
// 参数说明
// ids - 必填
// embeddings - 可选
// metadata - 可选
// documents - 可选
如果 Chroma 收到一个文档列表(documents),它会自动使用集合的嵌入函数对文档进行向量计算(如果创建集合时未提供嵌入函数,则使用默认值)。Chroma 还会存储文档本身。如果文档太大,无法使用所选的嵌入函数计算,则会出现异常。
每个文件都必须有一个唯一的ID(ids)。两次添加相同的 ID 会导致只存储初始值。可以为每个文档提供一个可选的元数据字典(metadatas)列表,以存储更多信息,用于支持查询的时候筛选数据。
或者,你也可以直接提供文档相关向量数据的列表,Chroma直接使用你填写的向量数据,而不会自动计算向量。
await collection.add({
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: ["lorem ipsum...", "doc2", "doc3", ...],
})
如果提供的向量数据维度(长度)与集合的维度不一致,则会出现异常。
你也可以将文档存储在其他地方,只需向 Chroma 提供向量数据和元数据列表即可。你可以使用 ids 将向量与存储在其他地方的文档关联起来。
await collection.add({
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"}, ...],
})
说明:向量数据库的核心功能是基于向量数据的语义相似搜索,为减小向量数据库的大小,提高效率,我们可以选择在向量数据库存储向量数据和一些需要筛选的属性条件就行,其他数据,例如文章内容等数据,存储到MYSQL之类的数据库,只要通过id关联起来就行。
查询集合数据
使用 .query 方法可以以多种方式查询 Chroma 数据集。
你可以通过一组 query_embeddings(向量数据) 进行查询。
提示:query_embeddings向量数据怎么来,实际开发场景,通常是先把用户的查询问题,通过文本嵌入模型计算出问题向量,然后拿着这个向量去查询相似的内容。
const result = await collection.query({
queryEmbeddings: [[11.1, 12.1, 13.1],[1.1, 2.3, 3.2], ...],
nResults: 10,
where: {"metadata_field": "is_equal_to_this"},
})
// input order
// query_embeddings - optional
// n_results - required
// where - optional
// query_texts - optional
查询将按顺序返回与每个查询向量(query_embedding)最匹配的 n_results 个结果。可以提供一个可选的 where 过滤字典,根据与每个文档相关的元数据过滤结果。此外,还可提供一个可选的 where_document 过滤字典,用于根据文档内容过滤结果。
如果提供的 query_embeddings 与集合的维度不一致,则会出现异常,为了确保向量维度一致,统一使用同一个文本嵌入模型计算向量就行。
你也可以通过一组查询文本进行查询。Chroma 会首先使用集合的嵌入函数计算每一个查询文本的向量,然后使用生成的文本向量执行查询。
await collection.query({
nResults: 10, // n_results
where: {"metadata_field": "is_equal_to_this"}, // where
queryTexts: ["doc10", "thus spake zarathustra", ...], // query_text
})
您还可以使用 .get 从集合中按 id 查询数据。
await collection.get({
ids: ["id1", "id2", "id3", ...], //ids
where: {"style": "style1"} // where
})
.get
还支持 where
和 where_document
筛选器。如果没有提供 id
,它将返回集合中符合 where
和 where_document
筛选器的所数据。
指定返回字段
使用 get
或 query
时,可以使用 include
参数指定需要返回的数据字段,可以指定返回向量数据、文档、元数据中的任意数据。默认情况下,Chroma 会返回文档、元数据,向量距离。您可以通过get或query的 includes 参数传递一个包含字段名称的数组来指定要返回的字段。
# 仅返回documents 和ids
collection.get(
include=["documents"]
)
collection.query(
query_embeddings=[[11.1, 12.1, 13.1],[1.1, 2.3, 3.2], ...],
include=["documents"]
)
使用 Where 过滤器
Chroma 支持通过元数据和文档内容过滤查询。where 过滤器用于过滤元数据,where_document 过滤器用于过滤文档内容,下面讲解过滤条件表达式怎么写。
通过元数据过滤
要对元数据进行过滤,必须为查询提供一个 where 过滤器字典。字典必须具有以下结构:
{
"metadata_field": {
<Operator>: <Value>
}
}
过滤元数据支持以下操作符:
- $eq - 等于(字符串、整数、浮点数)
- $ne - 不等于(字符串、整数、浮点数)
- $gt - 大于(int、浮点数)
- $gte - 大于或等于(int、浮点数)
- $lt - 小于(整数、浮点数)
- $lte - 小于或等于(int、浮点数)
使用 $eq 操作符等同于使用 where 过滤器。
{
"metadata_field": "search_string"
}
# 等价表达式
{
"metadata_field": {
"$eq": "search_string"
}
}
过滤文档内容
要对文档内容进行过滤,必须为查询提供一个 where_document 过滤字典。字典必须具有以下结构:
# 查询包含search_string字符串的内容
{
"$contains": "search_string"
}
使用逻辑操作符
您还可以使用逻辑运算符 $and
和 $or
来组合多个筛选器。
$and
运算符将返回与列表中所有筛选器匹配的结果。
{
"$and": [
{
"metadata_field": {
<Operator>: <Value>
}
},
{
"metadata_field": {
<Operator>: <Value>
}
}
]
}
$or
运算符将返回与列表中任意筛选条件相匹配的结果。
{
"$or": [
{
"metadata_field": {
<Operator>: <Value>
}
},
{
"metadata_field": {
<Operator>: <Value>
}
}
]
}
更新数据
Chroma 还支持向上插入(upsert)操作,它可以更新现有数据,如果数据丕存在则插入新数据。
await collection.upsert({
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"]
})
删除数据
Chroma 支持使用 .delete 按 id 从集合中删除数据。
await collection.delete({
ids: ["id1", "id2", "id3",...], //ids
where: {"chapter": "20"} //where
})