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

배열 필드

배열 유형은 동일한 데이터 유형의 여러 값을 포함하는 필드를 저장하는 데 사용됩니다. 여러 요소가 포함된 속성을 유연하게 저장할 수 있는 방법을 제공하므로 관련 데이터 집합을 저장해야 하는 시나리오에서 특히 유용합니다. Milvus에서는 배열 필드를 벡터 데이터와 함께 저장할 수 있으므로 보다 복잡한 쿼리 및 필터링 요구 사항을 충족할 수 있습니다.

예를 들어, 음악 추천 시스템에서 배열 필드는 노래의 태그 목록을 저장할 수 있으며, 사용자 행동 분석에서는 노래에 대한 사용자 평점을 저장할 수 있습니다. 다음은 일반적인 배열 필드의 예입니다.

{
  "tags": ["pop", "rock", "classic"],
  "ratings": [5, 4, 3]
}

이 예에서 tagsratings 은 모두 배열 필드입니다. tags 필드는 팝, 록, 클래식 등의 노래 장르를 나타내는 문자열 배열이고 ratings 필드는 노래에 대한 사용자 평점을 나타내는 1에서 5까지의 정수 배열입니다. 이러한 배열 필드는 여러 값의 데이터를 유연하게 저장할 수 있는 방법을 제공하여 쿼리 및 필터링 중에 세부 분석을 쉽게 수행할 수 있도록 해줍니다.

배열 필드 추가

Milvus에서 배열 필드를 사용하려면 컬렉션 스키마를 만들 때 관련 필드 유형을 정의하세요. 이 프로세스에는 다음이 포함됩니다.

  1. datatype 을 지원되는 배열 데이터 유형인 ARRAY 으로 설정합니다.

  2. element_type 매개변수를 사용하여 배열에 있는 요소의 데이터 유형을 지정합니다. VARCHAR 또는 INT64 과 같이 Milvus에서 지원하는 모든 스칼라 데이터 유형이 될 수 있습니다. 동일한 배열의 모든 요소는 동일한 데이터 유형이어야 합니다.

  3. max_capacity 매개변수를 사용하여 배열의 최대 용량, 즉 배열에 포함할 수 있는 최대 요소 수를 정의합니다.

배열 필드를 포함하는 컬렉션 스키마를 정의하는 방법은 다음과 같습니다.

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://localhost:19530")

schema = client.create_schema(
    auto_id=False,
    enable_dynamic_fields=True,
)

# Add an Array field with elements of type VARCHAR
schema.add_field(field_name="tags", datatype=DataType.ARRAY, element_type=DataType.VARCHAR, max_capacity=10)
# Add an Array field with elements of type INT64
schema.add_field(field_name="ratings", datatype=DataType.ARRAY, element_type=DataType.INT64, max_capacity=5)

# Add primary field
schema.add_field(field_name="pk", datatype=DataType.INT64, is_primary=True)

# Add vector field
schema.add_field(field_name="embedding", datatype=DataType.FLOAT_VECTOR, dim=3)

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")
        .build());
        
CreateCollectionReq.CollectionSchema schema = client.createSchema();
schema.setEnableDynamicField(true);

schema.addField(AddFieldReq.builder()
        .fieldName("tags")
        .dataType(DataType.Array)
        .elementType(DataType.VarChar)
        .maxCapacity(10)
        .build());

schema.addField(AddFieldReq.builder()
        .fieldName("ratings")
        .dataType(DataType.Array)
        .elementType(DataType.Int64)
        .maxCapacity(5)
        .build());

schema.addField(AddFieldReq.builder()
        .fieldName("pk")
        .dataType(DataType.Int64)
        .isPrimaryKey(true)
        .build());

schema.addField(AddFieldReq.builder()
        .fieldName("embedding")
        .dataType(DataType.FloatVector)
        .dimension(3)
        .build());

import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";
const schema = [
  {
    name: "tags",
    data_type: DataType.Array,
    element_type: DataType.VarChar,
    max_capacity: 10,
    max_length: 65535
  },
  {
    name: "rating",
    data_type: DataType.Array,
    element_type: DataType.Int64,
    max_capacity: 5,
  },
  {
    name: "pk",
    data_type: DataType.Int64,
    is_primary_key: true,
  },
  {
    name: "embedding",
    data_type: DataType.FloatVector,
    dim: 3,
  },
];

export arrayField1='{
    "fieldName": "tags",
    "dataType": "Array",
    "elementDataType": "VarChar",
    "elementTypeParams": {
        "max_capacity": 10,
        "max_length": 100
    }
}'

export arrayField2='{
    "fieldName": "ratings",
    "dataType": "Array",
    "elementDataType": "Int64",
    "elementTypeParams": {
        "max_capacity": 5
    }
}'

export pkField='{
    "fieldName": "pk",
    "dataType": "Int64",
    "isPrimary": true
}'

export vectorField='{
    "fieldName": "embedding",
    "dataType": "FloatVector",
    "elementTypeParams": {
        "dim": 3
    }
}'

export schema="{
    \"autoID\": false,
    \"fields\": [
        $arrayField1,
        $arrayField2,
        $pkField,
        $vectorField
    ]
}"

이 예제에서

  • tags 는 문자열 배열이며 element_typeVARCHAR 로 설정되어 배열의 요소가 문자열이어야 함을 나타냅니다. max_capacity 는 10 으로 설정되어 배열에 최대 10 개의 요소가 포함될 수 있음을 의미합니다.

  • ratingselement_typeINT64 으로 설정된 정수 배열로, 요소는 정수여야 함을 나타냅니다. max_capacity 는 5로 설정되어 최대 5개의 등급을 허용합니다.

  • 또한 기본 키 필드 pk 와 벡터 필드 embedding 를 추가합니다.

기본 필드와 벡터 필드는 컬렉션을 만들 때 필수입니다. 기본 필드는 각 엔티티를 고유하게 식별하며, 벡터 필드는 유사성 검색에 중요합니다. 자세한 내용은 기본 필드 및 자동 ID, 고밀도 벡터, 이진 벡터 또는 스파스 벡터를 참조하세요.

인덱스 매개변수 설정

배열 필드에 대한 인덱스 매개변수를 설정하는 것은 선택 사항이지만 검색 효율성을 크게 향상시킬 수 있습니다.

다음 예제에서는 tags 필드에 대해 AUTOINDEX 을 생성하여 Milvus가 데이터 유형에 따라 적절한 스칼라 인덱스를 자동으로 생성합니다.

# Prepare index parameters
index_params = client.prepare_index_params()  # Prepare IndexParams object

index_params.add_index(
    field_name="tags",  # Name of the Array field to index
    index_type="AUTOINDEX",  # Index type
    index_name="inverted_index"  # Index name
)

import io.milvus.v2.common.IndexParam;
import java.util.*;

List<IndexParam> indexes = new ArrayList<>();
indexes.add(IndexParam.builder()
        .fieldName("tags")
        .indexName("inverted_index")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .build());

const indexParams = [{
    index_name: 'inverted_index',
    field_name: 'tags',
    index_type: IndexType.AUTOINDEX,
)];

export indexParams='[
        {
            "fieldName": "tags",
            "indexName": "inverted_index",
            "indexType": "AUTOINDEX"
        }
    ]'

AUTOINDEX 외에도 INVERTED 또는 BITMAP 와 같은 다른 스칼라 인덱스 유형을 지정할 수 있습니다. 지원되는 인덱스 유형은 스칼라 인덱스를 참조하세요.

또한 컬렉션을 만들기 전에 벡터 필드에 대한 인덱스를 만들어야 합니다. 이 예에서는 벡터 인덱스 설정을 간소화하기 위해 AUTOINDEX 을 사용합니다.

# Add vector index
index_params.add_index(
    field_name="embedding",
    index_type="AUTOINDEX",  # Use automatic indexing to simplify complex index settings
    metric_type="COSINE"  # Specify similarity metric type, such as L2, COSINE, or IP
)

indexes.add(IndexParam.builder()
        .fieldName("embedding")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .metricType(IndexParam.MetricType.COSINE)
        .build());

 indexParams.push({
    index_name: 'embedding_index',
    field_name: 'embedding',
    index_type: IndexType.AUTOINDEX,
});

export indexParams='[
        {
            "fieldName": "tags",
            "indexName": "inverted_index",
            "indexType": "AUTOINDEX"
        },
        {
            "fieldName": "embedding",
            "metricType": "COSINE",
            "indexType": "AUTOINDEX"
        }
    ]'

컬렉션 만들기

정의된 스키마 및 인덱스 매개변수를 사용하여 컬렉션을 만듭니다.

client.create_collection(
    collection_name="my_array_collection",
    schema=schema,
    index_params=index_params
)

CreateCollectionReq requestCreate = CreateCollectionReq.builder()
        .collectionName("my_array_collection")
        .collectionSchema(schema)
        .indexParams(indexes)
        .build();
client.createCollection(requestCreate);

client.create_collection({
    collection_name: "my_array_collection",
    schema: schema,
    index_params: indexParams
})

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d "{
    \"collectionName\": \"my_array_collection\",
    \"schema\": $schema,
    \"indexParams\": $indexParams
}"

데이터 삽입

컬렉션을 만든 후 배열 필드를 포함하는 데이터를 삽입할 수 있습니다.

data = [
    {
        "tags": ["pop", "rock", "classic"],
        "ratings": [5, 4, 3],
        "pk": 1,
        "embedding": [0.12, 0.34, 0.56]
    },
    {
        "tags": ["jazz", "blues"],
        "ratings": [4, 5],
        "pk": 2,
        "embedding": [0.78, 0.91, 0.23]
    },
    {
        "tags": ["electronic", "dance"],
        "ratings": [3, 3, 4],
        "pk": 3,
        "embedding": [0.67, 0.45, 0.89]
    }
]

client.insert(
    collection_name="my_array_collection",
    data=data
)

import com.google.gson.Gson;
import com.google.gson.JsonObject;

import io.milvus.v2.service.vector.request.InsertReq;
import io.milvus.v2.service.vector.response.InsertResp;

List<JsonObject> rows = new ArrayList<>();
Gson gson = new Gson();
rows.add(gson.fromJson("{\"tags\": [\"pop\", \"rock\", \"classic\"], \"ratings\": [5, 4, 3], \"pk\": 1, \"embedding\": [0.1, 0.2, 0.3]}", JsonObject.class));
rows.add(gson.fromJson("{\"tags\": [\"jazz\", \"blues\"], \"ratings\": [4, 5], \"pk\": 2, \"embedding\": [0.4, 0.5, 0.6]}", JsonObject.class));
rows.add(gson.fromJson("{\"tags\": [\"electronic\", \"dance\"], \"ratings\": [3, 3, 4], \"pk\": 3, \"embedding\": [0.7, 0.8, 0.9]}", JsonObject.class));

InsertResp insertR = client.insert(InsertReq.builder()
        .collectionName("my_array_collection")
        .data(rows)
        .build());

const data = [
    {
        "tags": ["pop", "rock", "classic"],
        "ratings": [5, 4, 3],
        "pk": 1,
        "embedding": [0.12, 0.34, 0.56]
    },
    {
        "tags": ["jazz", "blues"],
        "ratings": [4, 5],
        "pk": 2,
        "embedding": [0.78, 0.91, 0.23]
    },
    {
        "tags": ["electronic", "dance"],
        "ratings": [3, 3, 4],
        "pk": 3,
        "embedding": [0.67, 0.45, 0.89]
    }
];

client.insert({
  collection_name: "my_array_collection",
  data: data,
});

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "data": [
        {
        "tags": ["pop", "rock", "classic"],
        "ratings": [5, 4, 3],
        "pk": 1,
        "embedding": [0.12, 0.34, 0.56]
    },
    {
        "tags": ["jazz", "blues"],
        "ratings": [4, 5],
        "pk": 2,
        "embedding": [0.78, 0.91, 0.23]
    },
    {
        "tags": ["electronic", "dance"],
        "ratings": [3, 3, 4],
        "pk": 3,
        "embedding": [0.67, 0.45, 0.89]
    }       
    ],
    "collectionName": "my_array_collection"
}'

이 예제에서는

  • 각 데이터 항목에는 기본 필드(pk)가 포함되어 있고 tagsratings 는 태그와 등급을 저장하는 데 사용되는 배열 필드입니다.

  • embedding 는 벡터 유사도 검색에 사용되는 3차원 벡터 필드입니다.

검색 및 쿼리

배열 필드는 검색 중에 스칼라 필터링을 가능하게 하여 Milvus의 벡터 검색 기능을 향상시킵니다. 벡터 유사도 검색과 함께 배열 필드의 속성을 기반으로 쿼리할 수 있습니다.

쿼리 필터링

특정 요소에 액세스하거나 배열 요소가 특정 조건을 충족하는지 확인하는 등 배열 필드의 속성을 기반으로 데이터를 필터링할 수 있습니다.

filter = 'ratings[0] < 4'

res = client.query(
    collection_name="my_array_collection",
    filter=filter,
    output_fields=["tags", "ratings", "embedding"]
)

print(res)

# Output
# data: ["{'pk': 3, 'tags': ['electronic', 'dance'], 'ratings': [3, 3, 4], 'embedding': [np.float32(0.67), np.float32(0.45), np.float32(0.89)]}"] 

import io.milvus.v2.service.vector.request.QueryReq;
import io.milvus.v2.service.vector.response.QueryResp;

String filter = "ratings[0] < 4";
QueryResp resp = client.query(QueryReq.builder()
        .collectionName("my_array_collection")
        .filter(filter)
        .outputFields(Arrays.asList("tags", "ratings", "embedding"))
        .build());

System.out.println(resp.getQueryResults());

// Output
//
// [QueryResp.QueryResult(entity={ratings=[3, 3, 4], pk=3, embedding=[0.7, 0.8, 0.9], tags=[electronic, dance]})]

client.query({
    collection_name: 'my_array_collection',
    filter: 'ratings[0] < 4',
    output_fields: ['tags', 'ratings', 'embedding']
});

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/query" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "collectionName": "my_array_collection",
    "filter": "ratings[0] < 4",
    "outputFields": ["tags", "ratings", "embedding"]
}'
# {"code":0,"cost":0,"data":[{"embedding":[0.67,0.45,0.89],"pk":3,"ratings":{"Data":{"LongData":{"data":[3,3,4]}}},"tags":{"Data":{"StringData":{"data":["electronic","dance"]}}}}]}

이 쿼리에서 Milvus는 ratings 배열의 첫 번째 요소가 4보다 작은 엔티티를 필터링하여 조건에 일치하는 엔티티를 반환합니다.

배열 필터링을 사용한 벡터 검색

벡터 유사도와 배열 필터링을 결합하면 검색된 데이터가 의미론적으로 유사할 뿐만 아니라 특정 조건을 충족하는지 확인하여 검색 결과를 보다 정확하고 비즈니스 요구사항에 맞게 만들 수 있습니다.

filter = 'tags[0] == "pop"'

res = client.search(
    collection_name="my_array_collection",
    data=[[0.3, -0.6, 0.1]],
    limit=5,
    search_params={"params": {"nprobe": 10}},
    output_fields=["tags", "ratings", "embedding"],
    filter=filter
)

print(res)

# Output
# data: ["[{'id': 1, 'distance': 1.1276001930236816, 'entity': {'ratings': [5, 4, 3], 'embedding': [0.11999999731779099, 0.3400000035762787, 0.5600000023841858], 'tags': ['pop', 'rock', 'classic']}}]"]

import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.response.SearchResp;

String filter = "tags[0] == \"pop\"";
SearchResp resp = client.search(SearchReq.builder()
        .collectionName("my_array_collection")
        .annsField("embedding")
        .data(Collections.singletonList(new FloatVec(new float[]{0.3f, -0.6f, 0.1f})))
        .topK(5)
        .outputFields(Arrays.asList("tags", "ratings", "embedding"))
        .filter(filter)
        .build());

System.out.println(resp.getSearchResults());

// Output
//
// [[SearchResp.SearchResult(entity={ratings=[5, 4, 3], embedding=[0.1, 0.2, 0.3], tags=[pop, rock, classic]}, score=-0.2364331, id=1)]]

client.search({
    collection_name: 'my_array_collection',
    data: [0.3, -0.6, 0.1],
    limit: 5,
    output_fields: ['tags', 'ratings', 'embdding'],
    filter: 'tags[0] == "pop"'
});

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "collectionName": "my_array_collection",
    "data": [
        [0.3, -0.6, 0.1]
    ],
    "annsField": "embedding",
    "limit": 5,
    "filter": "tags[0] == \"pop\"",
    "outputFields": ["tags", "ratings", "embedding"]
}'

# {"code":0,"cost":0,"data":[{"distance":-0.24793813,"embedding":[0.12,0.34,0.56],"id":1,"ratings":{"Data":{"LongData":{"data":[5,4,3]}}},"tags":{"Data":{"StringData":{"data":["pop","rock","classic"]}}}}]}

이 예제에서 Milvus는 쿼리 벡터와 가장 유사한 상위 5개 엔티티를 반환하며, tags 배열의 첫 번째 요소는 "pop" 입니다.

또한 Milvus는 ARRAY_CONTAINS, ARRAY_CONTAINS_ALL, ARRAY_CONTAINS_ANY, ARRAY_LENGTH 과 같은 고급 배열 필터링 연산자를 지원하여 쿼리 기능을 더욱 향상시킵니다. 자세한 내용은 메타데이터 필터링을 참조하세요.

제한 사항

  • 데이터 유형: 배열 필드의 모든 요소는 element_type 에 지정된 대로 동일한 데이터 유형을 가져야 합니다.

  • 배열 용량: 배열 필드의 요소 수는 max_capacity 에 지정된 대로 배열을 생성할 때 정의된 최대 용량보다 작거나 같아야 합니다.

  • 문자열 처리: 배열 필드의 문자열 값은 의미 이스케이프나 변환 없이 있는 그대로 저장됩니다. 예를 들어 'a"b', "a'b", 'a\'b', "a\"b" 은 입력한 대로 저장되지만 'a'b'"a"b" 은 잘못된 값으로 간주됩니다.

번역DeepL

Try Managed Milvus for Free

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

Get Started
피드백

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