跳到主要内容

Dynamic Field

Zilliz Cloud 允许您通过 dynamic field 的特殊功能插入具有灵活、不断演进 schema 的 entity。此字段实现为名为 $meta 的隐藏 JSON 字段,它会自动存储数据中未在 collection schema 中明确定义的字段。

工作原理

当启用 dynamic field 时,Zilliz Cloud 会为每个 entity 添加一个隐藏的 $meta 字段。这个字段是 JSON 类型,意味着它可以存储任何与 JSON 兼容的数据结构,也可以通过 JSON 路径建立索引。

在数据插入过程中,任何未在 schema 中声明的字段都会自动作为键值对存储在这个 dynamic field 内。

您无需手动管理 $meta——Zilliz Cloud 会透明地处理它。

例如,如果您的 collection schema 只定义了 idvector,而您插入以下 entity:

{
"id": 1,
"vector": [0.1, 0.2, 0.3],
"name": "Item A", // 不在 schema 中
"category": "books" // 不在 schema 中
}

启用 dynamic field 功能后,Zilliz Cloud 会在内部存储为:

{
"id": 1,
"vector": [0.1, 0.2, 0.3],
// highlight-start
"$meta": {
"name": "Item A",
"category": "books"
}
// highlight-end
}

这使您能够在不修改 schema 的情况下演进数据结构。

常见使用场景包括:

  • 存储可选或不经常检索的字段

  • 捕获因实体而异的元数据

  • 通过特定 dynamic field 键的索引支持灵活过滤

支持的数据类型

Dynamic field 支持 Zilliz Cloud 提供的所有标量数据类型,包括简单和复杂值。这些数据类型适用于存储在 $meta 中的键值

支持的类型包括:

  • 字符串(VARCHAR

  • 整数(INT8INT32INT64

  • 浮点数(FLOATDOUBLE

  • 布尔值(BOOL

  • 标量值数组(ARRAY

  • JSON 对象(JSON

示例:

{
"brand": "Acme",
"price": 29.99,
"in_stock": true,
"tags": ["new", "hot"],
"specs": {
"weight": "1.2kg",
"dimensions": { "width": 10, "height": 20 }
}
}

上述每个键和值都将存储在 $meta 字段内。

启用 dynamic field

要使用 dynamic field 功能,请在创建 collection schema 时设置 enable_dynamic_field=True

from pymilvus import MilvusClient, DataType

# 初始化客户端
client = MilvusClient(uri="YOUR_CLUSTER_ENDPOINT")

# 创建启用 dynamic field 的 schema
schema = client.create_schema(
auto_id=False,
# highlight-next-line
enable_dynamic_field=True,
)

# 添加明确定义的字段
schema.add_field(field_name="my_id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="my_vector", datatype=DataType.FLOAT_VECTOR, dim=5)

# 创建 collection
client.create_collection(
collection_name="my_collection",
schema=schema
)

向 collection 插入 entity

Dynamic field 允许您插入 schema 中未定义的额外字段。这些字段将自动存储在 $meta 中。

entities = [
{
"my_id": 1, # 明确定义的主键字段
"my_vector": [0.1, 0.2, 0.3, 0.4, 0.5], # 明确定义的向量字段
"overview": "Great product", # schema 中未定义的标量键
"words": 150, # schema 中未定义的标量键
"dynamic_json": { # schema 中未定义的 JSON 键
"varchar": "some text",
"nested": {
"value": 42.5
},
"string_price": "99.99" # 以字符串形式存储的数字
}
}
]

client.insert(collection_name="my_collection", data=entities)

为 dynamic field 中的键建立索引

Zilliz Cloud 允许您使用 JSON 路径索引为 dynamic field 内的特定键创建索引。这些可以是标量值或 JSON 对象中的嵌套值。

📘说明

为 dynamic field 键建立索引是可选操作。您仍然可以在没有索引的情况下按 dynamic field 键查询或过滤,但由于需要进行暴力搜索,性能可能会较慢。

JSON 路径索引语法

要创建 JSON 路径索引,请指定:

  • JSON 路径json_path):您要索引的 JSON 对象内键或嵌套字段的路径。

    • 示例:metadata["category"]

      这定义了索引引擎在 JSON 结构内查找的位置。

  • JSON 转换类型json_cast_type):Zilliz Cloud 在解释和索引指定路径处的值时应使用的数据类型。

通过 JSON 路径为 dynamic field 中的键建索引

由于 dynamic field 是一个 JSON 字段,你可以使用 JSON 路径语法来索引其中的任意键。这适用于简单的标量值,也适用于复杂的嵌套结构。

JSON 路径示例:

  • 对于简单键:overviewwords

  • 对于嵌套键:dynamic['varchar']dynamic['nested']['value']

index_params = client.prepare_index_params()

# 为一个简单的字符串键创建索引
index_params.add_index(
field_name="overview", # dynamic field 中的键名
# highlight-next-line
index_type="AUTOINDEX", # 必须设置为 AUTOINDEX
index_name="overview_index", # 唯一的索引名称
# highlight-start
params={
"json_cast_type": "varchar", # 为该值创建索引时使用的数据类型
"json_path": "overview" # 指向该键的 JSON 路径
}
# highlight-end
)

# 为一个简单的数值键创建索引
index_params.add_index(
field_name="words", # dynamic field 中的键名
# highlight-next-line
index_type="AUTOINDEX", # 必须设置为 AUTOINDEX
index_name="words_index", # 唯一的索引名称
# highlight-start
params={
"json_cast_type": "double", # 为该值创建索引时使用的数据类型
"json_path": "words" # 指向该键的 JSON 路径
}
# highlight-end
)

# 为 JSON 对象中的嵌套键创建索引
index_params.add_index(
field_name="dynamic_json", # dynamic field 中的 JSON 键名
# highlight-next-line
index_type="AUTOINDEX", # 必须设置为 AUTOINDEX
index_name="json_varchar_index", # 唯一的索引名称
# highlight-start
params={
"json_cast_type": "varchar", # 为该值创建索引时使用的数据类型
"json_path": "dynamic_json['varchar']" # 指向嵌套键的 JSON 路径
}
# highlight-end
)

# 为深层嵌套的键创建索引
index_params.add_index(
field_name="dynamic_json",
# highlight-next-line
index_type="AUTOINDEX", # 必须设置为 AUTOINDEX
index_name="json_nested_index", # 唯一的索引名称
# highlight-start
params={
"json_cast_type": "double",
"json_path": "dynamic_json['nested']['value']"
}
# highlight-end
)

使用 JSON 转换函数进行类型转换

如果 dynamic field 键包含格式不正确的值(例如,以字符串形式存储的数字),您可以使用转换函数进行转换:

# 在索引前将字符串转换为 double
index_params.add_index(
field_name="dynamic_json", # JSON 键名
index_type="AUTOINDEX",
index_name="json_string_price_index",
params={
"json_path": "dynamic_json['string_price']",
"json_cast_type": "double", # 必须是转换函数的输出类型
# highlight-next-line
"json_cast_function": "STRING_TO_DOUBLE" # 不区分大小写;将字符串转换为 double
}
)
📘说明
  • 如果类型转换失败(例如值 "not_a_number" 无法转换为数字),该值将被跳过且不会被索引。

  • 有关转换函数参数的详细信息,请参考 JSON 类型

将索引参数应用到 collection

定义索引参数后,您可以使用 create_index() 将它们应用到 collection:

client.create_index(
collection_name="my_collection",
index_params=index_params
)

按 dynamic field 键过滤

插入带有 dynamic field 键的 entity 后,您可以使用标准过滤表达式对它们进行过滤。

  • 对于非 JSON 键(例如字符串、数字、布尔值),您可以直接通过键名引用它们。

  • 对于存储 JSON 对象的键,使用 JSON 路径语法访问嵌套值。

基于前面的示例 entity,有效的过滤表达式包括:

filter = 'overview == "Great product"'                # 非 JSON 键
filter = 'words >= 100' # 非 JSON 键
filter = 'dynamic_json["nested"]["value"] < 50' # JSON 对象键

检索 dynamic field 中的键:如果要在搜索或查询结果中返回 dynamic field 的键,必须在 output_fields 参数中显式指定这些键,使用与过滤时相同的 JSON 路径语法。

# 示例:在搜索结果中包含 dynamic 字段的键
results = client.search(
collection_name="my_collection",
data=[[0.1, 0.2, 0.3, 0.4, 0.5]],
filter=filter, # 前面定义的过滤条件
limit=10,
# highlight-start
output_fields=[
"overview", # 简单的 dynamic field 键
'dynamic_json["varchar"]' # 嵌套的 JSON 键
]
# highlight-end
)
📘说明

dynamic field 中的键默认不会包含在返回结果中,必须显式指定后才会返回。

有关支持的操作符和过滤表达式的完整列表,请参考 Filtered Search

整体流程

到目前为止,您已经学会了如何使用 dynamic field 灵活存储和索引未在 schema 中定义的键。一旦插入了 dynamic field 键,您就可以像使用任何其他字段一样在过滤表达式中使用它——无需特殊语法。

要在实际应用中完成工作流程,您还需要:

常见问题

什么时候应该在 schema 中明确定义字段而不是使用 dynamic field 键?

在以下情况下,您应该在 schema 中明确定义字段而不是使用 dynamic field 键:

  • 字段经常包含在 output_fields 中:只有明确定义的字段才能保证通过 output_fields 高效检索。Dynamic field 键没有针对高频检索进行优化,可能会产生性能开销。

  • 字段经常被访问或过滤:虽然为 dynamic field 键建立索引可以提供类似于固定 schema 字段的过滤性能,但明确定义的字段提供更清晰的结构和更好的可维护性。

  • 您需要完全控制字段行为:明确字段支持 schema 级别的约束、验证和更清晰的类型定义,这对于管理数据完整性和一致性很有用。

  • 您希望避免索引不一致:Dynamic field 键中的数据更容易出现类型或结构不一致。使用固定 schema 有助于确保数据质量,特别是如果您计划使用索引或转换。

我可以在同一个 dynamic field 键上使用不同的数据类型创建多个索引吗?

不可以,您每个 JSON 路径只能创建一个索引。即使 dynamic field 键包含混合类型值(例如,一些字符串和一些数字),在为该路径建立索引时也必须选择单个 json_cast_type。目前不支持在同一键上使用不同类型创建多个索引。

为 dynamic field 键建立索引时,如果数据转换失败会怎样?

如果您已为 dynamic field 键创建了索引,但数据转换失败——例如,要转换为 double 的值是像 "abc" 这样的非数字字符串——这些特定值将在索引创建期间被静默跳过。它们不会出现在索引中,因此不会在依赖索引的基于过滤器的搜索或查询结果中返回

这有几个重要影响:

  • 不会回退到全扫描:如果大多数实体成功建立索引,过滤查询将完全依赖索引。转换失败的实体将从结果集中排除——即使它们在逻辑上匹配过滤条件。

  • 搜索准确性风险:在数据质量不一致的大型数据集中(特别是在 dynamic field 键中),这种行为可能导致意外的缺失结果。在索引之前确保一致和有效的数据格式至关重要。

  • 谨慎使用转换函数:如果您使用 json_cast_function 在索引期间将字符串转换为数字,请确保字符串值可以可靠地转换。json_cast_type 和实际转换类型之间的不匹配将导致错误或跳过的条目。

如果我的查询使用与索引转换类型不同的数据类型会怎样?

如果您的查询使用与索引中使用的不同数据类型比较 dynamic field 键(例如,当索引转换为 double 时使用字符串比较进行查询),系统将不会使用索引,并且只有在可能的情况下才会回退到全扫描。为了获得最佳性能和准确性,请确保您的查询类型与索引创建期间使用的 json_cast_type 匹配。