add 添加数据

🎉摘要:本文详细介绍ChromaDB中Collection的add()方法,包括方法签名、必填参数ids、可选参数embeddings/metadatas/documents/images/uris的使用方法、三种写法、长度对齐规则、重复ID处理及向量维度一致性注意事项,帮助开发者正确高效地添加向量数据。

add() 方法用于向指定的集合添加数据。

方法签名

方法签名如下:

collection.add(
    ids,           # 必填,str 或 List[str]
    embeddings,    # 可选,二维 float 数组
    metadatas,     # 可选,dict 或 List[dict]
    documents,     # 可选,str 或 List[str]
    images,        # 可选,np.ndarray 或 List[np.ndarray]
    uris,          # 可选,str 或 List[str]
)

参数详细说明:

ids  必填

类型为 str | List[str],表示每条记录的唯一主键 ID,ID 重复会抛出 DuplicateIDError 错误,例如:

import chromadb

client = chromadb.EphemeralClient()
# 获取集合
col = client.get_or_create_collection("demo_collection", embedding_function=None)
# 添加数据
col.add(
    ids=["r1", "r1"],
    metadatas=[
        {"cat": "售后"},
        {"cat": "财务"}
    ],
    documents=[
        "退款流程:在订单页点申请退款",
        "发票开具:在订单详情页申请电子发票"
    ],
)

运行示例,输出错误信息如下:

chromadb.errors.DuplicateIDError: Expected IDs to be unique, found duplicates of: r1 in add.

注意:

  • 集合内 ID 必须唯一,add 遇到重复 ID 直接抛异常 DuplicateIDError(这一点和 upsert 不同,upsert 会覆盖)

  • 推荐业务唯一标识,如 chunk_001、doc_pdf_page_5

  • 批量传入时,ids[0]对应第 0 条记录,和其他数组下标对应,示例:ids=["id_01", "id_02"]

embeddings 可选

类型为 List[List[float]] 二维浮点数组,每一行是一条向量。

用来存放你提前算好的向量,直接存入索引,Chroma 不再调用 EmbeddingFunction 计算向量,推荐这样做。例如:

import chromadb

client = chromadb.EphemeralClient()
col = client.get_or_create_collection("demo_col", embedding_function=None)

col.add(
    ids=["d1", "d2"],
    embeddings=[
        [1.001, 1.002, 1.003],
        [0.980, 1.102, 0.996]
    ],
    documents=["今天天气不错", "明天要下雨"],
    metadatas=[
        {"source": "news"},
        {"source": "weather"}
    ],
)

print(f"集合合计数量 {col.count()}")
# 结果:
# 集合合计数量 2

注意:

  • 向量维度必须和集合内已存在向量维度完全一致,否则报错,例如:

import chromadb

client = chromadb.EphemeralClient()
col = client.get_or_create_collection("demo_col", embedding_function=None)
# 向量维度为 3
col.add(
    ids=["d1", "d2"],
    embeddings=[
        [1.001, 1.002, 1.003],
        [0.980, 1.102, 0.996]
    ],
    documents=["今天天气不错", "明天要下雨"],
    metadatas=[
        {"source": "news"},
        {"source": "weather"}
    ],
)

# 向量维度为 5
col.add(
    ids=["d3"],
    embeddings=[
        [1.001, 1.002, 1.003, 1.459, 0.896],
    ],
    documents=["今天天气不错"],
    metadatas=[
        {"source": "news"},
    ],
)

运行上面代码,你会收到如下错误信息:

chromadb.errors.InvalidArgumentError: Collection expecting embedding with dimension of 3, got 5

metadatas 可选

类型为 dict | List[Optional[dict]],用来存储每条记录的元数据,用于 where 条件过滤检索。

支持的值类型有 str / int / float / bool,也支持一维数组,但是不支持嵌套复杂对象。如果单条记录为 None 代表这条记录没有元数据。

注意:批量添加数据时,列表长度必须等于 ids 长度。

示例,见 embeddings 参数。

documents 可选

类型为 str | List[str],用来存储原始文本片段(chunk),Chroma 会原样存储文本,query 的时候可以取回原文。

如果你不想自己计算向量,可以交给集合的 EmbeddingFunction 自动计算,实际使用中,推荐自己使用中文嵌入模型进行计算。

images 可选

类型为 np.ndarray | List[np.ndarray],用于存储图像像素数组,配合多模态 EmbeddingFunction(OpenCLIP)使用,自动生成图片向量。适合多模态场景,纯文本 RAG 一般不用这个参数。

uris 可选

类型为 str | List[str],存储资源定位地址(本地文件路径 /http 链接) ,标记文档原始文件路径。

在多模态图片场景中,配合多模态 Embedding,从 URI 读取图片。

三种写法

下面介绍三种 col.add() 方法的写法:

写法一:只给文本,让 Chroma 帮你算向量

col.add(
    ids=["d1", "d2"],
    documents=["今天天气不错", "明天要下雨"],
    metadatas=[{"source": "news"}, {"source": "weather"}],
)

这是最省事的写法,但有两个前提:集合挂了嵌入函数,且你能接受它的速度。每批都要过一遍模型,几千条数据能让你等上好一会儿。

写法二:只给向量

col.add(
    ids=["d1", "d2"],
    embeddings=[[0.12, -0.33, 0.58], [0.44, 0.21, -0.09]],
    metadatas=[{"source": "news"}, {"source": "weather"}],
)

注意,没有 documents。这样查回来的 documents 是 None,只有 metadata 和距离。通常在主库已经存了正文、Chroma 只用来找 id 的场景下这么干,能省一半存储空间。

写法三:两个都给(最推荐)

col.add(
    ids=["d1", "d2"],
    embeddings=[[0.12, -0.33, 0.58], [0.44, 0.21, -0.09]],
    documents=["今天天气不错", "明天要下雨"],
)

你已经有向量了,Chroma 不会重算;同时把原文存进去,查的时候能直接拿到文本。

单条也能传字符串

如果你觉得写列表麻烦,不想写列表的时候,可以直接传标量,ids/documents/uris 都支持:

import chromadb

client = chromadb.EphemeralClient()
col = client.get_or_create_collection("demo_col", embedding_function=None)
col.add(
    ids="d1",
    embeddings=[1.001, 1.002, 1.003],
    documents="今天天气不错",
    metadatas={"source": "news"},
)

不过实际项目里我很少这么写,统一用列表省得后面批量化要改代码。

长度必须对齐

ids、embeddings、documents、metadatas、uris 这几个,只要传了就必须是同样的长度(或者标量)。对不上会直接报 ValueError。例如:

import chromadb

client = chromadb.EphemeralClient()
col = client.get_or_create_collection("demo_col", embedding_function=None)
col.add(
    ids=["d1", "d2"],
    embeddings=[
        [1.001, 1.002, 1.003],
        [0.980, 1.102, 0.996]
    ],
    documents=["今天天气不错", "明天要下雨", "这里长度不一致"], # 看这里
    metadatas=[
        {"source": "news"},
        {"source": "weather"}
    ],
)

运行上面代码,你将得到如下错误:

ValueError: Unequal lengths for fields: ids: 2, metadatas: 2, embeddings: 2, documents: 3 in add.

重复 id:静默忽略

这是全章最重要的一条:

import chromadb

client = chromadb.EphemeralClient()
col = client.get_or_create_collection("demo_col", embedding_function=None)
col.add(ids=["m1"], embeddings=[[1, 0, 0]], documents=["第一版"])
col.add(ids=["m1"], embeddings=[[0, 1, 0]], documents=["第二版"])
print(col.count())                          # 1
print(col.get(ids=["m1"])["documents"])     # ['第一版']

第二次 add 没有任何反应,也不报错。 你以为更新了,其实什么都没发生。

想要 "有就更新,没有就插入",用 upsert。

维度必须一致

col.add(ids=["a"], embeddings=[[1, 0, 0]])        # 集合维度变成 3
col.add(ids=["b"], embeddings=[[1, 0, 0, 0]])     # 报错
chromadb.errors.InvalidArgumentError: Collection expecting embedding with
dimension of 3, got 4

集合的维度由第一条写入的数据决定,之后就锁死了。

说说我的看法
全部评论()
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号