개요

AI와 머신러닝의 급격한 발전으로 벡터 검색(Vector Search)의 중요성이 날로 커지고 있습니다. pgvector는 PostgreSQL 확장으로, 기존 관계형 데이터베이스에 벡터 유사도 검색 기능을 추가합니다. Pinecone이나 Weaviate 같은 전용 벡터 DB 없이도, 이미 사용 중인 PostgreSQL에서 임베딩 검색을 수행할 수 있어 인프라 복잡도를 크게 줄일 수 있습니다.

핵심 개념

벡터 데이터베이스의 핵심은 임베딩(Embedding)입니다. 텍스트, 이미지, 오디오 등의 데이터를 고차원 벡터(예: 1536차원)로 변환하고, 벡터 간의 거리(유사도)를 계산하여 의미적으로 유사한 데이터를 찾습니다.

pgvector는 세 가지 거리 함수를 지원합니다. L2 거리(유클리드 거리), 내적(Inner Product), 코사인 거리입니다. 대부분의 텍스트 임베딩에서는 코사인 유사도가 가장 좋은 결과를 보여줍니다.

2024년 pgvector 0.7.0부터는 HNSW(Hierarchical Navigable Small World) 인덱스를 지원하여 대규모 데이터셋에서도 밀리초 단위의 검색 성능을 제공합니다. 기존 IVFFlat 인덱스보다 검색 정확도와 속도 모두 향상되었습니다.

실전 예제

pgvector 설치부터 RAG(Retrieval-Augmented Generation) 파이프라인 구축까지의 과정입니다.

-- pgvector 확장 설치
CREATE EXTENSION IF NOT EXISTS vector;

-- 문서 테이블 생성 (1536차원 = OpenAI text-embedding-3-small)
CREATE TABLE documents (
  id BIGSERIAL PRIMARY KEY,
  content TEXT NOT NULL,
  metadata JSONB DEFAULT '{}',
  embedding vector(1536)
);

-- HNSW 인덱스 생성 (코사인 거리)
CREATE INDEX ON documents
  USING hnsw (embedding vector_cosine_ops)
  WITH (m = 16, ef_construction = 64);

-- 유사도 검색 함수
CREATE OR REPLACE FUNCTION match_documents(
  query_embedding vector(1536),
  match_threshold FLOAT DEFAULT 0.78,
  match_count INT DEFAULT 5
)
RETURNS TABLE (id BIGINT, content TEXT, similarity FLOAT)
LANGUAGE plpgsql AS $$
BEGIN
  RETURN QUERY
  SELECT
    documents.id,
    documents.content,
    1 - (documents.embedding <=> query_embedding) AS similarity
  FROM documents
  WHERE 1 - (documents.embedding <=> query_embedding) > match_threshold
  ORDER BY documents.embedding <=> query_embedding
  LIMIT match_count;
END;
$$;

Python에서 OpenAI 임베딩과 함께 사용하는 예제입니다.

import openai
from supabase import create_client

def embed_and_store(text: str):
    # OpenAI 임베딩 생성
    response = openai.embeddings.create(
        model="text-embedding-3-small",
        input=text
    )
    embedding = response.data[0].embedding

    # Supabase에 저장
    supabase.table('documents').insert({
        'content': text,
        'embedding': embedding
    }).execute()

def semantic_search(query: str, top_k: int = 5):
    query_embedding = openai.embeddings.create(
        model="text-embedding-3-small",
        input=query
    ).data[0].embedding

    result = supabase.rpc('match_documents', {
        'query_embedding': query_embedding,
        'match_count': top_k
    }).execute()
    return result.data

활용 팁

  • 차원 축소: text-embedding-3-small의 1536차원을 512차원으로 줄여도 대부분의 유스케이스에서 충분한 성능을 보입니다. 저장 공간과 검색 속도가 크게 개선됩니다.
  • 하이브리드 검색: 벡터 검색과 전문 검색(tsvector)을 결합하면 키워드 매칭과 의미 검색의 장점을 모두 활용할 수 있습니다.
  • 파티셔닝: 대규모 데이터는 카테고리별로 테이블을 파티셔닝하고 각 파티션에 별도 인덱스를 생성하면 성능이 향상됩니다.
  • 배치 처리: 임베딩 생성은 API 호출 비용이 발생하므로, 배치로 처리하고 변경된 문서만 재임베딩하는 전략이 효율적입니다.
  • Supabase에서 활용: Supabase는 pgvector를 기본 지원하므로, Dashboard에서 확장을 활성화하고 바로 사용할 수 있습니다.

마무리

pgvector는 기존 PostgreSQL 인프라에 벡터 검색을 추가할 수 있는 가장 실용적인 선택입니다. 전용 벡터 DB 대비 관리 포인트가 적고, 관계형 데이터와 벡터 데이터를 하나의 트랜잭션으로 처리할 수 있다는 것이 큰 장점입니다. RAG 기반 AI 애플리케이션을 구축한다면 pgvector를 먼저 검토해보시기 바랍니다.