Использование Partition Key
Partition Key - это решение для оптимизации поиска на основе разделов. Назначив определенное скалярное поле в качестве ключа раздела и задав условия фильтрации на основе ключа раздела во время поиска, можно сузить область поиска до нескольких разделов, тем самым повысив эффективность поиска. В этой статье мы расскажем о том, как использовать ключ раздела, и о связанных с этим моментах.
Обзор
В Milvus можно использовать разделы для разделения данных и повышения эффективности поиска, ограничивая область поиска определенными разделами. Если вы решили управлять разделами вручную, вы можете создать максимум 1024 раздела в коллекции и вставить сущности в эти разделы на основе определенного правила, чтобы сузить область поиска, ограничив поиск определенным количеством разделов.
Milvus представляет ключ раздела для повторного использования разделов при разделении данных, чтобы преодолеть ограничение на количество разделов, которые можно создать в коллекции. При создании коллекции в качестве ключа раздела можно использовать скалярное поле. Когда коллекция готова, Milvus создает указанное количество разделов внутри коллекции. Получив вставленную сущность, Milvus вычисляет хэш-значение, используя значение Partition Key сущности, выполняет операцию modulo на основе хэш-значения и свойства partitions_num коллекции, чтобы получить идентификатор целевого раздела, и сохраняет сущность в целевом разделе.
Раздел Vs ключ раздела
На следующем рисунке показано, как Milvus обрабатывает поисковые запросы в коллекции с включенной функцией Partition Key и без нее.
Если ключ раздела отключен, Milvus ищет в коллекции сущности, наиболее похожие на вектор запроса. Вы можете сузить область поиска, если знаете, какой раздел содержит наиболее релевантные результаты.
Если ключ раздела включен, Milvus определяет область поиска на основе значения ключа раздела, указанного в фильтре поиска, и сканирует только те сущности в разделах, которые совпадают.
С ключом раздела и без него
Использование ключа раздела
Чтобы использовать ключ раздела, вам необходимо
Задать количество создаваемых разделов (необязательно) и
Установка ключа раздела
Чтобы назначить скалярное поле в качестве ключа раздела, необходимо установить его атрибут is_partition_key на true при добавлении скалярного поля.
Когда вы устанавливаете скалярное поле в качестве ключа раздела, значения поля не могут быть пустыми или нулевыми.
from pymilvus import (
MilvusClient, DataType
)
client = MilvusClient(
uri="http://localhost:19530",
token="root:Milvus"
)
schema = client.create_schema()
schema.add_field(field_name="id",
datatype=DataType.INT64,
is_primary=True)
schema.add_field(field_name="vector",
datatype=DataType.FLOAT_VECTOR,
dim=5)
# Add the partition key
schema.add_field(
field_name="my_varchar",
datatype=DataType.VARCHAR,
max_length=512,
is_partition_key=True,
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
.uri("http://localhost:19530")
.token("root:Milvus")
.build());
// Create schema
CreateCollectionReq.CollectionSchema schema = client.createSchema();
schema.addField(AddFieldReq.builder()
.fieldName("id")
.dataType(DataType.Int64)
.isPrimaryKey(true)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("vector")
.dataType(DataType.FloatVector)
.dimension(5)
.build());
// Add the partition key
schema.addField(AddFieldReq.builder()
.fieldName("my_varchar")
.dataType(DataType.VarChar)
.maxLength(512)
.isPartitionKey(true)
.build());
import (
"context"
"fmt"
"github.com/milvus-io/milvus/client/v2/column"
"github.com/milvus-io/milvus/client/v2/entity"
"github.com/milvus-io/milvus/client/v2/index"
"github.com/milvus-io/milvus/client/v2/milvusclient"
)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
milvusAddr := "localhost:19530"
client, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
Address: milvusAddr,
})
if err != nil {
fmt.Println(err.Error())
// handle error
}
defer client.Close(ctx)
schema := entity.NewSchema().WithDynamicFieldEnabled(false)
schema.WithField(entity.NewField().
WithName("id").
WithDataType(entity.FieldTypeInt64).
WithIsPrimaryKey(true),
).WithField(entity.NewField().
WithName("my_varchar").
WithDataType(entity.FieldTypeVarChar).
WithIsPartitionKey(true).
WithMaxLength(512),
).WithField(entity.NewField().
WithName("vector").
WithDataType(entity.FieldTypeFloatVector).
WithDim(5),
)
import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";
const address = "http://localhost:19530";
const token = "root:Milvus";
const client = new MilvusClient({address, token});
// 3. Create a collection in customized setup mode
// 3.1 Define fields
const fields = [
{
name: "my_varchar",
data_type: DataType.VarChar,
max_length: 512,
is_partition_key: true
}
]
export schema='{
"autoId": true,
"enabledDynamicField": false,
"fields": [
{
"fieldName": "id",
"dataType": "Int64",
"isPrimary": true
},
{
"fieldName": "vector",
"dataType": "FloatVector",
"elementTypeParams": {
"dim": "5"
}
},
{
"fieldName": "my_varchar",
"dataType": "VarChar",
"isPartitionKey": true,
"elementTypeParams": {
"max_length": 512
}
}
]
}'
Установка номеров разделов
Когда вы назначаете скалярное поле в коллекции в качестве ключа раздела, Milvus автоматически создает 16 разделов в коллекции. Получив сущность, Milvus выбирает раздел на основе значения Partition Key этой сущности и сохраняет сущность в этом разделе, в результате чего некоторые или все разделы будут содержать сущности с разными значениями Partition Key.
Вы также можете определить количество разделов, которые нужно создать вместе с коллекцией. Это возможно только в том случае, если в качестве ключа раздела указано скалярное поле.
client.create_collection(
collection_name="my_collection",
schema=schema,
num_partitions=128
)
import io.milvus.v2.service.collection.request.CreateCollectionReq;
CreateCollectionReq createCollectionReq = CreateCollectionReq.builder()
.collectionName("my_collection")
.collectionSchema(schema)
.numPartitions(128)
.build();
client.createCollection(createCollectionReq);
err = client.CreateCollection(ctx,
milvusclient.NewCreateCollectionOption("my_collection", schema).
WithNumPartitions(128))
if err != nil {
fmt.Println(err.Error())
// handle error
}
await client.create_collection({
collection_name: "my_collection",
schema: schema,
num_partitions: 128
})
export params='{
"partitionsNum": 128
}'
export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
-d "{
\"collectionName\": \"my_collection\",
\"schema\": $schema,
\"params\": $params
}"
Создание условия фильтрации
При выполнении ANN-поиска в коллекции с включенной функцией Partition Key необходимо включить в запрос поиска выражение фильтрации, включающее Partition Key. В выражении фильтрации можно ограничить значение Partition Key определенным диапазоном, чтобы Milvus ограничил область поиска соответствующими разделами.
При выполнении операций удаления рекомендуется включать выражение фильтрации, в котором указывается один ключ раздела, чтобы добиться более эффективного удаления. Такой подход ограничивает операцию удаления определенным разделом, уменьшая усиление записи при уплотнении и экономя ресурсы для уплотнения и индексирования.
Следующие примеры демонстрируют фильтрацию на основе ключей разделов по конкретному значению ключа раздела и набору значений ключей разделов.
# Filter based on a single partition key value, or
filter='partition_key == "x" && <other conditions>'
# Filter based on multiple partition key values
filter='partition_key in ["x", "y", "z"] && <other conditions>'
// Filter based on a single partition key value, or
String filter = "partition_key == 'x' && <other conditions>";
// Filter based on multiple partition key values
String filter = "partition_key in ['x', 'y', 'z'] && <other conditions>";
// Filter based on a single partition key value, or
filter = "partition_key == 'x' && <other conditions>"
// Filter based on multiple partition key values
filter = "partition_key in ['x', 'y', 'z'] && <other conditions>"
// Filter based on a single partition key value, or
const filter = 'partition_key == "x" && <other conditions>'
// Filter based on multiple partition key values
const filter = 'partition_key in ["x", "y", "z"] && <other conditions>'
# Filter based on a single partition key value, or
export filter='partition_key == "x" && <other conditions>'
# Filter based on multiple partition key values
export filter='partition_key in ["x", "y", "z"] && <other conditions>'
Замените partition_key на имя поля, назначенного в качестве ключа раздела.
Использование изоляции ключей разделов
В сценарии с несколькими арендаторами можно назначить скалярное поле, связанное с идентификаторами арендаторов, в качестве ключа раздела и создать фильтр на основе определенного значения в этом скалярном поле. Чтобы еще больше повысить производительность поиска в подобных сценариях, Milvus представляет функцию Partition Key Isolation.
Изоляция ключей разделов
Как показано на рисунке выше, Milvus группирует сущности на основе значения Partition Key и создает отдельный индекс для каждой из этих групп. Получив запрос на поиск, Milvus находит индекс на основе значения Partition Key, указанного в условии фильтрации, и ограничивает область поиска сущностями, включенными в индекс, что позволяет избежать сканирования нерелевантных сущностей во время поиска и значительно повысить производительность поиска.
После включения функции Partition Key Isolation вы должны включить только одно конкретное значение в фильтр на основе ключа раздела, чтобы Milvus мог ограничить область поиска в пределах сущностей, включенных в индекс, которые соответствуют.
В настоящее время функция Partition-Key Isolation применяется только к поиску с типом индекса, установленным на HNSW.
Включение функции изоляции ключей разделов
В следующих примерах кода показано, как включить функцию Partition Key Isolation.
client.create_collection(
collection_name="my_collection",
schema=schema,
properties={"partitionkey.isolation": True}
)
import io.milvus.v2.service.collection.request.CreateCollectionReq;
Map<String, String> properties = new HashMap<>();
properties.put("partitionkey.isolation", "true");
CreateCollectionReq createCollectionReq = CreateCollectionReq.builder()
.collectionName("my_collection")
.collectionSchema(schema)
.properties(properties)
.build();
client.createCollection(createCollectionReq);
err = client.CreateCollection(ctx,
milvusclient.NewCreateCollectionOption("my_collection", schema).
WithProperty("partitionkey.isolation", true))
if err != nil {
fmt.Println(err.Error())
// handle error
}
res = await client.alterCollection({
collection_name: "my_collection",
properties: {
"partitionkey.isolation": true
}
})
export params='{
"partitionKeyIsolation": true
}'
export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
-d "{
\"collectionName\": \"my_collection\",
\"schema\": $schema,
\"params\": $params
}"
После включения изоляции ключа раздела вы можете задать ключ раздела и количество разделов, как описано в разделе Установка номеров разделов. Обратите внимание, что фильтр на основе ключа раздела должен включать только определенное значение ключа раздела.