upsert 更新或新增数据

🎉摘要:本文详解ChromaDB向量库的upsert API用法,解决原update接口id不存在时静默跳过的排查难题,涵盖方法签名、参数说明、可运行Python代码示例,对比upsert与add、update的核心差异,明确upsert整条替换的使用注意事项,适配数据重跑的写入场景。

前面介绍了通过 update API 根据 ID 更新数据,如果 ID 不存在,不会报错,也不会做任何更新动作。虽然没有报错,但是在真实业务中,这比报错还难受,不好怕查问题。

为此,引入 upsert API,如果数据不存在,就插入新数据,如果存在,则更新数据。这是我平常用的最多的写入方法,因为灌数据经常要重跑,用 add 的话第二次就全被忽略了。

方法签名

方法签名如下:

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

参数说明:

  • ids:必填,文档唯一标识,类型为 list[str]

  • embeddings:向量数组,类型为 list[list[float]]。如果传 None,自动调用 collection 的 embedding 函数,从 documents/images 生成向量。

  • metadatas:元数据,类型为 list[dict],每条记录附加自定义键值对,用于过滤检索。例如:[{"source":"pdf", "page":1}]

  • documents:原始文本,类型为 list[str]。文本向量库常用,可以不填(只用 embedding)

  • images:图像数据,多模态专用,图像数组,类型为 list[np.ndarray]。注意,只有多模态集合才会用到,普通文本向量库填 None

  • uris:资源路径,类型为 list[str],如文件 / 图片 url、本地路径,多模态使用。  

简单示例

下面通过一个简单示例验证 upsert 方法的用法和效果:

import chromadb

client = chromadb.EphemeralClient()
collection = client.get_or_create_collection("demo_collection", embedding_function=None)

# 新增文档
collection.add(
    ids=["q1", "q2"],
    documents=[
        "订单付款后多久发货?一般 48 小时内出库",
        "如何申请退款?在订单详情页点击申请退款",
    ],
    metadatas=[
        {"category": "物流"},
        {"category": "售后"},
    ],
)

# 更新文档
collection.upsert(
    ids=["q1", "q2","q3"],
    embeddings=None,
    metadatas=None,
    documents=[
        "订单付款后多久发货? 48小时",
        "如何申请退款? 订单页",
        "快递丢了怎么办?联系客服补发或全额退款",
    ],
    images=None,
    uris=None,
)

print(collection.get(ids=["q1", "q2", "q3"]))

运行示例,输出如下:

{'ids': ['q1', 'q2', 'q3'], 'embeddings': None, 
 'documents': ['订单付款后多久发货? 48小时', '如何申请退款? 订单页', '快递丢了怎么办?联系客服补发或全额退款'], 
 'uris': None, 'included': ['metadatas', 'documents'], 'data': None, 
 'metadatas': [{'category': '物流'}, {'category': '售后'}, None]}

从输出得知,更新时 q3 是不存在的,upsert 自动帮我们新增了,而且 metadatas 也被清空了,是因为我们调用 upsert 时没有传递 metadatas。

upsert & update 区别

主要区别如下:

行为addupdateupsert
id 不存在插入静默跳过插入
id 已存在静默忽略局部覆盖整体覆盖
只传部分字段—保留其他字段未传字段会被清空

特别注意:upsert 是“整条替换”语义,你 upsert(ids=["x"], metadatas=[{"a":1}]) 而不带 documents,那这条记录的 document 会被设成空。

所以,用 upsert 就把所有字段都带上,别偷懒。

  

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