동적 스키마란 무엇인가요?
이 게시물은 Yujian Tang과 Zhenshan Cao가 공동으로 작성했습니다.
모든 데이터베이스에는 스키마가 있지만, 모두가 동적인 것은 아닙니다. SQL 데이터베이스에는 일반적으로 변경되지 않는 사전 정의된 스키마가 있습니다. 이를 만들 때 각 테이블이 어떤 모습이기를 원하는지 데이터베이스에 알려주고, 각 항목이 해당 테이블의 스키마에 맞도록 강제합니다. NoSQL 데이터베이스는 일반적으로 동적 스키마를 갖습니다(또는 스키마가 없을 수 있습니다). 각 객체의 속성은 데이터베이스를 만들 때 정의할 필요가 없습니다.
Milvus 벡터 데이터베이스에서 동적 스키마는 데이터를 추가함에 따라 변경되는 스키마입니다. 예를 들어, 동적 스키마 지원은 NoSQL 데이터베이스에서처럼 데이터 입력을 처리하고 JSON 형식으로 데이터를 추가할 수 있음을 의미합니다. 이전에는 Milvus가 스키마를 엄격하게 강제했습니다. 몇 달 전 Milvus 2.2.9에서 동적 스키마 옵션을 출시했으며, 구현하기 쉽게 만들었습니다.
이 글에서는 다음을 다룹니다:
- 데이터베이스 스키마란 무엇인가?
- 벡터 데이터베이스 스키마란 무엇인가?
- Milvus 벡터 데이터베이스에서 동적 스키마를 사용하는 방법
- Milvus에서 동적 스키마 기능이 구현되는 방식
동적 스키마의 장단점
벡터 데이터베이스를 위한 동적 스키마 요약
데이터베이스 스키마란 무엇인가?
스키마는 데이터가 데이터베이스에 삽입되고 보관되는 방식을 구조화합니다. 위의 예시는 관계형 데이터베이스를 위해 정규화된 데이터베이스 스키마를 어떻게 만들 수 있는지 보여줍니다. 위의 예시에서 가운데 테이블에는 네 개의 열이 있습니다. 이 데이터베이스에는 네 개의 테이블과 각 테이블에 대한 스키마가 있을 것입니다.
세 개의 테이블은 두 열 스키마를 갖고, 가운데 테이블은 네 열 스키마를 갖게 됩니다. 열에 대한 스키마에는 데이터 정의도 포함됩니다. “Employee”, “Title”, “DeptName” 열은 모두 문자열 또는 VARCHAR일 것입니다. 아마도 “CourseID”도 그럴 가능성이 높습니다. “EmpID”와 “DeptID”는 정수이고, “Date”는 날짜 타입이거나 VARCHAR 타입일 수도 있습니다.
벡터 데이터베이스 스키마란 무엇인가?
아래 이미지는 제가 Chat Towards Data Science 프로젝트에 사용하는 Milvus의 완전 관리형 벡터 데이터베이스 서비스인 Zilliz 인스턴스에 들어간 항목을 보여줍니다. 이를 관계형 데이터베이스 스키마처럼 정의한다면 11개의 열이 있을 것입니다. 문자열 또는 VARCHAR 열은 “id”, “paragraph”, “subtitle”, “publication”, “article_url”, “title”의 여섯 개가 될 것입니다. 나머지 다섯 열 중 세 개는 “reading_time”, “responses”, “claps”와 같은 일종의 INT 데이터 타입일 것입니다. 남은 두 열은 DATE 타입인 “date”와 우리가 “FLOAT_VECTOR”라고 부르는 임베딩 벡터가 될 것입니다.
Milvus 벡터 데이터베이스에서 동적 스키마를 사용하는 방법은?
Milvus는 성능, 확장성, 신뢰성을 위해 구축된 인기 있는 오픈 소스 벡터 데이터베이스입니다. 몇 달 전 Milvus 2.2.9에서 동적 스키마 옵션을 출시했으며, 구현하기 쉽게 만들었습니다.
다음 코드 스니펫은 Milvus에서 동적 스키마 기능을 활성화하고 활용하는 방법, 그리고 동적 필드에 데이터를 삽입하고 필터링된 검색을 수행하는 방법을 보여줍니다.
from pymilvus import (
connections,
FieldSchema, CollectionSchema, DataType,
Collection,
)
DIMENSION = 8
COLLECTION_NAME = "books"
connections.connect("default", host="localhost", port="19530")
fields = [
FieldSchema(name='id', dtype=DataType.INT64, is_primary=True),
FieldSchema(name='title', dtype=DataType.VARCHAR, max_length=200),
FieldSchema(name='embeddings', dtype=DataType.FLOAT_VECTOR, dim=DIMENSION)
]
schema = CollectionSchema(fields=fields, enable_dynamic_field=True)
collection = Collection(name=COLLECTION_NAME, schema=schema)
data_rows = [
{"id": 1, "title": "Lord of the Flies",
"embeddings": [0.64, 0.44, 0.13, 0.47, 0.74, 0.03, 0.32, 0.6],
"isbn": "978-0399501487"},
{"id": 2, "title": "The Great Gatsby",
"embeddings": [0.9, 0.45, 0.18, 0.43, 0.4, 0.4, 0.7, 0.24],
"author": "F. Scott Fitzgerald"},
{"id": 3, "title": "The Catcher in the Rye",
"embeddings": [0.43, 0.57, 0.43, 0.88, 0.84, 0.69, 0.27, 0.98],
"claps": 100},
]
collection.insert(data_rows)
collection.create_index("embeddings", {"index_type": "FLAT", "metric_type": "L2"})
collection.load()
vector_to_search = [0.57, 0.94, 0.19, 0.38, 0.32, 0.28, 0.61, 0.07]
result = collection.search(
data=[vector_to_search],
anns_field="embeddings",
param={},
limit=3,
expr="claps > 30 || title =='The Great Gatsby'",
output_fields=["title", "author", "claps", "isbn"],
consistency_level="Strong")
for hits in result:
for hit in hits:
print(hit.to_dict())
생성된 컬렉션 "books"에서 id, title, embeddings라는 세 개의 필드로 스키마를 정의합니다. id는 기본 키이며 각 행의 고유 식별자이고 INT64 형식입니다. title은 책 이름을 나타내며 타입은 VARCHAR이고, 임베딩은 8차원 벡터 열입니다. 이 게시글에서는 데모 목적으로 벡터 데이터를 코드에서 무작위로 설정했습니다.
schema = CollectionSchema(fields=fields, enable_dynamic_field=True)
collection = Collection(name=COLLECTION_NAME, schema=schema)
정의에서 CollectionSchema 객체에 필드를 전달하여 동적 스키마를 활성화합니다. 우리가 하는 일은 enable_dynamic_field 스키마를 추가하고 이를 True로 설정하는 것뿐입니다.
data_rows = [
{"id": 1, "title": "Lord of the Flies",
"embeddings": [0.64, 0.44, 0.13, 0.47, 0.74, 0.03, 0.32, 0.6],
"isbn": "978-0399501487"},
{"id": 2, "title": "The Great Gatsby",
"embeddings": [0.9, 0.45, 0.18, 0.43, 0.4, 0.4, 0.7, 0.24],
"author": "F. Scott Fitzgerald"},
{"id": 3, "title": "The Catcher in the Rye",
"embeddings": [0.43, 0.57, 0.43, 0.88, 0.84, 0.69, 0.27, 0.98],
"claps": 100},
]
위 코드에서는 세 행의 데이터를 삽입합니다. id=1의 데이터에는 동적 필드 isbn이 포함되고, id=2에는 author가 포함되며, id=3에는 claps가 포함됩니다. 이러한 동적 필드들은 문자열 타입(isbn 및 author)과 정수 타입(claps)을 포함하여 서로 다른 타입을 가집니다.
result = collection.search(
data=[vector_to_search],
anns_field="embeddings",
param={},
limit=3,
expr="claps > 30 || title =='The Great Gatsby'",
output_fields=["title", "author", "claps", "isbn"],
consistency_level="Strong")
위 코드에서는 동적 필드를 기반으로 한 필터링과 ANNS(Approximate Nearest Neighbors) 검색을 결합한 하이브리드 검색을 수행합니다. 쿼리는 expr 매개변수에 지정된 조건을 만족하는 행의 데이터를 검색하는 것을 목표로 합니다. 출력에는 존재하는 경우 title, author, claps, isbn 필드가 포함됩니다. expr 매개변수는 스키마 필드(title)와 동적 필드(claps) 기반의 필터링을 허용합니다.
코드를 실행한 후 출력 결과는 다음과 같습니다.
{'id': 2, 'distance': 0.40939998626708984, 'entity': {'title': 'The Great Gatsby', 'author': 'F. Scott Fitzgerald'}}
{'id': 3, 'distance': 1.8463000059127808, 'entity': {'title': 'The Catcher in the Rye', 'claps': 100}}
Milvus에서 Dynamic Schema 기능은 어떻게 구현되나요?
Milvus 커널은 숨겨진 메타 열을 사용하여 사용자가 각 데이터 행에 서로 다른 이름과 데이터 타입을 가진 동적 필드를 추가할 수 있도록 합니다. 사용자가 테이블을 생성하고 동적 필드를 활성화하면 $meta라는 숨겨진 열이 테이블과 함께 생성됩니다. 이 숨겨진 열은 JSON을 데이터 타입으로 사용합니다. JSON은 JSON 형식 데이터를 생성하고 파싱하기 위해 최신 프로그래밍 언어에서 널리 지원되는 언어 독립적인 데이터 형식이기 때문입니다.
Milvus는 데이터를 열 지향 구조로 구성합니다. 삽입 중에 각 행의 동적 필드에 대한 데이터는 하나의 JSON 데이터로 패키징되며, 모든 행의 JSON 데이터가 함께 숨겨진 열 $meta를 형성합니다.
Dynamic Schema의 장단점은 무엇인가요?
동적 스키마는 데이터 모델링의 다양한 요구에 맞춰 장점과 단점을 제공합니다.
장점
- 동적 스키마는 설정이 쉬워 복잡한 구성을 요구하지 않고도 폭넓은 사용자층이 접근할 수 있습니다.
- 동적 스키마는 시간이 지남에 따라 데이터 모델의 변경을 수용하여, 개발자가 큰 구조 변경 없이 조정할 수 있도록 합니다.
단점:
- 동적 스키마를 사용한 필터링 검색은 고정 스키마보다 훨씬 느립니다.
- 동적 스키마에서의 대량 삽입은 복잡합니다.
이러한 과제를 해결하기 위해 Milvus는 필터링 검색 효율성을 높이기 위해 벡터화된 실행 모델을 통합했습니다. 호출된 연산자를 통해 한 번에 한 행의 데이터를 처리하는 기존의 volcano 모델과 달리, 벡터화된 실행 모델은 전체 데이터 배치를 동시에 처리합니다. 이 컴퓨팅 패러다임은 계산 중 데이터 지역성을 최적화하여 전체 시스템 성능을 크게 향상시킵니다.
앞으로 Milvus 2.4에서 스칼라 인덱싱 기능을 계속 강화할 예정입니다. 이 향상은 정적 및 동적 필드에 대한 inverted indexing을 통해 필터링 검색을 가속화하는 것을 목표로 하며, 동적 스키마를 관리하고 쿼리하는 데 있어 향상된 성능과 효율성을 약속합니다.
벡터 데이터베이스를 위한 Dynamic Schema 요약
이 글에서는 데이터베이스 스키마를 살펴보았습니다. 스키마를 더 잘 이해하기 위해 관계형 데이터베이스의 예제 스키마를 사용했습니다. 관계형 데이터베이스에는 정의해야 하는 엄격한 스키마가 있습니다. 스키마에는 정의된 필드가 있어야 하며, 필드에는 정의된 데이터 유형이 있어야 합니다. 이것이 Milvus의 스키마가 이전에 적용되던 방식입니다.
하지만 Milvus는 실제로 두 필드가 어떻게 정의되는지만 알면 됩니다. 하나는 엔트리의 ID이고, 다른 하나는 임베딩 필드입니다. 나머지 필드는 정의할 필요가 없지만, 정의할 수도 있습니다. enable_dynamic_field 매개변수를 사용해 전달되는 동적 스키마의 도입으로 Milvus는 더 이상 다른 필드를 정의할 필요가 없습니다.
동적 스키마는 양날의 검으로, 설정의 용이성, 유연성, 효율성을 제공하지만 그에 따른 트레이드오프가 있습니다. 예를 들어, 동적 스키마를 사용한 필터링 검색은 고정 스키마보다 느리고, 동적 스키마에서 대량 삽입은 더 복잡합니다. Milvus는 동적 스키마와 함께 발생하는 과제를 해결하기 위해 벡터화된 실행 모델을 활용하여 전체 시스템 성능을 최적화했습니다. 또한 Milvus 2.4에서 스칼라 인덱싱 기능을 강화하여 동적 스키마를 관리하고 쿼리하는 데 있어 성능과 효율성을 개선할 예정입니다.
계속 읽기

Our Journey to 35K+ GitHub Stars: The Real Story of Building Milvus from Scratch
Join us in celebrating Milvus, the vector database that hit 35.5K stars on GitHub. Discover our story and how we’re making AI solutions easier for developers.

Selecting the Right ETL Tools for Unstructured Data to Prepare for AI
Learn the right ETL tools for unstructured data to power AI. Explore key challenges, tool comparisons, and integrations with Milvus for vector search.

DeepRAG: Thinking to Retrieval Step by Step for Large Language Models
Discover DeepRAG, an advanced retrieval-augmented generation (RAG) model that improves LLM accuracy by retrieving only essential data through step-by-step reasoning.



