milvus-logo
LFAI
홈페이지
  • 사용자 가이드

파티션 키 사용

이 가이드에서는 컬렉션에서 데이터 검색 속도를 높이기 위해 파티션 키를 사용하는 방법을 안내합니다.

개요

컬렉션의 특정 필드를 파티션 키로 설정하면 Milvus가 이 필드의 각 파티션 값에 따라 들어오는 엔티티를 다른 파티션으로 분배할 수 있습니다. 이렇게 하면 키 값이 동일한 엔티티를 파티션에 그룹화할 수 있으므로 키 필드로 필터링할 때 관련 없는 파티션을 스캔할 필요가 없어 검색 성능이 빨라집니다. 기존 필터링 방법과 비교했을 때, 파티션 키는 쿼리 성능을 크게 향상시킬 수 있습니다.

파티션 키를 사용하여 멀티테넌시를 구현할 수 있습니다. 멀티 테넌시에 대한 자세한 내용은 멀티 테넌시에서 자세히 알아보세요.

파티션 키 사용

필드를 파티션 키로 설정하려면 컬렉션 스키마를 만들 때 partition_key_field 을 지정합니다.

아래 예제 코드에서 num_partitions 은 생성될 파티션의 수를 결정합니다. 기본적으로 64 으로 설정되어 있습니다. 기본값을 그대로 유지하는 것이 좋습니다.

매개 변수에 대한 자세한 내용은 MilvusClient, create_schema()add_field() 를 참조하세요.

파라미터에 대한 자세한 내용은 MilvusClientV2, createSchema()addField() 를 참조하세요.

파라미터에 대한 자세한 내용은 MilvusClientcreateCollection() 를 참조하세요.

import random, time
from pymilvus import connections, MilvusClient, DataType

SERVER_ADDR = "http://localhost:19530"

# 1. Set up a Milvus client
client = MilvusClient(
    uri=SERVER_ADDR
)

# 2. Create a collection
schema = MilvusClient.create_schema(
    auto_id=False,
    enable_dynamic_field=True,
    partition_key_field="color",
    num_partitions=64 # Number of partitions. Defaults to 64.
)

schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=5)
schema.add_field(field_name="color", datatype=DataType.VARCHAR, max_length=512)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
import io.milvus.v2.common.IndexParam;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;

String CLUSTER_ENDPOINT = "http://localhost:19530";

// 1. Connect to Milvus server
ConnectConfig connectConfig = ConnectConfig.builder()
    .uri(CLUSTER_ENDPOINT)
    .build();

MilvusClientV2 client = new MilvusClientV2(connectConfig);

// 2. Create a collection in customized setup mode

// 2.1 Create schema
CreateCollectionReq.CollectionSchema schema = client.createSchema();
schema.setEnableDynamicField(true);

// 2.2 Add fields to schema
schema.addField(AddFieldReq.builder()
        .fieldName("id")
        .dataType(DataType.Int64)
        .isPrimaryKey(true)
        .autoID(false)
        .build());

schema.addField(AddFieldReq.builder()
        .fieldName("vector")
        .dataType(DataType.FloatVector)
        .dimension(5)
        .build());

schema.addField(AddFieldReq.builder()
        .fieldName("color")
        .dataType(DataType.VarChar)
        .maxLength(512)
        .isPartitionKey(true)
        .build());
const { MilvusClient, DataType, sleep } = require("@zilliz/milvus2-sdk-node")

const address = "http://localhost:19530"

async function main() {
// 1. Set up a Milvus Client
client = new MilvusClient({address}); 

// 2. Create a collection
// 2.1 Define fields
const fields = [
    {
        name: "id",
        data_type: DataType.Int64,
        is_primary_key: true,
        auto_id: false
    },
    {
        name: "vector",
        data_type: DataType.FloatVector,
        dim: 5
    },
    {
        name: "color",
        data_type: DataType.VarChar,
        max_length: 512,
        is_partition_key: true
    }
]

필드를 정의한 후 인덱스 매개변수를 설정합니다.

index_params = MilvusClient.prepare_index_params()

index_params.add_index(
    field_name="id",
    index_type="STL_SORT"
)

index_params.add_index(
    field_name="color",
    index_type="Trie"
)

index_params.add_index(
    field_name="vector",
    index_type="IVF_FLAT",
    metric_type="L2",
    params={"nlist": 1024}
)
// 2.3 Prepare index parameters
Map<String, Object> params = new HashMap<>();
params.put("nlist", 1024);
IndexParam indexParamForVectorField = IndexParam.builder()
        .fieldName("vector")
        .indexType(IndexParam.IndexType.IVF_FLAT)
        .metricType(IndexParam.MetricType.IP)
        .extraParams(params)
        .build();

List<IndexParam> indexParams = new ArrayList<>();
indexParams.add(indexParamForVectorField);
// 2.2 Prepare index parameters
const index_params = [{
    field_name: "color",
    index_type: "Trie"
},{
    field_name: "id",
    index_type: "STL_SORT"
},{
    field_name: "vector",
    index_type: "IVF_FLAT",
    metric_type: "IP",
    params: { nlist: 1024}
}]

마지막으로 컬렉션을 만들 수 있습니다.

client.create_collection(
    collection_name="test_collection",
    schema=schema,
    index_params=index_params
)
// 2.4 Create a collection with schema and index parameters
CreateCollectionReq customizedSetupReq = CreateCollectionReq.builder()
        .collectionName("test_collection")
        .collectionSchema(schema)
        .indexParams(indexParams)
        .build();

client.createCollection(customizedSetupReq);
// 2.3 Create a collection with fields and index parameters
res = await client.createCollection({
    collection_name: "test_collection",
    fields: fields, 
    index_params: index_params,
})

console.log(res.error_code)

// Output
// 
// Success
//

목록 파티션

컬렉션의 필드가 파티션 키로 사용되면 Milvus는 지정된 수의 파티션을 생성하고 사용자를 대신하여 관리합니다. 따라서 이 컬렉션의 파티션은 더 이상 조작할 수 없습니다.

다음 코드 조각은 컬렉션의 필드 중 하나가 파티션 키로 사용되면 컬렉션에 64개의 파티션이 생성되는 것을 보여줍니다.

데이터 삽입

컬렉션이 준비되면 다음과 같이 데이터 삽입을 시작합니다:

데이터 준비

# 3. Insert randomly generated vectors 
colors = ["green", "blue", "yellow", "red", "black", "white", "purple", "pink", "orange", "brown", "grey"]
data = []

for i in range(1000):
    current_color = random.choice(colors)
    current_tag = random.randint(1000, 9999)
    data.append({
        "id": i,
        "vector": [ random.uniform(-1, 1) for _ in range(5) ],
        "color": current_color,
        "tag": current_tag,
        "color_tag": f"{current_color}_{str(current_tag)}"
    })

print(data[0])
// 3. Insert randomly generated vectors
List<String> colors = Arrays.asList("green", "blue", "yellow", "red", "black", "white", "purple", "pink", "orange", "brown", "grey");
List<JsonObject> data = new ArrayList<>();

Gson gson = new Gson();
Random rand = new Random();
for (int i=0; i<1000; i++) {
    String current_color = colors.get(rand.nextInt(colors.size()-1));
    int current_tag = rand.nextInt(8999) + 1000;
    JsonObject row = new JsonObject();
    row.addProperty("id", (long) i);
    row.add("vector", gson.toJsonTree(Arrays.asList(rand.nextFloat(), rand.nextFloat(), rand.nextFloat(), rand.nextFloat(), rand.nextFloat())));
    row.addProperty("color", current_color);
    row.addProperty("tag", current_tag);
    row.addProperty("color_tag", current_color + "_" + (rand.nextInt(8999) + 1000));
    data.add(row);
}

System.out.println(data.get(0));
// 3. Insert randomly generated vectors 
const colors = ["green", "blue", "yellow", "red", "black", "white", "purple", "pink", "orange", "brown", "grey"]
var data = []

for (let i = 0; i < 1000; i++) {
    const current_color = colors[Math.floor(Math.random() * colors.length)]
    const current_tag = Math.floor(Math.random() * 8999 + 1000)
    data.push({
        id: i,
        vector: [Math.random(), Math.random(), Math.random(), Math.random(), Math.random()],
        color: current_color,
        tag: current_tag,
        color_tag: `${current_color}_${current_tag}`
    })
}

console.log(data[0])

첫 번째 항목을 확인하여 생성된 데이터의 구조를 볼 수 있습니다.

{
    id: 0,
    vector: [
        0.1275656405044483,
        0.47417858592773277,
        0.13858264437643286,
        0.2390904907020377,
        0.8447862593689635
    ],
    color: 'blue',
    tag: 2064,
    color_tag: 'blue_2064'
}

데이터 삽입

컬렉션에 데이터를 삽입하려면 insert() 메서드를 사용하여 컬렉션에 데이터를 삽입합니다.

컬렉션에 데이터를 삽입하려면 insert() 메서드를 사용하여 컬렉션에 데이터를 삽입합니다.

컬렉션에 데이터를 삽입하려면 insert() 메서드를 사용하여 컬렉션에 데이터를 삽입합니다.

res = client.insert(
    collection_name="test_collection",
    data=data
)

print(res)

# Output
#
# {
#     "insert_count": 1000,
#     "ids": [
#         0,
#         1,
#         2,
#         3,
#         4,
#         5,
#         6,
#         7,
#         8,
#         9,
#         "(990 more items hidden)"
#     ]
# }
// 3.1 Insert data into the collection
InsertReq insertReq = InsertReq.builder()
        .collectionName("test_collection")
        .data(data)
        .build();

InsertResp insertResp = client.insert(insertReq);

System.out.println(insertResp.getInsertCnt());

// Output:
// 1000
res = await client.insert({
    collection_name: "test_collection",
    data: data,
})

console.log(res.insert_cnt)

// Output
// 
// 1000
// 

파티션 키 사용

컬렉션을 색인하고 로드하고 데이터를 삽입한 후에는 파티션 키를 사용하여 유사성 검색을 수행할 수 있습니다.

매개변수에 대한 자세한 내용은 search() 를 참조하세요.

매개변수에 대한 자세한 내용은 search() 를 참조하세요.

파라미터에 대한 자세한 내용은 search() 를 참조하세요.

참고

파티션 키를 사용하여 유사도 검색을 수행하려면 검색 요청의 부울 표현식에 다음 중 하나를 포함해야 합니다:

  • expr='<partition_key>=="xxxx"'

  • expr='<partition_key> in ["xxx", "xxx"]'

<partition_key> 을 파티션 키로 지정된 필드의 이름으로 대체하세요.

# 4. Search with partition key
query_vectors = [[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]]

res = client.search(
    collection_name="test_collection",
    data=query_vectors,
    filter="color == 'green'",
    search_params={"metric_type": "L2", "params": {"nprobe": 10}},
    output_fields=["id", "color_tag"],
    limit=3
)

print(res)

# Output
#
# [
#     [
#         {
#             "id": 970,
#             "distance": 0.5770174264907837,
#             "entity": {
#                 "id": 970,
#                 "color_tag": "green_9828"
#             }
#         },
#         {
#             "id": 115,
#             "distance": 0.6898155808448792,
#             "entity": {
#                 "id": 115,
#                 "color_tag": "green_4073"
#             }
#         },
#         {
#             "id": 899,
#             "distance": 0.7028976678848267,
#             "entity": {
#                 "id": 899,
#                 "color_tag": "green_9897"
#             }
#         }
#     ]
# ]
// 4. Search with partition key
List<BaseVector> query_vectors = Collections.singletonList(new FloatVec(new float[]{0.3580376395471989f, -0.6023495712049978f, 0.18414012509913835f, -0.26286205330961354f, 0.9029438446296592f}));

SearchReq searchReq = SearchReq.builder()
        .collectionName("test_collection")
        .data(query_vectors)
        .filter("color == \"green\"")
        .topK(3)
        .outputFields(Collections.singletonList("color_tag"))
        .build();

SearchResp searchResp = client.search(searchReq);

List<List<SearchResp.SearchResult>> searchResults = searchResp.getSearchResults();
for (List<SearchResp.SearchResult> results : searchResults) {
    System.out.println("TopK results:");
    for (SearchResp.SearchResult result : results) {
        System.out.println(result);
    }
}

// Output:
// SearchResp.SearchResult(entity={color_tag=green_4945}, score=1.192079, id=542)
// SearchResp.SearchResult(entity={color_tag=green_4633}, score=0.9138917, id=144)
// SearchResp.SearchResult(entity={color_tag=green_8038}, score=0.8381896, id=962)
// 4. Search with partition key
const query_vectors = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]

res = await client.search({
    collection_name: "test_collection",
    data: query_vectors,
    filter: "color == 'green'",
    output_fields: ["color_tag"],
    limit: 3
})

console.log(res.results)

// Output
// 
// [
//   { score: 2.402090549468994, id: '135', color_tag: 'green_2694' },
//   { score: 2.3938629627227783, id: '326', color_tag: 'green_7104' },
//   { score: 2.3235254287719727, id: '801', color_tag: 'green_3162' }
// ]
// 

일반적인 사용 사례

파티션 키 기능을 활용하여 검색 성능을 개선하고 멀티테넌시를 활성화할 수 있습니다. 각 엔티티의 파티션 키 필드에 테넌트별 값을 할당하면 됩니다. 컬렉션을 검색하거나 쿼리할 때 부울 표현식에 파티션 키 필드를 포함시켜 테넌트별 값을 기준으로 엔티티를 필터링할 수 있습니다. 이 접근 방식은 테넌트별 데이터 격리를 보장하고 불필요한 파티션 스캔을 피할 수 있습니다.

번역DeepL

Try Managed Milvus for Free

Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

Get Started
피드백

이 페이지가 도움이 되었나요?