JSON 字段概述
在构建产品目录、内容管理系统或用户偏好引擎等应用程序时,您往往需要在存储向量 Embeddings 的同时存储灵活的元数据。产品属性因类别而异,用户偏好随时间演变,文档属性具有复杂的嵌套结构。Milvus 中的 JSON 字段解决了这一难题,允许您在不牺牲性能的情况下存储和查询灵活的结构化数据。
什么是 JSON 字段?
JSON 字段是 Milvus 中的一种 Schema 定义数据类型 (DataType.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 定义 |
标量字段,必须在 Collections Schema 中以 |
一个隐藏的 JSON 字段(名为 |
使用情况 |
存储模式已知且一致的结构化数据。 |
存储不适合固定模式的灵活、不断变化或半结构化数据。 |
控制 |
由您控制字段名称和结构。 |
系统管理未定义的字段。 |
查询 |
使用字段名或 JSON 字段内的目标键进行查询: |
直接使用 Dynamic Field 关键字查询: |
基本操作符
使用 JSON 字段的基本工作流程包括在 Schema 中定义字段、插入数据,然后使用特定的过滤表达式查询数据。
定义 JSON 字段
要使用 JSON 字段,请在创建 Collection 时在模式 Schema 中明确定义该字段。下面的示例演示了如何创建一个带有metadata 类型字段DataType.JSON 的 Collections:
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
)
在本例中,集合模式 Schema 中定义的 JSON 字段允许使用nullable=True 的空值。有关详情,请参阅 "可为空值和默认值"。
插入数据
创建 Collections 后,在指定的 JSON 字段中插入包含结构化 JSON 对象的实体。数据格式应为字典列表。
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 字段执行过滤操作前,请确保
您已在每个向量字段上创建了索引。
Collections 已加载到内存中。
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 字段内的值对 Collections 进行过滤。这些过滤表达式利用了特定的 JSON 路径语法和专用操作符。
使用 JSON 路径语法进行筛选
要查询特定键,请使用括号符号访问 JSON 键:json_field_name["key"] 。对于嵌套键,可将它们串联起来:json_field_name["key1"]["key2"] 。
要过滤category 是"electronics" 的实体:
# Define filter expression
filter = 'metadata["category"] == "electronics"'
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
)
过滤嵌套键supplier["country"] 为"USA" 的实体:
# 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" 值的产品:
# 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" 值的产品:
# 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 粉碎 |
普遍加快多个键的速度,灵活适用于各种查询 |
否(不加速数组内的值) |
额外的存储配置,数组仍需要按键索引 |
NGRAM 索引 |
通配符搜索、文本字段中的子串匹配 |
不适用 |
不适用于数字/范围筛选器 |
提示:您可以将这些方法结合起来--例如,使用 JSON 切碎来加速广泛查询,使用 JSON 索引来处理高频数组键,使用 NGRAM 索引来进行灵活的文本搜索。
有关实施细节,请参阅
常见问题
JSON 字段的大小有限制吗?
有。每个 JSON 字段的大小限制为 65,536 字节。
JSON 字段是否支持设置默认值?
不支持,JSON 字段不支持默认值。不过,您可以在定义字段时设置nullable=True ,以允许空条目。
详情请参阅 "可空和默认"。
JSON 字段键有任何命名约定吗?
有,以确保与查询和索引的兼容性:
在 JSON 键中只使用字母、数字和下划线。
避免使用特殊字符、空格或点(
.,/等)。不兼容的键可能会导致过滤表达式出现解析问题。
Milvus 如何处理 JSON 字段中的字符串值?
Milvus 完全按照 JSON 输入中的字符串值进行存储,不进行语义转换。引号不当的字符串可能会在解析过程中导致错误。
有效字符串示例
"a\"b", "a'b", "a\\b"
无效字符串示例
'a"b', 'a\'b'