본문으로 건너뛰기
Kreath Archive
TechProjectsBooksAbout
TechProjectsBooksAbout

내비게이션

  • Tech
  • Projects
  • Books
  • About
  • Tags

카테고리

  • AI / ML
  • 웹 개발
  • 프로그래밍
  • 개발 도구

연결

  • GitHub
  • Email
  • RSS
© 2026 Kreath Archive. All rights reserved.Built with Next.js + MDX
홈TechProjectsBooksAbout
//
  1. 홈
  2. 테크
  3. 8장: Qdrant와 pgvector -- 특화 솔루션들
2026년 2월 28일·AI / ML·

8장: Qdrant와 pgvector -- 특화 솔루션들

Rust 기반 고성능 벡터 엔진 Qdrant의 페이로드 필터링, 명명된 벡터, 하이브리드 배포를 분석하고, PostgreSQL 확장 pgvector의 트랜잭션 일관성과 pgvectorscale 성능을 비교합니다.

14분533자5개 섹션
vector-databaseaiembeddingsearchinfrastructure
공유
vector-database8 / 11
1234567891011
이전7장: Weaviate -- 오픈소스 벡터 검색 엔진다음9장: 하이브리드 검색 구현

학습 목표

  • Qdrant의 Rust 기반 아키텍처와 성능 특성을 이해합니다
  • 페이로드 필터링과 명명된 벡터의 활용법을 학습합니다
  • pgvector의 PostgreSQL 확장 방식과 트랜잭션 일관성의 가치를 파악합니다
  • pgvectorscale의 성능 최적화를 살펴봅니다
  • 두 솔루션의 적합한 사용 시나리오를 비교합니다

Qdrant: Rust 기반 고성능 벡터 엔진

개요

Qdrant는 Rust로 작성된 오픈소스 벡터 데이터베이스입니다. 2021년에 첫 출시된 이후 빠르게 성장하여, 성능과 안정성 면에서 높은 평가를 받고 있습니다.

Rust의 메모리 안전성과 제로 코스트 추상화는 벡터 데이터베이스에 매우 적합합니다. 가비지 컬렉션으로 인한 지연시간 스파이크가 없으며, C/C++ 수준의 성능을 안전하게 달성합니다.

성능 벤치마크

10M 벡터 환경에서의 벤치마크 결과를 보면, Qdrant는 인상적인 P95 지연시간을 보여줍니다.

메트릭QdrantPinecone (관리형)
P95 지연시간 (10M 벡터)22ms45ms
recall@1099%+99%+
Warning

벤치마크 결과는 하드웨어 구성, 벡터 차원, 데이터 분포에 따라 크게 달라집니다. 위 수치는 특정 조건에서의 결과이며, 실제 워크로드에서는 직접 벤치마크를 수행하는 것이 중요합니다.

페이로드 필터링

Qdrant에서는 메타데이터를 **페이로드(payload)**라 부릅니다. 페이로드 필터링은 Qdrant의 핵심 강점 중 하나로, 다양한 데이터 타입과 복합 조건을 지원합니다.

qdrant_filtering.py
python
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)

하나의 포인트에 여러 벡터를 저장할 수 있는 명명된 벡터(Named Vectors) 기능은 Qdrant의 독특한 특징입니다.

qdrant_named_vectors.py
python
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
)
Tip

명명된 벡터는 멀티모달 검색에 매우 유용합니다. 제품의 제목, 설명, 이미지를 각각 다른 임베딩 모델로 벡터화하고, 검색 상황에 따라 적합한 벡터를 선택할 수 있습니다. 하이브리드 검색에서 밀집 벡터와 희소 벡터를 함께 저장할 때도 활용됩니다.

배포 옵션

배포 형태비용특징
셀프호스트 (Docker)무료완전한 제어, 운영 부담
Qdrant Cloud$30-300+/월관리형, 자동 백업
하이브리드 클라우드커스텀자체 인프라 + Qdrant 관리

Qdrant의 하이브리드 클라우드는 자체 인프라(AWS, GCP, 온프레미스)에 Qdrant를 배포하면서 Qdrant의 관리 콘솔로 운영하는 방식입니다. 데이터 주권이 중요한 환경에서 유용합니다.


pgvector: PostgreSQL의 벡터 확장

개요

pgvector는 PostgreSQL에 벡터 검색 기능을 추가하는 확장(extension)입니다. 새로운 데이터베이스를 도입하지 않고, 기존 PostgreSQL 인프라에서 벡터 검색을 사용할 수 있다는 것이 핵심 가치입니다.

트랜잭션 일관성의 가치

pgvector의 가장 큰 장점은 PostgreSQL의 ACID 트랜잭션을 그대로 활용할 수 있다는 점입니다. 벡터와 구조화 데이터를 하나의 트랜잭션으로 원자적으로 관리할 수 있습니다.

pgvector_setup.sql
sql
-- 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
);
pgvector_search.sql
sql
-- 코사인 유사도 기반 검색 + 필터링
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;
Info

pgvector의 거리 연산자는 다음과 같습니다. <=> 코사인 거리, <-> 유클리드 거리(L2), <#> 음수 내적. SQL의 ORDER BY와 자연스럽게 결합되므로, SQL에 익숙한 개발자라면 학습 곡선이 매우 낮습니다.

Python에서 pgvector 사용

pgvector_python.py
python
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: 성능 최적화

pgvectorscale은 Timescale에서 개발한 pgvector의 성능 확장입니다. StreamingDiskANN 인덱스와 RaBitQ 양자화를 도입하여 대규모 데이터셋에서의 성능을 크게 향상시켰습니다.

50M 벡터 벤치마크에서 다음과 같은 결과를 보고했습니다.

메트릭pgvectorscaleQdrant
QPS (99% recall)47141
지연시간 P50~5ms~15ms

이 벤치마크는 특정 조건(50M 벡터, 768차원, 99% recall)에서의 결과이며, pgvectorscale의 디스크 기반 인덱스가 특히 높은 recall 요구사항에서 강점을 보입니다.

pgvectorscale_index.sql
sql
-- 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의 한계

pgvector는 강력하지만 몇 가지 한계가 있습니다.

  1. 하이브리드 검색 미지원: BM25 키워드 검색과의 네이티브 결합이 없습니다. pg_trgm이나 Full Text Search를 별도로 사용해야 합니다
  2. 수평 확장 제한: PostgreSQL의 단일 노드 한계를 공유합니다. Citus 같은 확장으로 보완 가능
  3. 벡터 전용 최적화 부족: 전용 벡터 DB에 비해 벡터 연산 최적화가 제한적
  4. 대규모 스케일: 1억 개 이하에서 최적, 그 이상은 전용 솔루션 고려
Tip

이미 PostgreSQL을 사용 중이고 벡터 수가 1억 개 이하라면, pgvector가 가장 실용적인 선택일 수 있습니다. 새로운 인프라를 도입하지 않아도 되고, 기존 ORM과 마이그레이션 도구를 그대로 사용할 수 있습니다.

Qdrant vs pgvector 비교

기준Qdrantpgvector
언어/기반Rust (독립 엔진)C (PostgreSQL 확장)
인덱스HNSWHNSW, IVFFlat, DiskANN*
트랜잭션제한적ACID 완전 지원
하이브리드 검색명명된 벡터 기반미지원 (별도 구현)
필터링풍부한 페이로드 필터SQL WHERE 절
멀티테넌시컬렉션 분리Row-Level Security
확장성분산 클러스터단일 노드 (Citus 활용 가능)
최적 규모1000만-10억+100만-1억
운영 복잡도중간낮음 (기존 PG 인프라)

선택 가이드

Qdrant를 선택해야 할 때:

  • 벡터 수가 1억 개 이상이거나 빠르게 증가하는 경우
  • 밀리초 단위 지연시간이 중요한 경우
  • 복잡한 필터링과 명명된 벡터가 필요한 경우
  • 분산 클러스터가 필요한 경우

pgvector를 선택해야 할 때:

  • 이미 PostgreSQL을 사용 중인 경우
  • 벡터와 관계형 데이터의 트랜잭션 일관성이 필요한 경우
  • 벡터 수가 1억 개 이하인 경우
  • 새로운 인프라 도입을 최소화하고 싶은 경우

정리

이번 장에서는 Qdrant와 pgvector 두 가지 특화 솔루션을 비교 분석했습니다. Qdrant는 Rust의 성능과 풍부한 필터링, 명명된 벡터로 대규모 고성능 벡터 검색에 강점을 보이며, pgvector는 PostgreSQL의 트랜잭션 일관성과 기존 인프라 활용이라는 실용적 가치를 제공합니다.

6장부터 8장까지 네 가지 주요 벡터 데이터베이스 솔루션을 살펴보았습니다. 다음 장에서는 이 솔루션들을 활용한 하이브리드 검색의 구현 방법을 심층적으로 다룹니다. 시맨틱 검색과 키워드 검색을 결합하여 검색 품질을 높이는 전략을 살펴보겠습니다.

이 글이 도움이 되셨나요?

관련 주제 더 보기

#vector-database#ai#embedding#search#infrastructure

관련 글

AI / ML

9장: 하이브리드 검색 구현

시맨틱 검색과 키워드 검색을 결합하는 하이브리드 검색의 원리, BM25+벡터 퓨전 전략, Reciprocal Rank Fusion, 리랭커 통합, 프레임워크별 구현 방법을 다룹니다.

2026년 3월 2일·14분
AI / ML

7장: Weaviate -- 오픈소스 벡터 검색 엔진

Weaviate의 오브젝트 지향 스키마, 모듈화 아키텍처, 내장 벡터라이저, 멀티테넌시, BlockMax WAND 하이브리드 검색, GraphQL API, 배포 옵션과 Python 실습을 다룹니다.

2026년 2월 26일·12분
AI / ML

10장: 메타데이터 필터링과 고급 쿼리

사전 필터링과 사후 필터링의 차이, 필터 인덱스 설계, 복합 필터 조건, 지오 필터, 멀티테넌시 필터 패턴, 성능 최적화 전략을 다룹니다.

2026년 3월 4일·16분
이전 글7장: Weaviate -- 오픈소스 벡터 검색 엔진
다음 글9장: 하이브리드 검색 구현

댓글

목차

약 14분 남음
  • 학습 목표
  • Qdrant: Rust 기반 고성능 벡터 엔진
    • 개요
    • 성능 벤치마크
    • 페이로드 필터링
    • 명명된 벡터 (Named Vectors)
    • 배포 옵션
  • pgvector: PostgreSQL의 벡터 확장
    • 개요
    • 트랜잭션 일관성의 가치
    • Python에서 pgvector 사용
    • pgvectorscale: 성능 최적화
    • pgvector의 한계
  • Qdrant vs pgvector 비교
    • 선택 가이드
  • 정리