修改 Collection Schema
随着 Collection 从开发阶段进入生产阶段,其 Schema 往往也会发生变化。您可能需要添加 source_uri 或 review_status 等标量字段,以用于过滤和应用逻辑;添加新的向量字段,以存储应用生成的 Embedding;添加 BM25 Function 及其生成的稀疏向量字段,以便对现有文本执行词法搜索;或者删除不再使用的字段和 Function。修改 Collection Schema 功能允许您就地完成受支持的字段和 Function 变更,无需重新创建 Collection。
-
本指南介绍托管 Collection 中用户自定义字段,以及 Function 及其生成的向量字段的 Schema 变更。对于字段属性变更,例如修改
max_length(针对VARCHAR字段)或max_capacity(针对ARRAY字段),请参阅修改字段设置。对于动态字段行为,请参阅动态字段和修改 Collection。 -
本页介绍如何向托管 Collection 添加字段。若要向外部 Collection 添加字段,请参阅修改外部 Collection Schema。
限制
添加用户自定义字段
-
新增的用户自定义字段必须可为空。请将
nullable=True作为调用add_collection_field()时的设置。对于现有 Entity,新增字段的值为NULL;但如果添加的是带有default_value的标量字段,则使用默认值。 -
Milvus 2.6.x 及更高版本支持添加用户自定义标量字段。Milvus 2.6.18 及更高版本支持添加用户自定义向量字段。
-
字段名称在 Collection 的所有字段中必须唯一。
添加 Function 及其生成的向量字段
-
每次 Schema 更新只能添加一个 Function 和一个生成的向量字段。
-
受支持的 Function 决定生成的向量字段类型:
BM25生成SPARSE_FLOAT_VECTOR字段,MINHASH生成BINARY_VECTOR字段。 -
生成的向量字段必须是新字段,不能指向 Collection Schema 中已有的字段。
-
生成的向量字段不能可为空。
-
Function 使用的输入字段必须已存在于 Collection 中。对于此现有 Collection 工作流,BM25 和 MinHash 的输入字段必须是
VARCHAR。使用TEXT输入的 BM25 Function 必须在创建 Collection 时定义。
删除用户自定义字段
-
不能删除主键字段、Partition Key 字段、Clustering Key 字段或 Collection 中的最后一个向量字段。
-
可以删除整个
ARRAY<STRUCT>字段,但不能删除ARRAY<STRUCT>字段中的单个子字段。 -
不能直接删除用作 Function 输入字段或由 Function 生成的输出字段。若要删除 Function 输出字段,请删除生成该字段的 Function。
删除 Function 及其生成的向量字段
-
在此 Schema 变更工作流中,删除 Function 会同时删除该 Function、其生成的向量字段以及关联索引。Function 的输入字段会保留在 Collection Schema 中。
-
如果删除 Function 生成的向量字段会导致 Collection 中不再包含任何向量字段,则删除操作会被拒绝。
对于受支持的添加和删除操作之外的 Schema 变更,请重新创建或迁移 Collection。
向现有 Collection 添加字段和 Function
请根据要添加的是用户自定义字段,还是生成向量字段的 Function 来选择工作流:
-
添加用户自定义标量字段,适用于需要用于过滤、查询输出或应用逻辑的新 Metadata 的场景。
-
添加用户自定义向量字段,适用于应用生成 Embedding,并将向量值写入 Zilliz Cloud 的场景。
-
添加 Function 及其生成的向量字段,适用于需要由 Zilliz Cloud 根据现有字段生成向量值的场景,例如根据文本生成 BM25 稀疏向量或 MinHash 签名。
在这些情况下,字段总数不能超过 Zilliz Cloud 的字段数量限制。详情请参阅 Zilliz Cloud 限制。
添加用户自定义标量字段
使用 add_collection_field() 向现有 Collection 添加用户自定义标量字段。
这与在动态字段中存储任意键不同:Schema 更新生效后,新的标量字段会成为 Collection Schema 的常规组成部分。您可以在 Insert 或 Upsert 时为其写入值;在支持的情况下为其创建索引;在 Query 和 Search 过滤表达式中使用该字段;以及在 Query 或 Search 结果中返回该字段。
由于现有 Entity 是在新字段存在之前插入的,因此新增的每个用户自定义标量字段都必须可为空:
-
如果添加标量字段时设置
nullable=True,但不设置default_value,则现有 Entity 的新字段返回NULL。 -
如果添加标量字段时设置
nullable=True和default_value,则现有 Entity 返回默认值,而不是NULL。
标量过滤表达式不会匹配值为 NULL 的标量字段。详情请参阅可空字段。
示例:添加可空标量字段
以下示例向名为 product_catalog 的现有 Collection 添加一个可空的 source 字段。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
from pymilvus import DataType, MilvusClient
client = MilvusClient(uri="YOUR_CLUSTER_ENDPOINT")
client.add_collection_field(
collection_name="product_catalog",
field_name="source",
data_type=DataType.VARCHAR,
max_length=128,
nullable=True,
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddCollectionFieldReq;
ConnectConfig connectConfig = ConnectConfig.builder()
.uri("YOUR_CLUSTER_ENDPOINT")
.build();
MilvusClientV2 client = new MilvusClientV2(connectConfig);
client.addCollectionField(AddCollectionFieldReq.builder()
.collectionName("product_catalog")
.fieldName("source")
.dataType(DataType.VarChar)
.maxLength(128)
.isNullable(true)
.build());
import (
"context"
"log"
"github.com/milvus-io/milvus/client/v3/entity"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
ctx := context.Background()
cli, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
Address: "YOUR_CLUSTER_ENDPOINT",
})
if err != nil {
log.Fatal("failed to connect to milvus server: ", err.Error())
}
newField := entity.NewField().
WithName("source").
WithDataType(entity.FieldTypeVarChar).
WithNullable(true).
WithMaxLength(128)
err = cli.AddCollectionField(ctx, milvusclient.NewAddCollectionFieldOption("product_catalog", newField))
if err != nil {
log.Fatal("failed to add field: ", err.Error())
}
use milvus::v2::prelude::*;
let config = ConnectConfig::new().uri("YOUR_CLUSTER_ENDPOINT");
let client = ClientV2::new(&config).await?;
client
.add_collection_field(
AddCollectionFieldRequest::builder()
.collection_name("product_catalog")
.field(
FieldSchema::new()
.name("source")
.data_type(DataType::VarChar)
.max_length(128)
.nullable(true),
)
.build()?,
)
.await?;
#include <iostream>
#include "milvus/MilvusClientV2.h"
auto client = milvus::MilvusClientV2::Create();
auto status = client->Connect(milvus::ConnectParam("YOUR_CLUSTER_ENDPOINT"));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
milvus::FieldSchema field = milvus::FieldSchema("source", milvus::DataType::VARCHAR)
.WithMaxLength(128)
.WithNullable(true);
status = client->AddCollectionField(
milvus::AddCollectionFieldRequest().WithCollectionName("product_catalog").WithField(std::move(field)));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
import { MilvusClient } from "@zilliz/milvus2-sdk-node";
const client = new MilvusClient({ address: "YOUR_CLUSTER_ENDPOINT" });
await client.addCollectionField({
collection_name: "product_catalog",
field: {
name: "source",
data_type: "VarChar",
max_length: 128,
nullable: true,
},
});
curl --request POST \
--url YOUR_CLUSTER_ENDPOINT/v2/vectordb/collections/fields/add \
--header "Authorization: Bearer YOUR_CLUSTER_TOKEN" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "product_catalog",
"schema": {
"fieldName": "source",
"dataType": "VarChar",
"nullable": true,
"elementTypeParams": {
"max_length": 128
}
}
}'
字段添加后,Collection 中原有 Entity 的 source 返回 NULL。新 Entity 可以在 Insert 或 Upsert 时设置 source。
示例:添加带默认值的标量字段
如果希望现有 Entity 返回具体值而不是 NULL,请在添加字段时指定 default_value。以下示例添加 review_status 字段,并使用 "unreviewed" 作为默认值。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
from pymilvus import DataType, MilvusClient
client = MilvusClient(uri="YOUR_CLUSTER_ENDPOINT")
client.add_collection_field(
collection_name="product_catalog",
field_name="review_status",
data_type=DataType.VARCHAR,
max_length=32,
nullable=True,
default_value="unreviewed",
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddCollectionFieldReq;
ConnectConfig connectConfig = ConnectConfig.builder()
.uri("YOUR_CLUSTER_ENDPOINT")
.build();
MilvusClientV2 client = new MilvusClientV2(connectConfig);
client.addCollectionField(AddCollectionFieldReq.builder()
.collectionName("product_catalog")
.fieldName("review_status")
.dataType(DataType.VarChar)
.maxLength(32)
.isNullable(true)
.defaultValue("unreviewed")
.build());
import (
"context"
"log"
"github.com/milvus-io/milvus/client/v3/entity"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
ctx := context.Background()
cli, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
Address: "YOUR_CLUSTER_ENDPOINT",
})
if err != nil {
log.Fatal("failed to connect to milvus server: ", err.Error())
}
newField := entity.NewField().
WithName("review_status").
WithDataType(entity.FieldTypeVarChar).
WithNullable(true).
WithMaxLength(32).
WithDefaultValueString("unreviewed")
err = cli.AddCollectionField(ctx, milvusclient.NewAddCollectionFieldOption("product_catalog", newField))
if err != nil {
log.Fatal("failed to add field: ", err.Error())
}
use milvus::v2::prelude::*;
let config = ConnectConfig::new().uri("YOUR_CLUSTER_ENDPOINT");
let client = ClientV2::new(&config).await?;
client
.add_collection_field(
AddCollectionFieldRequest::builder()
.collection_name("product_catalog")
.field(
FieldSchema::new()
.name("review_status")
.data_type(DataType::VarChar)
.max_length(32)
.nullable(true)
.default_value(DefaultValue::String("unreviewed".into())),
)
.build()?,
)
.await?;
#include <iostream>
#include "milvus/MilvusClientV2.h"
auto client = milvus::MilvusClientV2::Create();
auto status = client->Connect(milvus::ConnectParam("YOUR_CLUSTER_ENDPOINT"));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
milvus::FieldSchema field = milvus::FieldSchema("review_status", milvus::DataType::VARCHAR)
.WithMaxLength(32)
.WithNullable(true)
.WithDefaultValue("unreviewed");
status = client->AddCollectionField(
milvus::AddCollectionFieldRequest().WithCollectionName("product_catalog").WithField(std::move(field)));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
import { MilvusClient } from "@zilliz/milvus2-sdk-node";
const client = new MilvusClient({ address: "YOUR_CLUSTER_ENDPOINT" });
await client.addCollectionField({
collection_name: "product_catalog",
field: {
name: "review_status",
data_type: "VarChar",
max_length: 32,
nullable: true,
default_value: "unreviewed",
},
});
curl --request POST \
--url YOUR_CLUSTER_ENDPOINT/v2/vectordb/collections/fields/add \
--header "Authorization: Bearer YOUR_CLUSTER_TOKEN" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "product_catalog",
"schema": {
"fieldName": "review_status",
"dataType": "VarChar",
"nullable": true,
"defaultValue": "unreviewed",
"elementTypeParams": {
"max_length": 32
}
}
}'
字段添加后,Collection 中原有 Entity 的 review_status 返回 "unreviewed"。新 Entity 可以设置其他值;如果未提供值,则使用默认值。
添加 StructArray 字段
使用 add_collection_struct_field() 添加可接收 Struct 数组的 StructArray 字段。添加 StructArray 字段的步骤如下:
-
创建一个 StructSchema,其中包含所需且数据类型受支持的子字段。适用的数据类型请参阅StructArray 概述。
-
引用上一步创建的 StructSchema,并在
add_collection_struct_field()中设置字段的最大容量。 -
在请求中将
nullable设置为True。
示例:添加可空 StructArray 字段
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
from pymilvus import DataType, MilvusClient
client = MilvusClient(uri="YOUR_CLUSTER_ENDPOINT")
# Create a struct schema
struct_schema = client.create_struct_field_schema()
# add a scalar field to the struct
struct_schema.add_field("text", DataType.VARCHAR, max_length=65535)
struct_schema.add_field("chapter", DataType.VARCHAR, max_length=512)
# add a vector field to the struct with mmap enabled
struct_schema.add_field("text_vector", DataType.FLOAT_VECTOR, mmap_enabled=True, dim=5)
struct_schema.add_field("chapter_vector", DataType.FLOAT_VECTOR, mmap_enabled=True, dim=5)
client.add_collection_struct_field(
collection_name="books",
field_name="chunks",
struct_schema=struct_schema,
max_capacity=1024,
nullable=True
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddCollectionStructFieldReq;
import io.milvus.v2.service.collection.request.AddFieldReq;
import java.util.HashMap;
import java.util.Map;
ConnectConfig connectConfig = ConnectConfig.builder()
.uri("YOUR_CLUSTER_ENDPOINT")
.build();
MilvusClientV2 client = new MilvusClientV2(connectConfig);
// Create a struct schema and add its subfields
// add a vector subfield with mmap enabled
Map<String, String> mmapParams = new HashMap<>();
mmapParams.put("mmap.enabled", "true");
client.addCollectionStructField(AddCollectionStructFieldReq.builder()
.collectionName("books")
.fieldName("chunks")
.maxCapacity(1024)
.nullable(true)
.addStructField(AddFieldReq.builder()
.fieldName("text")
.dataType(DataType.VarChar)
.maxLength(65535)
.build())
.addStructField(AddFieldReq.builder()
.fieldName("chapter")
.dataType(DataType.VarChar)
.maxLength(512)
.build())
.addStructField(AddFieldReq.builder()
.fieldName("text_vector")
.dataType(DataType.FloatVector)
.dimension(5)
.typeParams(mmapParams)
.build())
.addStructField(AddFieldReq.builder()
.fieldName("chapter_vector")
.dataType(DataType.FloatVector)
.dimension(5)
.typeParams(mmapParams)
.build())
.build());
import (
"context"
"log"
"github.com/milvus-io/milvus/client/v3/entity"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
ctx := context.Background()
cli, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
Address: "YOUR_CLUSTER_ENDPOINT",
})
if err != nil {
log.Fatal("failed to connect to milvus server: ", err.Error())
}
// Create a struct schema and add its subfields
// add a vector subfield with mmap enabled
structSchema := entity.NewStructSchema().
WithField(entity.NewField().WithName("text").WithDataType(entity.FieldTypeVarChar).WithMaxLength(65535)).
WithField(entity.NewField().WithName("chapter").WithDataType(entity.FieldTypeVarChar).WithMaxLength(512)).
WithField(entity.NewField().WithName("text_vector").WithDataType(entity.FieldTypeFloatVector).WithDim(5).WithTypeParams("mmap.enabled", "true")).
WithField(entity.NewField().WithName("chapter_vector").WithDataType(entity.FieldTypeFloatVector).WithDim(5).WithTypeParams("mmap.enabled", "true"))
newField := entity.NewField().
WithName("chunks").
WithDataType(entity.FieldTypeArray).
WithElementType(entity.FieldTypeStruct).
WithNullable(true).
WithMaxCapacity(1024).
WithStructSchema(structSchema)
err = cli.AddCollectionStructField(ctx, milvusclient.NewAddCollectionStructFieldOption("books", newField))
if err != nil {
log.Fatal("failed to add struct field: ", err.Error())
}
use milvus::v2::prelude::*;
let config = ConnectConfig::new().uri("YOUR_CLUSTER_ENDPOINT");
let client = ClientV2::new(&config).await?;
// Create a struct schema and add its subfields
// add a vector subfield with mmap enabled
let struct_schema = StructFieldSchema::new()
.name("chunks")
.max_capacity(1024)
.nullable(true)
.add_field(
FieldSchema::new()
.name("text")
.data_type(DataType::VarChar)
.max_length(65535),
)
.add_field(
FieldSchema::new()
.name("chapter")
.data_type(DataType::VarChar)
.max_length(512),
)
.add_field(
FieldSchema::new()
.name("text_vector")
.data_type(DataType::FloatVector)
.dimension(5)
.type_params(
std::collections::HashMap::from([("mmap.enabled".to_string(), "true".to_string())]),
),
)
.add_field(
FieldSchema::new()
.name("chapter_vector")
.data_type(DataType::FloatVector)
.dimension(5)
.type_params(
std::collections::HashMap::from([("mmap.enabled".to_string(), "true".to_string())]),
),
);
client
.add_collection_struct_field(
AddCollectionStructFieldRequest::builder()
.collection_name("books")
.struct_field(struct_schema)
.build()?,
)
.await?;
#include <iostream>
#include "milvus/MilvusClientV2.h"
auto client = milvus::MilvusClientV2::Create();
auto status = client->Connect(milvus::ConnectParam("YOUR_CLUSTER_ENDPOINT"));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
// Create a struct schema and add its subfields
// add a vector subfield with mmap enabled
milvus::StructFieldSchema struct_schema = milvus::StructFieldSchema("chunks")
.WithMaxCapacity(1024)
.WithNullable(true)
.AddField(milvus::FieldSchema("text", milvus::DataType::VARCHAR).WithMaxLength(65535))
.AddField(milvus::FieldSchema("chapter", milvus::DataType::VARCHAR).WithMaxLength(512))
.AddField(milvus::FieldSchema("text_vector", milvus::DataType::FLOAT_VECTOR).WithDimension(5).AddTypeParam("mmap.enabled", "true"))
.AddField(milvus::FieldSchema("chapter_vector", milvus::DataType::FLOAT_VECTOR).WithDimension(5).AddTypeParam("mmap.enabled", "true"));
status = client->AddCollectionStructField(
milvus::AddCollectionStructFieldRequest().WithCollectionName("books").WithStructField(std::move(struct_schema)));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
import { MilvusClient } from "@zilliz/milvus2-sdk-node";
const client = new MilvusClient({ address: "YOUR_CLUSTER_ENDPOINT" });
// Create a struct schema and add its subfields
// add a vector subfield with mmap enabled
await client.addCollectionField({
collection_name: "books",
field: {
name: "chunks",
data_type: "Array",
element_type: "Struct",
max_capacity: 1024,
nullable: true,
fields: [
{ name: "text", data_type: "VarChar", max_length: 65535 },
{ name: "chapter", data_type: "VarChar", max_length: 512 },
{ name: "text_vector", data_type: "FloatVector", dim: 5, "mmap.enabled": true },
{ name: "chapter_vector", data_type: "FloatVector", dim: 5, "mmap.enabled": true },
],
},
});
# Note: The REST API does not expose a StructArray add-field operation as of v3.0.x. Use the gRPC SDKs instead.
添加 StructArray 字段后,Collection 中原有 Entity 的 chunks 及其所有子字段均返回 null。插入新 Entity 时,请确保所有子字段要么均为 null,要么均具有有效值。如果部分子字段设置为 null,而其他子字段具有有效值,插入操作会报错。
添加用户自定义向量字段
当应用生成 Embedding,并将向量值写入 Zilliz Cloud 时,使用 add_collection_field() 添加用户自定义向量字段。
新增的每个用户自定义向量字段都必须可为空。在通过 Upsert 或回填工作流写入向量值之前,现有 Entity 的新向量字段值为 NULL。新 Entity 可以在 Insert 时包含该向量字段。向量搜索会跳过向量值为 NULL 的 Entity。详情请参阅可空字段。
示例:添加可空向量字段
以下示例向现有 Collection 添加一个名为 embedding_v2 的可空稠密向量字段。请将 dim 设置为应用所生成 Embedding 的维度。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
from pymilvus import DataType, MilvusClient
client = MilvusClient(uri="YOUR_CLUSTER_ENDPOINT")
client.add_collection_field(
collection_name="product_catalog",
field_name="embedding_v2",
data_type=DataType.FLOAT_VECTOR,
dim=768,
nullable=True,
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddCollectionFieldReq;
ConnectConfig connectConfig = ConnectConfig.builder()
.uri("YOUR_CLUSTER_ENDPOINT")
.build();
MilvusClientV2 client = new MilvusClientV2(connectConfig);
client.addCollectionField(AddCollectionFieldReq.builder()
.collectionName("product_catalog")
.fieldName("embedding_v2")
.dataType(DataType.FloatVector)
.dimension(768)
.isNullable(true)
.build());
import (
"context"
"log"
"github.com/milvus-io/milvus/client/v3/entity"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
ctx := context.Background()
cli, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
Address: "YOUR_CLUSTER_ENDPOINT",
})
if err != nil {
log.Fatal("failed to connect to milvus server: ", err.Error())
}
newField := entity.NewField().
WithName("embedding_v2").
WithDataType(entity.FieldTypeFloatVector).
WithNullable(true).
WithDim(768)
err = cli.AddCollectionField(ctx, milvusclient.NewAddCollectionFieldOption("product_catalog", newField))
if err != nil {
log.Fatal("failed to add field: ", err.Error())
}
use milvus::v2::prelude::*;
let config = ConnectConfig::new().uri("YOUR_CLUSTER_ENDPOINT");
let client = ClientV2::new(&config).await?;
client
.add_collection_field(
AddCollectionFieldRequest::builder()
.collection_name("product_catalog")
.field(
FieldSchema::new()
.name("embedding_v2")
.data_type(DataType::FloatVector)
.dimension(768)
.nullable(true),
)
.build()?,
)
.await?;
#include <iostream>
#include "milvus/MilvusClientV2.h"
auto client = milvus::MilvusClientV2::Create();
auto status = client->Connect(milvus::ConnectParam("YOUR_CLUSTER_ENDPOINT"));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
milvus::FieldSchema field = milvus::FieldSchema("embedding_v2", milvus::DataType::FLOAT_VECTOR)
.WithDimension(768)
.WithNullable(true);
status = client->AddCollectionField(
milvus::AddCollectionFieldRequest().WithCollectionName("product_catalog").WithField(std::move(field)));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
import { MilvusClient } from "@zilliz/milvus2-sdk-node";
const client = new MilvusClient({ address: "YOUR_CLUSTER_ENDPOINT" });
await client.addCollectionField({
collection_name: "product_catalog",
field: {
name: "embedding_v2",
data_type: "FloatVector",
dim: 768,
nullable: true,
},
});
curl --request POST \
--url YOUR_CLUSTER_ENDPOINT/v2/vectordb/collections/fields/add \
--header "Authorization: Bearer YOUR_CLUSTER_TOKEN" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "product_catalog",
"schema": {
"fieldName": "embedding_v2",
"dataType": "FloatVector",
"nullable": true,
"elementTypeParams": {
"dim": 768
}
}
}'
添加字段后,请先为新的向量字段创建索引,再使用该字段执行搜索:
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
index_params = client.prepare_index_params()
index_params.add_index(
field_name="embedding_v2",
index_type="AUTOINDEX",
metric_type="COSINE",
)
client.create_index(
collection_name="product_catalog",
index_params=index_params,
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.IndexParam;
import io.milvus.v2.service.index.request.CreateIndexReq;
import java.util.Collections;
ConnectConfig connectConfig = ConnectConfig.builder()
.uri("YOUR_CLUSTER_ENDPOINT")
.build();
MilvusClientV2 client = new MilvusClientV2(connectConfig);
client.createIndex(CreateIndexReq.builder()
.collectionName("product_catalog")
.indexParams(Collections.singletonList(IndexParam.builder()
.fieldName("embedding_v2")
.indexType(IndexParam.IndexType.AUTOINDEX)
.metricType(IndexParam.MetricType.COSINE)
.build()))
.build());
import (
"context"
"log"
"github.com/milvus-io/milvus/client/v3/entity"
"github.com/milvus-io/milvus/client/v3/index"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
ctx := context.Background()
cli, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
Address: "YOUR_CLUSTER_ENDPOINT",
})
if err != nil {
log.Fatal("failed to connect to milvus server: ", err.Error())
}
indexOpt := milvusclient.NewCreateIndexOption("product_catalog", "embedding_v2", index.NewAutoIndex(entity.COSINE))
_, err = cli.CreateIndex(ctx, indexOpt)
if err != nil {
log.Fatal("failed to create index: ", err.Error())
}
use milvus::v2::prelude::*;
let config = ConnectConfig::new().uri("YOUR_CLUSTER_ENDPOINT");
let client = ClientV2::new(&config).await?;
client
.create_index(
CreateIndexRequest::builder()
.collection_name("product_catalog")
.index_param(
IndexParam::new()
.field_name("embedding_v2")
.index_type(IndexType::AutoIndex)
.metric_type(MetricType::Cosine),
)
.build()?,
)
.await?;
#include <iostream>
#include "milvus/MilvusClientV2.h"
auto client = milvus::MilvusClientV2::Create();
auto status = client->Connect(milvus::ConnectParam("YOUR_CLUSTER_ENDPOINT"));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
milvus::IndexDesc index_desc("embedding_v2", "", milvus::IndexType::AUTOINDEX, milvus::MetricType::COSINE);
status = client->CreateIndex(
milvus::CreateIndexRequest().WithCollectionName("product_catalog").AddIndex(std::move(index_desc)));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
import { MilvusClient } from "@zilliz/milvus2-sdk-node";
const client = new MilvusClient({ address: "YOUR_CLUSTER_ENDPOINT" });
await client.createIndex({
collection_name: "product_catalog",
field_name: "embedding_v2",
index_type: "AUTOINDEX",
metric_type: "COSINE",
});
curl --request POST \
--url YOUR_CLUSTER_ENDPOINT/v2/vectordb/indexes/create \
--header "Authorization: Bearer YOUR_CLUSTER_TOKEN" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "product_catalog",
"indexParams": [
{
"fieldName": "embedding_v2",
"indexType": "AUTOINDEX",
"metricType": "COSINE"
}
]
}'
现有 Entity 的 embedding_v2 值为 NULL,因此在该字段上搜索时会被跳过。若要让现有 Entity 可通过 embedding_v2 搜索,请通过 Upsert 工作流写入非 NULL 向量值。新 Entity 可以在 Insert 时包含 embedding_v2。
添加 Function 及其生成的向量字段
此 Milvus 3.0 Schema 变更工作流目前仅针对 Zilliz Cloud 按量付费 Cluster 提供文档说明。本页不界定首个受支持的 Cloud 补丁版本,也不说明 Serving Cluster 的可用性。
使用此工作流可根据现有 Collection 中已经存储的数据生成新的向量字段。例如,BM25 Function 读取现有 VARCHAR 字段,并生成用于词法搜索的 SPARSE_FLOAT_VECTOR 字段;MinHash Function 则生成用于近似重复检测的 BINARY_VECTOR 字段。此工作流不会添加或替换 Function 的输入字段。
该操作会添加一个 Function 定义、一个新的向量输出字段和一个绑定的索引定义:
-
一个 Function 定义(例如
text_bm25),用于读取现有输入字段。 -
一个新的向量输出字段(例如
text_sparse),用于存储 Function 输出,以及绑定到该字段的索引定义。
受支持的 Function 决定生成的向量字段类型:
| Function | 生成的向量字段类型 | 典型输入字段 |
|---|---|---|
BM25 | SPARSE_FLOAT_VECTOR | 启用了 Analyzer 的 VARCHAR 字段 |
MINHASH | BINARY_VECTOR | 一个 VARCHAR 字段 |
有关每种 Function 工作方式的详情,请参阅 BM25 Function 和 MinHash Function。
生成的向量字段不能已经存在于 Collection 中,也不能可为空。Function 输入字段必须已经存在。对于此现有 Collection 工作流,请使用 VARCHAR 输入字段。使用 TEXT 输入字段的 BM25 Function 必须在创建 Collection 时定义;否则,请重新创建或迁移 Collection,并在其 Schema 中包含该 Function。
示例:添加 BM25 Function 及其生成的稀疏向量字段
以下示例向现有 Collection 添加名为 text_bm25 的 BM25 Function,以及名为 text_sparse 的生成稀疏向量字段。该 Collection 必须已经包含一个名为 text 且启用了 Analyzer 的 VARCHAR 字段。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
from pymilvus import DataType, Function, FunctionType, MilvusClient
client = MilvusClient(uri="YOUR_CLUSTER_ENDPOINT")
sparse_field = client.create_field_schema(
name="text_sparse",
data_type=DataType.SPARSE_FLOAT_VECTOR,
desc="BM25-generated sparse vector field",
)
bm25_function = Function(
name="text_bm25",
input_field_names=["text"],
output_field_names=["text_sparse"],
function_type=FunctionType.BM25,
)
index_params = client.prepare_index_params()
index_params.add_index(
field_name="text_sparse",
index_type="SPARSE_INVERTED_INDEX",
metric_type="BM25",
params={
"inverted_index_algo": "DAAT_MAXSCORE",
"bm25_k1": 1.2,
"bm25_b": 0.75,
},
)
client.add_function_field(
collection_name="product_catalog",
field_schema=sparse_field,
func=bm25_function,
index_params=index_params,
)
import io.milvus.common.clientenum.FunctionType;
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
import io.milvus.v2.common.IndexParam;
import io.milvus.v2.service.collection.request.AddFunctionFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
import java.util.Collections;
ConnectConfig connectConfig = ConnectConfig.builder()
.uri("YOUR_CLUSTER_ENDPOINT")
.build();
MilvusClientV2 client = new MilvusClientV2(connectConfig);
// Add a BM25 function, its generated sparse vector field, and the bound index
client.addFunctionField(AddFunctionFieldReq.builder()
.collectionName("product_catalog")
.fieldName("text_sparse")
.dataType(DataType.SparseFloatVector)
.indexParam(IndexParam.builder()
.fieldName("text_sparse")
.indexType(IndexParam.IndexType.SPARSE_INVERTED_INDEX)
.metricType(IndexParam.MetricType.BM25)
.build())
.function(CreateCollectionReq.Function.builder()
.name("text_bm25")
.functionType(FunctionType.BM25)
.inputFieldNames(Collections.singletonList("text"))
.outputFieldNames(Collections.singletonList("text_sparse"))
.build())
.build());
import (
"context"
"log"
"github.com/milvus-io/milvus/client/v3/entity"
"github.com/milvus-io/milvus/client/v3/index"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
ctx := context.Background()
cli, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
Address: "YOUR_CLUSTER_ENDPOINT",
})
if err != nil {
log.Fatal("failed to connect to milvus server: ", err.Error())
}
// Add a BM25 function, its generated sparse vector field, and the bound index
field := entity.NewField().
WithName("text_sparse").
WithDataType(entity.FieldTypeSparseVector)
function := entity.NewFunction().
WithName("text_bm25").
WithType(entity.FunctionTypeBM25).
WithInputFields("text").
WithOutputFields("text_sparse")
boundIndex := index.NewSparseInvertedIndex(entity.BM25, 0.2)
err = cli.AddFunctionField(ctx, milvusclient.NewAddFunctionFieldOption("product_catalog", field, function, boundIndex))
if err != nil {
log.Fatal("failed to add function field: ", err.Error())
}
use milvus::v2::prelude::*;
let config = ConnectConfig::new().uri("YOUR_CLUSTER_ENDPOINT");
let client = ClientV2::new(&config).await?;
// Add a BM25 function, its generated sparse vector field, and the bound index
client
.add_function_field(
AddFunctionFieldRequest::builder()
.collection_name("product_catalog")
.field(
FieldSchema::new()
.name("text_sparse")
.data_type(DataType::SparseFloatVector),
)
.function(
Function::new()
.name("text_bm25")
.function_type(FunctionType::Bm25)
.input_fields(["text"])
.output_fields(["text_sparse"]),
)
.index(
IndexParam::new()
.field_name("text_sparse")
.index_type(IndexType::SparseInvertedIndex)
.metric_type(MetricType::Bm25),
)
.build()?,
)
.await?;
#include <iostream>
#include "milvus/MilvusClientV2.h"
auto client = milvus::MilvusClientV2::Create();
auto status = client->Connect(milvus::ConnectParam("YOUR_CLUSTER_ENDPOINT"));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
// Add a BM25 function, its generated sparse vector field, and the bound index
milvus::FieldSchema sparse_field("text_sparse", milvus::DataType::SPARSE_FLOAT_VECTOR);
milvus::FunctionPtr function = std::make_shared<milvus::Function>("text_bm25", milvus::FunctionType::BM25);
function->AddInputFieldName("text");
function->AddOutputFieldName("text_sparse");
milvus::IndexDesc index("text_sparse", "", milvus::IndexType::SPARSE_INVERTED_INDEX, milvus::MetricType::BM25);
status = client->AddFunctionField(milvus::AddFunctionFieldRequest()
.WithCollectionName("product_catalog")
.WithField(std::move(sparse_field))
.WithFunction(function)
.WithIndex(std::move(index)));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
import { MilvusClient } from "@zilliz/milvus2-sdk-node";
const client = new MilvusClient({ address: "YOUR_CLUSTER_ENDPOINT" });
// Add a BM25 function, its generated sparse vector field, and the bound index
await client.addFunctionField({
collection_name: "product_catalog",
field: {
name: "text_sparse",
data_type: "SparseFloatVector",
},
function: {
name: "text_bm25",
type: "BM25",
input_field_names: ["text"],
output_field_names: ["text_sparse"],
},
extra_params: {
index_type: "SPARSE_INVERTED_INDEX",
metric_type: "BM25",
params: {
inverted_index_algo: "DAAT_MAXSCORE",
bm25_k1: 1.2,
bm25_b: 0.75,
},
},
});
# Note: The REST /v2/vectordb/collections/add_function endpoint maps to the
# deprecated AddCollectionFunction RPC, which Milvus 3.0 rejects. Adding a
# Function together with its generated vector field and bound index is not
# exposed via the REST API as of v3.0.x; use the gRPC SDKs instead.
index_params 对象必须只包含一个针对新 Function 输出字段的索引定义。Function、其生成的向量字段和绑定的索引定义会在同一次 Schema 变更中提交。调用 add_function_field() 后,请勿再单独调用 create_index()。
从概念上看,该操作会添加以下 Function、生成的输出字段和绑定的索引定义:
New Function:
name: "text_bm25"
type: BM25
input_field_names: ["text"]
output_field_names: ["text_sparse"]
New generated output field:
name: "text_sparse"
data_type: SPARSE_FLOAT_VECTOR
nullable: false
Bound index:
field_name: "text_sparse"
index_type: SPARSE_INVERTED_INDEX
metric_type: BM25
请求成功后,describe_collection() 会在 Collection Schema 中同时返回新的 text_bm25 Function 和其生成的 text_sparse 向量字段。完整的 BM25 Search 工作流请参阅全文搜索。
MinHash Function 及其生成的二进制向量字段支持近似重复检测。MinHash Function 使用 FunctionType.MINHASH,并写入新的 BINARY_VECTOR 输出字段。配置详情请参阅 MinHash Function。
从现有 Collection 中删除字段和 Function
当用户自定义字段不再属于 Collection 模型时,可以直接将其删除。若要删除 Function 及其生成的向量字段,请删除该 Function;生成的字段及其索引会在同一次 Schema 变更中一并删除。
删除用户自定义字段
使用 drop_collection_field() 删除不再属于 Collection 模型的用户自定义标量字段或向量字段。
删除字段会先改变 Collection Schema 和字段可见性:
-
在
drop_collection_field()成功后,Collection Schema 会更新:describe_collection()不再返回已删除字段,Query 或 Search 也无法再通过output_fields返回该字段或在表达式中使用该字段。 -
基于已删除字段构建的索引会作为 Schema 更新的一部分被清理。
存储清理与 Schema 清理是分开处理的。详情请参阅删除字段后何时回收存储空间?
示例:删除用户自定义标量字段
以下示例假设 experiment_tag 是 product_catalog 中的用户自定义标量字段,并将其从 Collection 中删除。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
from pymilvus import MilvusClient
client = MilvusClient(uri="YOUR_CLUSTER_ENDPOINT")
client.drop_collection_field(
collection_name="product_catalog",
field_name="experiment_tag",
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.collection.request.DropCollectionFieldReq;
ConnectConfig connectConfig = ConnectConfig.builder()
.uri("YOUR_CLUSTER_ENDPOINT")
.build();
MilvusClientV2 client = new MilvusClientV2(connectConfig);
client.dropCollectionField(DropCollectionFieldReq.builder()
.collectionName("product_catalog")
.fieldName("experiment_tag")
.build());
import (
"context"
"log"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
ctx := context.Background()
cli, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
Address: "YOUR_CLUSTER_ENDPOINT",
})
if err != nil {
log.Fatal("failed to connect to milvus server: ", err.Error())
}
err = cli.DropCollectionField(ctx, milvusclient.NewDropCollectionFieldOption("product_catalog", "experiment_tag"))
if err != nil {
log.Fatal("failed to drop field: ", err.Error())
}
use milvus::v2::prelude::*;
let config = ConnectConfig::new().uri("YOUR_CLUSTER_ENDPOINT");
let client = ClientV2::new(&config).await?;
client
.drop_collection_field(
DropCollectionFieldRequest::builder()
.collection_name("product_catalog")
.field_name("experiment_tag")
.build()?,
)
.await?;
#include <iostream>
#include "milvus/MilvusClientV2.h"
auto client = milvus::MilvusClientV2::Create();
auto status = client->Connect(milvus::ConnectParam("YOUR_CLUSTER_ENDPOINT"));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
status = client->DropCollectionField(milvus::DropCollectionFieldRequest()
.WithCollectionName("product_catalog")
.WithFieldName("experiment_tag"));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
import { MilvusClient } from "@zilliz/milvus2-sdk-node";
const client = new MilvusClient({ address: "YOUR_CLUSTER_ENDPOINT" });
await client.dropCollectionField({
collection_name: "product_catalog",
field_name: "experiment_tag",
});
# Note: The REST API does not expose a drop-field operation as of v3.0.x. Use the gRPC SDKs instead.
删除字段后,可以调用 describe_collection() 验证该字段已不再属于 Schema。
示例:删除 StructArray 字段
以下示例假设 chunks 字段是 my_collection 中的 StructArray 字段,并将其从 Collection 中删除。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
from pymilvus import MilvusClient
client = MilvusClient(uri="YOUR_CLUSTER_ENDPOINT")
client.drop_collection_field(
collection_name="my_collection",
field_name="chunks",
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.collection.request.DropCollectionFieldReq;
ConnectConfig connectConfig = ConnectConfig.builder()
.uri("YOUR_CLUSTER_ENDPOINT")
.build();
MilvusClientV2 client = new MilvusClientV2(connectConfig);
client.dropCollectionField(DropCollectionFieldReq.builder()
.collectionName("my_collection")
.fieldName("chunks")
.build());
import (
"context"
"log"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
ctx := context.Background()
cli, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
Address: "YOUR_CLUSTER_ENDPOINT",
})
if err != nil {
log.Fatal("failed to connect to milvus server: ", err.Error())
}
err = cli.DropCollectionField(ctx, milvusclient.NewDropCollectionFieldOption("my_collection", "chunks"))
if err != nil {
log.Fatal("failed to drop field: ", err.Error())
}
use milvus::v2::prelude::*;
let config = ConnectConfig::new().uri("YOUR_CLUSTER_ENDPOINT");
let client = ClientV2::new(&config).await?;
client
.drop_collection_field(
DropCollectionFieldRequest::builder()
.collection_name("my_collection")
.field_name("chunks")
.build()?,
)
.await?;
#include <iostream>
#include "milvus/MilvusClientV2.h"
auto client = milvus::MilvusClientV2::Create();
auto status = client->Connect(milvus::ConnectParam("YOUR_CLUSTER_ENDPOINT"));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
status = client->DropCollectionField(milvus::DropCollectionFieldRequest()
.WithCollectionName("my_collection")
.WithFieldName("chunks"));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
import { MilvusClient } from "@zilliz/milvus2-sdk-node";
const client = new MilvusClient({ address: "YOUR_CLUSTER_ENDPOINT" });
await client.dropCollectionField({
collection_name: "my_collection",
field_name: "chunks",
});
# Note: The REST API does not expose a drop-field operation as of v3.0.x. Use the gRPC SDKs instead.
示例:删除用户自定义向量字段
可以使用相同的 drop_collection_field() 方法删除向量字段,但删除后 Collection 中必须仍保留至少一个向量字段。对于暂时包含多种向量表示、之后再统一为其中一种表示的 Collection,此操作非常有用。
以下示例假设 image_vector 是 hybrid_catalog 中的用户自定义向量字段,并且该 Collection 仍保留另一个向量字段,例如 text_vector。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
from pymilvus import MilvusClient
client = MilvusClient(uri="YOUR_CLUSTER_ENDPOINT")
client.drop_collection_field(
collection_name="hybrid_catalog",
field_name="image_vector",
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.collection.request.DropCollectionFieldReq;
ConnectConfig connectConfig = ConnectConfig.builder()
.uri("YOUR_CLUSTER_ENDPOINT")
.build();
MilvusClientV2 client = new MilvusClientV2(connectConfig);
client.dropCollectionField(DropCollectionFieldReq.builder()
.collectionName("hybrid_catalog")
.fieldName("image_vector")
.build());
import (
"context"
"log"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
ctx := context.Background()
cli, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
Address: "YOUR_CLUSTER_ENDPOINT",
})
if err != nil {
log.Fatal("failed to connect to milvus server: ", err.Error())
}
err = cli.DropCollectionField(ctx, milvusclient.NewDropCollectionFieldOption("hybrid_catalog", "image_vector"))
if err != nil {
log.Fatal("failed to drop field: ", err.Error())
}
use milvus::v2::prelude::*;
let config = ConnectConfig::new().uri("YOUR_CLUSTER_ENDPOINT");
let client = ClientV2::new(&config).await?;
client
.drop_collection_field(
DropCollectionFieldRequest::builder()
.collection_name("hybrid_catalog")
.field_name("image_vector")
.build()?,
)
.await?;
#include <iostream>
#include "milvus/MilvusClientV2.h"
auto client = milvus::MilvusClientV2::Create();
auto status = client->Connect(milvus::ConnectParam("YOUR_CLUSTER_ENDPOINT"));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
status = client->DropCollectionField(milvus::DropCollectionFieldRequest()
.WithCollectionName("hybrid_catalog")
.WithFieldName("image_vector"));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
import { MilvusClient } from "@zilliz/milvus2-sdk-node";
const client = new MilvusClient({ address: "YOUR_CLUSTER_ENDPOINT" });
await client.dropCollectionField({
collection_name: "hybrid_catalog",
field_name: "image_vector",
});
# Note: The REST API does not expose a drop-field operation as of v3.0.x. Use the gRPC SDKs instead.
如果 image_vector 是 Collection 中的最后一个向量字段,删除操作会被拒绝。
删除 Function 及其生成的向量字段
当不再需要某个 Function 或其生成的向量字段时,请使用此操作,例如删除 BM25 Function 及其生成的稀疏向量字段。
使用 Function 名称调用 drop_function_field()。该操作会删除 Function、其生成的向量字段和关联索引,同时保留 Function 的输入字段。
示例:删除 BM25 Function 及其生成的稀疏向量字段
以下示例假设 text_bm25 是 product_catalog 中的 BM25 Function,并生成名为 text_sparse 的稀疏向量输出字段。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
from pymilvus import MilvusClient
client = MilvusClient(uri="YOUR_CLUSTER_ENDPOINT")
client.drop_function_field(
collection_name="product_catalog",
function_name="text_bm25",
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.collection.request.DropFunctionFieldReq;
ConnectConfig connectConfig = ConnectConfig.builder()
.uri("YOUR_CLUSTER_ENDPOINT")
.build();
MilvusClientV2 client = new MilvusClientV2(connectConfig);
client.dropFunctionField(DropFunctionFieldReq.builder()
.collectionName("product_catalog")
.functionName("text_bm25")
.build());
import (
"context"
"log"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
ctx := context.Background()
cli, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
Address: "YOUR_CLUSTER_ENDPOINT",
})
if err != nil {
log.Fatal("failed to connect to milvus server: ", err.Error())
}
err = cli.DropFunctionField(ctx, milvusclient.NewDropFunctionFieldOption("product_catalog", "text_bm25"))
if err != nil {
log.Fatal("failed to drop function field: ", err.Error())
}
use milvus::v2::prelude::*;
let config = ConnectConfig::new().uri("YOUR_CLUSTER_ENDPOINT");
let client = ClientV2::new(&config).await?;
client
.drop_function_field(
DropFunctionFieldRequest::builder()
.collection_name("product_catalog")
.function_name("text_bm25")
.build()?,
)
.await?;
#include <iostream>
#include "milvus/MilvusClientV2.h"
auto client = milvus::MilvusClientV2::Create();
auto status = client->Connect(milvus::ConnectParam("YOUR_CLUSTER_ENDPOINT"));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
status = client->DropFunctionField(milvus::DropFunctionFieldRequest()
.WithCollectionName("product_catalog")
.WithFunctionName("text_bm25"));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
import { MilvusClient } from "@zilliz/milvus2-sdk-node";
const client = new MilvusClient({ address: "YOUR_CLUSTER_ENDPOINT" });
await client.dropFunctionField({
collection_name: "product_catalog",
function_name: "text_bm25",
});
# Note: The REST /v2/vectordb/collections/drop_function endpoint maps to the
# deprecated DropCollectionFunction RPC, which Milvus 3.0 rejects. Dropping a
# Function together with its generated vector field is not exposed via the
# REST API as of v3.0.x; use the gRPC SDKs instead.
操作成功后,describe_collection() 不再返回已删除的 Function 或其生成的向量字段。Function 的输入字段仍保留在 Schema 中。
如果删除 Function 输出字段会导致 Collection 中不再包含任何向量字段,则该操作会被拒绝。
常见问题
应该使用哪种方法添加字段或 Function?
当应用提供用于过滤、查询输出或应用逻辑的标量值时,使用 add_collection_field() 添加用户自定义标量字段。
当应用生成 Embedding,并将向量值写入 Zilliz Cloud 时,使用 add_collection_field() 添加用户自定义向量字段。
当需要根据现有字段生成向量值时,使用 add_function_field()。该方法会在同一次 Schema 变更中添加 Function、其生成的向量字段和绑定的索引定义。本指南展示用于词法搜索的 BM25 路径;MinHash Function 则生成用于近似重复检测的二进制向量字段。
为什么新增的用户自定义字段必须可为空?
现有 Entity 是在新字段存在之前插入的,因此没有该字段的值。设置 nullable=True 后,在应用写入值之前,或者对于标量字段,在默认值生效之前,Zilliz Cloud 可以使用 NULL 表示缺失值。
此规则适用于通过 add_collection_field() 添加的用户自定义标量字段和用户自定义向量字段,但不适用于 Function 生成的向量字段,因为该字段不能可为空。
添加用户自定义字段后,现有 Entity 会发生什么变化?
对于用户自定义标量字段,除非设置 default_value,否则现有 Entity 返回 NULL。如果设置了 default_value,现有 Entity 会返回该默认值。
对于用户自定义向量字段,现有 Entity 的新向量字段值为 NULL。在新增字段上执行向量搜索时,会跳过向量值为 NULL 的 Entity。若要让现有 Entity 可通过新向量字段搜索,请通过 Upsert 或回填工作流写入非 NULL 向量值。新 Entity 可以在 Insert 时包含该向量字段。
可以向现有 Collection 添加 BM25 Function 及其生成的稀疏向量字段吗?
可以。如果 Collection 已经包含启用了 Analyzer 的 VARCHAR 字段,则可以添加 BM25 Function 及其生成的稀疏向量字段,用于词法搜索。该操作会在同一次 Schema 变更中添加 Function、新的 SPARSE_FLOAT_VECTOR 输出字段和绑定的索引定义。在此 Schema 变更工作流中,不能使用现有 TEXT 字段作为 BM25 输入。若要使用 TEXT,请在创建 Collection 时定义该字段和 BM25 Function;否则,请重新创建或迁移 Collection,并在其 Schema 中包含该 Function。
调用 add_function_field() 时,请提供一个 index_params 对象,其中针对新的输出字段包含一个指标类型为 metric_type="BM25" 的 SPARSE_INVERTED_INDEX 索引。该索引定义会作为同一次 Schema 变更的一部分绑定到生成字段。
如何删除 Function 及其生成的向量字段?
使用 Function 名称调用 drop_function_field()。该操作会一并删除 Function、其生成的向量字段和关联索引,同时保留 Function 的输入字段。
修改 Collection Schema 后需要等待吗?
通常无需手动等待。如果后续操作依赖更新后的 Schema,可以先调用 describe_collection(),确认 Zilliz Cloud 当前返回的 Schema。
在分布式部署中,Zilliz Cloud 各组件刷新 Collection Metadata 时,可能存在短暂的传播窗口。如果 Schema 变更后的操作立即因 Schema 相关错误而失败,请刷新 Schema 并重试该操作。
删除字段后何时回收存储空间?
删除字段会将其从当前 Schema 以及常规 Query/Search 的可见范围中移除,但对象存储中该字段的历史数据不会立即被物理删除。
之后可通过 Compaction 回收存储空间。Compaction 是一种后台过程,用于将现有数据文件重新组织为更紧凑的新文件。字段删除后,新生成的 Compaction 文件会遵循当前 Schema,并省略已删除字段。Zilliz Cloud 不保证删除字段后会立即回收存储空间,也不保证在固定时间内减少存储占用。
如果添加与动态字段键同名的标量字段,会发生什么?
如果启用了动态字段,可以添加与现有动态字段键同名的标量字段。在常规 Query 输出中,新标量字段会遮蔽该动态字段键,但原始动态数据仍保留在 $meta 中。
例如,如果现有 Entity 存储了名为 source 的动态键,之后又添加了名为 source 的标量字段,则常规输出中的 source 指向该标量字段。若要访问原始动态值,请使用 $meta["source"] 等 $meta 路径语法。