Insert Data into StructArray Fields
当每个 Entity 包含一个有序的结构化元素列表时,可以向 StructArray field 插入数据。在 insert payload 中,StructArray field 表示为对象数组。每个对象表示一个 Struct element,并使用 collection schema 中定义的 Struct subfield 名称。
本页使用 Create a StructArray Field 中的 tech_articles collection。每个 Entity 都是一篇技术文章,chunks field 将文章 chunk 存储为 Struct element。
Before you begin
确保 Collection Schema 已包含 chunks StructArray 字段。
| Field | Type | Insert value |
|---|---|---|
doc_id | INT64 | 文章 ID。 |
title | VARCHAR | 文章标题。 |
category | VARCHAR | 文章类别。 |
title_vector | FLOAT_VECTOR | 文章级 Embedding。 |
chunks | ARRAY | chunk 对象列表。 |
chunks 中的每个对象都必须遵循 Struct schema。
| Subfield | Type | Insert value |
|---|---|---|
text | VARCHAR | chunk 文本。 |
section | VARCHAR | section 名称,例如 index、search 或 filter。 |
page | INT64 | 页码或逻辑位置。 |
quality_score | FLOAT | chunk 级分数。 |
has_code | BOOL | chunk 是否包含代码。 |
emb_list_vector | FLOAT_VECTOR | 用于 EmbeddingList search 写入的向量。 |
emb | FLOAT_VECTOR | 用于 element-level search 写入的向量。 |
在 insert payload 中,chunks 是一个常规字段,其值是 Struct 对象数组。在每个对象内部,使用 text 和 emb 等子字段名。仅在插入之后创建索引、运行搜索、构建 Filter 或指定输出字段时,才使用 chunks[text] 或 chunks[emb] 等路径语法。
Understand the insert payload shape
chunks 的值是一个 Struct 元素数组。每个元素都是一个对象,其键为 subfield 名称。
{
"doc_id": 1,
"title": "StructArray indexing patterns",
"category": "index",
"title_vector": [0.12, 0.08, 0.32, 0.48],
"chunks": [
{
"text": "Create one index for each vector subfield.",
"section": "index",
"page": 1,
"quality_score": 0.96,
"has_code": false,
"emb_list_vector": [0.10, 0.20, 0.30, 0.40],
"emb": [0.10, 0.20, 0.30, 0.40]
},
{
"text": "Use MAX_SIM metrics for EmbeddingList search.",
"section": "index",
"page": 2,
"quality_score": 0.91,
"has_code": true,
"emb_list_vector": [0.16, 0.24, 0.35, 0.45],
"emb": [0.16, 0.24, 0.35, 0.45]
}
]
}
emb_list_vector 和 emb 是独立的 vector subfield,因为它们支持不同的搜索模式。EmbeddingList search 会将 StructArray 字段中的所有 vector 视为一个 embedding list,并使用 MAX_SIM* metrics 返回 Entity 级别的结果。Element-level search 会独立搜索每个 Struct 元素,并可以返回匹配元素的 offset。为简单起见,本示例在两个字段中存储相同的 vector 值。在生产应用中,如果两种搜索模式使用相同的 chunk embedding,你可以在两个 subfield 中存储相同的 Embedding;如果两种搜索模式使用不同的表示,则可以存储不同的 Embedding。
Insert rows
使用 client.insert() 插入包含 StructArray 值的行。
from pymilvus import MilvusClient
client = MilvusClient(
uri="http://localhost:19530",
token="root:Milvus",
)
data = [
{
"doc_id": 1,
"title": "StructArray indexing patterns",
"category": "index",
"title_vector": [0.12, 0.08, 0.32, 0.48],
"chunks": [
{
"text": "Create one index for each vector subfield.",
"section": "index",
"page": 1,
"quality_score": 0.96,
"has_code": False,
"emb_list_vector": [0.10, 0.20, 0.30, 0.40],
"emb": [0.10, 0.20, 0.30, 0.40],
},
{
"text": "Use MAX_SIM metrics for EmbeddingList search.",
"section": "index",
"page": 2,
"quality_score": 0.91,
"has_code": True,
"emb_list_vector": [0.16, 0.24, 0.35, 0.45],
"emb": [0.16, 0.24, 0.35, 0.45],
},
],
},
{
"doc_id": 2,
"title": "Filtered StructArray search",
"category": "filter",
"title_vector": [0.20, 0.18, 0.22, 0.40],
"chunks": [
{
"text": "Use element_filter to match scalar conditions within the same Struct element.",
"section": "filter",
"page": 1,
"quality_score": 0.93,
"has_code": True,
"emb_list_vector": [0.21, 0.18, 0.33, 0.44],
"emb": [0.21, 0.18, 0.33, 0.44],
},
{
"text": "MATCH_LEAST checks how many elements satisfy a predicate.",
"section": "filter",
"page": 2,
"quality_score": 0.88,
"has_code": False,
"emb_list_vector": [0.24, 0.22, 0.31, 0.39],
"emb": [0.24, 0.22, 0.31, 0.39],
},
],
},
{
"doc_id": 3,
"title": "Element-level search with offsets",
"category": "search",
"title_vector": [0.33, 0.11, 0.29, 0.37],
"chunks": [
{
"text": "Element-level search can return the offset of the matched Struct element.",
"section": "search",
"page": 1,
"quality_score": 0.95,
"has_code": False,
"emb_list_vector": [0.32, 0.14, 0.28, 0.41],
"emb": [0.32, 0.14, 0.28, 0.41],
}
],
},
]
result = client.insert(
collection_name="tech_articles",
data=data,
)
print(result)
Insert into nullable StructArray fields
如果 chunks 字段为 nullable,Entity 可以将整个 chunks 字段设为 NULL。在 Python 中,使用 None 表示 NULL 值。
client.insert(
collection_name="tech_articles",
data=[
{
"doc_id": 10,
"title": "Article without chunks yet",
"category": "draft",
"title_vector": [0.05, 0.10, 0.15, 0.20],
"chunks": None,
}
],
)
当 nullable StructArray 字段包含有效的 StructArray 值时,该值中的所有子字段都应为 NULL 或包含有效值。插入某些子字段设为 NULL、其他子字段设为有效值的 Entity 会导致错误。
警告
nullable StructArray 字段仅在 Milvus v3.0.x 中可用。如果你动态向现有 Collection 添加 StructArray 字段,则新增字段必须为 nullable,并且对于现有 Entity,新字段的所有子字段都会返回 null。
Validate inserted data
你可以查询 Collection,并返回 StructArray 字段或选定的子字段。
rows = client.query(
collection_name="tech_articles",
filter="doc_id in [1, 2, 3]",
output_fields=[
"doc_id",
"title",
"chunks[text]",
"chunks[section]",
"chunks[quality_score]",
],
)
for row in rows:
print(row)
仅在执行 query、search、filter 或创建 index 时使用 StructArray 字段路径,例如 chunks[text]。插入 payload 仍应在 chunks 下使用嵌套对象。
Insert rules
| 规则 | 说明 |
|---|---|
| 对 StructArray 字段使用对象数组。 | chunks 的值是一个列表,列表中的每一项都是一个 Struct 元素。 |
| 在每个 Struct 元素内部使用子字段名称。 | 在 chunks 中插入 {"text": "...", "emb": [...]},而不是 {"chunks[text]": "..."}。 |
| 匹配 Struct schema。 | 每个 Struct 元素都必须使用 Struct schema 中定义的子字段。 |
| 匹配向量维度。 | 向量值必须匹配其向量子字段配置的 dim。 |
遵守 max_capacity。 | 一个 Entity 中的 Struct 元素数量不得超过 StructArray 字段的 max_capacity。 |
| 为不同的搜索模式使用不同的向量子字段。 | 如果同时需要 EmbeddingList search 和 element-level search,请将向量值写入两个向量子字段。 |
仅在字段 nullable 时使用 null。 | 非 nullable 的 StructArray 字段需要有效的 StructArray 值。 |
常见错误
-
在插入 payload 中使用
chunks[text]这类字段路径。 -
从 Struct 元素中省略必需的子字段。
-
插入维度错误的向量。
-
插入的 Struct 元素数量超过
max_capacity允许的数量。 -
仅将某一个子字段设为
null,而同一 StructArray 值中的其他子字段仍为有效值。 -
仅将向量写入
emb_list_vector,然后尝试在chunks[emb]上执行元素级搜索。 -
仅将向量写入
emb,然后尝试在chunks[emb_list_vector]上执行 EmbeddingList search。
后续步骤
-
如需为
chunks[emb_list_vector]、chunks[emb]和标量子字段创建索引,请阅读 Index StructArray Fields。 -
如需搜索 StructArray 向量子字段,请阅读 Basic Vector Search with StructArray。
-
如需了解 nullable 行为和版本特定限制,请阅读 StructArray Limits。