Dynamisches Feld
Milvus ermöglicht Ihnen das Einfügen von Entitäten mit flexiblen, sich entwickelnden Strukturen durch eine spezielle Funktion, die als dynamisches Feld bezeichnet wird. Dieses Feld ist als verstecktes JSON-Feld namens $meta implementiert, das automatisch alle Felder in Ihren Daten speichert, die nicht explizit im Sammlungsschema definiert sind.
Wie es funktioniert
Wenn das dynamische Feld aktiviert ist, fügt Milvus ein verstecktes $meta Feld zu jeder Entität hinzu. Dieses Feld ist vom Typ JSON, d.h. es kann jede JSON-kompatible Datenstruktur speichern und kann mit der JSON-Pfadsyntax indiziert werden.
Beim Einfügen von Daten wird jedes Feld, das nicht im Schema deklariert ist, automatisch als Schlüssel-Wert-Paar in diesem dynamischen Feld gespeichert.
Sie brauchen $meta nicht manuell zu verwalten - Milvus handhabt dies transparent.
Wenn Ihr Sammlungsschema beispielsweise nur id und vector definiert, und Sie die folgende Entität einfügen:
{
"id": 1,
"vector": [0.1, 0.2, 0.3],
"name": "Item A", // Not in schema
"category": "books" // Not in schema
}
Wenn die dynamische Feldfunktion aktiviert ist, speichert Milvus sie intern als:
{
"id": 1,
"vector": [0.1, 0.2, 0.3],
"$meta": {
"name": "Item A",
"category": "books"
}
}
So können Sie Ihre Datenstruktur weiterentwickeln, ohne das Schema zu ändern.
Häufige Anwendungsfälle sind:
Speichern von optionalen oder selten abgerufenen Feldern
Erfassen von Metadaten, die je nach Entität variieren
Unterstützung einer flexiblen Filterung über Indizes für bestimmte dynamische Feldschlüssel
Unterstützte Datentypen
Das dynamische Feld unterstützt alle von Milvus bereitgestellten skalaren Datentypen, einschließlich einfacher und komplexer Werte. Diese Datentypen gelten für die **Werte der in $meta gespeicherten Schlüssel.
Zu den unterstützten Typen gehören:
String (
VARCHAR)Ganzzahl (
INT8,INT32,INT64)Fließkomma (
FLOAT,DOUBLE)Boolescher Wert (
BOOL)Array von Einzelwerten (
ARRAY)JSON-Objekte (
JSON)
Beispiel:
{
"brand": "Acme",
"price": 29.99,
"in_stock": true,
"tags": ["new", "hot"],
"specs": {
"weight": "1.2kg",
"dimensions": { "width": 10, "height": 20 }
}
}
Jeder der oben genannten Schlüssel und Werte würde in dem Feld $meta gespeichert werden.
Dynamisches Feld aktivieren
Um die Funktion des dynamischen Feldes zu nutzen, setzen Sie enable_dynamic_field=True bei der Erstellung des Sammlungsschemas:
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
}"
Einfügen von Entitäten in die Sammlung
Das dynamische Feld ermöglicht es Ihnen, zusätzliche Felder einzufügen, die nicht im Schema definiert sind. Diese Felder werden automatisch in $meta gespeichert.
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"
}'
Indexschlüssel im dynamischen FeldCompatible with Milvus 2.5.11+
Milvus ermöglicht es Ihnen, JSON-Pfadindizierung zu verwenden, um Indizes auf bestimmte Schlüssel innerhalb des dynamischen Feldes zu erstellen. Dies können skalare Werte oder verschachtelte Werte in JSON-Objekten sein.
Die Indizierung dynamischer Feldschlüssel ist optional. Sie können auch ohne einen Index nach dynamischen Feldschlüsseln abfragen oder filtern, aber dies kann zu einer langsameren Leistung aufgrund der Brute-Force-Suche führen.
Syntax der JSON-Pfadindizierung
Um einen JSON-Pfadindex zu erstellen, geben Sie an:
JSON-Pfad (
json_path): Der Pfad zu dem Schlüssel oder dem verschachtelten Feld in Ihrem JSON-Objekt, das Sie indizieren möchten.Beispiel:
metadata["category"]Damit wird festgelegt, wo die Indizierungsmaschine innerhalb der JSON-Struktur suchen soll.
JSON-Cast-Typ (
json_cast_type): Der Datentyp, den Milvus beim Interpretieren und Indizieren des Wertes am angegebenen Pfad verwenden soll.Dieser Typ muss mit dem tatsächlichen Datentyp des zu indizierenden Feldes übereinstimmen.
Eine vollständige Liste finden Sie unter Unterstützte JSON-Cast-Typen.
JSON-Pfad zum Indizieren dynamischer Feldschlüssel verwenden
Da das dynamische Feld ein JSON-Feld ist, können Sie jeden Schlüssel darin mit der JSON-Pfadsyntax indizieren. Dies funktioniert sowohl für einfache skalare Werte als auch für komplexe verschachtelte Strukturen.
JSON-Pfad-Beispiele:
Für einfache Schlüssel:
overview,wordsFür verschachtelte Schlüssel:
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-Cast-Funktionen für die Typkonvertierung verwendenCompatible with Milvus 2.5.14+
Wenn ein dynamischer Feldschlüssel Werte in einem falschen Format enthält (z. B. Zahlen, die als Zeichenketten gespeichert sind), können Sie eine Cast-Funktion verwenden, um sie umzuwandeln:
# 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"
}
}'
Wenn die Typkonvertierung fehlschlägt (z. B. kann der Wert
"not_a_number"nicht in eine Zahl konvertiert werden), wird der Wert übersprungen und nicht indiziert.Einzelheiten zu den Parametern der Cast-Funktion finden Sie unter JSON-Feld.
Indizes auf die Sammlung anwenden
Nachdem Sie die Indexparameter definiert haben, können Sie sie mit create_index() auf die Auflistung anwenden:
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
}"
Nach dynamischen Feldschlüsseln filtern
Nachdem Sie Entitäten mit dynamischen Feldschlüsseln eingefügt haben, können Sie diese mit Standard-Filterausdrücken filtern.
Bei Nicht-JSON-Schlüsseln (z.B. Strings, Zahlen, Booleans) können Sie diese direkt über den Schlüsselnamen referenzieren.
Für Schlüssel, die JSON-Objekte speichern, verwenden Sie die JSON-Pfadsyntax, um auf verschachtelte Werte zuzugreifen.
Basierend auf der Beispiel-Entität aus dem vorherigen Abschnitt, sind folgende Filterausdrücke gültig:
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'
Abrufen von dynamischen Feldschlüsseln: Um dynamische Feldschlüssel in Such- oder Abfrageergebnissen zurückzugeben, müssen Sie diese explizit im Parameter output_fields angeben und dabei dieselbe JSON-Pfadsyntax wie bei der Filterung verwenden:
# 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\"]
}"
Dynamische Feldschlüssel sind standardmäßig nicht in den Ergebnissen enthalten und müssen explizit angefordert werden.
Eine vollständige Liste der unterstützten Operatoren und Filterausdrücke finden Sie unter Gefilterte Suche.
Setzen Sie alles zusammen
Inzwischen haben Sie gelernt, wie Sie das dynamische Feld verwenden können, um Schlüssel, die nicht im Schema definiert sind, flexibel zu speichern und zu indizieren. Sobald ein dynamischer Feldschlüssel eingefügt ist, können Sie ihn wie jedes andere Feld in Filterausdrücken verwenden - eine spezielle Syntax ist nicht erforderlich.
Um den Arbeitsablauf in einer realen Anwendung zu vervollständigen, müssen Sie außerdem:
Erstellen Sie einen Index für Ihr Vektorfeld (obligatorisch für jede Sammlung)
Siehe Indexparameter festlegen
Laden Sie die Sammlung
Siehe Laden & Freigeben
Suchen oder Abfragen mit JSON-Pfadfiltern
Siehe Gefilterte Suche und JSON-Operatoren
FAQ
Wann sollte ich ein Feld explizit im Schema definieren, anstatt einen dynamischen Feldschlüssel zu verwenden?
Sie sollten ein Feld explizit im Schema definieren, anstatt einen dynamischen Feldschlüssel zu verwenden, wenn:
Das Feld häufig in output_fields enthalten ist: Nur bei explizit definierten Feldern ist gewährleistet, dass sie über
output_fieldseffizient abrufbar sind. Dynamische Feldschlüssel sind nicht für häufige Abrufe optimiert und können zu Leistungseinbußen führen.Auf das Feld wird häufig zugegriffen oder es wird gefiltert: Während die Indizierung eines dynamischen Feldschlüssels eine ähnliche Filterleistung wie bei festen Schemafeldern bieten kann, bieten explizit definierte Felder eine klarere Struktur und bessere Wartbarkeit.
Sie benötigen die volle Kontrolle über das Feldverhalten: Explizite Felder unterstützen Einschränkungen auf Schemaebene, Validierungen und eine klarere Typisierung, was für die Verwaltung der Datenintegrität und -konsistenz nützlich sein kann.
Sie möchten Indexierungsinkonsistenzen vermeiden: Daten in dynamischen Feldschlüsseln sind anfälliger für Inkonsistenzen in Typ oder Struktur. Die Verwendung eines festen Schemas trägt zur Sicherung der Datenqualität bei, insbesondere wenn Sie Indizierung oder Casting verwenden wollen.
Kann ich mehrere Indizes für denselben dynamischen Feldschlüssel mit unterschiedlichen Datentypen erstellen?
Nein, Sie können nur einen Index pro JSON-Pfad erstellen. Selbst wenn ein dynamischer Feldschlüssel Werte gemischten Typs enthält (z. B. einige Zeichenketten und einige Zahlen), müssen Sie einen einzigen json_cast_type wählen, wenn Sie diesen Pfad indizieren. Mehrere Indizes für denselben Schlüssel mit unterschiedlichen Typen werden derzeit nicht unterstützt.
Was passiert bei der Indizierung eines dynamischen Feldschlüssels, wenn das Data Casting fehlschlägt?
Wenn Sie einen Index für einen dynamischen Feldschlüssel erstellt haben und das Daten-Casting fehlschlägt - z. B. wenn ein Wert, der in double umgewandelt werden soll, eine nicht numerische Zeichenkette wie "abc"ist -, werden diese spezifischen Werte bei der Indexerstellung übersprungen. Sie erscheinen nicht im Index und werden daher auch nicht in filterbasierten Such- oder Abfrageergebnissen angezeigt, die auf dem Index basieren.
Dies hat einige wichtige Auswirkungen:
Kein Fallback auf Full Scan: Wenn die Mehrheit der Entitäten erfolgreich indiziert ist, verlassen sich die Filterabfragen vollständig auf den Index. Entitäten, bei denen das Casting fehlgeschlagen ist, werden aus der Ergebnismenge ausgeschlossen - selbst wenn sie logischerweise der Filterbedingung entsprechen.
Risiko der Suchgenauigkeit: In großen Datenbeständen, in denen die Datenqualität uneinheitlich ist (insbesondere bei dynamischen Feldschlüsseln), kann dieses Verhalten zu unerwarteten fehlenden Ergebnissen führen. Es ist wichtig, dass vor der Indizierung eine konsistente und gültige Datenformatierung sichergestellt wird.
Verwenden Sie Cast-Funktionen mit Bedacht: Wenn Sie
json_cast_functionverwenden, um Strings während der Indizierung in Zahlen zu konvertieren, stellen Sie sicher, dass die String-Werte zuverlässig konvertierbar sind. Eine Nichtübereinstimmung zwischenjson_cast_typeund dem tatsächlich konvertierten Typ führt zu Fehlern oder übersprungenen Einträgen.
Was passiert, wenn meine Abfrage einen anderen Datentyp als den indizierten Cast-Typ verwendet?
Wenn Ihre Abfrage einen dynamischen Feldschlüssel mit einem anderen Datentyp vergleicht als dem, der im Index verwendet wurde (z. B. Abfrage mit einem String-Vergleich, wenn der Index in double umgewandelt wurde), verwendet das System den Index nicht und greift , wenn möglich, auf einen vollständigen Scan zurück. Um die beste Leistung und Genauigkeit zu erzielen, stellen Sie sicher, dass Ihr Abfragetyp mit dem bei der Indexerstellung verwendeten json_cast_type übereinstimmt.