metadata 的写入规则

🎉摘要:详解Chroma中add方法metadata的规则:空字典直接报错,不支持嵌套对象和混合类型数组,值不能为None。提供clean_metadata数据清洗函数示例,过滤None值,拍平嵌套对象,保证metadata符合Chroma要求。

下面介绍 add 方法 metadata 属性的一些规则:

空字典不行

metadatas 传递空字典立即报错,例如:

import chromadb

client = chromadb.EphemeralClient()
col = client.get_or_create_collection("notes", embedding_function=None)
col.add(ids=["e1"], embeddings=[[1, 0, 0]], metadatas=[{}])

运行代码,错误信息如下:

ValueError: Expected metadata to be a non-empty dict, got 0 metadata attributes in add.

如果记录没有 metadata 要写,就别传这个参数,或者传 [None]:

import chromadb

client = chromadb.EphemeralClient()
col = client.get_or_create_collection("notes", embedding_function=None)
col.add(ids=["e1"], embeddings=[[1, 0, 0]], metadatas=[None])

或则,部分记录有 metadatas,部分记录没有:

import chromadb

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

不支持嵌套和混合类型数组

注意了,下面方式不支持:

{"author": {"name": "鲁迅"}}	# 对象嵌套
{"tags": ["a", 1]}          	# 数组元素类型不一致
{"tags": []}                	# 空数组

要表达嵌套就拍平:

{"author_name": "鲁迅", "author_id": 42}

值不能是 None

import chromadb

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

运行上面代码,抛出异常如下:

TypeError: argument 'metadatas': Cannot convert Python object to MetadataValue

注意,如果想表达"空",用空字符串、0,或者干脆不写这个 key。

一个清洗函数

下面自定义个函数,用来在写数据之前对 metadata 数据清洗一遍,尽量避免在运行时报错:

import chromadb
from datetime import date, datetime


def clean_metadata(md: dict | None) -> dict | None:
    """把 metadata 洗成 Chroma 能接受的样子"""
    if not md:
        return None
    out = {}
    for k, v in md.items():
        # 如果值为 None,过滤掉
        if v is None:
            continue
        # 如果值为 bool、int、float、str 基础类型,直接放行
        if isinstance(v, bool) or isinstance(v, int) or isinstance(v, float) or isinstance(v, str):
            out[k] = v
        # 如果值为列表或元组
        elif isinstance(v, (list, tuple)):
            # 遍历列表,仅保留基础数据类型的元素
            items = [x for x in v if x is not None and isinstance(x, (bool, int, float, str))]
            if not items:
                continue
            # 数组元素必须同类型,取第一个元素的类型为准
            t = type(items[0])
            items = [x for x in items if type(x) is t]
            if items:
                out[k] = items
        # 如果是日期类型,直接格式化为 ISO 标准
        elif isinstance(v, (datetime, date)):
            out[k] = v.isoformat()
        # 否则转换为字符串
        else:
            out[k] = str(v)
    return out or None


client = chromadb.EphemeralClient()
col = client.get_or_create_collection("notes", embedding_function=None)
col.add(
    ids=["q1",],
    documents=[
        "订单付款后多久发货?一般 48 小时内出库",
    ],
    metadatas=[
        clean_metadata({"category": "物流", "tags":None, "info": {"price":"27.9", "position":"四川"}}),
    ],
)

print(col.get(ids=["q1"]))
# 结果:
# {'ids': ['q1'], 'embeddings': None, 'documents': ['订单付款后多久发货?一般 48 小时内出库'],
#   'uris': None,
#   'included': ['metadatas', 'documents'], 'data': None,
#   'metadatas': [{'info': "{'price': '27.9', 'position': '四川'}", 'category': '物流'}]}

运行示例,并没有因为我们将 metadatas 的 tags 设置为 None,以及 info 使用嵌套对象而报错,反而将 tags 剔除,将 info 转换成字符串。

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