update 更新数据

🎉摘要:详解Chroma向量数据库update方法,涵盖ids、embeddings、metadatas等参数说明,解析局部更新与metadata合并机制,对比upsert差异,提供Python代码示例与避坑指南。

update 用来更新集合中的向量,只更新集合里已经存在的 ID 记录。如果 ID 不存在,直接忽略,不会新增记录(这是和 upsert 最大区别) 。

方法的入参是列格式数组,其中 ids[0]、embeddings [0]、metadatas [0] 属于同一条向量记录。所有传入的列表长度必须完全一致。否则,报错。

方法签名

方法签名如下:

collection.update(
    ids,
    embeddings=None,
    metadatas=None,
    documents=None,
    images=None,
    uris=None,
)

其中:

ids(必传)

类型为 str | List[str],表示待更新的文档唯一 ID 列表。仅处理集合内已经存在的 id;不存在的 id 会日志警告、直接跳过,不会 add 新增,如果批量传入多个 ID,做批量更新。

embeddings=None

类型为 List[List[float]],不建议传 numpy 数组。表示向量列表,每一项是单条 embedding 浮点数数组。传入 embeddings 会直接覆盖原有向量,不会自动重新向量化。当embeddings=None + 传入 documents,会自动调用 embedding 函数生成向量。

注意:向量维度必须和集合原有向量维度完全一致,否则抛异常。

metadatas=None

类型为List[dict | None],表示每条记录对应的元数据字典。用于覆盖原有 metadata,用于过滤查询(where 条件检索),支持基础类型:字符串、数字、bool,也支持数组;传None代表清空该条 metadata。

documents=None

类型为List[str | None],表示文本片段。覆盖原有文档文本,当 embeddings=None + 传入 documents,会自动调用 embedding 函数生成向量。

images=None(多模态专用)

类型为 List[np.ndarray],图片 numpy 数组。多模态集合使用(OpenCLIP 这类多模态 Embedding)。当embeddings=None + images,会自动对图片生成向量,同一条记录不能同时保留文本 + 图片,更新 images 会覆盖原有 documents。

uris=None

类型为List[str | None],表示资源地址(图片 / 文件 url、本地路径),多模态场景使用,存储图片资源引用地址。

简单用法

先给一个简单示例,写入数据到集合,然后修改这些数据,打印修改前后数据。

import chromadb

# 自己提供向量,省得下载默认的嵌入模型
client = chromadb.EphemeralClient()
col = client.get_or_create_collection("update_demo", embedding_function=None)

def show(title: str) -> None:
    """把当前集合里的记录打印出来,方便对比更新前后"""
    res = col.get(include=["documents", "metadatas"])
    print(title)
    for cid, doc, meta in zip(res["ids"], res["documents"], res["metadatas"]):
        print("  ", cid, meta, doc)


# 新增
col.add(
    ids=["u1", "u2"],
    embeddings=[[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]],
    documents=["退换货规则说明", "会员积分规则"],
    metadatas=[{"cat": "售后", "version": 1}, {"cat": "会员", "version": 1}],
)
show("新增后:")

# 修改已有记录
col.update(
    ids=["u1"],
    embeddings=[[0.11, 0.22, 0.33]],
    documents=["退换货规则说明(2026 修订版)"],
    metadatas=[{"cat": "售后", "version": 2, "revised": True}],
)
# 只改 metadata,不动文档和向量
col.update(
    ids=["u2"],
    metadatas=[{"cat": "会员", "version": 2, "note": "积分可兑换退款券"}],
)
show("修改后:")

运行代码,输出结果:

新增后:
   u1 {'version': 1, 'cat': '售后'} 退换货规则说明
   u2 {'cat': '会员', 'version': 1} 会员积分规则
修改后:
   u1 {'cat': '售后', 'revised': True, 'version': 2} 退换货规则说明(2026 修订版)
   u2 {'version': 2, 'cat': '会员', 'note': '积分可兑换退款券'} 会员积分规则

注意,update 只做局部更新,仅仅修改只传的字段,其他字段保持原样:

import chromadb

client = chromadb.EphemeralClient()
col = client.get_or_create_collection("notes", embedding_function=None)
col.add(ids=["u1"], embeddings=[[1, 0, 0]], documents=["原文"], metadatas=[{"a": 1}])

# 只改 metadata,document 和 embedding 不动
col.update(ids=["u1"], metadatas=[{"a": 2}])
print(col.get(ids=["u1"]))
# {'ids': ['u1'], 'embeddings': None, 'documents': ['原文'], 'uris': None, 
#   'included': ['metadatas', 'documents'], 'data': None, 'metadatas': [{'a': 2}]}

修改 metadata 是不是整体替换,而是进行合并操作:

import chromadb

client = chromadb.EphemeralClient()
col = client.get_or_create_collection("notes", embedding_function=None)
col.add(ids=["u1"], embeddings=[[1, 0, 0]], documents=["原文"], metadatas=[{"a": 1}])
print("更新前:", col.get(ids=["u1"]))
# 更新前: {'ids': ['u1'], 'embeddings': None, 'documents': ['原文'], 'uris': None,
#   'included': ['metadatas', 'documents'], 'data': None, 'metadatas': [{'a': 1}]}

# 更新 metadatas
col.update(ids=["u1"], metadatas=[{"b": 3}])
print("更新后:", col.get(ids=["u1"]))
# 更新后: {'ids': ['u1'], 'embeddings': None, 'documents': ['原文'], 'uris': None,
#   'included': ['metadatas', 'documents'], 'data': None, 'metadatas': [{'b': 3, 'a': 1}]}

上面代码,更新后的 metadatas 包含了更新前的数据。

update 不存在的 id

不会报错,会静默跳过:

import chromadb

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

# 插入数据
col.add(
    ids=["r1"],
    embeddings=[
        [1.0, 0.0, 0.0],
    ],
    metadatas=[
        {"cat": "售后", "year": 2024, "score": 0.9, "tags": ["退款"]},
    ],
)

# 更新数据,id=ghost 的数据不存在
col.update(ids=["ghost"], metadatas=[{"a": 9}])
print(col.count())   # 数量没变,还是1

这个行为挺坑的,你以为写进去了其实没有。如果需要“必须有就更新”的语义时,请使用 upsert 方法。

update 时改了文本

如果调用 update() 时传了 documents,但时没有传递 embeddings,chroma 会用集合的嵌入函数(embedding_function,如果没有指定,则使用默认的)重新算一遍向量。这通常是你要的,但也意味着一次 update 可能比你想象的慢很多(因为,需要重新计算向量)。

  

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