Milvus
Zilliz
フロントページへ
  • ユーザーガイド
  • Home
  • Docs
  • ユーザーガイド

  • スキーマとデータフィールド

  • ダイナミック・フィールド

ダイナミックフィールド

Milvusでは、ダイナミックフィールドと呼ばれる特別な機能により、柔軟で進化する構造を持つエンティティを挿入することができます。このフィールドは、$meta という名前の隠しJSONフィールドとして実装されており、コレクションスキーマで明示的に定義されていないフィールドがデータ内に自動的に格納されます。

どのように機能するか

ダイナミックフィールドを有効にすると、milvusは各エンティティに$meta の隠しフィールドを追加します。このフィールドはJSON型で、JSON互換のデータ構造を格納でき、JSONパス構文を使用してインデックスを作成できます。

データ挿入の際、スキーマで宣言されていないフィールドは、自動的にこのダイナミック・フィールド内にキーと値のペアとして格納されます。

milvusは透過的に処理するため、$meta を手動で管理する必要はありません。

たとえば、コレクションスキーマでidvector のみを定義し、以下のエンティティを挿入する場合:

{
  "id": 1,
  "vector": [0.1, 0.2, 0.3],
  "name": "Item A",    // Not in schema
  "category": "books"  // Not in schema
}

動的フィールド機能を有効にすると、Milvusはこれを内部的に次のように保存します:

{
  "id": 1,
  "vector": [0.1, 0.2, 0.3],
  "$meta": {
    "name": "Item A",
    "category": "books"
  }
}

これにより、スキーマを変更することなくデータ構造を進化させることができます。

一般的な使用例は以下の通りです:

  • オプションまたは取得頻度の低いフィールドの保存

  • エンティティによって異なるメタデータの取得

  • 特定の動的フィールド・キーのインデックスによる柔軟なフィルタリングのサポート

サポートされるデータ型

ダイナミックフィールドはMilvusが提供するすべてのスカラーデータ型をサポートします。これらのデータ型は$meta に格納されたキーの **値に適用されます。

サポートされるデータ型は以下の通りです:

  • 文字列 (VARCHAR)

  • 整数 (INT8,INT32,INT64)

  • 浮動小数点 (FLOAT,DOUBLE)

  • ブール値 (BOOL)

  • スカラー値の配列 (ARRAY)

  • JSONオブジェクト (JSON)

{
  "brand": "Acme",
  "price": 29.99,
  "in_stock": true,
  "tags": ["new", "hot"],
  "specs": {
    "weight": "1.2kg",
    "dimensions": { "width": 10, "height": 20 }
  }
}

上記の各キーと値は、$meta フィールド内に格納されます。

ダイナミック・フィールドを有効にする

ダイナミック・フィールド機能を使用するには、コレクション・スキーマの作成時にenable_dynamic_field=True を設定します:

from pymilvus import MilvusClient, DataType

# Initialize client
client = MilvusClient(uri="http://localhost:19530")

# Create schema with dynamic field enabled
schema = client.create_schema(
    auto_id=False,
    enable_dynamic_field=True,
)

# Add explicitly defined fields
schema.add_field(field_name="my_id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="my_vector", datatype=DataType.FLOAT_VECTOR, dim=5)

# Create the collection
client.create_collection(
    collection_name="my_collection",
    schema=schema
)
import io.milvus.v2.client.*;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
import io.milvus.v2.service.collection.request.AddFieldReq;

ConnectConfig config = ConnectConfig.builder()
        .uri("http://localhost:19530")
        .build();
MilvusClientV2 client = new MilvusClientV2(config);

CreateCollectionReq.CollectionSchema schema = CreateCollectionReq.CollectionSchema.builder()
        .enableDynamicField(true)
        .build();
schema.addField(AddFieldReq.builder()
        .fieldName("my_id")
        .dataType(DataType.Int64)
        .isPrimaryKey(Boolean.TRUE)
        .build());
schema.addField(AddFieldReq.builder()
        .fieldName("my_vector")
        .dataType(DataType.FloatVector)
        .dimension(5)
        .build());

CreateCollectionReq requestCreate = CreateCollectionReq.builder()
        .collectionName("my_collection")
        .collectionSchema(schema)
        .build();
client.createCollection(requestCreate);
import { MilvusClient, DataType, CreateCollectionReq } from '@zilliz/milvus2-sdk-node';

// Initialize client
const client = new MilvusClient({ address: 'localhost:19530' });

// Create collection
const res = await client.createCollection({
  collection_name: 'my_collection',
  schema:  [
      {
        name: 'my_id',
        data_type: DataType.Int64,
        is_primary_key: true,
        autoID: false,
      },
      {
        name: 'my_vector',
        data_type: DataType.FloatVector,
        type_params: {
          dim: '5',
      }
   ],
   enable_dynamic_field: true
});

import (
    "context"

    "github.com/milvus-io/milvus/client/v2/entity"
    "github.com/milvus-io/milvus/client/v2/milvusclient"
)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

client, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
    Address: "localhost:19530",
})
if err != nil {
    return err
}

schema := entity.NewSchema().WithDynamicFieldEnabled(true)
schema.WithField(entity.NewField().
    WithName("my_id").pk
    WithDataType(entity.FieldTypeInt64).
    WithIsPrimaryKey(true),
).WithField(entity.NewField().
    WithName("my_vector").
    WithDataType(entity.FieldTypeFloatVector).
    WithDim(5),
)

err = client.CreateCollection(ctx, milvusclient.NewCreateCollectionOption("my_collection", schema))
if err != nil {
    return err
}
# restful
export TOKEN="root:Milvus"
export CLUSTER_ENDPOINT="http://localhost:19530"

export myIdField='{
  "fieldName": "my_id",
  "dataType": "Int64",
  "isPrimary": true,
  "autoID": false
}'

export myVectorField='{
  "fieldName": "my_vector",
  "dataType": "FloatVector",
  "elementTypeParams": {
    "dim": 5
  }
}'

export schema="{
  \"autoID\": false,
  \"enableDynamicField\": true,
  \"fields\": [
    $myIdField,
    $myVectorField
  ]
}"

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--data "{
  \"collectionName\": \"my_collection\",
  \"schema\": $schema
}"

コレクションへのエンティティの挿入

動的フィールドを使用すると、スキーマで定義されていない追加フィールドを挿入できます。これらのフィールドは$meta に自動的に格納されます。

entities = [
    {
        "my_id": 1, # Explicitly defined primary field
        "my_vector": [0.1, 0.2, 0.3, 0.4, 0.5], # Explicitly defined vector field
        "overview": "Great product",       # Scalar key not defined in schema
        "words": 150,                      # Scalar key not defined in schema
        "dynamic_json": {                  # JSON key not defined in schema
            "varchar": "some text",
            "nested": {
                "value": 42.5
            },
            "string_price": "99.99"        # Number stored as string
        }
    }
]

client.insert(collection_name="my_collection", data=entities)
import com.google.gson.Gson;
import com.google.gson.JsonObject;

import io.milvus.v2.service.vector.request.InsertReq;

Gson gson = new Gson();
JsonObject row = new JsonObject();
row.addProperty("my_id", 1);
row.add("my_vector", gson.toJsonTree(Arrays.asList(0.1, 0.2, 0.3, 0.4, 0.5)));
row.addProperty("overview", "Great product");
row.addProperty("words", 150);

JsonObject dynamic = new JsonObject();
dynamic.addProperty("varchar", "some text");
dynamic.addProperty("string_price", "99.99");

JsonObject nested = new JsonObject();
nested.addProperty("value", 42.5);

dynamic.add("nested", nested);
row.add("dynamic_json", dynamic);

client.insert(InsertReq.builder()
        .collectionName("my_collection")
        .data(Collections.singletonList(row))
        .build());

const entities = [
  {
    my_id: 1,
    my_vector: [0.1, 0.2, 0.3, 0.4, 0.5],
    overview: 'Great product',
    words: 150,
    dynamic_json: {
      varchar: 'some text',
      nested: {
        value: 42.5,
      },
      string_price: '99.99',
    },
  },
];
const res = await client.insert({
    collection_name: 'my_collection',
    data: entities,
});
_, err = client.Insert(ctx, milvusclient.NewColumnBasedInsertOption("my_collection").
    WithInt64Column("my_id", []int64{1}).
    WithFloatVectorColumn("my_vector", 5, [][]float32{
        {0.1, 0.2, 0.3, 0.4, 0.5},
    }).WithColumns(
    column.NewColumnVarChar("overview", []string{"Great product"}),
    column.NewColumnInt32("words", []int32{150}),
    column.NewColumnJSONBytes("dynamic_json", [][]byte{
        []byte(`{
            varchar: 'some text',
            nested: {
                value: 42.5,
            },
            string_price: '99.99',
        }`),
    }),
))
if err != nil {
    return err
}
# restful
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--data '{
  "data": [
    {
      "my_id": 1,
      "my_vector": [0.1, 0.2, 0.3, 0.4, 0.5],
      "overview": "Great product",
      "words": 150,
      "dynamic_json": {
        "varchar": "some text",
        "nested": {
          "value": 42.5
        },
        "string_price": "99.99"
      }
    }
  ],
  "collectionName": "my_collection"
}'

ダイナミックフィールドのインデックスキーCompatible with Milvus 2.5.11+

Milvusでは、JSONパスインデックスを使用して、ダイナミックフィールド内の特定のキーにインデックスを作成することができます。これらはスカラー値でも、JSONオブジェクトのネストされた値でもかまいません。

ダイナミック・フィールド・キーのインデックスはオプションです。インデックスがなくても動的フィールドのキーによるクエリやフィルタリングは可能ですが、ブルートフォース検索によりパフォーマンスが低下する可能性があります。

JSON パスインデックスの構文

JSONパス・インデックスを作成するには、次のように指定します:

  • JSONパス(json_path):インデックスを作成したいJSONオブジェクト内のキーまたはネストされたフィールドへのパス。

    • metadata["category"]

      これは、インデックス作成エンジンがJSON構造内のどこを探すかを定義します。

  • JSONキャストタイプ(json_cast_type):Milvusが指定されたパスの値を解釈し、インデックスを作成する際に使用するデータ型です。

    • この型は、インデックスされるフィールドの実際のデータ型と一致しなければなりません。

    • 完全なリストについては、サポートされるJSONキャスト型を参照してください。

JSON パスを使用してダイナミック・フィールド・キーのインデックスを作成する

ダイナミック・フィールドはJSONフィールドなので、JSONパス構文を使用して、その中の任意のキーにインデックスを付けることができます。これは、単純なスカラー値と複雑な入れ子構造の両方で機能します。

JSONパスの例

  • 単純なキーの場合:overview,words

  • 入れ子になったキーの場合:dynamic_json['varchar'],dynamic_json['nested']['value']

index_params = client.prepare_index_params()

# Index a simple string key
index_params.add_index(
    field_name="overview",  # Key name in the dynamic field
    index_type="AUTOINDEX", # Must be set to AUTOINDEX or INVERTED for JSON path indexing
    index_name="overview_index",  # Unique index name
    params={
        "json_cast_type": "varchar",   # Data type that Milvus uses when indexing the values
        "json_path": "overview"        # JSON path to the key
    }
)

# Index a simple numeric key
index_params.add_index(
    field_name="words",  # Key name in the dynamic field
    index_type="AUTOINDEX", # Must be set to AUTOINDEX or INVERTED for JSON path indexing
    index_name="words_index",  # Unique index name
    params={
        "json_cast_type": "double",  # Data type that Milvus uses when indexing the values
        "json_path": "words" # JSON path to the key
    }
)

# Index a nested key within a JSON object
index_params.add_index(
    field_name="dynamic_json", # JSON key name in the dynamic field
    index_type="AUTOINDEX", # Must be set to AUTOINDEX or INVERTED for JSON path indexing
    index_name="json_varchar_index", # Unique index name
    params={
        "json_cast_type": "varchar", # Data type that Milvus uses when indexing the values
        "json_path": "dynamic_json['varchar']" # JSON path to the nested key
    }
)

# Index a deeply nested key
index_params.add_index(
    field_name="dynamic_json",
    index_type="AUTOINDEX", # Must be set to AUTOINDEX or INVERTED for JSON path indexing
    index_name="json_nested_index", # Unique index name
    params={
        "json_cast_type": "double",
        "json_path": "dynamic_json['nested']['value']"
    }
)
import io.milvus.v2.common.IndexParam;

Map<String,Object> extraParams1 = new HashMap<>();
extraParams1.put("json_path", "overview");
extraParams1.put("json_cast_type", "varchar");
indexParams.add(IndexParam.builder()
        .fieldName("overview")
        .indexName("overview_index")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .extraParams(extraParams1)
        .build());

Map<String,Object> extraParams2 = new HashMap<>();
extraParams2.put("json_path", "words");
extraParams2.put("json_cast_type", "double");
indexParams.add(IndexParam.builder()
        .fieldName("words")
        .indexName("words_index")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .extraParams(extraParams2)
        .build());

Map<String,Object> extraParams3 = new HashMap<>();
extraParams3.put("json_path", "dynamic_json['varchar']");
extraParams3.put("json_cast_type", "varchar");
indexParams.add(IndexParam.builder()
        .fieldName("dynamic_json")
        .indexName("json_varchar_index")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .extraParams(extraParams3)
        .build());

Map<String,Object> extraParams4 = new HashMap<>();
extraParams4.put("json_path", "dynamic_json['nested']['value']");
extraParams4.put("json_cast_type", "double");
indexParams.add(IndexParam.builder()
        .fieldName("dynamic_json")
        .indexName("json_nested_index")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .extraParams(extraParams4)
        .build());
const indexParams = [
    {
      collection_name: 'my_collection',
      field_name: 'overview',
      index_name: 'overview_index',
      index_type: 'AUTOINDEX',
      metric_type: 'NONE',
      params: {
        json_path: 'overview',
        json_cast_type: 'varchar',
      },
    },
    {
      collection_name: 'my_collection',
      field_name: 'words',
      index_name: 'words_index',
      index_type: 'AUTOINDEX',
      metric_type: 'NONE',
      params: {
        json_path: 'words',
        json_cast_type: 'double',
      },
    },
    {
      collection_name: 'my_collection',
      field_name: 'dynamic_json',
      index_name: 'json_varchar_index',
      index_type: 'AUTOINDEX',
      metric_type: 'NONE',
      params: {
        json_cast_type: 'varchar',
        json_path: "dynamic_json['varchar']",
      },
    },
    {
      collection_name: 'my_collection',
      field_name: 'dynamic_json',
      index_name: 'json_nested_index',
      index_type: 'AUTOINDEX',
      metric_type: 'NONE',
      params: {
        json_cast_type: 'double',
        json_path: "dynamic_json['nested']['value']",
      },
    },
  ];
import (
    "github.com/milvus-io/milvus/client/v2/index"
)

jsonIndex1 := index.NewJSONPathIndex(index.AUTOINDEX, "varchar", "overview")
    .WithIndexName("overview_index")
jsonIndex2 := index.NewJSONPathIndex(index.AUTOINDEX, "double", "words")
    .WithIndexName("words_index")
jsonIndex3 := index.NewJSONPathIndex(index.AUTOINDEX, "varchar", `dynamic_json['varchar']`)
    .WithIndexName("json_varchar_index")
jsonIndex4 := index.NewJSONPathIndex(index.AUTOINDEX, "double", `dynamic_json['nested']['value']`)
    .WithIndexName("json_nested_index")

indexOpt1 := milvusclient.NewCreateIndexOption("my_collection", "overview", jsonIndex1)
indexOpt2 := milvusclient.NewCreateIndexOption("my_collection", "words", jsonIndex2)
indexOpt3 := milvusclient.NewCreateIndexOption("my_collection", "dynamic_json", jsonIndex3)
indexOpt4 := milvusclient.NewCreateIndexOption("my_collection", "dynamic_json", jsonIndex4)
export TOKEN="root:Milvus"
export CLUSTER_ENDPOINT="http://localhost:19530"

export overviewIndex='{
  "fieldName": "dynamic_json",
  "indexName": "overview_index",
  "params": {
    "index_type": "AUTOINDEX",
    "json_cast_type": "varchar",
    "json_path": "dynamic_json[\"overview\"]"
  }
}'

export wordsIndex='{
  "fieldName": "dynamic_json",
  "indexName": "words_index",
  "params": {
    "index_type": "AUTOINDEX",
    "json_cast_type": "double",
    "json_path": "dynamic_json[\"words\"]"
  }
}'

export varcharIndex='{
  "fieldName": "dynamic_json",
  "indexName": "json_varchar_index",
  "params": {
    "index_type": "AUTOINDEX",
    "json_cast_type": "varchar",
    "json_path": "dynamic_json[\"varchar\"]"
  }
}'

export nestedIndex='{
  "fieldName": "dynamic_json",
  "indexName": "json_nested_index",
  "params": {
    "index_type": "AUTOINDEX",
    "json_cast_type": "double",
          "json_path": "dynamic_json[\"nested\"][\"value\"]"
    }
  }'

型変換にJSONキャスト関数を使用するCompatible with Milvus 2.5.14+

動的フィールドのキーに不正な形式の値(文字列として格納された数値など)が含まれている場合、キャスト関数を使用して変換できます:

# Convert a string to double before indexing
index_params.add_index(
    field_name="dynamic_json", # JSON key name
    index_type="AUTOINDEX",
    index_name="json_string_price_index",
    params={
        "json_path": "dynamic_json['string_price']",
        "json_cast_type": "double", # Must be the output type of the cast function
        "json_cast_function": "STRING_TO_DOUBLE" # Case insensitive; convert string to double
    }
)
Map<String,Object> extraParams5 = new HashMap<>();
extraParams5.put("json_path", "dynamic_json['string_price']");
extraParams5.put("json_cast_type", "double");
indexParams.add(IndexParam.builder()
        .fieldName("dynamic_json")
        .indexName("json_string_price_index")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .extraParams(extraParams5)
        .build());
indexParams.push({
    collection_name: 'my_collection',
    field_name: 'dynamic_json',
    index_name: 'json_string_price_index',
    index_type: 'AUTOINDEX',
    metric_type: 'NONE',
    params: {
      json_path: "dynamic_json['string_price']",
      json_cast_type: 'double',
      json_cast_function: 'STRING_TO_DOUBLE',
    },
  });
jsonIndex5 := index.NewJSONPathIndex(index.AUTOINDEX, "double", `dynamic_json['string_price']`)
    .WithIndexName("json_string_price_index")
indexOpt5 := milvusclient.NewCreateIndexOption("my_collection", "dynamic_json", jsonIndex5)
export TOKEN="root:Milvus"
export CLUSTER_ENDPOINT="http://localhost:19530"

export stringPriceIndex='{
  "fieldName": "dynamic_json",
  "indexName": "json_string_price_index",
  "params": {
    "index_type": "AUTOINDEX",
    "json_path": "dynamic_json[\"string_price\"]",
    "json_cast_type": "double",
    "json_cast_function": "STRING_TO_DOUBLE"
  }
}'

  • 型変換に失敗した場合(例:値"not_a_number" を数値に変換できない)、値はスキップされ、インデックスが解除されます。

  • キャスト関数のパラメータの詳細については、JSON Fieldを参照してください。

コレクションへのインデックスの適用

インデックスパラメータを定義した後、create_index() を使用してコレクションに適用できます:

client.create_index(
    collection_name="my_collection",
    index_params=index_params
)
import io.milvus.v2.service.index.request.CreateIndexReq;

client.createIndex(CreateIndexReq.builder()
        .collectionName("my_collection")
        .indexParams(indexParams)
        .build());
  await client.createIndex(indexParams);
indexTask1, err := client.CreateIndex(ctx, indexOpt1)
if err != nil {
    return err
}
indexTask2, err := client.CreateIndex(ctx, indexOpt2)
if err != nil {
    return err
}
indexTask3, err := client.CreateIndex(ctx, indexOpt3)
if err != nil {
    return err
}
indexTask4, err := client.CreateIndex(ctx, indexOpt4)
if err != nil {
    return err
}
indexTask5, err := client.CreateIndex(ctx, indexOpt5)
if err != nil {
    return err
}
# restful
export indexParams="[
  $varcharIndex,
  $nestedIndex,
  $overviewIndex,
  $wordsIndex,
  $stringPriceIndex
]"

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/indexes/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--data "{
  \"collectionName\": \"my_collection\",
  \"indexParams\": $indexParams
}"

ダイナミック・フィールド・キーによるフィルタリング

ダイナミック・フィールド・キーでエンティティを挿入した後、標準のフィルタ式を使用してフィルタリングできます。

  • JSON以外のキー(文字列、数値、ブーリアンなど)の場合は、キー名で直接参照できます。

  • JSONオブジェクトを格納するキーの場合は、JSONパス構文を使用してネストした値にアクセスします。

前のセクションの エンティティ例に基づくと、有効なフィルター式は以下のとおりです:

filter = 'overview == "Great product"'                # Non-JSON key
filter = 'words >= 100'                               # Non-JSON key
filter = 'dynamic_json["nested"]["value"] < 50'       # JSON object key
String filter = 'overview == "Great product"';
String filter = 'words >= 100';
String filter = 'dynamic_json["nested"]["value"] < 50';
filter = 'overview == "Great product"'                // Non-JSON key
filter = 'words >= 100'                               // Non-JSON key
filter = 'dynamic_json["nested"]["value"] < 50'       // JSON object key
filter := 'overview == "Great product"'
filter := 'words >= 100'
filter := 'dynamic_json["nested"]["value"] < 50'
# restful
export filterOverview='overview == "Great product"'
export filterWords='words >= 100'
export filterNestedValue='dynamic_json["nested"]["value"] < 50'

ダイナミック・フィールド・キーの取得検索結果やクエリ結果に動的フィールドキーを返すには、フィルタリングと同じ JSON パス構文を使用して、output_fields パラメータで明示的に指定する必要があります:

# Example: Include dynamic field keys in search results
results = client.search(
    collection_name="my_collection",
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],
    filter=filter,                         # Filter expression defined earlier
    limit=10,
    output_fields=[
        "overview",                        # Simple dynamic field key
        'dynamic_json["varchar"]'          # Nested JSON key
    ]
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.vector.request.SearchReq
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp

MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
        .uri("YOUR_CLUSTER_ENDPOINT")
        .token("YOUR_CLUSTER_TOKEN")
        .build());

FloatVec queryVector = new FloatVec(new float[]{0.1, 0.2, 0.3, 0.4, 0.5});
SearchReq searchReq = SearchReq.builder()
        .collectionName("my_collection")
        .data(Collections.singletonList(queryVector))
        .topK(5)
        .filter(filter)
        .outputFields(Arrays.asList("overview", "dynamic_json['varchar']"))
        .build();

SearchResp searchResp = client.search(searchReq);
import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";

const address = "YOUR_CLUSTER_ENDPOINT";
const token = "YOUR_CLUSTER_TOKEN";
const client = new MilvusClient({address, token});

const query_vector = [0.1, 0.2, 0.3, 0.4, 0.5]

const res = await client.search({
    collection_name: "my_collection",
    data: [query_vector],
    limit: 5,
    filters: filter,
    output_fields: ["overview", "dynamic_json['varchar']"]
})
import (
    "context"
    "fmt"

    "github.com/milvus-io/milvus/client/v2/entity"
    "github.com/milvus-io/milvus/client/v2/milvusclient"
)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

milvusAddr := "YOUR_CLUSTER_ENDPOINT"
token := "YOUR_CLUSTER_TOKEN"

client, err := client.New(ctx, &client.ClientConfig{
    Address: milvusAddr,
    APIKey:  token,
})
if err != nil {
    fmt.Println(err.Error())
    // handle error
}
defer client.Close(ctx)

queryVector := []float32{0.1, 0.2, 0.3, 0.4, 0.5}

resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
    "my_collection", // collectionName
    5,               // limit
    []entity.Vector{entity.FloatVector(queryVector)},
).WithConsistencyLevel(entity.ClStrong).
    WithANNSField("my_vector").
    WithFilter(filter).
    WithOutputFields("overview", "dynamic_json['varchar']"))
if err != nil {
    fmt.Println(err.Error())
    // handle error
}
export CLUSTER_ENDPOINT="YOUR_CLUSTER_ENDPOINT"
export TOKEN="YOUR_CLUSTER_TOKEN"
export FILTER='color like "red%" and likes > 50'

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--data "{
  \"collectionName\": \"my_collection\",
  \"data\": [
    [0.1, 0.2, 0.3, 0.4, 0.5]
  ],
  \"annsField\": \"my_vector\",
  \"filter\": \"${FILTER}\",
  \"limit\": 5,
  \"outputFields\": [\"overview\", \"dynamic_json.varchar\"]
}"

ダイナミック・フィールド・キーはデフォルトでは結果に含まれないため、明示的にリクエストする必要があります。

サポートされている演算子とフィルター式の完全なリストについては、フィルター検索を参照してください。

すべてをまとめる

ここまでで、動的フィールドを使用してスキーマで定義されていないキーを柔軟に格納し、インデックスを作成する方法を学びました。ダイナミック・フィールドのキーが挿入されると、フィルタ式で他のフィールドと同じように使用できます。

実際のアプリケーションでワークフローを完成させるには、以下の作業も必要です:

FAQ

動的フィールドキーを使用する代わりに、スキーマで明示的にフィールドを定義するのはどのような場合ですか?

以下のような場合、動的フィールド・キーを使用する代わりに、スキーマで明示的にフィールドを定義する必要があります:

  • フィールドが頻繁にoutput_fieldsに含まれる:明示的に定義されたフィールドだけが、output_fields によって効率的に検索できることが保証されています。動的フィールド・キーは高頻度の検索に最適化されておらず、パフォーマンス・オーバーヘッドが発生する可能性があります。

  • フィールドは頻繁にアクセスされるか、フィルタリングされる:動的フィールドキーのインデックスを作成することで、固定スキーマフィールドと同様のフィルタリングパフォーマンスを得ることができますが、明示的に定義されたフィールドはより明確な構造と優れた保守性を提供します。

  • フィールドの動作を完全に制御する必要がある:明示的フィールドは、スキーマレベルの制約、検証、より明確な型付けをサポートし、データの整合性と一貫性の管理に役立ちます。

  • インデックスの不整合を避けたい:動的なフィールドキーのデータは、型や構造に矛盾が生じやすくなります。固定スキーマを使用することで、特にインデックスやキャスティングを使用する予定がある場合、データの品質を確保することができます。

同じ動的フィールド・キーに、異なるデータ型で複数のインデックスを作成できますか?

いいえ、JSON パスごとに 1 つのインデックスしか作成できません。ダイナミック・フィールド・キーに混合型の値(文字列と数値など)が含まれている場合でも、そのパスにインデックスを作成する場合は、json_cast_type を 1 つだけ選択する必要があります。同じキーに異なる型の複数のインデックスを作成することは、現時点ではサポートされていません。

動的フィールド・キーにインデックスを作成する際、データ・キャストに失敗した場合はどうなりますか?

動的フィールド・キーにインデックスを作成し、データ・キャストに失敗した場合、例えば、double にキャストされるはずの値が"abc"のような非数値文字列であった場合、これらの特定の値はインデックス作成時にサイレント・スキップされます。これらの値はインデックスに表示されないため、インデックスに依存するフィルタベースの検索やクエリの結果には返されません

これにはいくつかの重要な意味があります:

  • フルスキャンへのフォールバックがない:フルスキャンへのフォールバックなし:エンティティの大半が正常にインデックス化されている場合、フィルタリングクエリは完全にインデックスに依存します。キャストに失敗したエンティティは、たとえ論理的にフィルタ条件に合致していても、結果セットから除外されます。

  • 検索精度のリスク:データ品質が一貫していない大規模なデータセット(特に動的なフィールドキー)では、この動作は予期せぬ欠落結果につながる可能性があります。インデックスを作成する前に、一貫性のある有効なデータフォーマットを確保することが重要です。

  • キャスト関数の使用は慎重に:イ ンデ ッ ク ス作成時にjson_cast_function を使用 し て文字列を数値に変換す る 場合は、 文字列値が確実に変換可能であ る こ と を確認 し て く だ さ い。json_cast_type 、実際に変換された型との間に不一致があると、エラーや項目のスキップが発生します。

クエリでインデックス付きキャスト型と異なるデータ型を使用するとどうなりますか?

クエリがインデックスで使用されたものと異なるデータ型を使用してダイナミック・フィールド・キーを比較する場合(例えば、インデックスがdouble にキャストされたときに文字列比較でクエリを実行する場合)、システムはインデックスを使用せず可能であればフル・スキャンのみにフォールバックする可能性があります。最高のパフォーマンスと精度を得るためには、クエリタイプがインデックス作成時に使用されたjson_cast_type と一致するようにしてください。