Поле JSON
Milvus позволяет хранить и индексировать структурированные данные в одном поле, используя тип данных JSON. Это позволяет создавать гибкие схемы с вложенными атрибутами и при этом эффективно фильтровать данные с помощью JSON-индексации.
Что такое поле JSON?
Поле JSON - это определенное схемой поле в Milvus, которое хранит структурированные данные типа ключ-значение. Значения могут включать строки, числа, булевы, массивы или глубоко вложенные объекты.
Вот пример того, как поле JSON может выглядеть в документе:
{
"metadata": {
"category": "electronics",
"brand": "BrandA",
"in_stock": true,
"price": 99.99,
"string_price": "99.99",
"tags": ["clearance", "summer_sale"],
"supplier": {
"name": "SupplierX",
"country": "USA",
"contact": {
"email": "support@supplierx.com",
"phone": "+1-800-555-0199"
}
}
}
}
В этом примере:
metadataэто поле JSON, определенное в схеме.Вы можете хранить плоские значения (например,
category,in_stock), массивы (tags) и вложенные объекты (supplier).
Определение поля JSON в схеме
Чтобы использовать поле JSON, явно определите его в схеме коллекции, указав DataType как JSON.
В приведенном ниже примере создается коллекция, схема которой содержит эти поля:
Первичный ключ (
product_id)Поле
vector(обязательное для каждой коллекции)Поле
metadataтипаJSON, которое может хранить структурированные данные, такие как плоские значения, массивы или вложенные объекты.
from pymilvus import MilvusClient, DataType
client = MilvusClient(uri="http://localhost:19530")
# Create schema with a JSON field
schema = client.create_schema(auto_id=False, enable_dynamic_field=True)
schema.add_field(field_name="product_id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=5)
schema.add_field(field_name="metadata", datatype=DataType.JSON, nullable=True) # JSON field that allows null values
client.create_collection(
collection_name="product_catalog",
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("product_id")
.dataType(DataType.Int64)
.isPrimaryKey(Boolean.TRUE)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("vector")
.dataType(DataType.FloatVector)
.dimension(5)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("metadata")
.dataType(DataType.JSON)
.isNullable(true)
.build());
CreateCollectionReq requestCreate = CreateCollectionReq.builder()
.collectionName("product_catalog")
.collectionSchema(schema)
.build();
client.createCollection(requestCreate);
import { MilvusClient, DataType } from '@zilliz/milvus2-sdk-node';
const client = new MilvusClient({
address: 'localhost:19530'
});
// Create collection
await client.createCollection({
collection_name: "product_catalog",
fields: [
{
name: "product_id",
data_type: DataType.Int64,
is_primary_key: true,
autoID: false
},
{
name: "vector",
data_type: DataType.FloatVector,
dim: 5
},
{
name: "metadata",
data_type: DataType.JSON,
nullable: true // JSON field that allows null values
}
],
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("product_id").pk
WithDataType(entity.FieldTypeInt64).
WithIsPrimaryKey(true),
).WithField(entity.NewField().
WithName("vector").
WithDataType(entity.FieldTypeFloatVector).
WithDim(5),
).WithField(entity.NewField().
WithName("metadata").
WithDataType(entity.FieldTypeJSON).
WithNullable(true),
)
err = client.CreateCollection(ctx, milvusclient.NewCreateCollectionOption("product_catalog", schema))
if err != nil {
return err
}
# restful
export TOKEN="root:Milvus"
export CLUSTER_ENDPOINT="http://localhost:19530"
# 字段定义
export productIdField='{
"fieldName": "product_id",
"dataType": "Int64",
"isPrimary": true,
"autoID": false
}'
export vectorField='{
"fieldName": "vector",
"dataType": "FloatVector",
"typeParams": {
"dim": 5
}
}'
export metadataField='{
"fieldName": "metadata",
"dataType": "JSON",
"isNullable": true
}'
# 构造 schema
export schema="{
\"autoID\": false,
\"enableDynamicField\": true,
\"fields\": [
$productIdField,
$vectorField,
$metadataField
]
}"
# 创建集合
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--data "{
\"collectionName\": \"product_catalog\",
\"schema\": $schema
}"
Вы также можете включить функцию динамического поля для гибкого хранения необъявленных полей, но это не обязательно для работы JSON-полей. Дополнительную информацию см. в разделе Динамическое поле.
Вставка сущностей с данными JSON
После создания коллекции вставьте сущности, содержащие структурированные JSON-объекты, в поле metadata JSON.
entities = [
{
"product_id": 1,
"vector": [0.1, 0.2, 0.3, 0.4, 0.5],
"metadata": {
"category": "electronics",
"brand": "BrandA",
"in_stock": True,
"price": 99.99,
"string_price": "99.99",
"tags": ["clearance", "summer_sale"],
"supplier": {
"name": "SupplierX",
"country": "USA",
"contact": {
"email": "support@supplierx.com",
"phone": "+1-800-555-0199"
}
}
}
}
]
client.insert(collection_name="product_catalog", 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("product_id", 1);
row.add("vector", gson.toJsonTree(Arrays.asList(0.1, 0.2, 0.3, 0.4, 0.5)));
JsonObject metadata = new JsonObject();
metadata.addProperty("category", "electronics");
metadata.addProperty("brand", "BrandA");
metadata.addProperty("in_stock", true);
metadata.addProperty("price", 99.99);
metadata.addProperty("string_price", "99.99");
metadata.add("tags", gson.toJsonTree(Arrays.asList("clearance", "summer_sale")));
JsonObject supplier = new JsonObject();
supplier.addProperty("name", "SupplierX");
supplier.addProperty("country", "USA");
JsonObject contact = new JsonObject();
contact.addProperty("email", "support@supplierx.com");
contact.addProperty("phone", "+1-800-555-0199");
supplier.add("contact", contact);
metadata.add("supplier", supplier);
row.add("metadata", metadata);
client.insert(InsertReq.builder()
.collectionName("product_catalog")
.data(Collections.singletonList(row))
.build());
const entities = [
{
"product_id": 1,
"vector": [0.1, 0.2, 0.3, 0.4, 0.5],
"metadata": {
"category": "electronics",
"brand": "BrandA",
"in_stock": True,
"price": 99.99,
"string_price": "99.99",
"tags": ["clearance", "summer_sale"],
"supplier": {
"name": "SupplierX",
"country": "USA",
"contact": {
"email": "support@supplierx.com",
"phone": "+1-800-555-0199"
}
}
}
}
]
await client.insert({
collection_name: "product_catalog",
data: entities
});
_, err = client.Insert(ctx, milvusclient.NewColumnBasedInsertOption("product_catalog").
WithInt64Column("product_id", []int64{1}).
WithFloatVectorColumn("vector", 5, [][]float32{
{0.1, 0.2, 0.3, 0.4, 0.5},
}).WithColumns(
column.NewColumnJSONBytes("metadata", [][]byte{
[]byte(`{
"category": "electronics",
"brand": "BrandA",
"in_stock": True,
"price": 99.99,
"string_price": "99.99",
"tags": ["clearance", "summer_sale"],
"supplier": {
"name": "SupplierX",
"country": "USA",
"contact": {
"email": "support@supplierx.com",
"phone": "+1-800-555-0199"
}
}
}`),
}),
))
if err != nil {
return err
}
# restful
export TOKEN="root:Milvus"
export CLUSTER_ENDPOINT="http://localhost:19530"
export entities='[
{
"product_id": 1,
"vector": [0.1, 0.2, 0.3, 0.4, 0.5],
"metadata": {
"category": "electronics",
"brand": "BrandA",
"in_stock": true,
"price": 99.99,
"string_price": "99.99",
"tags": ["clearance", "summer_sale"],
"supplier": {
"name": "SupplierX",
"country": "USA",
"contact": {
"email": "support@supplierx.com",
"phone": "+1-800-555-0199"
}
}
}
}
]'
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/product_catalog/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--data "{
\"data\": $entities
}"
Индексирование значений внутри JSON-поля
Чтобы ускорить скалярную фильтрацию по JSON-полям, Milvus поддерживает следующие типы индексов:
Индекс пути JSON - индексирует определенные пути JSON с объявленным скалярным типом.
Плоский индекс JSON - индексирование всего объекта JSON (или поддерева) с автоматическим определением типа.
Индексирование полей JSON необязательно. Вы все равно можете запрашивать или фильтровать по путям JSON без индекса, но это может привести к снижению производительности из-за поиска методом грубой силы.
Выбор между индексом пути и плоским индексомCompatible with Milvus 2.6.x
Возможность |
Индекс пути JSON |
Плоский индекс JSON |
|---|---|---|
Что индексирует |
Конкретный путь (пути), указанный вами |
Все плоские пути под объектным путем |
Работа с типами |
Вы объявляете |
Должен быть JSON (автоматическое определение типа) |
Массивы как LHS¹ |
Поддерживается |
Не поддерживается |
Скорость запросов |
Высокая на индексированных путях |
Высокая, в среднем немного ниже |
Использование диска |
Ниже |
Выше |
¹ Массивы в качестве LHS означают, что левая часть выражения фильтра представляет собой массив JSON, например:
metadata["tags"] == ["clearance", "summer_sale"]
json_contains(metadata["tags"], "clearance")
В этих случаях metadata["tags"] - это массив. Плоская индексация JSON не ускоряет работу таких фильтров - используйте вместо этого индекс пути JSON с типом приведения массив.
Используйте индекс пути JSON, когда:
Вы заранее знаете горячие клавиши для запроса.
Вам нужно отфильтровать данные, левая сторона которых представляет собой массив.
Вы хотите минимизировать использование диска.
Используйте плоский индекс JSON, когда:
Вы хотите проиндексировать все поддерево (включая корень).
Структура JSON часто меняется.
Вы хотите расширить охват запросов, не объявляя каждый путь.
Индексирование путей в JSON
Чтобы создать индекс пути JSON, укажите:
JSON path (
json_path): Путь к ключу или вложенному полю в объекте JSON, который вы хотите проиндексировать.Пример:
Для ключа,
metadata["category"]Для вложенного поля,
metadata["contact"]["email"]
Это определяет, где механизм индексирования должен искать внутри структуры JSON.
Тип приведения JSON (
json_cast_type): Тип данных, который Milvus должен использовать при интерпретации и индексировании значения по указанному пути.Этот тип должен совпадать с реальным типом данных индексируемого поля. Если во время индексирования необходимо преобразовать тип данных в другой, используйте функцию cast.
Полный список см. ниже.
Поддерживаемые типы приведения JSON
Типы приведения не чувствительны к регистру. Поддерживаются следующие типы:
Тип приведения |
Описание |
Пример значения JSON |
|---|---|---|
|
Булево значение |
|
|
Числовое значение (целое или плавающее) |
|
|
Строковое значение |
|
|
Массив булевых чисел |
|
|
Массив чисел |
|
|
Массив строк |
|
Массивы должны содержать элементы одного типа для оптимального индексирования. Для получения дополнительной информации обратитесь к разделу Поле массива.
Пример: Создание индексов путей в JSON
Используя структуру JSON metadata из нашего введения, приведем примеры создания индексов для различных путей JSON:
# Index the category field as a string
index_params = client.prepare_index_params()
index_params.add_index(
field_name="metadata",
index_type="AUTOINDEX", # Must be set to AUTOINDEX or INVERTED for JSON path indexing
index_name="category_index", # Unique index name
params={
"json_path": "metadata[\"category\"]", # Path to the JSON key to be indexed
"json_cast_type": "varchar" # Data cast type
}
)
# Index the tags array as string array
index_params.add_index(
field_name="metadata",
index_type="AUTOINDEX", # Must be set to AUTOINDEX or INVERTED for JSON path indexing
index_name="tags_array_index", # Unique index name
params={
"json_path": "metadata[\"tags\"]", # Path to the JSON key to be indexed
"json_cast_type": "array_varchar" # Data cast type
}
)
import io.milvus.v2.common.IndexParam;
Map<String,Object> extraParams1 = new HashMap<>();
extraParams1.put("json_path", "metadata[\"category\"]");
extraParams1.put("json_cast_type", "varchar");
indexParams.add(IndexParam.builder()
.fieldName("metadata")
.indexName("category_index")
.indexType(IndexParam.IndexType.AUTOINDEX)
.extraParams(extraParams1)
.build());
Map<String,Object> extraParams2 = new HashMap<>();
extraParams2.put("json_path", "metadata[\"tags\"]");
extraParams2.put("json_cast_type", "array_varchar");
indexParams.add(IndexParam.builder()
.fieldName("metadata")
.indexName("tags_array_index")
.indexType(IndexParam.IndexType.AUTOINDEX)
.extraParams(extraParams2)
.build());
const indexParams = [
{
collection_name: "product_catalog",
field_name: "metadata",
index_name: "category_index",
index_type: "AUTOINDEX", // Can also use "INVERTED" for JSON path indexing
extra_params: {
json_path: 'metadata["category"]',
json_cast_type: "varchar",
},
},
{
collection_name: "product_catalog",
field_name: "metadata",
index_name: "tags_array_index",
index_type: "AUTOINDEX", // Can also use "INVERTED" for JSON path indexing
extra_params: {
json_path: 'metadata["tags"]',
json_cast_type: "array_varchar",
},
},
];
import (
"github.com/milvus-io/milvus/client/v2/index"
)
jsonIndex1 := index.NewJSONPathIndex(index.AUTOINDEX, "varchar", `metadata["category"]`)
.WithIndexName("category_index")
jsonIndex2 := index.NewJSONPathIndex(index.AUTOINDEX, "array_varchar", `metadata["tags"]`)
.WithIndexName("tags_array_index")
indexOpt1 := milvusclient.NewCreateIndexOption("product_catalog", "metadata", jsonIndex1)
indexOpt2 := milvusclient.NewCreateIndexOption("product_catalog", "metadata", jsonIndex2)
# restful
export categoryIndex='{
"fieldName": "metadata",
"indexName": "category_index",
"params": {
"index_type": "AUTOINDEX",
"json_path": "metadata[\\\"category\\\"]",
"json_cast_type": "varchar"
}
}'
export tagsArrayIndex='{
"fieldName": "metadata",
"indexName": "tags_array_index",
"params": {
"index_type": "AUTOINDEX",
"json_path": "metadata[\\\"tags\\\"]",
"json_cast_type": "array_varchar"
}
}'
Используйте функции приведения JSON для преобразования типовCompatible with Milvus 2.5.14+
Если ключ поля JSON содержит значения в неправильном формате (например, числа, хранящиеся как строки), вы можете использовать функции приведения для преобразования значений во время индексирования.
Поддерживаемые функции приведения
Функции приведения не чувствительны к регистру. Поддерживаются следующие типы:
Функция приведения |
Преобразовывает из → в |
Случай использования |
|---|---|---|
|
Строка → Число (двойное) |
Преобразовать |
Пример: Преобразование строковых чисел в двойные
# Convert string numbers to double for indexing
index_params.add_index(
field_name="metadata",
index_type="AUTOINDEX", # Must be set to AUTOINDEX or INVERTED for JSON path indexing
index_name="string_to_double_index", # Unique index name
params={
"json_path": "metadata[\"string_price\"]", # Path to the JSON key to be indexed
"json_cast_type": "double", # Data cast type
"json_cast_function": "STRING_TO_DOUBLE" # Cast function; case insensitive
}
)
Map<String,Object> extraParams3 = new HashMap<>();
extraParams3.put("json_path", "metadata[\"string_price\"]");
extraParams3.put("json_cast_type", "double");
extraParams3.put("json_cast_function", "STRING_TO_DOUBLE");
indexParams.add(IndexParam.builder()
.fieldName("metadata")
.indexName("string_to_double_index")
.indexType(IndexParam.IndexType.AUTOINDEX)
.extraParams(extraParams3)
.build());
indexParams.push({
collection_name: "product_catalog",
field_name: "metadata",
index_name: "string_to_double_index",
index_type: "AUTOINDEX", // Can also use "INVERTED"
extra_params: {
json_path: 'metadata["string_price"]',
json_cast_type: "double",
json_cast_function: "STRING_TO_DOUBLE", // Case insensitive
},
});
jsonIndex3 := index.NewJSONPathIndex(index.AUTOINDEX, "double", `metadata["string_price"]`)
.WithIndexName("string_to_double_index")
indexOpt3 := milvusclient.NewCreateIndexOption("product_catalog", "metadata", jsonIndex3)
# restful
export stringToDoubleIndex='{
"fieldName": "metadata",
"indexName": "string_to_double_index",
"params": {
"index_type": "AUTOINDEX",
"json_path": "metadata[\\\"string_price\\\"]",
"json_cast_type": "double",
"json_cast_function": "STRING_TO_DOUBLE"
}
}'
Параметр
json_cast_typeявляется обязательным и должен совпадать с выходным типом функции приведения.Если преобразование не удается (например, нечисловая строка), значение пропускается и не индексируется.
Плоское индексирование JSONCompatible with Milvus 2.6.x
При плоском индексировании JSON Milvus индексирует все пары ключ-значение в пределах пути к объекту JSON (включая вложенные объекты), сглаживая структуру JSON и автоматически определяя тип каждого значения.
Как работают сглаживание и вывод типа
Когда вы создаете плоский индекс JSON на пути объекта, Milvus будет:
Flatten - рекурсивно обходит объект, начиная с указанного
json_path, и извлекает вложенные пары ключ-значение в виде полностью определенных путей. Используя предыдущий примерmetadata:"metadata": { "category": "electronics", "price": 99.99, "supplier": { "country": "USA" } }становится:
metadata["category"] = "electronics" metadata["price"] = 99.99 metadata["supplier"]["country"] = "USA"Автоматически определять типы - Для каждого значения Milvus определяет его тип в следующем порядке:
unsigned integer → signed integer → floating-point → stringПервый тип, соответствующий значению, используется для индексации.
Это означает, что определяемый тип всегда будет одним из этих четырех.
Вывод типа выполняется для каждого документа, поэтому один и тот же путь может иметь разные выведенные типы в разных документах.
После определения типа уплощенные данные внутренне представляются в виде терминов с их выведенными типами, например:
("category", Text, "electronics") ("price", Double, 99.99) ("supplier.country", Text, "USA")
Пример: Создание плоского индекса JSON
# 1. Create a flat index on the root object of the JSON column (covers the entire JSON subtree)
index_params.add_index(
field_name="metadata",
index_type="AUTOINDEX", # Or "INVERTED", same as Path Index
index_name="metadata_flat", # Unique index name
params={
"json_path": 'metadata', # Object path: the root object of the column
"json_cast_type": "JSON" # Key difference: must be "JSON" for Flat Index; case-insensitive
}
)
# 2. Optionally, create a flat index on a sub-object (e.g., supplier subtree)
index_params.add_index(
field_name="metadata",
index_type="AUTOINDEX",
index_name="metadata_supplier_flat",
params={
"json_path": 'metadata["supplier"]', # Object path: sub-object path
"json_cast_type": "JSON"
}
)
// java
// nodejs
// go
# restful
Применение индексов к коллекции
После определения параметров индекса вы можете применить их к коллекции с помощью create_index():
client.create_index(
collection_name="product_catalog",
index_params=index_params
)
import io.milvus.v2.service.index.request.CreateIndexReq;
client.createIndex(CreateIndexReq.builder()
.collectionName("product_catalog")
.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
}
# restful
export indexParams="[
$categoryIndex,
$tagsArrayIndex,
$stringToDoubleIndex
]"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/indexes/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--data "{
\"collectionName\": \"product_catalog\",
\"indexParams\": $indexParams
}"
Фильтр по значениям полей JSON
После вставки и индексирования JSON-полей вы можете фильтровать по ним, используя стандартные выражения фильтрации с синтаксисом JSON path.
Например:
filter = 'metadata["category"] == "electronics"'
filter = 'metadata["price"] > 50'
filter = 'json_contains(metadata["tags"], "featured")'
String filter = 'metadata["category"] == "electronics"';
String filter = 'metadata["price"] > 50';
String filter = 'json_contains(metadata["tags"], "featured")';
let filter = 'metadata["category"] == "electronics"'
let filter = 'metadata["price"] > 50'
let filter = 'json_contains(metadata["tags"], "featured")'
filter := 'metadata["category"] == "electronics"'
filter := 'metadata["price"] > 50'
filter := 'json_contains(metadata["tags"], "featured")'
# restful
export filterCategory='metadata["category"] == "electronics"'
export filterPrice='metadata["price"] > 50'
export filterTags='json_contains(metadata["tags"], "featured")'
Чтобы использовать эти выражения в поиске или запросе, убедитесь, что:
Вы создали индекс для каждого векторного поля.
Коллекция загружена в память.
Полный список поддерживаемых операторов и выражений см. в разделе Операторы JSON.
Соберите все воедино
К этому моменту вы уже научились определять, вставлять и, по желанию, индексировать структурированные значения в поле JSON.
Чтобы завершить этот процесс в реальном приложении, вам также потребуется:
Создать индекс для векторных полей (обязательно для каждого векторного поля в коллекции).
См. раздел "Установка параметров индекса
Загрузить коллекцию
См. раздел Загрузка и освобождение
Выполнить поиск или запрос с использованием фильтров пути JSON
См. раздел Фильтрованный поиск и операторы JSON
ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ
В чем разница между полем JSON и динамическим полем?
JSON-поле определяется схемой. Вы должны явно объявить поле в схеме.
Динамическое поле - это скрытый JSON-объект (
$meta), который автоматически сохраняет любое поле, не определенное в схеме.
Оба варианта поддерживают вложенные структуры и индексацию путей JSON, но динамические поля больше подходят для необязательных или развивающихся структур данных.
Подробности см. в разделе "Динамическое поле".
Существуют ли ограничения на размер поля JSON?
Да. Размер каждого поля JSON ограничен 65 536 байтами.
Поддерживает ли поле JSON установку значения по умолчанию?
Нет, поля JSON не поддерживают значения по умолчанию. Однако при определении поля можно установить значение nullable=True, чтобы разрешить пустые записи.
Подробности см. в разделе Nullable & Default.
Существуют ли какие-либо соглашения об именовании для ключей полей JSON?
Да, чтобы обеспечить совместимость с запросами и индексацией:
Используйте только буквы, цифры и символы подчеркивания в ключах JSON.
Избегайте использования специальных символов, пробелов или точек (
.,/, и т. д.).Несовместимые ключи могут вызвать проблемы с разбором в выражениях фильтров.
Как Milvus обрабатывает строковые значения в полях JSON?
Milvus хранит строковые значения именно в том виде, в каком они представлены во входном JSON-файле, без семантических преобразований. Неправильно заключенные в кавычки строки могут привести к ошибкам при разборе.
Примеры допустимых строк:
"a\"b", "a'b", "a\\b"
Примеры недопустимых строк:
'a"b', 'a\'b'
Какую логику фильтрации использует Milvus для индексированных путей JSON?
Численное индексирование:
Если индекс создан с помощью
json_cast_type="double", только числовые условия фильтрации (например,>,<,== 42) будут использовать индекс. Нечисловые условия могут вернуться к грубому сканированию.Индексирование строк:
Если в индексе используется
json_cast_type="varchar", только условия фильтрации строк получат преимущества от индекса; другие типы могут вернуться к грубому сканированию.Булево индексирование:
Булево индексирование ведет себя аналогично строковому индексированию, при этом индекс используется только тогда, когда условие строго соответствует true или false.
Как быть с точностью числовых значений при индексировании полей JSON?
Milvus хранит все индексируемые числовые значения в виде двоек.
Если числовое значение превышает 2^53, оно может потерять точность. Такая потеря точности может привести к тому, что запросы фильтров не будут точно соответствовать значениям, выходящим за пределы диапазона.
Можно ли создать несколько индексов на одном пути JSON с разными типами приведения?
Нет, каждый путь JSON поддерживает только один индекс. Вы должны выбрать один json_cast_type, который соответствует вашим данным. Создание нескольких индексов на одном и том же пути с разными типами приведения не поддерживается.
Что делать, если значения в пути JSON имеют несогласованные типы?
Несогласованные типы сущностей могут привести к частичному индексированию. Например, если metadata["price"] хранится и как число (99.99), и как строка ("99.99"), а индекс определен через json_cast_type="double", будут проиндексированы только числовые значения. Записи в строковой форме будут пропущены и не появятся в результатах фильтрации.
Можно ли использовать фильтры с типом, отличным от индексируемого типа?
Если в выражении фильтра используется тип, отличный от типа индекса json_cast_type, система не будет использовать индекс и может вернуться к более медленному грубому сканированию, если это позволяют данные. Для достижения наилучшей производительности всегда согласовывайте выражение фильтра с типом приведения индекса.