JSON 필드
JSON 필드는 벡터 임베딩과 함께 추가 정보를 키-값 쌍으로 저장하는 스칼라 필드입니다. 다음은 데이터가 JSON 형식으로 저장되는 방법의 예입니다:
{
"metadata": {
"product_info": {
"category": "electronics",
"brand": "BrandA"
},
"price": 99.99,
"in_stock": true,
"tags": ["summer_sale", "clearance"]
}
}
제한
필드 크기: JSON 필드의 크기는 65,536바이트로 제한됩니다.
중첩된 사전: 중첩 사전: JSON 필드 값 내에 중첩된 사전은 저장 시 일반 문자열로 취급됩니다.
기본값: JSON 필드는 기본값을 지원하지 않습니다. 그러나
nullable속성을True으로 설정하여 null 값을 허용할 수 있습니다. 자세한 내용은 Null 가능 및 기본값을 참조하세요.유형 일치: JSON 필드의 키 값이 정수 또는 실수인 경우 표현식 필터를 통해서만 같은 유형의 다른 숫자 키와 비교할 수 있습니다.
이름 지정: JSON 키의 이름을 지정할 때는 문자, 숫자, 밑줄만 사용하는 것이 좋습니다. 다른 문자를 사용하면 필터링이나 검색 시 문제가 발생할 수 있습니다.
문자열 처리: 밀버스는 문자열 값을 의미 변환 없이 입력한 그대로 JSON 필드에 저장합니다. 예를 들어
'a"b',"a'b",'a\\'b',"a\\"b"는 그대로 저장됩니다.'a'b'와"a"b"는 유효하지 않은 것으로 간주됩니다.
JSON 인덱싱: JSON 필드를 색인할 때 JSON 필드에 하나 이상의 경로를 지정하여 필터링을 가속화할 수 있습니다. 경로가 추가될 때마다 인덱싱 오버헤드가 증가하므로 인덱싱 전략을 신중하게 계획하세요. JSON 필드 인덱싱에 대한 자세한 고려 사항은 JSON 인덱싱에 대한 고려 사항을 참조하세요.
JSON 필드 추가
컬렉션 스키마에 이 JSON 필드 metadata 를 추가하려면 DataType.JSON 을 사용합니다. 아래 예제에서는 null 값을 허용하는 JSON 필드 metadata 를 정의합니다:
# Import necessary libraries
from pymilvus import MilvusClient, DataType
# Define server address
SERVER_ADDR = "http://localhost:19530"
# Create a MilvusClient instance
client = MilvusClient(uri=SERVER_ADDR)
# Define the collection schema
schema = client.create_schema(
auto_id=False,
enable_dynamic_fields=True,
)
# Add a JSON field that supports null values
schema.add_field(field_name="metadata", datatype=DataType.JSON, nullable=True)
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)
.isNullable(true)
.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 (
"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()
schema.WithField(entity.NewField().
WithName("pk").
WithDataType(entity.FieldTypeInt64).
WithIsAutoID(true),
).WithField(entity.NewField().
WithName("embedding").
WithDataType(entity.FieldTypeFloatVector).
WithDim(3),
).WithField(entity.NewField().
WithName("metadata").
WithDataType(entity.FieldTypeJSON),
)
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,
\"enableDynamicField\": true,
\"fields\": [
$jsonField,
$pkField,
$vectorField
]
}"
향후 정의되지 않은 필드를 추가로 삽입해야 하는 경우
enable_dynamic_fields=True을 설정하세요.누락되거나 null인 JSON 객체를 허용하려면
nullable=True을 사용합니다.
인덱스 매개변수 설정
인덱싱은 Milvus가 대량의 데이터를 빠르게 필터링하거나 검색하는 데 도움이 됩니다. Milvus에서 인덱싱은
벡터 필드의 경우필수 (유사도 검색을 효율적으로 실행하기 위해).
JSON 필드의 경우선택 사항 (특정 JSON 경로에서 스칼라 필터의 속도를 높이기 위해).
JSON 필드 색인화Compatible with Milvus 2.5.10+
기본적으로 JSON 필드는 색인화되지 않으므로 모든 필터 쿼리(예: metadata["price"] < 100)는 모든 행을 스캔해야 합니다. metadata 필드 내의 특정 경로에 대한 쿼리를 가속화하려면 관심 있는 각 경로에 반전된 인덱스를 만들 수 있습니다.
이 예제에서는 metadata 필드 내의 서로 다른 경로에 두 개의 인덱스를 생성합니다:
index_params = client.prepare_index_params()
# Example 1: Index the 'category' key inside 'product_info' as a string
index_params.add_index(
field_name="metadata", # JSON field name to index
index_type="INVERTED", # Index type. Set to INVERTED
index_name="json_index_1", # Index name
params={
"json_path": "metadata[\"product_info\"][\"category\"]", # Path in JSON field to index
"json_cast_type": "varchar" # Data type that the extracted JSON values will be cast to
}
)
# Example 2: Index 'price' as a numeric type (double)
index_params.add_index(
field_name="metadata",
index_type="INVERTED",
index_name="json_index_2",
params={
"json_path": "metadata[\"price\"]",
"json_cast_type": "double"
}
)
import io.milvus.v2.common.IndexParam;
List<IndexParam> indexes = new ArrayList<>();
Map<String,Object> extraParams_1 = new HashMap<>();
extraParams_1.put("json_path", "metadata[\"product_info\"][\"category\"]");
extraParams_1.put("json_cast_type", "varchar");
indexes.add(IndexParam.builder()
.fieldName("metadata")
.indexName("json_index_1")
.indexType(IndexParam.IndexType.INVERTED)
.extraParams(extraParams_1)
.build());
Map<String,Object> extraParams_2 = new HashMap<>();
extraParams_2.put("json_path", "metadata[\"price\"]");
extraParams_2.put("json_cast_type", "double");
indexes.add(IndexParam.builder()
.fieldName("metadata")
.indexName("json_index_2")
.indexType(IndexParam.IndexType.INVERTED)
.extraParams(extraParams_2)
.build());
jsonIndex1 := index.NewJSONPathIndex(index.Inverted, "varchar", `metadata["product_info"]["category"]`)
jsonIndex2 := index.NewJSONPathIndex(index.Inverted, "double", `metadata["price"]`)
indexOpt1 := milvusclient.NewCreateIndexOption("my_collection", "metadata", jsonIndex1)
indexOpt2 := milvusclient.NewCreateIndexOption("my_collection", "metadata", jsonIndex2)
const indexParams = [
{
field_name: "metadata",
index_type: "INVERTED",
index_name: "json_index_1",
params: {
json_path: "metadata[\"product_info\"][\"category\"]",
json_cast_type: "varchar"
}
},
{
field_name: "metadata",
index_type: "INVERTED",
index_name: "json_index_2",
params: {
json_path: "metadata[\"price\"]",
json_cast_type: "double"
}
}
]
# restful
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/indexes/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_collection",
"indexParams": [
{
"fieldName": "metadata",
"indexName": "json_index_1",
"indexType": "INVERTED",
"params": {
"json_path": "metadata[\"product_info\"][\"category\"]",
"json_cast_type": "varchar"
}
}
]
}'
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/indexes/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_collection",
"indexParams": [
{
"fieldName": "metadata",
"indexName": "json_index_2",
"indexType": "INVERTED",
"params": {
"json_path": "metadata[\"price\"]",
"json_cast_type": "double"
}
}
]
}'
파라미터 |
설명 |
예제 값 |
|---|---|---|
|
스키마에 있는 JSON 필드의 이름입니다. |
|
|
생성할 인덱스 유형(현재 JSON 경로 인덱싱에는 |
|
|
(선택 사항) 사용자 정의 인덱스 이름. 동일한 JSON 필드에 여러 인덱스를 생성하는 경우 다른 이름을 지정합니다. |
|
|
인덱싱할 JSON 경로를 지정합니다. 중첩된 키, 배열 위치 또는 둘 다(예: |
|
|
인덱스를 생성할 때 Milvus가 추출된 JSON 값을 캐스팅할 데이터 유형입니다. 유효한 값
|
|
JSON 인덱싱에 대한 고려 사항
필터링 로직:
이중 유형 인덱스(
json_cast_type="double")를 생성하는 경우 숫자 유형 필터 조건만 인덱스를 사용할 수 있습니다. 필터가 이중 인덱스를 숫자가 아닌 조건과 비교하는 경우, Milvus는 무차별 대입 검색으로 돌아갑니다.바차르 타입 인덱스(
json_cast_type="varchar")를 생성하는 경우 문자열 타입 필터 조건만 인덱스를 사용할 수 있습니다. 그렇지 않으면 Milvus는 무차별 대입 검색으로 돌아갑니다.부울 인덱싱은 바차르 타입과 유사하게 작동합니다.
용어 표현식:
json["field"] in [value1, value2, …]을 사용할 수 있습니다. 그러나 인덱스는 해당 경로 아래에 저장된 스칼라 값에 대해서만 작동합니다.json["field"]이 배열인 경우 쿼리는 무차별 대입으로 돌아갑니다(배열형 인덱싱은 아직 지원되지 않음).
숫자 정밀도:
- 내부적으로 Milvus는 모든 숫자 필드를 이중으로 색인합니다. 숫자 값이 2 초과하면 정밀도가 떨어지며, 범위를 벗어난 값에 대한 쿼리는 정확히 일치하지 않을 수 있습니다.
데이터 무결성:
- Milvus는 사용자가 지정한 형 변환을 넘어서는 JSON 키를 구문 분석하거나 변환하지 않습니다. 소스 데이터가 일관성이 없는 경우(예: 일부 행은
"k"키에 대해 문자열을 저장하고 다른 행은 숫자를 저장하는 경우), 일부 행은 색인되지 않습니다.
- Milvus는 사용자가 지정한 형 변환을 넘어서는 JSON 키를 구문 분석하거나 변환하지 않습니다. 소스 데이터가 일관성이 없는 경우(예: 일부 행은
벡터 필드 색인 생성
다음 예는 AUTOINDEX 인덱스 유형을 사용하여 벡터 필드 embedding 에 인덱스를 생성하는 예입니다. 이 유형을 사용하면 Milvus는 데이터 유형에 따라 가장 적합한 인덱스를 자동으로 선택합니다. 각 필드에 대한 인덱스 유형과 매개변수를 사용자 지정할 수도 있습니다. 자세한 내용은 인덱스 설명을 참조하세요.
# Set index params
# Index `embedding` with AUTOINDEX and specify similarity metric type
index_params.add_index(
field_name="embedding",
index_name="vector_index",
index_type="AUTOINDEX", # Use automatic indexing to simplify complex index settings
metric_type="COSINE" # Specify similarity metric type, options include L2, COSINE, or IP
)
import io.milvus.v2.common.IndexParam;
import java.util.*;
indexes.add(IndexParam.builder()
.fieldName("embedding")
.indexName("vector_index")
.indexType(IndexParam.IndexType.AUTOINDEX)
.metricType(IndexParam.MetricType.COSINE)
.build());
vectorIndex := index.NewAutoIndex(entity.COSINE)
indexOpt := milvusclient.NewCreateIndexOption("my_collection", "embedding", vectorIndex)
indexParams.push({
index_name: 'embedding_index',
field_name: 'embedding',
index_name: 'vector_index',
metricType: MetricType.CONSINE,
index_type: IndexType.AUTOINDEX,
));
export indexParams='[
{
"fieldName": "embedding",
"indexName": "vector_index",
"metricType": "COSINE",
"indexType": "AUTOINDEX"
}
]'
컬렉션 만들기
스키마와 인덱스가 정의되면 JSON 필드를 포함하는 컬렉션을 만듭니다.
client.create_collection(
collection_name="my_collection",
schema=schema,
index_params=index_params
)
CreateCollectionReq requestCreate = CreateCollectionReq.builder()
.collectionName("my_collection")
.collectionSchema(schema)
.indexParams(indexes)
.build();
client.createCollection(requestCreate);
err = client.CreateCollection(ctx, milvusclient.NewCreateCollectionOption("my_collection", schema).
WithIndexOptions(indexOpt1, indexOpt2, indexOpt))
if err != nil {
fmt.Println(err.Error())
// handler err
}
await client.create_collection({
collection_name: "my_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_collection\",
\"schema\": $schema,
\"indexParams\": $indexParams
}"
데이터 삽입
컬렉션을 생성한 후 스키마와 일치하는 엔티티를 삽입합니다.
# Sample data
data = [
{
"metadata": {
"product_info": {"category": "electronics", "brand": "BrandA"},
"price": 99.99,
"in_stock": True,
"tags": ["summer_sale"]
},
"pk": 1,
"embedding": [0.12, 0.34, 0.56]
},
{
"metadata": None, # Entire JSON object is null
"pk": 2,
"embedding": [0.56, 0.78, 0.90]
},
{
# JSON field is completely missing
"pk": 3,
"embedding": [0.91, 0.18, 0.23]
},
{
# Some sub-keys are null
"metadata": {
"product_info": {"category": None, "brand": "BrandB"},
"price": 59.99,
"in_stock": None
},
"pk": 4,
"embedding": [0.56, 0.38, 0.21]
}
]
client.insert(
collection_name="my_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("{\"metadata\":{\"product_info\":{\"category\":\"electronics\",\"brand\":\"BrandA\"},\"price\":99.99,\"in_stock\":True,\"tags\":[\"summer_sale\"]},\"pk\":1,\"embedding\":[0.12,0.34,0.56]}", JsonObject.class));
rows.add(gson.fromJson("{\"metadata\":null,\"pk\":2,\"embedding\":[0.56,0.78,0.90]}", JsonObject.class));
rows.add(gson.fromJson("{\"pk\":3,\"embedding\":[0.91,0.18,0.23]}", JsonObject.class));
rows.add(gson.fromJson("{\"metadata\":{\"product_info\":{\"category\":null,\"brand\":\"BrandB\"},\"price\":59.99,\"in_stock\":null},\"pk\":4,\"embedding\":[0.56,0.38,0.21]}", JsonObject.class));
InsertResp insertR = client.insert(InsertReq.builder()
.collectionName("my_collection")
.data(rows)
.build());
_, err = client.Insert(ctx, milvusclient.NewColumnBasedInsertOption("my_collection").
WithInt64Column("pk", []int64{1, 2, 3, 4}).
WithFloatVectorColumn("embedding", 3, [][]float32{
{0.12, 0.34, 0.56},
{0.56, 0.78, 0.90},
{0.91, 0.18, 0.23},
{0.56, 0.38, 0.21},
}).WithColumns(
column.NewColumnJSONBytes("metadata", [][]byte{
[]byte(`{
"product_info": {"category": "electronics", "brand": "BrandA"},
"price": 99.99,
"in_stock": True,
"tags": ["summer_sale"]
}`),
[]byte(`null`),
[]byte(`null`),
[]byte(`"metadata": {
"product_info": {"category": None, "brand": "BrandB"},
"price": 59.99,
"in_stock": None
}`),
}),
))
if err != nil {
fmt.Println(err.Error())
// handle err
}
const data = [
{
"metadata": {
"product_info": {"category": "electronics", "brand": "BrandA"},
"price": 99.99,
"in_stock": True,
"tags": ["summer_sale"]
},
"pk": 1,
"embedding": [0.12, 0.34, 0.56]
},
{
"metadata": None, # Entire JSON object is null
"pk": 2,
"embedding": [0.56, 0.78, 0.90]
},
{
# JSON field is completely missing
"pk": 3,
"embedding": [0.91, 0.18, 0.23]
},
{
# Some sub-keys are null
"metadata": {
"product_info": {"category": None, "brand": "BrandB"},
"price": 59.99,
"in_stock": None
},
"pk": 4,
"embedding": [0.56, 0.38, 0.21]
}
];
await client.insert({
collection_name: "my_collection",
data: data
});
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--data '{
"data": [
{
"metadata": {
"product_info": {"category": "electronics", "brand": "BrandA"},
"price": 99.99,
"in_stock": true,
"tags": ["summer_sale"]
},
"varchar_field2": "High quality product",
"pk": 1,
"embedding": [0.1, 0.2, 0.3]
},
{
"metadata": null,
"pk": 2,
"embedding": [0.56, 0.78, 0.90]
},
{
"pk": 3,
"embedding": [0.91, 0.18, 0.23]
},
{
"metadata": {
"product_info": {"category": null, "brand": "BrandB"},
"price": 59.99,
"in_stock": null
},
"pk": 4,
"embedding": [0.56, 0.38, 0.21]
}
],
"collectionName": "my_collection"
}'
필터 표현식을 사용하여 쿼리
엔티티를 삽입한 후 query 메서드를 사용하여 지정된 필터 표현식과 일치하는 엔티티를 검색합니다.
널 값을 허용하는 JSON 필드의 경우 전체 JSON 객체가 없거나 None 로 설정된 경우 필드가 널로 처리됩니다. 자세한 내용은 Null 값이 있는 JSON 필드를 참조하세요.
metadata 가 null이 아닌 엔티티를 검색하려면 다음과 같이 하세요:
# Query to filter out records with null metadata
filter = 'metadata is not null'
res = client.query(
collection_name="my_collection",
filter=filter,
output_fields=["metadata", "pk"]
)
# Expected result:
# Rows with pk=1 and pk=4 have valid, non-null metadata.
# Rows with pk=2 (metadata=None) and pk=3 (no metadata key) are excluded.
print(res)
# Output:
# data: [
# "{'metadata': {'product_info': {'category': 'electronics', 'brand': 'BrandA'}, 'price': 99.99, 'in_stock': True, 'tags': ['summer_sale']}, 'pk': 1}",
# "{'metadata': {'product_info': {'category': None, 'brand': 'BrandB'}, 'price': 59.99, 'in_stock': None}, 'pk': 4}"
# ]
import io.milvus.v2.service.vector.request.QueryReq;
import io.milvus.v2.service.vector.response.QueryResp;
String filter = "metadata is not null";
QueryResp resp = client.query(QueryReq.builder()
.collectionName("my_collection")
.filter(filter)
.outputFields(Arrays.asList("metadata", "pk"))
.build());
System.out.println(resp.getQueryResults());
// Output
//
// [
// QueryResp.QueryResult(entity={metadata={"product_info":{"category":"electronics","brand":"BrandA"},"price":99.99,"in_stock":true,"tags":["summer_sale"]}, pk=1}),
// QueryResp.QueryResult(entity={metadata={"product_info":{"category":null,"brand":"BrandB"},"price":59.99,"in_stock":null}, pk=4})
// ]
filter := "metadata is not null"
rs, err := client.Query(ctx, milvusclient.NewQueryOption("my_collection").
WithFilter(filter).
WithOutputFields("metadata", "pk"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
fmt.Println("pk", rs.GetColumn("pk").FieldData().GetScalars())
fmt.Println("metadata", rs.GetColumn("metadata").FieldData().GetScalars())
await 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_collection",
"filter": "metadata is not null",
"outputFields": ["metadata", "pk"]
}'
#{"code":0,"cost":0,"data":[{"metadata":"{\"product_info\": {\"category\": \"electronics\", \"brand\": \"BrandA\"}, \"price\": 99.99, \"in_stock\": true, \"tags\": [\"summer_sale\"]}","pk":1},{"metadata":"","pk":2},{"metadata":"","pk":3},{"metadata":"{\"product_info\": {\"category\": null, \"brand\": \"BrandB\"}, \"price\": 59.99, \"in_stock\": null}","pk":4}]}
metadata["product_info"]["category"] 이 "electronics" 인 엔티티를 검색하려면 다음과 같이 하세요:
filter = 'metadata["product_info"]["category"] == "electronics"'
res = client.query(
collection_name="my_collection",
filter=filter,
output_fields=["metadata", "pk"]
)
# Expected result:
# - Only pk=1 has "category": "electronics".
# - pk=4 has "category": None, so it doesn't match.
# - pk=2 and pk=3 have no valid metadata.
print(res)
# Output:
# data: [
# "{'pk': 1, 'metadata': {'product_info': {'category': 'electronics', 'brand': 'BrandA'}, 'price': 99.99, 'in_stock': True, 'tags': ['summer_sale']}}"
# ]
String filter = "metadata[\"product_info\"][\"category\"] == \"electronics\"";
QueryResp resp = client.query(QueryReq.builder()
.collectionName("my_collection")
.filter(filter)
.outputFields(Arrays.asList("metadata", "pk"))
.build());
System.out.println(resp.getQueryResults());
// Output
// [QueryResp.QueryResult(entity={metadata={"product_info":{"category":"electronics","brand":"BrandA"},"price":99.99,"in_stock":true,"tags":["summer_sale"]}, pk=1})]
filter = `metadata["product_info"]["category"] == "electronics"`
rs, err := client.Query(ctx, milvusclient.NewQueryOption("my_collection").
WithFilter(filter).
WithOutputFields("metadata", "pk"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
fmt.Println("pk", rs.GetColumn("pk").FieldData().GetScalars())
fmt.Println("metadata", rs.GetColumn("metadata").FieldData().GetScalars())
const filter = 'metadata["category"] == "electronics"';
const res = await client.query({
collection_name: "my_collection",
filter: filter,
output_fields: ["metadata", "pk"]
});
// Example output:
// {
//. data: [
// {'pk': 1, 'metadata': {'category': 'electronics', 'price': 99.99, 'brand': 'BrandA'}}
// ]
// }
# restful
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/query" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_collection",
"filter": "metadata[\"product_info\"][\"category\"] == \"electronics\"",
"outputFields": ["metadata", "pk"]
}'
#{"code":0,"cost":0,"data":[{"metadata":"{\"product_info\": {\"category\": \"electronics\", \"brand\": \"BrandA\"}, \"price\": 99.99, \"in_stock\": true, \"tags\": [\"summer_sale\"]}","pk":1}]}
필터 표현식을 사용한 벡터 검색
기본 스칼라 필드 필터링 외에도 벡터 유사도 검색을 스칼라 필드 필터와 결합할 수 있습니다. 예를 들어, 다음 코드는 벡터 검색에 스칼라 필드 필터를 추가하는 방법을 보여줍니다:
filter = 'metadata["product_info"]["brand"] == "BrandA"'
res = client.search(
collection_name="my_collection",
data=[[0.3, -0.6, 0.1]],
limit=5,
search_params={"params": {"nprobe": 10}},
output_fields=["metadata"],
filter=filter
)
# Expected result:
# - Only pk=1 has "brand": "BrandA" in metadata["product_info"].
# - pk=4 has "brand": "BrandB".
# - pk=2 and pk=3 have no valid metadata.
# Hence, only pk=1 matches the filter.
print(res)
# Output:
# data: [
# "[{'id': 1, 'distance': -0.2479381263256073, 'entity': {'metadata': {'product_info': {'category': 'electronics', 'brand': 'BrandA'}, 'price': 99.99, 'in_stock': True, 'tags': ['summer_sale']}}}]"
# ]
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.response.SearchResp;
String filter = "metadata[\"product_info\"][\"brand\"] == \"BrandA\"";
SearchResp resp = client.search(SearchReq.builder()
.collectionName("my_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={"product_info":{"category":"electronics","brand":"BrandA"},"price":99.99,"in_stock":true,"tags":["summer_sale"]}}, score=-0.24793813, id=1)
// ]
// ]
queryVector := []float32{0.3, -0.6, -0.1}
filter = "metadata[\"product_info\"][\"brand\"] == \"BrandA\""
annParam := index.NewCustomAnnParam()
annParam.WithExtraParam("nprobe", 10)
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
"my_collection", // collectionName
5, // limit
[]entity.Vector{entity.FloatVector(queryVector)},
).WithANNSField("embedding").
WithFilter(filter).
WithOutputFields("metadata").
WithAnnParam(annParam))
if err != nil {
fmt.Println(err.Error())
// handle error
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs.FieldData().GetScalars())
fmt.Println("Scores: ", resultSet.Scores)
fmt.Println("metadata", resultSet.GetColumn("metadata").FieldData().GetScalars())
}
await client.search({
collection_name: 'my_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/query" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_collection",
"data": [
[0.3, -0.6, 0.1]
],
"annsField": "embedding",
"limit": 5,
"searchParams": {
"params": {
"nprobe": 10
}
},
"outputFields": ["metadata"],
"filter": "metadata[\"product_info\"][\"brand\"] == \"BrandA\""
}'
##{"code":0,"cost":0,"data":[{"metadata":"{\"product_info\": {\"category\": \"electronics\", \"brand\": \"BrandA\"}, \"price\": 99.99, \"in_stock\": true, \"tags\": [\"summer_sale\"]}","pk":1}]}
또한 Milvus는 JSON_CONTAINS, JSON_CONTAINS_ALL, JSON_CONTAINS_ANY 와 같은 고급 JSON 필터링 연산자를 지원하여 쿼리 기능을 더욱 향상시킬 수 있습니다. 자세한 내용은 JSON 연산자를 참조하세요.