JSON 필드 개요
제품 카탈로그, 콘텐츠 관리 시스템 또는 사용자 환경 설정 엔진과 같은 애플리케이션을 구축할 때 벡터 임베딩과 함께 유연한 메타데이터를 저장해야 하는 경우가 많습니다. 제품 속성은 카테고리에 따라 다양하고, 사용자 선호도는 시간이 지남에 따라 변화하며, 문서 속성은 복잡한 중첩 구조를 가지고 있습니다. Milvus의 JSON 필드는 성능 저하 없이 유연한 구조화 데이터를 저장하고 쿼리할 수 있도록 지원하여 이러한 문제를 해결합니다.
JSON 필드란 무엇인가요?
JSON 필드는 구조화된 키-값 데이터를 저장하는 Milvus의 스키마 정의 데이터 유형(DataType.JSON)입니다. 기존의 리지드 데이터베이스 열과 달리 JSON 필드는 중첩된 개체, 배열 및 혼합 데이터 유형을 수용하는 동시에 빠른 쿼리를 위한 여러 인덱싱 옵션을 제공합니다.
JSON 필드 구조 예시:
{
"metadata": {
"category": "electronics",
"brand": "BrandA",
"in_stock": true,
"price": 99.99,
"string_price": "99.99",
"tags": ["clearance", "summer_sale"],
"supplier": {
"name": "SupplierX",
"country": "USA",
"contact": {
"email": "support@supplierx.com",
"phone": "+1-800-555-0199"
}
}
}
}
이 예에서 metadata 는 플랫 값(예: category, in_stock), 배열(tags), 중첩된 개체(supplier)가 혼합되어 있는 단일 JSON 필드입니다.
이름 지정 규칙: JSON 키에는 문자, 숫자, 밑줄만 사용하세요. 특수 문자, 공백 또는 점은 쿼리에서 구문 분석 문제를 일으킬 수 있으므로 피하세요.
JSON 필드와 동적 필드 비교
흔히 혼동하기 쉬운 점은 JSON 필드와 동적 필드의 차이점입니다. 둘 다 JSON과 관련이 있지만 서로 다른 용도로 사용됩니다.
아래 표에는 JSON 필드와 동적 필드의 주요 차이점이 요약되어 있습니다:
기능 |
JSON 필드 |
동적 필드 |
|---|---|---|
스키마 정의 |
컬렉션 스키마에서 |
선언되지 않은 필드를 자동으로 저장하는 숨겨진 JSON 필드(이름: |
사용 사례 |
스키마가 알려져 있고 일관성이 있는 구조화된 데이터를 저장합니다. |
고정된 스키마에 맞지 않는 유연하고 진화하는 데이터 또는 반정형 데이터를 저장합니다. |
제어 |
필드 이름과 구조를 제어합니다. |
정의되지 않은 필드에 대해 시스템에서 관리합니다. |
쿼리 |
JSON 필드 내에서 필드 이름 또는 대상 키를 사용하여 쿼리: |
동적 필드 키를 사용하여 직접 쿼리: |
기본 작업
JSON 필드를 사용하기 위한 기본적인 워크플로에는 스키마에서 필드를 정의하고, 데이터를 삽입한 다음, 특정 필터 표현식을 사용하여 데이터를 쿼리하는 것이 포함됩니다.
JSON 필드 정의하기
JSON 필드를 사용하려면 컬렉션을 만들 때 컬렉션 스키마에 명시적으로 정의합니다. 다음 예는 DataType.JSON 유형의 metadata 필드가 있는 컬렉션을 만드는 방법을 보여줍니다:
from pymilvus import MilvusClient, DataType
client = MilvusClient(uri="http://localhost:19530") # Replace with your server address
# Create schema
schema = client.create_schema(auto_id=False, enable_dynamic_field=True)
schema.add_field(field_name="product_id", datatype=DataType.INT64, is_primary=True) # Primary field
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=5) # Vector field
# Define a JSON field that allows null values
schema.add_field(field_name="metadata", datatype=DataType.JSON, nullable=True)
client.create_collection(
collection_name="product_catalog",
schema=schema
)
이 예제에서 컬렉션 스키마에 정의된 JSON 필드는 nullable=True 으로 null 값을 허용합니다. 자세한 내용은 Null 가능 및 기본값을 참조하세요.
데이터 삽입
컬렉션이 만들어지면 지정된 JSON 필드에 구조화된 JSON 개체를 포함하는 엔티티를 삽입합니다. 데이터의 형식은 사전 목록으로 지정해야 합니다.
entities = [
{
"product_id": 1,
"vector": [0.1, 0.2, 0.3, 0.4, 0.5],
"metadata": { # JSON field
"category": "electronics",
"brand": "BrandA",
"in_stock": True,
"price": 99.99,
"string_price": "99.99",
"tags": ["clearance", "summer_sale"],
"supplier": {
"name": "SupplierX",
"country": "USA",
"contact": {
"email": "support@supplierx.com",
"phone": "+1-800-555-0199"
}
}
}
}
]
client.insert(collection_name="product_catalog", data=entities)
필터링 작업
JSON 필드에서 필터링 작업을 수행하려면 먼저 다음 사항을 확인하세요:
각 벡터 필드에 인덱스를 만들었습니다.
컬렉션이 메모리에 로드되었습니다.
index_params = client.prepare_index_params()
index_params.add_index(
field_name="vector",
index_type="AUTOINDEX",
index_name="vector_index",
metric_type="COSINE"
)
client.create_index(collection_name="product_catalog", index_params=index_params)
client.load_collection(collection_name="product_catalog")
이러한 요구 사항이 충족되면 아래 표현식을 사용하여 JSON 필드 내의 값을 기준으로 컬렉션을 필터링할 수 있습니다. 이러한 필터 표현식은 특정 JSON 경로 구문과 전용 연산자를 활용합니다.
JSON 경로 구문을 사용한 필터링
특정 키를 쿼리하려면 대괄호 표기법을 사용하여 JSON 키에 액세스합니다: json_field_name["key"]. 중첩된 키의 경우, 서로 연결합니다: json_field_name["key1"]["key2"].
category 가 "electronics" 인 엔티티를 필터링하려면 다음과 같이 하세요:
# Define filter expression
filter = 'metadata["category"] == "electronics"'
client.search(
collection_name="product_catalog", # Collection name
data=[[0.1, 0.2, 0.3, 0.4, 0.5]], # Query vector (must match collection's vector dim)
limit=5, # Max. number of results to return
filter=filter, # Filter expression
output_fields=["product_id", "metadata"] # Fields to include in the search results
)
중첩된 키가 supplier["country"] 인 엔티티를 필터링하려면 "USA":
# Define filter expression
filter = 'metadata["supplier"]["country"] == "USA"'
res = client.search(
collection_name="product_catalog", # Collection name
data=[[0.1, 0.2, 0.3, 0.4, 0.5]], # Query vector (must match collection's vector dim)
limit=5, # Max. number of results to return
filter=filter, # Filter expression
output_fields=["product_id", "metadata"] # Fields to include in the search results
)
print(res)
JSON 전용 연산자로 필터링하기
Milvus는 특정 JSON 필드 키의 배열 값을 쿼리하기 위한 특수 연산자도 제공합니다. 예를 들어
json_contains(identifier, expr): JSON 배열 내에 특정 요소 또는 하위 배열이 존재하는지 확인합니다.json_contains_all(identifier, expr): 지정된 JSON 표현식의 모든 요소가 필드에 있는지 확인합니다.json_contains_any(identifier, expr): 필드 내에 JSON 표현식의 멤버가 하나 이상 존재하는 엔티티를 필터링합니다.
tags 키 아래에 "summer_sale" 값이 있는 제품을 찾으려면 다음과 같이 입력합니다:
# Define filter expression
filter = 'json_contains(metadata["tags"], "summer_sale")'
res = client.search(
collection_name="product_catalog", # Collection name
data=[[0.1, 0.2, 0.3, 0.4, 0.5]], # Query vector (must match collection's vector dim)
limit=5, # Max. number of results to return
filter=filter, # Filter expression
output_fields=["product_id", "metadata"] # Fields to include in the search results
)
print(res)
tags 키 아래에 "electronics", "new", "clearance" 값 중 하나 이상이 있는 제품을 찾으려면 다음을 수행합니다:
# Define filter expression
filter = 'json_contains_any(metadata["tags"], ["electronics", "new", "clearance"])'
res = client.search(
collection_name="product_catalog", # Collection name
data=[[0.1, 0.2, 0.3, 0.4, 0.5]], # Query vector (must match collection's vector dim)
limit=5, # Max. number of results to return
filter=filter, # Filter expression
output_fields=["product_id", "metadata"] # Fields to include in the search results
)
print(res)
JSON 관련 연산자에 대한 자세한 내용은 JSON 연산자를 참조하세요.
다음: JSON 쿼리 가속화하기
기본적으로 가속 기능이 없는 JSON 필드에 대한 쿼리는 모든 행에 대한 전체 스캔을 수행하므로 대규모 데이터 세트에서는 속도가 느려질 수 있습니다. JSON 쿼리 속도를 높이기 위해 Milvus는 고급 인덱싱 및 저장소 최적화 기능을 제공합니다.
아래 표에는 이 기능들의 차이점과 최상의 사용 시나리오가 요약되어 있습니다:
기술 |
최상의 용도 |
배열 가속화 |
참고 |
|---|---|---|---|
JSON 인덱싱 |
자주 액세스하는 키의 작은 집합, 특정 배열 키의 배열 |
예(인덱싱된 배열 키에) |
키를 미리 선택해야 함, 스키마가 진화하는 경우 유지 관리 필요 |
JSON 파쇄 |
많은 키에 걸쳐 일반적인 속도 향상, 다양한 쿼리에 유연하게 적용 가능 |
아니요(배열 내부의 값을 가속하지 않음) |
추가 스토리지 구성, 배열에는 여전히 키별 인덱스 필요 |
NGRAM 인덱스 |
와일드카드 검색, 텍스트 필드에서 하위 문자열 매칭 |
N/A |
숫자/범위 필터에는 사용 불가 |
팁: 이러한 접근 방식을 결합할 수 있습니다. 예를 들어, 광범위한 쿼리 가속을 위해 JSON 파쇄를 사용하고, 빈도가 높은 배열 키에는 JSON 인덱싱을 사용하고, 유연한 텍스트 검색을 위해 NGRAM 인덱싱을 사용할 수 있습니다.
구현에 대한 자세한 내용은 다음을 참조하세요:
FAQ
JSON 필드의 크기에 제한이 있나요?
네. 각 JSON 필드는 65,536바이트로 제한됩니다.
JSON 필드에서 기본값 설정을 지원하나요?
아니요, JSON 필드는 기본값을 지원하지 않습니다. 그러나 필드를 정의할 때 nullable=True 을 설정하여 빈 항목을 허용할 수 있습니다.
자세한 내용은 Null 가능 및 기본값을 참조하세요.
JSON 필드 키에 대한 명명 규칙이 있나요?
예, 쿼리 및 인덱싱과의 호환성을 보장하기 위한 것입니다:
JSON 키에는 문자, 숫자, 밑줄만 사용하세요.
특수 문자, 공백 또는 점(
.,/, 등)은 사용하지 마세요.호환되지 않는 키는 필터 표현식에서 구문 분석 문제를 일으킬 수 있습니다.
Milvus는 JSON 필드에서 문자열 값을 어떻게 처리하나요?
Milvus는 의미 변환 없이 JSON 입력에 표시된 그대로 문자열 값을 저장합니다. 부적절하게 따옴표로 묶인 문자열은 구문 분석 중에 오류가 발생할 수 있습니다.
유효한 문자열의 예
"a\"b", "a'b", "a\\b"
유효하지 않은 문자열의 예
'a"b', 'a\'b'