Динамическое поле
Milvus позволяет вставлять сущности с гибкой, развивающейся структурой с помощью специальной функции, называемой динамическим полем. Это поле реализовано в виде скрытого JSON-поля с именем $meta, которое автоматически сохраняет любые поля в ваших данных, которые не определены явно в схеме коллекции.
Как это работает
Когда динамическое поле включено, Milvus добавляет скрытое поле $meta к каждой сущности. Это поле имеет тип JSON, что означает, что оно может хранить любую JSON-совместимую структуру данных и может быть проиндексировано с помощью синтаксиса JSON path.
При вставке данных любое поле, не объявленное в схеме, автоматически сохраняется в виде пары ключ-значение в этом динамическом поле.
Вам не нужно управлять $meta вручную - Milvus делает это прозрачно.
Например, если в схеме вашей коллекции определены только id и vector, и вы вставляете следующую сущность:
{
"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.
Поддерживаемые типы включают:
String (
VARCHAR)Целое число (
INT8,INT32,INT64)Плавающая точка (
FLOAT,DOUBLE)Boolean (
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 path (
json_path): Путь к ключу или вложенному полю в объекте JSON, который вы хотите проиндексировать.Пример:
metadata["category"]Это определяет, где механизм индексирования должен искать внутри структуры JSON.
JSON cast type (
json_cast_type): Тип данных, который Milvus должен использовать при интерпретации и индексировании значения по указанному пути.Этот тип должен совпадать с реальным типом данных индексируемого поля.
Полный список см. в разделе Поддерживаемые типы данных JSON.
Использование пути JSON для индексации ключей динамических полей
Поскольку динамическое поле является полем JSON, вы можете индексировать любой ключ в нем, используя синтаксис JSON path. Это работает как для простых скалярных значений, так и для сложных вложенных структур.
Примеры путей 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"не может быть преобразовано в число), значение пропускается и не индексируется.Подробнее о параметрах функции cast см. в разделе Поле JSON.
Применение индексов к коллекции
После определения параметров индекса вы можете применить их к коллекции с помощью 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'
Получение динамических ключей полей: Чтобы вернуть ключи динамических полей в результатах поиска или запроса, вы должны явно указать их в параметре output_fields, используя тот же синтаксис пути JSON, что и при фильтрации:
# 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\"]
}"
Динамические ключи полей не включаются в результаты по умолчанию и должны быть явно запрошены.
Полный список поддерживаемых операторов и выражений фильтрации см. в разделе Фильтрованный поиск.
Соберите все вместе
К этому моменту вы узнали, как использовать динамическое поле для гибкого хранения и индексирования ключей, не определенных в схеме. После вставки ключа динамического поля вы можете использовать его так же, как и любое другое поле в выражениях фильтрации - специальный синтаксис не требуется.
Чтобы завершить рабочий процесс в реальном приложении, вам также потребуется:
Создать индекс для векторного поля (обязательно для каждой коллекции).
См. раздел "Установка параметров индекса
Загрузить коллекцию
См. раздел Загрузка и освобождение
Выполнить поиск или запрос с использованием фильтров пути JSON
См. раздел Фильтрованный поиск и операторы JSON
ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ
Когда я должен определять поле явно в схеме, а не использовать динамический ключ поля?
Вы должны определить поле явно в схеме, а не использовать динамический ключ поля, когда:
Поле часто включается в output_fields: Только явно определенные поля гарантированно будут эффективно извлекаться через
output_fields. Динамические ключи полей не оптимизированы для высокочастотного поиска и могут иметь избыточную производительность.К полю часто обращаются или фильтруют его: Хотя индексирование по динамическому ключу поля может обеспечить такую же производительность фильтрации, как и для полей фиксированной схемы, явно определенные поля предлагают более четкую структуру и более удобны в обслуживании.
Вам нужен полный контроль над поведением поля: Явно определенные поля поддерживают ограничения на уровне схемы, проверки и более четкую типизацию, что может быть полезно для управления целостностью и непротиворечивостью данных.
Вы хотите избежать несоответствий в индексировании: Данные в ключах динамических полей более склонны к несоответствию типа или структуры. Использование фиксированной схемы помогает обеспечить качество данных, особенно если вы планируете использовать индексирование или приведение.
Можно ли создать несколько индексов для одного и того же ключа динамического поля с разными типами данных?
Нет, вы можете создать только один индекс для каждого пути JSON. Даже если ключ динамического поля содержит значения смешанного типа (например, несколько строк и несколько чисел), при индексировании этого пути необходимо выбрать один json_cast_type. Несколько индексов для одного и того же ключа с разными типами в настоящее время не поддерживаются.
Что делать, если при индексировании ключа динамического поля приведение данных не удается?
Если вы создали индекс по ключу динамического поля, а приведение данных не удалось - например, значение, предназначенное для приведения к double, является нечисловой строкой, такой как "abc", - эти конкретные значения будут молча пропущены при создании индекса. Они не появятся в индексе и, следовательно, не будут возвращены в результатах поиска и запросов, основанных на фильтрах, которые полагаются на индекс.
Это имеет несколько важных последствий:
Отсутствие возврата к полному сканированию: Если большинство сущностей успешно проиндексировано, запросы фильтрации будут полностью полагаться на индекс. Сущности с ошибками в индексировании будут исключены из набора результатов - даже если они логически соответствуют условию фильтра.
Риск точности поиска: В больших массивах данных, где качество данных непостоянно (особенно в динамических ключах полей), такое поведение может привести к неожиданным пропущенным результатам. Очень важно обеспечить последовательное и корректное форматирование данных перед индексированием.
Осторожно используйте функции приведения: Если вы используете
json_cast_functionдля преобразования строк в числа во время индексирования, убедитесь, что строковые значения надежно преобразуются. Несоответствие междуjson_cast_typeи реальным преобразованным типом приведет к ошибкам или пропуску записей.
Что произойдет, если в моем запросе используется тип данных, отличный от индексируемого приведенного типа?
Если ваш запрос сравнивает ключ динамического поля с типом данных, отличным от того, который использовался в индексе (например, запрос со строковым сравнением, когда индекс был приведен к double), система не будет использовать индекс и может вернуться к полному сканированию , только если это возможно. Для достижения наилучшей производительности и точности убедитесь, что тип запроса соответствует типу json_cast_type, использованному при создании индекса.