跳到主要内容

JSON 类型

Zilliz Cloud 允许您使用 JSON 数据类型在单个字段中存储和索引结构化数据。这使得灵活的 schema 能够包含嵌套属性,同时仍然允许通过 JSON 路径索引进行高效过滤。

什么是 JSON 字段?

JSON 字段是 Zilliz Cloud 中定义在 schema 中的字段,用于存储结构化的键值对数据。值可以包括字符串、数值、布尔值、数组或深度嵌套的对象。

以下是 JSON 字段的示例:

{
"metadata": {
"category": "electronics",
"brand": "BrandA",
"in_stock": true,
"price": 99.99,
"string_price": "99.99",
"tags": ["clearance", "summer_sale"],
"supplier": {
"name": "SupplierX",
"country": "USA",
"contact": {
"email": "support@supplierx.com",
"phone": "+1-800-555-0199"
}
}
}
}

在这个示例中:

  • metadata 是可以在 schema 中定义的 JSON 字段。

  • 您可以存储扁平值(如 categoryin_stock)、数组(tags)和嵌套对象(supplier)等。

在 schema 中定义 JSON 字段

要使用 JSON 字段,需要在 collection schema 中明确定义它,将 DataType 指定为 JSON

以下示例创建一个包含以下字段的 collection 及其 schema:

  • 主键(product_id

  • vector 字段(每个 collection 必须有至少一个向量字段)

  • metadata 字段,类型为 JSON,可以存储结构化数据,如扁平值、数组或嵌套对象

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="YOUR_CLUSTER_ENDPOINT")

# 创建包含 JSON 字段的 schema
schema = client.create_schema(auto_id=False, enable_dynamic_field=True)

schema.add_field(field_name="product_id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=5)
# highlight-next-line
schema.add_field(field_name="metadata", datatype=DataType.JSON, nullable=True) # 允许空值的 JSON 字段

client.create_collection(
collection_name="product_catalog",
schema=schema
)
📘说明

您还可以启用 dynamic field 功能来灵活存储未声明的字段,但这不是 JSON 字段正常工作的必要条件。更多信息请参考 Dynamic Field

插入带有 JSON 数据的 entity

创建 collection 后,插入在 metadata JSON 字段中包含结构化 JSON 对象的实体。

entities = [
{
"product_id": 1,
"vector": [0.1, 0.2, 0.3, 0.4, 0.5],
"metadata": {
"category": "electronics",
"brand": "BrandA",
"in_stock": True,
"price": 99.99,
"string_price": "99.99",
"tags": ["clearance", "summer_sale"],
"supplier": {
"name": "SupplierX",
"country": "USA",
"contact": {
"email": "support@supplierx.com",
"phone": "+1-800-555-0199"
}
}
}
}
]

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

为 JSON 字段内的值建立索引

为了加速 JSON 字段的标量过滤,Zilliz Cloud 支持使用 JSON 路径索引为 JSON 字段建立索引。这允许您按 JSON 对象内的键或嵌套值进行过滤,而无需扫描整个字段。

📘说明

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

JSON 路径索引语法

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

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

    • 示例:metadata["category"]

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

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

    • 此类型必须与被索引字段的实际数据类型匹配。如果您想在索引期间将数据类型转换为另一种类型,请考虑使用转换函数

    • 完整列表请参见下文

支持的 JSON 转换类型

转换类型不区分大小写。支持以下类型:

转换类型

描述

示例 JSON 值

bool

布尔值

truefalse

double

数值(整数或浮点数)

4299.99-15.5

varchar

字符串值

"electronics""BrandA"

array_bool

布尔值数组

[true, false, true]

array_double

数值数组

[1.2, 3.14, 42]

array_varchar

字符串数组

["tag1", "tag2", "tag3"]

📘说明

为了优化索引,数组应包含相同类型的元素。更多信息请参考 Array 类型

示例:创建 JSON 路径索引

使用我们介绍中的 metadata JSON 结构,以下是为不同 JSON 路径创建索引的示例:

# 将 category 字段作为字符串索引
index_params = client.prepare_index_params()

index_params.add_index(
field_name="metadata",
# highlight-next-line
index_type="AUTOINDEX", # 对于 JSON 路径索引必须设置为 AUTOINDEX
index_name="category_index", # 唯一的索引名称
# highlight-start
params={
"json_path": "metadata[\"category\"]", # 要索引的 JSON 键的路径
"json_cast_type": "varchar" # 数据转换类型
}
# highlight-end
)

# 将 tags 数组作为字符串数组索引
index_params.add_index(
field_name="metadata",
# highlight-next-line
index_type="AUTOINDEX", # 对于 JSON 路径索引必须设置为 AUTOINDEX
index_name="tags_array_index", # 唯一的索引名称
# highlight-start
params={
"json_path": "metadata[\"tags\"]", # 要索引的 JSON 键的路径
"json_cast_type": "array_varchar" # 数据转换类型
}
# highlight-end
)

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

如果您的 JSON 字段键包含格式不正确的值(例如,以字符串形式存储的数字),您可以使用转换函数在索引期间转换值。

支持的转换函数

转换函数不区分大小写。支持以下类型:

转换函数

转换类型

使用场景

"STRING_TO_DOUBLE"

字符串 → 数值 (double)

"99.99" 转换为 99.99

示例:将字符串数字转换为 double

# 将字符串数字转换为 double 用于索引
index_params.add_index(
field_name="metadata",
# highlight-next-line
index_type="AUTOINDEX", # 对于 JSON 路径索引必须设置为 AUTOINDEX
index_name="string_to_double_index", # 唯一的索引名称
params={
"json_path": "metadata[\"string_price\"]", # 要索引的 JSON 键的路径
"json_cast_type": "double", # 数据转换类型
# highlight-next-line
"json_cast_function": "STRING_TO_DOUBLE" # 转换函数;不区分大小写
}
)
📘说明
  • json_cast_type 参数是必需的,且必须与转换函数的输出类型相同。

  • 如果转换失败(例如,非数字字符串),该值将被跳过并且不会被索引。

将索引参数应用到 collection

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

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

按 JSON 字段值过滤

插入和索引 JSON 字段后,您可以使用标准过滤表达式和 JSON 路径语法对它们进行过滤。

例如:

filter = 'metadata["category"] == "electronics"'
filter = 'metadata["price"] > 50'
filter = 'json_contains(metadata["tags"], "featured")'

要在搜索或查询中使用这些表达式,请确保:

  • 您已为每个向量字段创建了索引。

  • collection 已加载到内存中。

有关支持的操作符和表达式的完整列表,请参考 JSON 操作符

整体流程

到目前为止,您已经学会了如何定义、插入和可选地为 JSON 字段内的结构化值建立索引。

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

常见问题

JSON 字段和 dynamic field 有什么区别?

  • JSON 字段是 schema 定义的。您必须在 schema 中明确声明该字段。

  • Dynamic field是一个隐藏的 JSON 对象($meta),它自动存储任何未在 schema 中定义的字段。

两者都支持嵌套结构和 JSON 路径索引,但 dynamic field 更适合可选或不断变化的数据结构。

详情请参考 Dynamic Field

JSON 字段的大小有限制吗?

有的。每个 JSON 字段限制为 65,536 字节。

JSON 字段支持设置默认值吗?

不支持,JSON 字段不支持默认值。但是,您可以在定义字段时设置 nullable=True 来允许空条目。

详情请参考 Nullable 和默认值

JSON 字段键有命名规范吗?

有的。为了确保与查询和索引的兼容性:

  • 在 JSON 键中只使用字母、数字和下划线。

  • 避免使用特殊字符、空格或点(./ 等)。

  • 不兼容的键可能会在过滤表达式中导致解析问题。

Zilliz Cloud 如何处理 JSON 字段中的字符串值?

Zilliz Cloud 完全按照 JSON 输入中的字符串值存储——不进行语义转换。引号不当的字符串可能会在解析过程中导致错误。

有效字符串示例

"a\"b", "a'b", "a\b"

无效字符串示例

'a"b', 'a\'b'

Zilliz Cloud 对索引的 JSON 路径使用什么过滤逻辑?

  • 数值索引

    如果使用 json_cast_type="double" 创建索引,只有数值过滤条件(例如 ><== 42)会利用索引。非数值条件将强制进行暴力扫描。

  • 字符串索引

    如果索引使用 json_cast_type="varchar",只有字符串过滤条件会受益于索引;其他类型将回退到暴力搜索。

  • 布尔索引

    布尔索引的行为类似于字符串索引,只有条件严格匹配 true 或 false 时才会使用索引。

Term 表达式如何与 JSON 字段索引配合使用?

您可以使用 term 表达式如 json["field"] IN [value1, value2, …] 来过滤 entity。

  • 只有当目标值是标量时才会应用索引。

  • 如果 json["field"] 是数组,查询将不会使用索引,将回退到暴力搜索。

索引 JSON 字段时的数值精度如何?

Zilliz Cloud 将所有索引的数值存储为 double。

如果数值超过 2^53,可能会失去精度。这种精度损失可能导致过滤查询无法精确匹配超出范围的值。

Zilliz Cloud 如何处理 JSON 字段索引的数据完整性?

Zilliz Cloud 不会自动转换或规范化不一致的数据类型。

例如,如果某些行将 "price": "99.99" 存储为字符串,而其他行将 "price": 99.99 存储为数字,同时索引定义为 double,只有具有数值的行才会被索引。

不一致会导致受影响的行在索引期间被静默跳过。

索引 JSON 字段时类型转换失败会怎样?

如果值无法转换为指定的 json_cast_type(例如,期望 double 时遇到非数字字符串),该值会被静默跳过并且不包含在索引中。因此,具有转换失败的实体将从依赖索引的过滤结果中排除

为了避免意外的查询行为,请确保索引的 JSON 路径下的所有值都具有一致的类型。

我可以在同一个 JSON 路径上使用不同的转换类型创建多个索引吗?

不可以,每个 JSON 路径只支持一个索引。您必须选择一个与您的数据匹配的 json_cast_type。不支持在同一路径上使用不同转换类型创建多个索引。

如果 JSON 路径上的值具有不一致的类型怎么办?

跨实体的不一致类型可能导致部分索引。例如,如果 metadata["price"] 既存储为数字(99.99)又存储为字符串("99.99"),而索引定义为 json_cast_type="double",只有数值会被索引。字符串形式的条目将被跳过,不会出现在过滤结果中。

我可以使用与索引转换类型不同的类型进行过滤吗?

如果您的过滤表达式使用的类型与索引的 json_cast_type 不同,系统将不会使用索引,并且可能会回退到更慢的暴力扫描——如果数据允许的话。为了获得最佳性能,请始终将过滤表达式与索引的转换类型保持一致。