既存コレクションへのフィールド追加
Milvusでは、既存のコレクションに新しいフィールドを動的に追加でき、アプリケーションのニーズに応じてデータスキーマを容易に変更できます。このガイドでは、実際の例を使用してさまざまなシナリオでフィールドを追加する方法を示します。
考慮事項
コレクションにフィールドを追加する前に、以下の重要な点を考慮してください。
-
スカラー型フィールド(
INT64、VARCHAR、FLOAT、DOUBLEなど)を追加できます。ベクトル型フィールドは既存のコレクションに追加することはできません。 -
新しいフィールドには、新しいフィールドの値を持たない既存のエンティティに対応できるように、nullable(nullable=True)にする必要があります。
-
ロード済みコレクションにフィールドを追加すると、メモリ使用量が増加します。
-
コレクションあたりのフィールド総数には最大制限があります。詳細はMilvusの制限事項を参照してください。
-
フィールド名は静的フィールド間で一意である必要があります。
-
元々
enable_dynamic_field=Trueで作成されていないコレクションに対して、動的フィールド機能を有効にするために#metaフィールドを追加することはできません。
前提条件
このガイドでは、以下があることを前提としています。
-
実行中のMilvusインスタンス
-
インストール済みのMilvus SDK
-
既存のコレクション
コレクション作成と基本操作については、コレクションの管理を参照してください。
基本的な使用方法
- Python
- Java
- NodeJS
- Go
- cURL
from pymilvus import MilvusClient, DataType
# Milvusサーバーに接続
client = MilvusClient(
uri="YOUR_CLUSTER_ENDPOINT" # お使いのMilvusサーバーURIに置き換えてください
)
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.client.ConnectConfig;
ConnectConfig config = ConnectConfig.builder()
.uri("YOUR_CLUSTER_ENDPOINT")
.build();
MilvusClientV2 client = new MilvusClientV2(config);
import { MilvusClient } from '@zilliz/milvus2-sdk-node';
const milvusClient = new MilvusClient({
address: 'YOUR_CLUSTER_ENDPOINT'
});
// go
# restful
export CLUSTER_ENDPOINT="YOUR_CLUSTER_ENDPOINT"
シナリオ1: null許容フィールドを迅速に追加する
コレクションを拡張する最も簡単な方法は、null許容フィールドを追加することです。これは、データに新しい属性を迅速に追加する必要がある場合に最適です。
- Python
- Java
- NodeJS
- Go
- cURL
# 既存コレクションにnull許容フィールドを追加
# この操作:
# - 即座に完了する(非同期)
# - 最小限の遅延でフィールドを利用可能にする
# - 既存のエンティティにはNULLを設定
client.add_collection_field(
collection_name="product_catalog",
field_name="created_timestamp", # 追加する新しいフィールドの名前
data_type=DataType.INT64, # データ型はスカラー型でなければならない
nullable=True # 追加されたフィールドではTrueでなければならない
# 既存エンティティにNULL値を許可
)
import io.milvus.v2.service.collection.request.AddCollectionFieldReq;
client.addCollectionField(AddCollectionFieldReq.builder()
.collectionName("product_catalog")
.fieldName("created_timestamp")
.dataType(DataType.Int64)
.isNullable(true)
.build());
await client.addCollectionField({
collection_name: 'product_catalog',
field: {
name: 'created_timestamp',
dataType: 'Int64',
nullable: true
}
});
// go
# restful
curl -X POST "YOUR_CLUSTER_ENDPOINT/v2/vectordb/collections/fields/add" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"collectionName": "product_catalog",
"schema": {
"fieldName": "created_timestamp",
"dataType": "Int64",
"nullable": true
}
}'
期待される動作:
-
既存エンティティには新しいフィールドにNULLが設定されます
-
新規エンティティにはNULLまたは実際の値を設定できます
-
フィールド利用可能には内部スキーマ同期による最小限の遅延で可能になります
-
クエリ可能には短い同期期間の後で即座に可能になります
- Python
- Java
- NodeJS
- Go
- cURL
# クエリ結果の例
{
'id': 1,
'created_timestamp': None # 既存エンティティでは新しいフィールドにNULLが表示されます
}
// java
// nodejs
{
'id': 1,
'created_timestamp': None # 既存エンティティでは新しいフィールドにNULLが表示されます
}
// go
# restful
{
"code": 0,
"data": {},
"cost": 0
}
シナリオ2: デフォルト値付きフィールドを追加する
既存のエンティティにNULLの代わりに意味のある初期値を持たせたい場合は、デフォルト値を指定してください。
- Python
- Java
- NodeJS
- Go
- cURL
# デフォルト値付きフィールドを追加
# この操作:
# - 既存エンティティにデフォルト値を設定
# - 最小限の遅延でフィールドを利用可能にする
# - デフォルト値によるデータの整合性を維持
client.add_collection_field(
collection_name="product_catalog",
field_name="priority_level", # 新しいフィールドの名前
data_type=DataType.VARCHAR, # 文字列型フィールド
max_length=20, # 最大文字列長
nullable=True, # 追加フィールドではTrueが必要
default_value="standard" # 既存エンティティに割り当てられる値
# 値が提供されない場合に新規エンティティにも使用
)
client.addCollectionField(AddCollectionFieldReq.builder()
.collectionName("product_catalog")
.fieldName("priority_level")
.dataType(DataType.VarChar)
.maxLength(20)
.isNullable(true)
.build());
await client.addCollectionField({
collection_name: 'product_catalog',
field: {
name: 'priority_level',
dataType: 'VarChar',
nullable: true,
default_value: 'standard',
}
});
// go
# restful
curl -X POST "YOUR_CLUSTER_ENDPOINT/v2/vectordb/collections/fields/add" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"collectionName": "product_catalog",
"schema": {
"fieldName": "priority_level",
"dataType": "VarChar",
"nullable": true,
"defaultValue": "standard",
"elementTypeParams": {
"max_length": "20"
}
}
}'
期待される動作:
-
既存エンティティには新しく追加されたフィールドにデフォルト値(
"standard")が設定されます -
新規エンティティにはデフォルト値を上書きするか、値が提供されない場合は利用できます
-
フィールド利用可能には内部スキーマ同期による最小限の遅延で可能になります
-
クエリ可能には短い同期期間の後で即座に可能になります
- Python
- Java
- NodeJS
- Go
- cURL
# クエリ結果の例
{
'id': 1,
'priority_level': 'standard' # 既存エンティティではデフォルト値が表示されます
}
// java
{
'id': 1,
'priority_level': 'standard' # 既存エンティティではデフォルト値が表示されます
}
// go
# restful
{
'id': 1,
'priority_level': 'standard' # 既存エンティティではデフォルト値が表示されます
}
FAQ
#meta フィールドを追加して動的スキーマ機能を有効にできますか?
いいえ、add_collection_field を使用して #meta フィールドを追加し、動的フィールド機能を有効にすることはできません。たとえば、以下のコードは機能しません。
- Python
- Java
- NodeJS
- Go
- cURL
# ❌ これはサポートされていません
client.add_collection_field(
collection_name="existing_collection",
field_name="$meta",
data_type=DataType.JSON # この操作は失敗します
)
// ❌ これはサポートされていません
client.addCollectionField(AddCollectionFieldReq.builder()
.collectionName("existing_collection")
.fieldName("$meta")
.dataType(DataType.JSON)
.build());
// ❌ これはサポートされていません
await client.addCollectionField({
collection_name: 'product_catalog',
field: {
name: '$meta',
dataType: 'JSON',
}
});
// go
# restful
# ❌ これはサポートされていません
curl -X POST "YOUR_CLUSTER_ENDPOINT/v2/vectordb/collections/fields/add" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"collectionName": "existing_collection",
"schema": {
"fieldName": "$meta",
"dataType": "JSON",
"nullable": true
}
}'
動的スキーマ機能を有効にするには:
-
新規コレクション:コレクション作成時に
enable_dynamic_fieldを True に設定してください。詳細はコレクション作成を参照してください。 -
既存コレクション:コレクションレベルのプロパティ
dynamicfield.enabledを True に設定してください。詳細はコレクションの変更を参照してください。
動的フィールドキーと同じ名前のフィールドを追加するとどうなりますか?
コレクションで動的フィールドが有効になっている(#meta が存在する)場合、既存の動的フィールドキーと同じ名前の静的フィールドを追加できます。新しい静的フィールドは動的フィールドキーをマスクしますが、元の動的データは保持されます。
フィールド名の競合を避けるために、実際に追加する前に既存のフィールドや動的フィールドキーを参照してフィールド名を検討してください。
例のシナリオ:
- Python
- Java
- NodeJS
- Go
- cURL
# 動的フィールドが有効な元のコレクション
# 動的フィールドキーでデータを挿入
data = [{
"id": 1,
"my_vector": [0.1, 0.2, ...],
"extra_info": "これは動的フィールドキーです", # 文字列としての動的フィールドキー
"score": 99.5 # 他の動的フィールドキー
}]
client.insert(collection_name="product_catalog", data=data)
# 既存動的フィールドキーと同じ名前の静的フィールドを追加
client.add_collection_field(
collection_name="product_catalog",
field_name="extra_info", # 動的フィールドキーと同じ名前
data_type=DataType.INT64, # データ型は動的フィールドキーとは異なってもよい
nullable=True # 追加フィールドではTrueにする必要があります
)
# 静的フィールド追加後の新規データを挿入
new_data = [{
"id": 2,
"my_vector": [0.3, 0.4, ...],
"extra_info": 100, # 今度はINT64型で使用(静的フィールド)
"score": 88.0 # まだ動的フィールドキー
}]
client.insert(collection_name="product_catalog", data=new_data)
import com.google.gson.*;
import io.milvus.v2.service.vector.request.InsertReq;
import io.milvus.v2.service.vector.response.InsertResp;
Gson gson = new Gson();
JsonObject row = new JsonObject();
row.addProperty("id", 1);
row.add("my_vector", gson.toJsonTree(new float[]{0.1f, 0.2f, ...}));
row.addProperty("extra_info", "これは動的フィールドキーです");
row.addProperty("score", 99.5);
InsertResp insertR = client.insert(InsertReq.builder()
.collectionName("product_catalog")
.data(Collections.singletonList(row))
.build());
client.addCollectionField(AddCollectionFieldReq.builder()
.collectionName("product_catalog")
.fieldName("extra_info")
.dataType(DataType.Int64)
.isNullable(true)
.build());
JsonObject newRow = new JsonObject();
newRow.addProperty("id", 2);
newRow.add("my_vector", gson.toJsonTree(new float[]{0.3f, 0.4f, ...}));
newRow.addProperty("extra_info", 100);
newRow.addProperty("score", 88.0);
insertR = client.insert(InsertReq.builder()
.collectionName("product_catalog")
.data(Collections.singletonList(newRow))
.build());
// 動的フィールドが有効な元のコレクション
// 動的フィールドキーでデータを挿入
const data = [{
"id": 1,
"my_vector": [0.1, 0.2, ...],
"extra_info": "これは動的フィールドキーです", // 文字列としての動的フィールドキー
"score": 99.5 // 他の動的フィールドキー
}]
await client.insert({
collection_name: "product_catalog",
data: data
});
// 既存動的フィールドキーと同じ名前の静的フィールドを追加
await client.add_collection_field({
collection_name: "product_catalog",
field_name: "extra_info", // 動的フィールドキーと同じ名前
data_type: DataType.INT64, // データ型は動的フィールドキーとは異なってもよい
nullable: true // 追加フィールドではTrueにする必要があります
});
// 静的フィールド追加後の新規データを挿入
const new_data = [{
"id": 2,
"my_vector": [0.3, 0.4, ...],
"extra_info": 100, # 今度はINT64型で使用(静的フィールド)
"score": 88.0 # まだ動的フィールドキー
}];
await client.insert({
collection_name:"product_catalog",
data: new_data
});
// go
# restful
#!/bin/bash
export MILVUS_HOST="YOUR_CLUSTER_ENDPOINT"
export AUTH_TOKEN="your_token_here"
export COLLECTION_NAME="product_catalog"
echo "ステップ1: 動的フィールドを持つ初期データを挿入..."
curl -X POST "http://${MILVUS_HOST}/v2/vectordb/entities/insert" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${AUTH_TOKEN}" \
-d "{
\"collectionName\": \"${COLLECTION_NAME}\",
\"data\": [{
\"id\": 1,
\"my_vector\": [0.1, 0.2, 0.3, 0.4, 0.5],
\"extra_info\": \"これは動的フィールドキーです\",
\"score\": 99.5
}]
}"
echo -e "\n\nステップ2: 動的フィールドと同じ名前の静的フィールドを追加..."
curl -X POST "http://${MILVUS_HOST}/v2/vectordb/collections/fields/add" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${AUTH_TOKEN}" \
-d "{
\"collectionName\": \"${COLLECTION_NAME}\",
\"schema\": {
\"fieldName\": \"extra_info\",
\"dataType\": \"Int64\",
\"nullable\": true
}
}"
echo -e "\n\nステップ3: 静的フィールド追加後の新規データを挿入..."
curl -X POST "http://${MILVUS_HOST}/v2/vectordb/entities/insert" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${AUTH_TOKEN}" \
-d "{
\"collectionName\": \"${COLLECTION_NAME}\",
\"data\": [{
\"id\": 2,
\"my_vector\": [0.3, 0.4, 0.5, 0.6, 0.7],
\"extra_info\": 100,
\"score\": 88.0
}]
}"
期待される動作:
-
既存エンティティには新しい静的フィールド
extra_infoにNULLが設定されます -
新規エンティティは静的フィールドのデータ型(
INT64)を使用する必要があります -
元の動的フィールドキー値は保持され、
#meta構文でアクセス可能です -
静的フィールドは通常のクエリで動的フィールドキーをマスクします
静的値と動的値の両方へのアクセス:
- Python
- Java
- NodeJS
- Go
- cURL
# 1. 静的フィールドのみをクエリ(動的フィールドキーはマスクされます)
results = client.query(
collection_name="product_catalog",
filter="id == 1",
output_fields=["extra_info"]
)
# 返り値: {"id": 1, "extra_info": None} # 既存エンティティではNULL
# 2. 静的および元の動的値の両方をクエリ
results = client.query(
collection_name="product_catalog",
filter="id == 1",
output_fields=["extra_info", "$meta['extra_info']"]
)
# 返り値: {
# "id": 1,
# "extra_info": None, # 静的フィールド値(NULL)
# "$meta['extra_info']": "これは動的フィールドキーです" # 元の動的値
# }
# 3. 静的フィールド値を持つ新規エンティティをクエリ
results = client.query(
collection_name="product_catalog",
filter="id == 2",
output_fields=["extra_info"]
)
# 返り値: {"id": 2, "extra_info": 100} # 静的フィールド値
// java
// 1. 静的フィールドのみをクエリ(動的フィールドキーはマスクされます)
let results = client.query({
collection_name: "product_catalog",
filter: "id == 1",
output_fields: ["extra_info"]
})
# 返り値: {"id": 1, "extra_info": None} # 既存エンティティではNULL
// 2. 静的および元の動的値の両方をクエリ
results = client.query({
collection_name:"product_catalog",
filter: "id == 1",
output_fields: ["extra_info", "$meta['extra_info']"]
});
# 返り値: {
# "id": 1,
# "extra_info": None, # 静的フィールド値(NULL)
# "$meta['extra_info']": "これは動的フィールドキーです" # 元の動的値
# }
// 3. 静的フィールド値を持つ新規エンティティをクエリ
results = client.query({
collection_name: "product_catalog",
filter: "id == 2",
output_fields: ["extra_info"]
})
# 返り値: {"id": 2, "extra_info": 100} # 静的フィールド値
// go
# restful
#!/bin/bash
export MILVUS_HOST="YOUR_CLUSTER_ENDPOINT"
export AUTH_TOKEN="your_token_here"
export COLLECTION_NAME="product_catalog"
echo "クエリ1: 静的フィールドのみ(動的フィールドはマスク済み)..."
curl -X POST "http://${MILVUS_HOST}/v2/vectordb/entities/query" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${AUTH_TOKEN}" \
-d "{
\"collectionName\": \"${COLLECTION_NAME}\",
\"filter\": \"id == 1\",
\"outputFields\": [\"extra_info\"]
}"
echo -e "\n\nクエリ2: 静的および元の動的値の両方..."
curl -X POST "http://${MILVUS_HOST}/v2/vectordb/entities/query" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${AUTH_TOKEN}" \
-d "{
\"collectionName\": \"${COLLECTION_NAME}\",
\"filter\": \"id == 1\",
\"outputFields\": [\"extra_info\", \"\$meta['extra_info']\"]
}"
echo -e "\n\nクエリ3: 静的フィールド値を持つ新規エンティティ..."
curl -X POST "http://${MILVUS_HOST}/v2/vectordb/entities/query" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${AUTH_TOKEN}" \
-d "{
\"collectionName\": \"${COLLECTION_NAME}\",
\"filter\": \"id == 2\",
\"outputFields\": [\"extra_info\"]
}"
新しいフィールドが利用可能になるまでどれくらいかかりますか?
追加されたフィールドは即座に利用可能になりますが、Milvusクラスター全体でスキーマ変更をブロードキャストする内部処理のため、短い遅延が発生する場合があります。この同期処理により、新しいフィールドを含むクエリを処理する前にすべてのノードがスキーマの更新を認識していることを保証します。