跳到主要内容

Nullable 和默认值

Zilliz Cloud 支持为除主键字段以外的其他标量字段设置 nullable 属性(nullable)和默认值(default_value)。对于被标记为 nullable=True 的字段,您可以在插入数据时省略该字段,或直接将字段值指定为空值,系统会将其视为空值而不会报错;当字段设置了默认值时,如果插入数据时未指定该字段的值,系统会自动使用默认值。

默认值和 nullable 属性简化了从其他数据库系统向 Zilliz Cloud 的数据迁移,允许处理包含空值的数据集,同时保持原有的默认值设置。在创建 collection 时,对于值不确定的字段,您也可以选择启用 nullable 属性或设置默认值。

使用限制

  • 仅支持为除主键列以外的其他标量字段设置默认值和 nullable 属性。

  • 不支持为 JSON 或 Array 字段设置默认值。

  • 当前仅支持在创建 collection 时为字段设置默认值或 nullable 属性。collection 创建完成后将无法修改相关配置。

  • 开启了 nullable 属性的标量字段不能作为分组字段(group_by_field)用于 Grouping Search

  • 设置为 nullable 的字段不支持用作 Partition Key。

  • 对开启了 nullable 属性的标量字段创建索引时,空值将不参与索引创建。

Nullable 属性

Nullable 属性允许您在 collection 中存储空值。这为处理未知数据提供了灵活性。

设置 nullable 属性

在创建 collection 时,通过设置 nullable=True 来定义 nullable 列(默认为 False)。以下示例创建了名为 user_profiles_null 的 collection,并将 age 字段设置为 nullable 列。

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri='YOUR_CLUSTER_ENDPOINT')

# Define collection schema
schema = client.create_schema(
auto_id=False,
enable_dynamic_schema=True,
)

schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=5)
schema.add_field(field_name="age", datatype=DataType.INT64, nullable=True) # Nullable field

# Set index params
index_params = client.prepare_index_params()
index_params.add_index(field_name="vector", index_type="IVF_FLAT", metric_type="L2", params={ "nlist": 128 })

# Create collection
client.create_collection(collection_name="user_profiles_null", schema=schema, index_params=index_params)

插入数据

当您向 user_profiles_null 中插入数据时,可以为可空列提供空值或直接省略该字段:

data = [
{"id": 1, "vector": [0.1, 0.2, 0.3, 0.4, 0.5], "age": 30},
{"id": 2, "vector": [0.2, 0.3, 0.4, 0.5, 0.6], "age": None},
{"id": 3, "vector": [0.3, 0.4, 0.5, 0.6, 0.7]}
]

client.insert(collection_name="user_profiles_null", data=data)

搜索查询处理

在使用 search 方法时,如果插入的数据中某个字段的值为空值,搜索结果中对应的字段也会返回空值。

res = client.search(
collection_name="user_profiles_null",
data=[[0.1, 0.2, 0.4, 0.3, 0.128]],
limit=2,
search_params={"params": {"nprobe": 16}},
output_fields=["id", "age"]
)

print(res)

# Output
# data: ["[{'id': 1, 'distance': 0.15838398039340973, 'entity': {'age': 30, 'id': 1}}, {'id': 2, 'distance': 0.28278401494026184, 'entity': {'age': None, 'id': 2}}]"]

在使用 query 方法进行标量过滤时,null 值的过滤结果都为 false,即不会被选出:

# 回顾之前插入的数据:
# {"id": 1, "vector": [0.1, 0.2, ..., 0.128], "age": 30}
# {"id": 2, "vector": [0.2, 0.3, ..., 0.129], "age": None}
# {"id": 3, "vector": [0.3, 0.4, ..., 0.130], "age": None} # 省略的 age 字段被视为 None

results = client.query(
collection_name="user_profiles_null",
filter="age >= 0",
output_fields=["id", "age"]
)

# 返回结果示例:
# [
# {"id": 1, "age": 30}
# ]
# 注意:age 为 null 的记录(id 为 2 和 3 的记录)不会出现在结果中

如果希望查询包含 null 值的记录,可以使用空表达式 ""

null_results = client.query(
collection_name="user_profiles_null",
filter="",
output_fields=["id", "age"]
)

# 结果示例
# [{"id": 2, "age": None}, {"id": 3, "age": None}]

默认值

默认值是指为标量字段指定的预设值。当插入数据时,如果您没有为设置了默认值的字段提供具体值,系统会自动使用这个预设的默认值。

设置默认值

在创建 collection 时,通过设置 default_value 参数来定义字段的默认值。以下示例展示了如何为标量列 age 设置默认值 10status 列设置默认值 active

schema = client.create_schema(
auto_id=False,
enable_dynamic_schema=True,
)

schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=5)
schema.add_field(field_name="age", datatype=DataType.INT64, default_value=18)
schema.add_field(field_name="status", datatype=DataType.VARCHAR, default_value="active", max_length=10)

index_params = client.prepare_index_params()
index_params.add_index(field_name="vector", index_type="IVF_FLAT", metric_type="L2", params={ "nlist": 128 })

client.create_collection(collection_name="user_profiles_default", schema=schema, index_params=index_params)

插入数据

插入数据时,如果省略了设置了默认值的字段,或设置了默认值的字段值为 null,系统会自动使用默认值。

data = [
{"id": 1, "vector": [0.1, 0.2, 0.3, 0.4, 0.5], "age": 30, "status": "premium"},
{"id": 2, "vector": [0.2, 0.3, 0.4, 0.5, 0.6]},
{"id": 3, "vector": [0.3, 0.4, 0.5, 0.6, 0.7], "age": 25, "status": None},
{"id": 4, "vector": [0.4, 0.5, 0.6, 0.7, 0.8], "age": None, "status": "inactive"}
]

client.insert(collection_name="user_profiles_default", data=data)
📘说明

有关更多默认值和 nullable 属性组合使用的生效规则,请参阅生效规则

搜索查询处理

默认值在搜索(search)和查询(query)时的处理方式与普通值相同。您可以在 searchquery 操作中查询使用了默认值的记录。

search 操作中,使用默认值的记录会正常参与向量搜索和标量过滤。

res = client.search(
collection_name="user_profiles_default",
data=[[0.1, 0.2, 0.4, 0.3, 0.128]],
search_params={"params": {"nprobe": 16}},
filter="age == 18", # 18 is the default value of the `age` field
limit=10,
output_fields=["id", "age", "status"]
)

print(res)

# Output
# data: ["[{'id': 2, 'distance': 0.28278401494026184, 'entity': {'id': 2, 'age': 18, 'status': 'active'}}, {'id': 4, 'distance': 0.8315839767456055, 'entity': {'id': 4, 'age': 18, 'status': 'inactive'}}]"]

query 操作中,可以直接使用默认值进行精确匹配或范围查询。

# 查询所有 age 为默认值(18)的记录
default_age_results = client.query(
collection_name="user_profiles_default",
filter="age == 18",
output_fields=["id", "age", "status"]
)

# 查询所有 status 为默认值("active")的记录
default_status_results = client.query(
collection_name="user_profiles_default",
filter='status == "active"',
output_fields=["id", "age", "status"]
)

生效规则

下表总结了 nullable 列和默认值在不同配置组合下的行为规则。这些规则决定了当您试图插入空值或未提供字段值时,系统如何处理数据。

是否可空

是否有默认值

默认值

用户输入

结果

示例

非 null

None/null

使用默认值

字段:age

默认值:18

输入:null

结果:实际存储 18

-

None/null

存储为 null

字段:middle_name

默认值:-

输入:null

结果:实际存储 null

非 null

None/null

使用默认值

字段:status

默认值:"active"

输入:null

结果:实际存储 "active"

-

None/null

报错

字段:email

默认值:-

输入:null

结果:操作被拒绝,系统报错

null

None/null

报错

字段:username

默认值:null

输入:null

结果:操作被拒绝,系统报错