当前位置: 首页 > news >正文

Milvus(10):JSON 字段、数组字段

1 JSON 字段

JSON        JSON字段是一种标量字段,它以键值对的形式与向量嵌入一起存储附加信息。下面是一个以 JSON 格式存储数据的示例:

{"metadata": {"product_info": {"category": "electronics","brand": "BrandA"},"price": 99.99,"in_stock": true,"tags": ["summer_sale", "clearance"]}
}

1.1 限制

  • 字段大小:JSON 字段的大小限制为 65,536 字节。

  • 嵌套字典:JSON 字段值中的任何嵌套字典都将作为纯字符串存储。

  • 默认值:JSON 字段不支持默认值。不过,您可以将nullable 属性设置为True ,以允许空值。

  • 类型匹配:如果 JSON 字段的键值是整数或浮点数,则只能(通过表达式过滤器)与另一个相同类型的数字键进行比较。

  • 命名:命名 JSON 键时,建议只使用字母、数字和下划线。使用其他字符可能会在过滤或搜索时造成问题。

  • 字符串处理:Milvus 在 JSON 字段中存储输入的字符串值,不进行语义转换。例如

    • 'a"b',"a'b",'a\\'b', 和"a\\"b" 会按原样存储。

    • 'a'b' 和 被视为无效。"a"b"

  • JSON 索引:为 JSON 字段编制索引时,可以在 JSON 字段中指定一个或多个路径,以加快过滤速度。每增加一条路径都会增加索引开销,因此请仔细规划索引策略。

1.2 添加 JSON 字段

        要将此 JSON 字段metadata 添加到 Collections Schema 中,请使用DataType.JSON 。下面的示例定义了一个允许空值的 JSON 字段metadata :

# 导入必要的库
from pymilvus import MilvusClient, DataType# 定义服务器地址
SERVER_ADDR = "http://localhost:19530"# 创建一个MilvusClient实例
client = MilvusClient(uri=SERVER_ADDR)# 定义集合模式
schema = client.create_schema(auto_id=False,enable_dynamic_fields=True,
)# 添加一个支持空值的JSON字段
schema.add_field(field_name="metadata", datatype=DataType.JSON, nullable=True)
schema.add_field(field_name="pk", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="embedding", datatype=DataType.FLOAT_VECTOR, dim=3)

1.3 设置索引参数

        索引可帮助 Milvus 快速过滤或搜索大量数据。在 Milvus 中,索引是

  • 必须为向量字段建立索引(以高效运行相似性搜索)。
  • JSON 字段可选(加快特定 JSON 路径上的标量过滤器)。

1.3.1 为 JSON 字段建立索引

        默认情况下,JSON 字段未编入索引,因此任何过滤查询(如metadata["price"] < 100 )都必须扫描所有行。如果想加速对metadata 字段中特定路径的查询,可以在关心的每条路径上创建一个反向索引。在本例中,我们将针对 JSON 字段metadata 中的不同路径创建两个索引:

index_params = client.prepare_index_params()# 示例1:将‘product_info’中的‘category’键索引为字符串
index_params.add_index(field_name="metadata", # JSON字段名称到索引index_type="INVERTED", # 索引类型。设置为倒置index_name="json_index_1", # 索引名params={"json_path": "metadata[\"product_info\"][\"category\"]", # JSON字段到索引的路径"json_cast_type": "varchar" # 提取的JSON值将被强制转换为的数据类型}
)# 示例2:索引‘price’作为数字类型(double)
index_params.add_index(field_name="metadata",index_type="INVERTED",index_name="json_index_2",params={"json_path": "metadata[\"price\"]","json_cast_type": "double"}
)

参数

说明

示例值

field_name

Schema 中 JSON 字段的名称。

"metadata"

index_type

要创建的索引类型;目前仅INVERTED 支持 JSON 路径索引。

"INVERTED"

index_name

(可选)自定义索引名称。如果在同一 JSON 字段上创建多个索引,请指定不同的名称。

"json_index_1"

params.json_path

指定要索引的 JSON 路径。可以针对嵌套键、数组位置或两者(如metadata["product_info"]["category"] 或metadata["tags"][0] )。如果路径缺失或数组元素不存在于某一行,则在索引过程中会跳过该行,不会抛出错误。

"metadata[\"product_info\"][\"category\"]"

params.json_cast_type

在建立索引时,Milvus 将把提取的 JSON 值转换成的数据类型。有效值

  • "bool" 或"BOOL"

  • "double" 或"DOUBLE"

  • "varchar" 或"VARCHAR"

    注意:对于整数值,Milvus 内部使用 double 作为索引。超过 2^53 的大整数将失去精度。如果类型转换失败(由于类型不匹配),不会抛出错误,也不会索引该行的值。

"varchar"

        JSON 索引的注意事项

  • 过滤逻辑

    • 如果创建了一个双类型索引json_cast_type="double" ),则只有数字类型的过滤条件才能使用该索引。如果过滤器将双索引与非数值型条件进行比较,Milvus 就会退回到蛮力搜索。

    • 如果创建了 varchar 类型的索引(json_cast_type="varchar"),则只有字符串类型的过滤条件才能使用该索引。否则,Milvus 将退回蛮力搜索。

    • 布尔索引的行为与 varchar 类型类似。

  • 术语表达式

    • 可以使用json["field"] in [value1, value2, …] 。但是,索引只对存储在该路径下的标量值有效。如果json["field"] 是一个数组,查询将退回到蛮力方式(尚未支持数组类型索引)。
  • 数值精度

    • 在内部,Milvus 将所有数值字段索引为双倍。如果数值超过 2^{53},就会失去精度,对超出范围的数值进行查询时可能无法精确匹配。
  • 数据完整性

    • Milvus 不会解析或转换超出你指定铸造的 JSON 键。如果源数据不一致(例如,某些行的键"k" 存储的是字符串,而其他行存储的是数字),某些行将不会被索引。

1.3.2 索引一个向量字段

        下面的示例使用AUTOINDEX 索引类型为向量字段embedding 创建了一个索引。使用这种类型,Milvus 会根据数据类型自动选择最合适的索引。你也可以为每个字段自定义索引类型和参数。

# 设置索引参数index_params = client.prepare_index_params()# 索引“嵌入”与AUTOINDEX并指定相似度度量类型
index_params.add_index(field_name="embedding",index_name="vector_index",index_type="AUTOINDEX",  # 使用自动索引来简化复杂的索引设置metric_type="COSINE"  # 指定相似度量类型,选项包括L2、COSINE或IP
)

1..4 创建 Collections

        定义好 Schema 和索引后,创建一个包含字符串字段的 Collection。

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

1.5 插入数据

        创建 Collections 后,插入与 Schema 匹配的实体。

# 样本数据
data = [{"metadata": {"product_info": {"category": "electronics", "brand": "BrandA"},"price": 99.99,"in_stock": True,"tags": ["summer_sale"]},"pk": 1,"embedding": [0.12, 0.34, 0.56]},{"metadata": None,  # 整个JSON对象为空"pk": 2,"embedding": [0.56, 0.78, 0.90]},{# JSON字段完全丢失"pk": 3,"embedding": [0.91, 0.18, 0.23]},{# 有些子键为空"metadata": {"product_info": {"category": None, "brand": "BrandB"},"price": 59.99,"in_stock": None},"pk": 4,"embedding": [0.56, 0.38, 0.21]}
]client.insert(collection_name="my_collection",data=data
)

1.6 使用过滤表达式查询

        插入实体后,使用query 方法检索与指定过滤表达式匹配的实体。对于允许空值的 JSON 字段,如果整个 JSON 对象缺失或设置为None ,则该字段将被视为空值。检索metadata 不为空值的实体:

# 过滤掉元数据为空的记录filter = 'metadata is not null'res = client.query(collection_name="my_collection",filter=filter,output_fields=["metadata", "pk"]
)# 预期结果
# pk=1和pk=4的行具有有效的非空元数据。
# 排除pk=2(元数据=None)和pk=3(无元数据键)的行。print(res)# Output:
# data: [
#     "{'metadata': {'product_info': {'category': 'electronics', 'brand': 'BrandA'}, 'price': 99.99, 'in_stock': True, 'tags': ['summer_sale']}, 'pk': 1}",
#     "{'metadata': {'product_info': {'category': None, 'brand': 'BrandB'}, 'price': 59.99, 'in_stock': None}, 'pk': 4}"
# ]

        检索metadata["product_info"]["category"] 为"electronics" 的实体:

filter = 'metadata["product_info"]["category"] == "electronics"'res = client.query(collection_name="my_collection",filter=filter,output_fields=["metadata", "pk"]
)# 预期结果
# - 只有pk=1有 "category": "electronics".
# - pk=4有“category”:None,所以它不匹配。
# - Pk =2和Pk =3没有有效的元数据。print(res)# Output:
# data: [
#     "{'pk': 1, 'metadata': {'product_info': {'category': 'electronics', 'brand': 'BrandA'}, 'price': 99.99, 'in_stock': True, 'tags': ['summer_sale']}}"
# ]

1.7 使用过滤表达式进行向量搜索

        除了基本的标量字段筛选外,您还可以将向量相似性搜索与标量字段筛选结合起来。例如,下面的代码展示了如何在向量搜索中添加标量字段过滤器:

filter = 'metadata["product_info"]["brand"] == "BrandA"'res = client.search(collection_name="my_collection",data=[[0.3, -0.6, 0.1]],limit=5,search_params={"params": {"nprobe": 10}},output_fields=["metadata"],filter=filter
)# 预期结果:
# - 元数据["product_info“]中只有pk=1有”brand": “BrandA”。
# - pk=4有“brand”:“BrandB”。
# - Pk =2和Pk =3没有有效的元数据。
# 因此,只有pk=1匹配过滤器。print(res)# Output:
# data: [
#     "[{'id': 1, 'distance': -0.2479381263256073, 'entity': {'metadata': {'product_info': {'category': 'electronics', 'brand': 'BrandA'}, 'price': 99.99, 'in_stock': True, 'tags': ['summer_sale']}}}]"
# ]

        此外,Milvus 还支持高级 JSON 过滤操作符,如JSON_CONTAINS 、JSON_CONTAINS_ALL 和JSON_CONTAINS_ANY ,这可以进一步增强查询功能。

2 数组字段

        ARRAY 字段存储相同数据类型元素的有序集合。下面举例说明 ARRAY 字段如何存储数据:

{"tags": ["pop", "rock", "classic"],"ratings": [5, 4, 3]
}

2.1 限制

  • 默认值:ARRAY 字段不支持默认值。但是,可以将nullable 属性设置为True ,以允许空值。

  • 数据类型:数组字段中的所有元素必须具有相同的数据类型,由element_type 指定。如果将element_type 设置为VARCHAR ,则还应为数组元素设置max_length 。

  • 数组容量:数组字段中元素的数量必须小于或等于创建数组时定义的最大容量,具体由max_capacity 指定。该值应为14096 范围内的整数。

  • 字符串处理:数组字段中的字符串值按原样存储,不进行语义转义或转换。例如,'a"b' 、"a'b" 、'a\'b' 和"a\"b" 按输入值存储,而'a'b' 和"a"b" 则被视为无效值。

2.2 添加 ARRAY 字段

        要使用 ARRAY 字段,Milvus 需要在创建 Collections Schema 时定义相关字段类型。这一过程包括

  1. datatype 设置为支持的数组数据类型ARRAY 。
  2. 使用element_type 参数指定数组中元素的数据类型。这可以是 Milvus 支持的任何标量数据类型,如VARCHAR 或INT64 。同一数组中的所有元素必须具有相同的数据类型。
  3. 使用max_capacity 参数定义数组的最大容量,即数组可包含的最大元素数。

        下面介绍如何定义包含 ARRAY 字段的 Collections Schema:

# 导入必要的库
from pymilvus import MilvusClient, DataType# 定义服务器地址
SERVER_ADDR = "http://localhost:19530"# 创建一个MilvusClient实例
client = MilvusClient(uri=SERVER_ADDR)# 定义集合模式
schema = client.create_schema(auto_id=False,enable_dynamic_fields=True,
)#  添加‘ tags ’和‘ ratings ’ ARRAY字段,null =True
schema.add_field(field_name="tags", datatype=DataType.ARRAY, element_type=DataType.VARCHAR, max_capacity=10, max_length=65535, nullable=True)
schema.add_field(field_name="ratings", datatype=DataType.ARRAY, element_type=DataType.INT64, max_capacity=5, nullable=True)
schema.add_field(field_name="pk", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="embedding", datatype=DataType.FLOAT_VECTOR, dim=3)
export arrayField1='{"fieldName": "tags","dataType": "Array","elementDataType": "VarChar","elementTypeParams": {"max_capacity": 10,"max_length": 65535}
}'export arrayField2='{"fieldName": "ratings","dataType": "Array","elementDataType": "Int64","elementTypeParams": {"max_capacity": 5}
}'export pkField='{"fieldName": "pk","dataType": "Int64","isPrimary": true
}'export vectorField='{"fieldName": "embedding","dataType": "FloatVector","elementTypeParams": {"dim": 3}
}'export schema="{\"autoID\": false,\"fields\": [$arrayField1,$arrayField2,$pkField,$vectorField]
}"

2.3  设置索引参数

        索引有助于提高搜索和查询性能。在 Milvus 中,对于向量字段必须建立索引,但对于标量字段则是可选的。下面的示例使用AUTOINDEX 索引类型为向量字段embedding 和 ARRAY 字段tags 创建了索引。使用这种类型,Milvus 会根据数据类型自动选择最合适的索引。您还可以自定义每个字段的索引类型和参数。

# 设置索引参数index_params = client.prepare_index_params()# 设置索引参数
index_params.add_index(field_name="tags",index_type="AUTOINDEX",index_name="tags_index"
)# 索引“嵌入”与AUTOINDEX并指定相似度度量类型
index_params.add_index(field_name="embedding",index_type="AUTOINDEX",  # 使用自动索引来简化复杂的索引设置metric_type="COSINE"  # 指定相似度量类型,选项包括L2、COSINE或IP
)

2.4 创建 Collections

        定义好 Schema 和索引后,创建一个包含 ARRAY 字段的 Collection。

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

2.5 插入数据

        创建 Collections 后,就可以插入包含 ARRAY 字段的数据。

# 样本数据
data = [{"tags": ["pop", "rock", "classic"],"ratings": [5, 4, 3],"pk": 1,"embedding": [0.12, 0.34, 0.56]},{"tags": None,  # 整个数组为空"ratings": [4, 5],"pk": 2,"embedding": [0.78, 0.91, 0.23]},{  # 标签字段完全缺失"ratings": [9, 5],"pk": 3,"embedding": [0.18, 0.11, 0.23]}
]client.insert(collection_name="my_collection",data=data
)

2.6 使用过滤表达式查询

        插入实体后,使用query 方法检索与指定过滤表达式匹配的实体。检索tags 不为空的实体:

# 排除‘ tags ’不为空的实体的查询filter = 'tags IS NOT NULL'res = client.query(collection_name="my_collection",filter=filter,output_fields=["tags", "ratings", "pk"]
)print(res)# Example output:
# data: [
#     "{'tags': ['pop', 'rock', 'classic'], 'ratings': [5, 4, 3], 'pk': 1}"
# ]

        检索ratings 第一个元素的值大于 4 的实体:

filter = 'ratings[0] > 4'res = client.query(collection_name="my_collection",filter=filter,output_fields=["tags", "ratings", "embedding"]
)print(res)# Example output:
# data: [
#     "{'tags': ['pop', 'rock', 'classic'], 'ratings': [5, 4, 3], 'embedding': [0.12, 0.34, 0.56], 'pk': 1}",
#     "{'tags': None, 'ratings': [9, 5], 'embedding': [0.18, 0.11, 0.23], 'pk': 3}"
# ]

2.7 使用过滤表达式进行向量搜索

        除了基本的标量字段筛选外,您还可以将向量相似性搜索与标量字段筛选结合起来。例如,下面的代码展示了如何在向量搜索中添加标量字段过滤器:

filter = 'tags[0] == "pop"'res = client.search(collection_name="my_collection",data=[[0.3, -0.6, 0.1]],limit=5,search_params={"params": {"nprobe": 10}},output_fields=["tags", "ratings", "embedding"],filter=filter
)print(res)# Example output:
# data: [
#     "[{'id': 1, 'distance': -0.2479381263256073, 'entity': {'tags': ['pop', 'rock', 'classic'], 'ratings': [5, 4, 3], 'embedding': [0.11999999731779099, 0.3400000035762787, 0.5600000023841858]}}]"
# ]

        此外,Milvus 还支持高级数组过滤操作符,如ARRAY_CONTAINS,ARRAY_CONTAINS_ALL,ARRAY_CONTAINS_ANY 和ARRAY_LENGTH ,以进一步增强查询功能。

相关文章:

  • SpringBoot中获取系统及硬件信息
  • C++学习:六个月从基础到就业——模板编程:模板元编程基础
  • mermaid 序列图 解析
  • 如何用python脚本把一个表格有4万多条数据分为两个文件表,每个2万条数据?
  • 华为云IoT平台与MicroPython实战:从MQTT协议到物联网设备开发
  • 基于PHP的宠物用品商城
  • TCL科技2025一季度归母净利润10.1亿,半导体显示业务业绩创新高
  • 大模型备案实操手册:材料准备、流程解析与常见问题避坑指南
  • Spark GraphX 机器学习:图计算
  • 数据库所有知识
  • 如何设计一个会员码表!唯一索引的使用,字段区分度不高如何处理
  • 【AI面试准备】深度学习、大模型原理,算法项目经验
  • jthread是否可以完全取代thread?
  • Java高频面试之并发编程-11
  • Git 操作命令
  • 1.PowerBi保姆级安装教程
  • 驱动开发硬核特训 · Day 24(下篇):深入理解 Linux 内核时钟子系统结构
  • PSO详解变体上新!新型混合蛾焰粒子群优化(MFPSO)算法
  • 如何搭建一个简单的文件服务器的方法
  • 使用 DBeaver 将数据从 PostgreSQL 导出到 SQLite
  • 从孔雀尾巴到蒙娜丽莎,一个鸟类学博士眼中的“美”
  • “光荣之城”2025上海红色文化季启动,红色主题市集亮相
  • 中方发布《不跪!》视频传递何种信息?外交部回应
  • 历史新高!上海机场一季度营收增至31.72亿元,净利润增34%
  • 见证上海援藏30年成果,萨迦非遗珍品展来沪
  • 马上评|“AI神医宇宙”欺诈,连演员都不请了