🤖 AI/ML

Qdrant

Qdrant Vector Database

Rust 기반 벡터 검색 엔진. 필터링과 검색 결합에 강점.

📖 상세 설명

Qdrant(쿼드런트)는 Rust로 개발된 고성능 오픈소스 벡터 데이터베이스입니다. 2021년 독일 베를린의 스타트업에서 시작되었으며, 메모리 안전성과 성능을 동시에 추구하는 Rust의 장점을 활용하여 설계되었습니다. 특히 "Filtered Vector Search" 기능이 강력하여, 벡터 유사도 검색과 메타데이터 필터링을 동시에 수행할 때 성능 저하가 거의 없습니다.

Qdrant의 아키텍처는 세그먼트 기반 스토리지를 사용합니다. 데이터는 여러 세그먼트로 분할되어 저장되며, 각 세그먼트는 HNSW(Hierarchical Navigable Small World) 인덱스를 독립적으로 가집니다. 이 구조 덕분에 데이터 삽입이 검색 성능에 미치는 영향이 최소화되고, 샤딩(Sharding)과 복제(Replication)를 통한 수평 확장이 용이합니다. gRPC와 REST API를 모두 지원하여 다양한 환경에서 유연하게 통합할 수 있습니다.

필터링 기능은 Qdrant의 핵심 차별점입니다. "should", "must", "must_not" 조건을 조합하여 복잡한 필터를 구성할 수 있고, 범위 쿼리, 지리 좌표 필터, 중첩 필터까지 지원합니다. 예를 들어 "최근 30일 이내 작성된, 카테고리가 '기술'인, 특정 사용자가 작성한" 문서 중에서 유사한 것을 찾는 복합 쿼리가 가능합니다. 이런 실전적인 요구사항에 대응하기 위해 설계되어, RAG 시스템에서 Pinecone, Weaviate와 함께 가장 많이 선택되는 벡터 DB입니다.

배포 옵션이 다양한 것도 장점입니다. Docker 컨테이너로 간단히 셀프 호스팅할 수 있고, Kubernetes Helm 차트도 제공합니다. Qdrant Cloud는 완전 관리형 서비스로, 무료 티어에서 1GB까지 사용 가능합니다. 하이브리드 클라우드 옵션을 통해 자체 인프라에서 Qdrant를 운영하면서 클라우드 관리 콘솔의 편의성을 누릴 수도 있습니다. LangChain, LlamaIndex, Haystack 등 주요 LLM 프레임워크와 네이티브 통합을 지원합니다.

💻 코드 예제

Qdrant Python 클라이언트를 사용한 RAG 파이프라인 구축 예제입니다:

from qdrant_client import QdrantClient
from qdrant_client.models import (
    Distance, VectorParams, PointStruct,
    Filter, FieldCondition, MatchValue, Range
)
import openai
from datetime import datetime, timedelta

# 1. Qdrant 클라이언트 초기화
# 로컬: client = QdrantClient(path="./qdrant_data")
# Docker: client = QdrantClient(host="localhost", port=6333)
client = QdrantClient(
    url="https://your-cluster.qdrant.io",
    api_key="your-api-key"
)

# 2. 컬렉션 생성 (벡터 저장소)
collection_name = "documents"
client.recreate_collection(
    collection_name=collection_name,
    vectors_config=VectorParams(
        size=1536,                    # OpenAI ada-002 차원
        distance=Distance.COSINE     # 유사도 측정 방식
    )
)

# 3. 문서와 메타데이터를 함께 저장
def embed_text(text):
    """OpenAI 임베딩 생성"""
    response = openai.embeddings.create(
        model="text-embedding-3-small",
        input=text
    )
    return response.data[0].embedding

documents = [
    {"id": 1, "text": "PyTorch는 동적 계산 그래프를 지원하는 딥러닝 프레임워크입니다.",
     "category": "ML", "author": "kim", "created_at": "2024-01-15"},
    {"id": 2, "text": "Qdrant는 Rust로 개발된 고성능 벡터 데이터베이스입니다.",
     "category": "Database", "author": "lee", "created_at": "2024-01-20"},
    {"id": 3, "text": "RAG는 검색과 생성을 결합한 AI 기술입니다.",
     "category": "ML", "author": "kim", "created_at": "2024-01-25"},
]

# 벡터와 메타데이터를 함께 업로드
points = [
    PointStruct(
        id=doc["id"],
        vector=embed_text(doc["text"]),
        payload={                      # 메타데이터
            "text": doc["text"],
            "category": doc["category"],
            "author": doc["author"],
            "created_at": doc["created_at"]
        }
    )
    for doc in documents
]

client.upsert(collection_name=collection_name, points=points)
print(f"Uploaded {len(points)} documents")

# 4. 필터링 + 벡터 검색 (Qdrant의 강점!)
query = "딥러닝 프레임워크에 대해 알려줘"
query_vector = embed_text(query)

# 복합 필터: category가 'ML'이고, 2024-01-01 이후 작성된 문서
results = client.search(
    collection_name=collection_name,
    query_vector=query_vector,
    query_filter=Filter(
        must=[
            FieldCondition(key="category", match=MatchValue(value="ML")),
        ]
    ),
    limit=5,
    with_payload=True
)

print("\n=== 검색 결과 ===")
for result in results:
    print(f"Score: {result.score:.4f}")
    print(f"Text: {result.payload['text']}")
    print(f"Author: {result.payload['author']}")
    print("---")

# 5. 다양한 필터 조합 예시
# must_not: 특정 저자 제외
# should: 여러 조건 중 하나 이상 매칭
complex_filter = Filter(
    must=[
        FieldCondition(key="category", match=MatchValue(value="ML"))
    ],
    must_not=[
        FieldCondition(key="author", match=MatchValue(value="park"))
    ]
)

# 6. 배치 검색 (여러 쿼리 동시 처리)
from qdrant_client.models import SearchRequest

batch_results = client.search_batch(
    collection_name=collection_name,
    requests=[
        SearchRequest(vector=embed_text("벡터 DB"), limit=3),
        SearchRequest(vector=embed_text("딥러닝"), limit=3),
    ]
)

📊 성능 & 비용

플랜 가격 스토리지 특징
Free (Cloud) 무료 1GB 프로토타입, 개인 프로젝트
Starter (Cloud) $25/월~ 10GB~ 소규모 프로덕션
Business (Cloud) $100/월~ 50GB~ HA, 전용 리소스
Self-Hosted 무료 (인프라 비용) 무제한 완전 제어, 커스터마이징
Hybrid Cloud $0.014/hr~ 자체 인프라 관리형 + 데이터 로컬리티

성능 벤치마크: 1M 벡터 기준 검색 지연 시간 ~5ms (필터 포함 ~10ms). Pinecone 대비 셀프호스팅 비용 70% 절감 가능. Rust 기반으로 메모리 효율성이 뛰어나 동일 스펙에서 더 많은 벡터 저장 가능.

🗣️ 실무에서 이렇게 말하세요

💼 회의에서

"RAG 시스템 벡터 DB로 Qdrant 추천드립니다. 필터링 성능이 뛰어나서 '최근 1주일 내, A팀 문서만' 같은 복합 조건 검색할 때 지연 시간 증가가 거의 없어요. 셀프호스팅도 Docker 한 줄이면 됩니다."

👔 면접에서

"Qdrant를 선택한 이유는 Rust 기반의 메모리 안전성과 성능, 그리고 filtered vector search의 우수함입니다. Pinecone은 완전 관리형이라 편하지만 비용이 높고, Qdrant는 셀프호스팅으로 비용을 70% 절감하면서 동등한 성능을 얻을 수 있었습니다."

🔧 기술 토론에서

"Qdrant의 세그먼트 아키텍처가 write 성능에 유리해요. 새 데이터가 별도 세그먼트에 먼저 쓰여서 기존 인덱스에 영향 없이 검색 계속 가능하고, 백그라운드에서 머지됩니다. 다만 세그먼트가 너무 많아지면 검색 속도가 느려질 수 있어서 optimizer 설정이 중요합니다."

⚠️ 흔한 실수 & 주의사항

인덱스 없이 필터링: 자주 사용하는 필터 필드에 인덱스를 생성하지 않으면 full scan이 발생합니다. create_payload_index()로 category, author 등 필터 대상 필드에 인덱스를 만드세요.
메모리 과소 할당: HNSW 인덱스는 메모리에 로드되어야 빠릅니다. 벡터 수 x 차원 x 4bytes + 여유분을 계산하여 충분한 RAM을 할당하세요. 메모리 부족 시 디스크 스왑으로 성능이 급격히 저하됩니다.
Best Practice: 프로덕션 배포 시 최소 3노드 클러스터로 복제본을 구성하세요. wal_segments_ahead 설정으로 WAL(Write-Ahead Log)을 튜닝하고, snapshot을 정기적으로 백업하여 데이터 손실에 대비하세요.

🔗 관련 용어

📚 더 배우기