跳到主要内容
版本:v2.6.x

JSON 字段概述

在构建产品目录、内容管理系统或用户偏好引擎等应用程序时,您往往需要在存储向量 Embedding 的同时存储灵活的元数据。产品属性因类别而异,用户偏好随时间演变,文档属性具有复杂的嵌套结构。Milvus 中的 JSON 字段解决了这一难题,允许您在不牺牲性能的情况下存储和查询灵活的结构化数据。

什么是 JSON 字段?

JSON 字段是 Milvus 中的一种 Schema 定义数据类型 (DataType.JSON),用于存储结构化的键值数据。与传统的刚性数据库列不同,JSON 字段可容纳嵌套对象、数组和混合数据类型,同时提供多种索引选项,以实现快速查询。

JSON 字段结构示例:

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 是一个单一的 JSON 字段,包含平面值(如 category,in_stock)、数组 (tags) 和嵌套对象 (supplier) 的混合数据。

说明

命名约定:在 JSON 键中只能使用字母、数字和下划线。避免使用特殊字符、空格或点,因为它们可能会在查询中导致解析问题。

JSON 字段与动态字段

一个常见的混淆点是 JSON 字段与 动态字段的区别。虽然两者都与 JSON 有关,但目的不同。

下表总结了 JSON 字段和动态字段的主要区别:

对比维度

JSON 字段

动态字段

Schema 定义

必须在 Collection Schema 中显式声明为 DataType.JSON 的标量字段。

由系统维护的隐藏 JSON 字段(名为 $meta),用于自动存储未在 Schema 中声明的字段。

适用场景

存储 Schema 已知且结构稳定的数据。

存储无法纳入固定 Schema 的动态或半结构化数据。

控制

由用户显式定义字段名称和结构。

由系统管理未在 Schema 中定义的字段。

查询

使用字段名及 JSON 键路径查询,例如 metadata["key"]

可直接使用动态字段键 "dynamic_key",也可通过 $meta["dynamic_key"] 查询。

基本运算符

使用 JSON 字段的基本工作流程包括在 Schema 中定义字段、插入数据,然后使用特定的过滤表达式查询数据。

定义 JSON 字段

要使用 JSON 字段,请在创建 Collection 时在 Schema 中明确定义该字段。下面的示例演示了如何创建一个包含 metadata 字段、且字段类型为 DataType.JSON 的 Collection:

Python
from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://localhost:19530") # Replace with your server address

# Create 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) # Primary field
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=5) # Vector field
# Define a JSON field that allows null values
schema.add_field(field_name="metadata", datatype=DataType.JSON, nullable=True)

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

在本例中,CollectionSchema 中定义的 JSON 字段允许使用 nullable=True 的空值。有关详情,请参阅 "可为空值和默认值"。

插入数据

创建 Collection 后,在指定的 JSON 字段中插入包含结构化 JSON 对象的实体。数据格式应为字典列表。

Python
entities = [
{
"product_id": 1,
"vector": [0.1, 0.2, 0.3, 0.4, 0.5],
"metadata": { # JSON field
"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 字段执行过滤操作前,请确保

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

  • Collection 已加载到内存中。

显示代码
Python
index_params = client.prepare_index_params()
index_params.add_index(
field_name="vector",
index_type="AUTOINDEX",
index_name="vector_index",
metric_type="COSINE"
)

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

client.load_collection(collection_name="product_catalog")

满足这些要求后,您就可以使用下面的表达式,根据 JSON 字段内的值对 Collection 进行过滤。这些过滤表达式利用了特定的 JSON 路径语法和专用运算符。

使用 JSON 路径语法进行筛选

要查询特定键,请使用括号符号访问 JSON 键:json_field_name["key"]。对于嵌套键,可将它们串联起来:json_field_name["key1"]["key2"]

要过滤 category"electronics" 的实体:

Python
category_filter = 'metadata["category"] == "electronics"'
price_filter = 'metadata["price"] > 50'
tags_filter = 'json_contains(metadata["tags"], "featured")'

过滤嵌套键 supplier["country"]"USA" 的实体:

Python
# Define filter expression
filter = 'metadata["supplier"]["country"] == "USA"'

res = client.search(
collection_name="product_catalog", # Collection name
data=[[0.1, 0.2, 0.3, 0.4, 0.5]], # Query vector (must match collection's vector dim)
limit=5, # Max. number of results to return
filter=filter, # Filter expression
output_fields=["product_id", "metadata"] # Fields to include in the search results
)

print(res)

使用特定于 JSON 的运算符进行过滤

Milvus 还提供特殊运算符,用于查询特定 JSON 字段键上的数组值。例如

  • json_contains(identifier, expr):检查 JSON 数组中是否存在特定元素或子数组

  • json_contains_all(identifier, expr):确保指定 JSON 表达式的所有元素都存在于字段中

  • json_contains_any(identifier, expr):过滤字段中至少存在一个 JSON 表达式成员的实体

查找 tags 关键字下具有 "summer_sale" 值的产品:

Python
# Define filter expression
filter = 'json_contains(metadata["tags"], "summer_sale")'

res = client.search(
collection_name="product_catalog", # Collection name
data=[[0.1, 0.2, 0.3, 0.4, 0.5]], # Query vector (must match collection's vector dim)
limit=5, # Max. number of results to return
filter=filter, # Filter expression
output_fields=["product_id", "metadata"] # Fields to include in the search results
)

print(res)

查找在 tags 关键字下至少有一个 "electronics""new""clearance" 值的产品:

Python
# Define filter expression
filter = 'json_contains_any(metadata["tags"], ["electronics", "new", "clearance"])'

res = client.search(
collection_name="product_catalog", # Collection name
data=[[0.1, 0.2, 0.3, 0.4, 0.5]], # Query vector (must match collection's vector dim)
limit=5, # Max. number of results to return
filter=filter, # Filter expression
output_fields=["product_id", "metadata"] # Fields to include in the search results
)

print(res)

有关 JSON 特定运算符的更多信息,请参阅 JSON 运算符

下一步:加速 JSON 查询

默认情况下,在没有加速的情况下,对 JSON 字段的查询将对所有行执行全扫描,这在大型数据集上可能会比较慢。为了加快 JSON 查询,Milvus 提供了高级索引和存储优化功能。

下表总结了它们的区别和最佳使用场景:

技术

最适合

阵列 加速

注释

JSON 索引

一小部分频繁访问的键,特定数组键上的数组

是(在索引数组键上)

必须预先选择键,如果 Schema 发生变化则需要维护

JSON Shredding(JSON 列式拆分)

普遍加快多个键的速度,灵活适用于各种查询

否(不加速数组内的值)

额外的存储配置,数组仍需要按键索引

NGRAM 索引

通配符搜索、文本字段中的子串匹配

N/A

不适用于数字/范围筛选器

提示:您可以将这些方法结合起来--例如,使用 JSON Shredding(JSON 列式拆分)来加速广泛查询,使用 JSON 索引来处理高频数组键,使用 NGRAM 索引来进行灵活的文本搜索。

有关实施细节,请参阅

常见问题

JSON 字段的大小有限制吗?

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

JSON 字段是否支持设置默认值?

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

详情请参阅 "可空和默认"。

JSON 字段键有任何命名约定吗?

有,以确保与查询和索引的兼容性:

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

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

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

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

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

有效字符串示例

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

无效字符串示例

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