Contents
see List개요
Vector Database는 임베딩 벡터를 효율적으로 저장하고 유사도 검색(Similarity Search)을 수행하는 데이터베이스입니다. ChatGPT, Stable Diffusion 등 생성형 AI의 대중화와 함께 RAG(Retrieval-Augmented Generation) 패턴의 핵심 인프라로 주목받고 있습니다.
이 글에서는 주요 Vector Database를 비교하고, 실무에서 어떻게 선택하고 활용할지 살펴보겠습니다.
핵심 개념
1. 임베딩과 유사도 검색
텍스트, 이미지, 오디오 등의 비정형 데이터를 고차원 벡터(예: 1536차원)로 변환한 것이 임베딩입니다. 벡터 간 거리(코사인 유사도, 유클리드 거리 등)를 계산하여 유사한 데이터를 찾는 것이 유사도 검색입니다.
2. ANN(Approximate Nearest Neighbor)
정확한 최근접 이웃 검색은 O(n) 시간 복잡도로 대규모 데이터셋에서 느립니다. ANN 알고리즘(HNSW, IVF, PQ 등)은 약간의 정확도를 희생하여 O(log n) 수준의 성능을 제공합니다.
3. 주요 Vector Database
- Pinecone: 완전 관리형 SaaS, 가장 쉬운 시작
- Weaviate: GraphQL API, 하이브리드 검색 지원
- Qdrant: Rust 기반, 높은 성능, 오픈소스
- Milvus: CNCF 프로젝트, 대규모 엔터프라이즈용
- pgvector: PostgreSQL 확장, 기존 DB 활용
- Chroma: 임베딩 함수 내장, AI 네이티브
실전 예제
Pinecone 활용 (가장 간단한 시작)
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: process.env.PINECONE_API_KEY });
// 인덱스 생성 (1회만)
await pc.createIndex({
name: 'my-index',
dimension: 1536, // OpenAI text-embedding-ada-002
metric: 'cosine',
spec: {
serverless: {
cloud: 'aws',
region: 'us-east-1'
}
}
});
const index = pc.index('my-index');
// 벡터 삽입
await index.upsert([
{
id: 'doc1',
values: [0.1, 0.2, 0.3, ...], // 1536차원 벡터
metadata: { text: '원본 텍스트', category: 'tech' }
},
{
id: 'doc2',
values: [0.4, 0.5, 0.6, ...],
metadata: { text: '다른 문서', category: 'news' }
}
]);
// 유사도 검색
const results = await index.query({
vector: queryEmbedding, // 검색 쿼리의 임베딩
topK: 5,
includeMetadata: true,
filter: { category: 'tech' } // 메타데이터 필터링
});
console.log(results.matches);
// [{ id: 'doc1', score: 0.95, metadata: {...} }, ...]
pgvector 활용 (PostgreSQL 기반)
-- pgvector 확장 설치 (Supabase는 기본 제공)
CREATE EXTENSION IF NOT EXISTS vector;
-- 문서 테이블 생성
CREATE TABLE documents (
id BIGSERIAL PRIMARY KEY,
content TEXT,
embedding vector(1536), -- 1536차원 벡터
metadata JSONB
);
-- HNSW 인덱스 생성 (빠른 검색)
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops);
-- 벡터 삽입
INSERT INTO documents (content, embedding, metadata)
VALUES (
'PostgreSQL은 강력한 오픈소스 데이터베이스입니다.',
'[0.1, 0.2, 0.3, ...]', -- 실제로는 OpenAI API로 생성
'{"category": "database"}'
);
-- 유사도 검색 (코사인 거리)
SELECT id, content, metadata,
1 - (embedding <=> '[0.4, 0.5, 0.6, ...]') AS similarity
FROM documents
ORDER BY embedding <=> '[0.4, 0.5, 0.6, ...]'
LIMIT 5;
Supabase Vector 활용 (pgvector + Edge Functions)
// supabase/functions/semantic-search/index.ts
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
serve(async (req) => {
const { query } = await req.json()
// OpenAI API로 쿼리 임베딩 생성
const embeddingResponse = await fetch('https://api.openai.com/v1/embeddings', {
method: 'POST',
headers: {
'Authorization': `Bearer ${Deno.env.get('OPENAI_API_KEY')}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'text-embedding-ada-002',
input: query
})
})
const { data: [{ embedding }] } = await embeddingResponse.json()
// Supabase에서 유사도 검색
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
)
const { data, error } = await supabase.rpc('match_documents', {
query_embedding: embedding,
match_threshold: 0.7,
match_count: 5
})
return new Response(JSON.stringify({ results: data }), {
headers: { 'Content-Type': 'application/json' }
})
})
-- PostgreSQL 함수 (Supabase에서 실행)
CREATE OR REPLACE FUNCTION match_documents (
query_embedding vector(1536),
match_threshold float,
match_count int
)
RETURNS TABLE (
id bigint,
content text,
metadata jsonb,
similarity float
)
LANGUAGE plpgsql
AS $$
BEGIN
RETURN QUERY
SELECT
documents.id,
documents.content,
documents.metadata,
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;
$$;
Qdrant 활용 (고성능 오픈소스)
import { QdrantClient } from '@qdrant/js-client-rest';
const client = new QdrantClient({ url: 'http://localhost:6333' });
// 컬렉션 생성
await client.createCollection('my_collection', {
vectors: {
size: 1536,
distance: 'Cosine'
}
});
// 포인트 삽입
await client.upsert('my_collection', {
points: [
{
id: 1,
vector: [0.1, 0.2, 0.3, ...],
payload: { text: '문서 내용', category: 'tech' }
}
]
});
// 검색 (하이브리드 필터링)
const result = await client.search('my_collection', {
vector: queryEmbedding,
limit: 5,
filter: {
must: [
{ key: 'category', match: { value: 'tech' } }
]
}
});
console.log(result);
활용 팁
- 선택 기준: 소규모 프로젝트는 pgvector(Supabase), 확장성 중요하면 Pinecone, 온프레미스는 Qdrant, 엔터프라이즈는 Milvus를 고려하세요.
- 임베딩 모델: OpenAI text-embedding-ada-002(1536차원)가 가장 범용적입니다. 한국어 특화는 multilingual-e5 모델도 좋습니다.
- 청크 크기: 텍스트를 너무 작게 나누면 문맥 손실, 너무 크게 나누면 정확도 하락. 보통 500-1000 토큰이 적당합니다.
- 하이브리드 검색: 벡터 검색 + 키워드 검색을 결합하면 정확도가 크게 향상됩니다. Weaviate가 이를 네이티브로 지원합니다.
- 메타데이터 필터링: 날짜, 카테고리 등으로 사전 필터링 후 벡터 검색을 수행하면 성능과 관련성이 모두 개선됩니다.
- 재순위화(Re-ranking): 초기 검색 결과를 Cross-Encoder 모델로 재평가하면 정확도가 크게 향상됩니다.
- 캐싱: 동일 쿼리는 결과를 캐싱하여 임베딩 API 비용과 지연시간을 줄이세요.
마무리
Vector Database는 AI 애플리케이션의 핵심 인프라로 자리 잡았습니다. RAG 패턴은 LLM의 환각(hallucination)을 줄이고 최신 정보를 제공하는 검증된 아키텍처입니다.
프로젝트 규모와 요구사항에 맞는 Vector DB를 선택하고, 임베딩 전략과 검색 파라미터를 조정하여 최적의 결과를 얻으시기 바랍니다. pgvector + Supabase 조합은 가장 빠르게 시작할 수 있는 좋은 선택지입니다.