Rust 기반 고성능 벡터 엔진 Qdrant의 페이로드 필터링, 명명된 벡터, 하이브리드 배포를 분석하고, PostgreSQL 확장 pgvector의 트랜잭션 일관성과 pgvectorscale 성능을 비교합니다.
Qdrant는 Rust로 작성된 오픈소스 벡터 데이터베이스입니다. 2021년에 첫 출시된 이후 빠르게 성장하여, 성능과 안정성 면에서 높은 평가를 받고 있습니다.
Rust의 메모리 안전성과 제로 코스트 추상화는 벡터 데이터베이스에 매우 적합합니다. 가비지 컬렉션으로 인한 지연시간 스파이크가 없으며, C/C++ 수준의 성능을 안전하게 달성합니다.
10M 벡터 환경에서의 벤치마크 결과를 보면, Qdrant는 인상적인 P95 지연시간을 보여줍니다.
| 메트릭 | Qdrant | Pinecone (관리형) |
|---|---|---|
| P95 지연시간 (10M 벡터) | 22ms | 45ms |
| recall@10 | 99%+ | 99%+ |
벤치마크 결과는 하드웨어 구성, 벡터 차원, 데이터 분포에 따라 크게 달라집니다. 위 수치는 특정 조건에서의 결과이며, 실제 워크로드에서는 직접 벤치마크를 수행하는 것이 중요합니다.
Qdrant에서는 메타데이터를 **페이로드(payload)**라 부릅니다. 페이로드 필터링은 Qdrant의 핵심 강점 중 하나로, 다양한 데이터 타입과 복합 조건을 지원합니다.
from qdrant_client import QdrantClient
from qdrant_client.models import (
Distance, VectorParams, PointStruct,
Filter, FieldCondition, MatchValue, Range,
PayloadSchemaType
)
client = QdrantClient(url="http://localhost:6333")
# 컬렉션 생성
client.create_collection(
collection_name="articles",
vectors_config=VectorParams(size=1536, distance=Distance.COSINE)
)
# 페이로드 인덱스 생성 (필터링 성능 최적화)
client.create_payload_index(
collection_name="articles",
field_name="category",
field_schema=PayloadSchemaType.KEYWORD
)
client.create_payload_index(
collection_name="articles",
field_name="published_year",
field_schema=PayloadSchemaType.INTEGER
)
# 포인트 삽입
client.upsert(
collection_name="articles",
points=[
PointStruct(
id=1,
vector=[0.1, 0.2, ...],
payload={
"title": "HNSW 알고리즘 분석",
"category": "algorithm",
"published_year": 2025,
"tags": ["hnsw", "ann", "graph"],
"author": {"name": "Kim", "org": "Lab"}
}
)
]
)
# 복합 필터 검색
results = client.query_points(
collection_name="articles",
query=[0.1, 0.2, ...],
query_filter=Filter(
must=[
FieldCondition(key="category", match=MatchValue(value="algorithm")),
FieldCondition(key="published_year", range=Range(gte=2024)),
],
must_not=[
FieldCondition(key="tags", match=MatchValue(value="deprecated"))
]
),
limit=10
)Qdrant의 필터링은 중첩 필드(nested field) 접근도 지원합니다. author.org 같은 경로로 중첩 오브젝트의 필드를 필터링할 수 있어, 복잡한 데이터 구조에서도 유연하게 활용할 수 있습니다.
하나의 포인트에 여러 벡터를 저장할 수 있는 명명된 벡터(Named Vectors) 기능은 Qdrant의 독특한 특징입니다.
client.create_collection(
collection_name="products",
vectors_config={
"title": VectorParams(size=384, distance=Distance.COSINE),
"description": VectorParams(size=1536, distance=Distance.COSINE),
"image": VectorParams(size=768, distance=Distance.COSINE),
}
)
# 삽입: 하나의 포인트에 세 개의 벡터
client.upsert(
collection_name="products",
points=[
PointStruct(
id=1,
vector={
"title": [0.1, 0.2, ...], # 제목 임베딩
"description": [0.3, 0.1, ...], # 설명 임베딩
"image": [0.5, 0.4, ...] # 이미지 임베딩
},
payload={"name": "벡터 DB 교재", "price": 35000}
)
]
)
# 특정 벡터로 검색
results = client.query_points(
collection_name="products",
query=[0.1, 0.2, ...],
using="description", # 설명 벡터 기준으로 검색
limit=10
)명명된 벡터는 멀티모달 검색에 매우 유용합니다. 제품의 제목, 설명, 이미지를 각각 다른 임베딩 모델로 벡터화하고, 검색 상황에 따라 적합한 벡터를 선택할 수 있습니다. 하이브리드 검색에서 밀집 벡터와 희소 벡터를 함께 저장할 때도 활용됩니다.
| 배포 형태 | 비용 | 특징 |
|---|---|---|
| 셀프호스트 (Docker) | 무료 | 완전한 제어, 운영 부담 |
| Qdrant Cloud | $30-300+/월 | 관리형, 자동 백업 |
| 하이브리드 클라우드 | 커스텀 | 자체 인프라 + Qdrant 관리 |
Qdrant의 하이브리드 클라우드는 자체 인프라(AWS, GCP, 온프레미스)에 Qdrant를 배포하면서 Qdrant의 관리 콘솔로 운영하는 방식입니다. 데이터 주권이 중요한 환경에서 유용합니다.
pgvector는 PostgreSQL에 벡터 검색 기능을 추가하는 확장(extension)입니다. 새로운 데이터베이스를 도입하지 않고, 기존 PostgreSQL 인프라에서 벡터 검색을 사용할 수 있다는 것이 핵심 가치입니다.
pgvector의 가장 큰 장점은 PostgreSQL의 ACID 트랜잭션을 그대로 활용할 수 있다는 점입니다. 벡터와 구조화 데이터를 하나의 트랜잭션으로 원자적으로 관리할 수 있습니다.
-- pgvector 확장 활성화
CREATE EXTENSION IF NOT EXISTS vector;
-- 테이블 생성 (벡터 + 일반 컬럼 통합)
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
content TEXT NOT NULL,
category TEXT NOT NULL,
published_at TIMESTAMP DEFAULT NOW(),
embedding vector(1536) -- 1536차원 벡터 컬럼
);
-- HNSW 인덱스 생성
CREATE INDEX ON articles
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 200);
-- 벡터 삽입
INSERT INTO articles (title, content, category, embedding)
VALUES (
'HNSW 알고리즘 분석',
'벡터 데이터베이스에서 가장 널리 사용되는...',
'algorithm',
'[0.1, 0.2, ...]'::vector
);-- 코사인 유사도 기반 검색 + 필터링
SELECT
id,
title,
1 - (embedding <=> '[0.1, 0.2, ...]'::vector) AS similarity
FROM articles
WHERE category = 'algorithm'
AND published_at >= '2024-01-01'
ORDER BY embedding <=> '[0.1, 0.2, ...]'::vector
LIMIT 10;pgvector의 거리 연산자는 다음과 같습니다. <=> 코사인 거리, <-> 유클리드 거리(L2), <#> 음수 내적. SQL의 ORDER BY와 자연스럽게 결합되므로, SQL에 익숙한 개발자라면 학습 곡선이 매우 낮습니다.
import psycopg2
from pgvector.psycopg2 import register_vector
import numpy as np
conn = psycopg2.connect("postgresql://user:pass@localhost:5432/mydb")
register_vector(conn)
cur = conn.cursor()
# 벡터 삽입
embedding = np.random.randn(1536).astype(np.float32)
cur.execute(
"INSERT INTO articles (title, content, category, embedding) VALUES (%s, %s, %s, %s)",
("테스트 문서", "내용...", "test", embedding)
)
# 트랜잭션: 벡터와 메타데이터 원자적 업데이트
try:
cur.execute("BEGIN")
cur.execute(
"UPDATE articles SET embedding = %s WHERE id = %s",
(new_embedding, article_id)
)
cur.execute(
"UPDATE article_stats SET update_count = update_count + 1 WHERE article_id = %s",
(article_id,)
)
cur.execute("COMMIT")
except Exception:
cur.execute("ROLLBACK")
raise
# 검색
query_vector = np.random.randn(1536).astype(np.float32)
cur.execute(
"""
SELECT id, title, 1 - (embedding <=> %s) AS similarity
FROM articles
WHERE category = 'algorithm'
ORDER BY embedding <=> %s
LIMIT 10
""",
(query_vector, query_vector)
)
results = cur.fetchall()pgvectorscale은 Timescale에서 개발한 pgvector의 성능 확장입니다. StreamingDiskANN 인덱스와 RaBitQ 양자화를 도입하여 대규모 데이터셋에서의 성능을 크게 향상시켰습니다.
50M 벡터 벤치마크에서 다음과 같은 결과를 보고했습니다.
| 메트릭 | pgvectorscale | Qdrant |
|---|---|---|
| QPS (99% recall) | 471 | 41 |
| 지연시간 P50 | ~5ms | ~15ms |
이 벤치마크는 특정 조건(50M 벡터, 768차원, 99% recall)에서의 결과이며, pgvectorscale의 디스크 기반 인덱스가 특히 높은 recall 요구사항에서 강점을 보입니다.
-- pgvectorscale의 StreamingDiskANN 인덱스
CREATE INDEX ON articles
USING diskann (embedding vector_cosine_ops)
WITH (
num_neighbors = 50,
search_list_size = 100,
max_alpha = 1.2,
num_dimensions = 1536,
num_bits_per_dimension = 2 -- RaBitQ 양자화
);pgvector는 강력하지만 몇 가지 한계가 있습니다.
이미 PostgreSQL을 사용 중이고 벡터 수가 1억 개 이하라면, pgvector가 가장 실용적인 선택일 수 있습니다. 새로운 인프라를 도입하지 않아도 되고, 기존 ORM과 마이그레이션 도구를 그대로 사용할 수 있습니다.
| 기준 | Qdrant | pgvector |
|---|---|---|
| 언어/기반 | Rust (독립 엔진) | C (PostgreSQL 확장) |
| 인덱스 | HNSW | HNSW, IVFFlat, DiskANN* |
| 트랜잭션 | 제한적 | ACID 완전 지원 |
| 하이브리드 검색 | 명명된 벡터 기반 | 미지원 (별도 구현) |
| 필터링 | 풍부한 페이로드 필터 | SQL WHERE 절 |
| 멀티테넌시 | 컬렉션 분리 | Row-Level Security |
| 확장성 | 분산 클러스터 | 단일 노드 (Citus 활용 가능) |
| 최적 규모 | 1000만-10억+ | 100만-1억 |
| 운영 복잡도 | 중간 | 낮음 (기존 PG 인프라) |
Qdrant를 선택해야 할 때:
pgvector를 선택해야 할 때:
이번 장에서는 Qdrant와 pgvector 두 가지 특화 솔루션을 비교 분석했습니다. Qdrant는 Rust의 성능과 풍부한 필터링, 명명된 벡터로 대규모 고성능 벡터 검색에 강점을 보이며, pgvector는 PostgreSQL의 트랜잭션 일관성과 기존 인프라 활용이라는 실용적 가치를 제공합니다.
6장부터 8장까지 네 가지 주요 벡터 데이터베이스 솔루션을 살펴보았습니다. 다음 장에서는 이 솔루션들을 활용한 하이브리드 검색의 구현 방법을 심층적으로 다룹니다. 시맨틱 검색과 키워드 검색을 결합하여 검색 품질을 높이는 전략을 살펴보겠습니다.
이 글이 도움이 되셨나요?
시맨틱 검색과 키워드 검색을 결합하는 하이브리드 검색의 원리, BM25+벡터 퓨전 전략, Reciprocal Rank Fusion, 리랭커 통합, 프레임워크별 구현 방법을 다룹니다.
Weaviate의 오브젝트 지향 스키마, 모듈화 아키텍처, 내장 벡터라이저, 멀티테넌시, BlockMax WAND 하이브리드 검색, GraphQL API, 배포 옵션과 Python 실습을 다룹니다.
사전 필터링과 사후 필터링의 차이, 필터 인덱스 설계, 복합 필터 조건, 지오 필터, 멀티테넌시 필터 패턴, 성능 최적화 전략을 다룹니다.