JSON 필드
JSON (JavaScript 객체 표기법)은 복잡한 데이터 구조를 저장하고 쿼리할 수 있는 유연한 방법을 제공하는 경량 데이터 교환 형식입니다. Milvus에서는 JSON 필드를 사용하여 벡터 데이터와 함께 추가적인 구조화된 정보를 저장할 수 있으므로 벡터 유사성과 구조화된 필터링을 결합한 고급 검색 및 쿼리가 가능합니다.
JSON 필드는 검색 결과를 최적화하기 위해 메타데이터가 필요한 애플리케이션에 이상적입니다. 예를 들어, 이커머스에서는 카테고리, 가격, 브랜드와 같은 속성으로 제품 벡터를 강화할 수 있습니다. 추천 시스템에서는 사용자 벡터를 선호도 및 인구통계학적 정보와 결합할 수 있습니다. 다음은 일반적인 JSON 필드의 예입니다.
{
"category": "electronics",
"price": 99.99,
"brand": "BrandA"
}
JSON 필드 추가하기
Milvus에서 JSON 필드를 사용하려면 컬렉션 스키마에서 관련 필드 유형을 정의하고 datatype
을 지원되는 JSON 유형(예: JSON
으로 설정합니다.
JSON 필드를 포함하는 컬렉션 스키마를 정의하는 방법은 다음과 같습니다.
from pymilvus import MilvusClient, DataType
client = MilvusClient(uri="http://localhost:19530")
schema = client.create_schema(
auto_id=False,
enable_dynamic_fields=True,
)
schema.add_field(field_name="metadata", datatype=DataType.JSON)
schema.add_field(field_name="pk", datatype=DataType.INT64, is_primary=True)
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("metadata")
.dataType(DataType.JSON)
.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: "metadata",
data_type: DataType.JSON,
},
{
name: "pk",
data_type: DataType.Int64,
is_primary_key: true,
},
{
name: "embedding",
data_type: DataType.FloatVector,
dim: 3,
},
];
export jsonField='{
"fieldName": "metadata",
"dataType": "JSON"
}'
export pkField='{
"fieldName": "pk",
"dataType": "Int64",
"isPrimary": true
}'
export vectorField='{
"fieldName": "embedding",
"dataType": "FloatVector",
"elementTypeParams": {
"dim": 3
}
}'
export schema="{
\"autoID\": false,
\"fields\": [
$jsonField,
$pkField,
$vectorField
]
}"
이 예에서는 제품 카테고리, 가격, 브랜드 정보 등 벡터 데이터와 관련된 추가 메타데이터를 저장하기 위해 metadata
이라는 JSON 필드를 추가합니다.
기본 필드와 벡터 필드는 컬렉션을 만들 때 필수입니다. 기본 필드는 각 엔티티를 고유하게 식별하는 반면, 벡터 필드는 유사성 검색에 매우 중요합니다. 자세한 내용은 기본 필드 및 자동 ID, 고밀도 벡터, 이진 벡터 또는 스파스 벡터를 참조하세요.
컬렉션 만들기
컬렉션을 만들 때 검색 성능을 보장하기 위해 벡터 필드에 대한 인덱스를 만들어야 합니다. 이 예에서는 인덱스 설정을 간소화하기 위해 AUTOINDEX
을 사용합니다. 자세한 내용은 자동 인덱스를 참조하세요.
index_params = client.prepare_index_params()
index_params.add_index(
field_name="embedding",
index_type="AUTOINDEX",
metric_type="COSINE"
)
import io.milvus.v2.common.IndexParam;
import java.util.*;
List<IndexParam> indexes = new ArrayList<>();
indexes.add(IndexParam.builder()
.fieldName("embedding")
.indexType(IndexParam.IndexType.AUTOINDEX)
.metricType(IndexParam.MetricType.COSINE)
.build());
const indexParams = {
index_name: 'embedding_index',
field_name: 'embedding',
metricType: MetricType.CONSINE,
index_type: IndexType.AUTOINDEX,
);
export indexParams='[
{
"fieldName": "embedding",
"metricType": "COSINE",
"indexType": "AUTOINDEX"
}
]'
정의된 스키마 및 인덱스 매개변수를 사용하여 컬렉션을 생성합니다.
client.create_collection(
collection_name="my_json_collection",
schema=schema,
index_params=index_params
)
CreateCollectionReq requestCreate = CreateCollectionReq.builder()
.collectionName("my_json_collection")
.collectionSchema(schema)
.indexParams(indexes)
.build();
client.createCollection(requestCreate);
client.create_collection({
collection_name: "my_json_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_json_collection\",
\"schema\": $schema,
\"indexParams\": $indexParams
}"
데이터 삽입
컬렉션을 생성한 후 JSON 필드를 포함하는 데이터를 삽입할 수 있습니다.
# Data to be inserted
data = [
{
"metadata": {"category": "electronics", "price": 99.99, "brand": "BrandA"},
"pk": 1,
"embedding": [0.12, 0.34, 0.56]
},
{
"metadata": {"category": "home_appliances", "price": 249.99, "brand": "BrandB"},
"pk": 2,
"embedding": [0.56, 0.78, 0.90]
},
{
"metadata": {"category": "furniture", "price": 399.99, "brand": "BrandC"},
"pk": 3,
"embedding": [0.91, 0.18, 0.23]
}
]
# Insert data into the collection
client.insert(
collection_name="your_collection_name",
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("{\"metadata\": {\"category\": \"electronics\", \"price\": 99.99, \"brand\": \"BrandA\"}, \"pk\": 1, \"embedding\": [0.1, 0.2, 0.3]}", JsonObject.class));
rows.add(gson.fromJson("{\"metadata\": {\"category\": \"home_appliances\", \"price\": 249.99, \"brand\": \"BrandB\"}, \"pk\": 2, \"embedding\": [0.4, 0.5, 0.6]}", JsonObject.class));
rows.add(gson.fromJson("{\"metadata\": {\"category\": \"furniture\", \"price\": 399.99, \"brand\": \"BrandC\"}, \"pk\": 3, \"embedding\": [0.7, 0.8, 0.9]}", JsonObject.class));
InsertResp insertR = client.insert(InsertReq.builder()
.collectionName("my_json_collection")
.data(rows)
.build());
const data = [
{
"metadata": {"category": "electronics", "price": 99.99, "brand": "BrandA"},
"pk": 1,
"embedding": [0.12, 0.34, 0.56]
},
{
"metadata": {"category": "home_appliances", "price": 249.99, "brand": "BrandB"},
"pk": 2,
"embedding": [0.56, 0.78, 0.90]
},
{
"metadata": {"category": "furniture", "price": 399.99, "brand": "BrandC"},
"pk": 3,
"embedding": [0.91, 0.18, 0.23]
}
]
client.insert({
collection_name: "my_json_collection",
data: data
});
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"data": [
{
"metadata": {"category": "electronics", "price": 99.99, "brand": "BrandA"},
"pk": 1,
"embedding": [0.12, 0.34, 0.56]
},
{
"metadata": {"category": "home_appliances", "price": 249.99, "brand": "BrandB"},
"pk": 2,
"embedding": [0.56, 0.78, 0.90]
},
{
"metadata": {"category": "furniture", "price": 399.99, "brand": "BrandC"},
"pk": 3,
"embedding": [0.91, 0.18, 0.23]
}
],
"collectionName": "my_json_collection"
}'
이 예제에서는
각 데이터 항목에는 제품 카테고리, 가격, 브랜드 등의 정보를 저장하는 기본 필드(
pk
),metadata
이 JSON 필드로 포함되어 있습니다.embedding
는 벡터 유사도 검색에 사용되는 3차원 벡터 필드입니다.
검색 및 쿼리
JSON 필드는 검색 시 스칼라 필터링이 가능하여 Milvus의 벡터 검색 기능을 향상시킵니다. 벡터 유사도와 함께 JSON 속성을 기반으로 쿼리할 수 있습니다.
쿼리 필터링
특정 값을 일치시키거나 특정 범위 내에 숫자가 있는지 확인하는 등 JSON 속성을 기반으로 데이터를 필터링할 수 있습니다.
filter = 'metadata["category"] == "electronics" and metadata["price"] < 150'
res = client.query(
collection_name="my_json_collection",
filter=filter,
output_fields=["metadata"]
)
print(res)
# Output
# data: ["{'metadata': {'category': 'electronics', 'price': 99.99, 'brand': 'BrandA'}, 'pk': 1}"]
import io.milvus.v2.service.vector.request.QueryReq;
import io.milvus.v2.service.vector.response.QueryResp;
String filter = "metadata[\"category\"] == \"electronics\" and metadata[\"price\"] < 150";
QueryResp resp = client.query(QueryReq.builder()
.collectionName("my_json_collection")
.filter(filter)
.outputFields(Collections.singletonList("metadata"))
.build());
System.out.println(resp.getQueryResults());
// Output
//
// [QueryResp.QueryResult(entity={metadata={"category":"electronics","price":99.99,"brand":"BrandA"}, pk=1})]
client.query({
collection_name: 'my_scalar_collection',
filter: 'metadata["category"] == "electronics" and metadata["price"] < 150',
output_fields: ['metadata']
});
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/query" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_json_collection",
"filter": "metadata[\"category\"] == \"electronics\" and metadata[\"price\"] < 150",
"outputFields": ["metadata"]
}'
{"code":0,"cost":0,"data":[{"metadata":"{\"category\": \"electronics\", \"price\": 99.99, \"brand\": \"BrandA\"}","pk":1}]}
위의 쿼리에서 Milvus는 metadata
필드의 카테고리가 "electronics"
, 가격이 150 미만인 엔티티를 필터링하여 이 조건과 일치하는 엔티티를 반환합니다.
JSON 필터링을 사용한 벡터 검색
벡터 유사성과 JSON 필터링을 결합하면 검색된 데이터가 의미론적으로 일치할 뿐만 아니라 특정 비즈니스 조건을 충족하는지 확인하여 검색 결과를 보다 정확하고 사용자 요구에 맞게 조정할 수 있습니다.
filter = 'metadata["brand"] == "BrandA"'
res = client.search(
collection_name="my_json_collection",
data=[[0.3, -0.6, 0.1]],
limit=5,
search_params={"params": {"nprobe": 10}},
output_fields=["metadata"],
filter=filter
)
print(res)
# Output
# data: ["[{'id': 1, 'distance': -0.2479381263256073, 'entity': {'metadata': {'category': 'electronics', 'price': 99.99, 'brand': 'BrandA'}}}]"]
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.response.SearchResp;
String filter = "metadata[\"brand\"] == \"BrandA\"";
SearchResp resp = client.search(SearchReq.builder()
.collectionName("my_json_collection")
.annsField("embedding")
.data(Collections.singletonList(new FloatVec(new float[]{0.3f, -0.6f, 0.1f})))
.topK(5)
.outputFields(Collections.singletonList("metadata"))
.filter(filter)
.build());
System.out.println(resp.getSearchResults());
// Output
//
// [[SearchResp.SearchResult(entity={metadata={"category":"electronics","price":99.99,"brand":"BrandA"}}, score=-0.2364331, id=1)]]
client.search({
collection_name: 'my_json_collection',
data: [0.3, -0.6, 0.1],
limit: 5,
output_fields: ['metadata'],
filter: 'metadata["category"] == "electronics" and metadata["price"] < 150',
});
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_json_collection",
"data": [
[0.3, -0.6, 0.1]
],
"annsField": "embedding",
"limit": 5,
"searchParams":{
"params":{"nprobe":10}
},
"outputFields": ["metadata"],
"filter": "metadata[\"brand\"] == \"BrandA\""
}'
## {"code":0,"cost":0,"data":[{"distance":-0.24793813,"id":1,"metadata":"{\"category\": \"electronics\", \"price\": 99.99, \"brand\": \"BrandA\"}"}]}
이 예제에서 Milvus는 metadata
필드에 "BrandA"
이라는 브랜드가 포함된 쿼리 벡터와 가장 유사한 상위 5개 엔티티를 반환합니다.
또한 Milvus는 JSON_CONTAINS
, JSON_CONTAINS_ALL
, JSON_CONTAINS_ANY
와 같은 고급 JSON 필터링 연산자를 지원하여 쿼리 기능을 더욱 향상시킬 수 있습니다. 자세한 내용은 메타데이터 필터링을 참조하세요.
제한 사항
인덱싱 제한: 데이터 구조의 복잡성으로 인해 JSON 필드 인덱싱은 지원되지 않습니다.
데이터 유형 일치: JSON 필드의 키 값이 정수 또는 부동 소수점인 경우 다른 정수 또는 부동 소수점 키 또는
INT32/64
또는FLOAT32/64
필드와만 비교할 수 있습니다. 키 값이 문자열(VARCHAR
)인 경우 다른 문자열 키와만 비교할 수 있습니다.이름 지정 제한: 다른 문자는 필터링이나 검색 중에 문제를 일으킬 수 있으므로 JSON 키의 이름을 지정할 때는 문자, 숫자, 밑줄만 사용하는 것이 좋습니다.
문자열 값 처리하기: 문자열 값(
VARCHAR
)의 경우, Milvus는 의미 변환 없이 JSON 필드 문자열을 그대로 저장합니다. 예를 들어'a"b'
,"a'b"
,'a\\'b'
,"a\\"b"
은 입력한 대로 저장되지만'a'b'
과"a"b"
은 유효하지 않은 것으로 간주됩니다.중첩된 사전 처리: JSON 필드 값 내에 중첩된 사전은 모두 문자열로 처리됩니다.