PostgreSQL 17 자체에는 AI 기능이 내장되지 않았지만, pgvector 확장을 설치하면 "벡터 타입 + 유사도 검색(k‑NN)"을 바로 쓸 수 있어요. 이 글은 PaaS(PostgreSQL 17) 환경을 기준으로 설치 → 스키마 설계 → 인덱스 튜닝 → RAG/추천 시나리오까지 한 번에 정리합니다.
1. 빠른 개요
- 무엇을? 텍스트/이미지/오디오 임베딩(고차원 벡터)을 DB에 저장하고, 질의 벡터와 가장 가까운 문서를 찾습니다.
- 왜 Postgres? 정형(SQL) + 반정형(JSONB) + 벡터(vector)를 한 DB에서 관리 → 운영 단순화, 트랜잭션/권한/백업 일원화.
- 어떻게? pgvector 확장으로 vector 타입/연산자를 활성화하고, IVFFlat/HNSW 인덱스로 근사 최근접 탐색을 가속합니다.
2. 준비물 & 설치
PaaS마다 확장 지원이 다릅니다. 콘솔/문서에서 pgvector 지원 여부를 확인하세요. (미지원이면 자체 호스팅 고려)
-- 슈퍼유저/확장 설치 권한 필요
CREATE EXTENSION IF NOT EXISTS vector; -- pgvector
버전/권한 팁
- DB 단위(스키마 아님)로 확장을 설치합니다.
- 동일 인스턴스에 여러 DB가 있다면 각 DB마다 CREATE EXTENSION 실행.
3. 스키마 설계 (하이브리드 모델)
핵심 아이디어: 많이 조회/필터되는 메타 필드는 정규 컬럼, 나머지는 jsonb, 검색은 vector.
CREATE TABLE doc (
id bigserial PRIMARY KEY,
title text NOT NULL,
body text, -- 원문 전문(선택)
meta jsonb, -- 태그/카테고리 등 유연 필드
embedding vector(768), -- 임베딩 차원수 고정(예: 768)
created_at timestamptz DEFAULT now()
);
- vector(768): 모델 차원에 맞춰 고정합니다 (예: OpenAI 1536, bge 768 등).
- 자주 쓰는 필터(예: category, lang)는 생성 컬럼으로 승격해 B‑tree 인덱스를 걸면 플래너가 안정적입니다.
ALTER TABLE doc
ADD COLUMN category text GENERATED ALWAYS AS (meta->>'category') STORED,
ADD COLUMN lang text GENERATED ALWAYS AS (meta->>'lang') STORED;
CREATE INDEX ON doc (category);
CREATE INDEX ON doc (lang);
4. 인덱스 선택: IVFFlat vs HNSW
pgvector는 정확 탐색(Seq/B‑tree 등) 외에 근사 최근접 탐색(ANN) 인덱스를 제공합니다.
4‑1) IVFFlat (인버티드 파일)
- 생성 빠름, 파라미터 간단, 대규모 데이터셋에 적합.
- 파라미터: lists(클러스터 개수), 검색 시 probe(탐색 클러스터 수).
-- L2 거리 기준 IVFFlat 인덱스
CREATE INDEX idx_doc_vec_ivf
ON doc USING ivfflat (embedding vector_l2_ops)
WITH (lists = 100);
-- 검색 시(세션/쿼리 단위)
SET ivfflat.probes = 10; -- 더 정확히 찾고 싶으면 상향(지연 증가)
4‑2) HNSW (그래프 탐색)
- 더 높은 정확도/재현율, 읽기 성능 우수. 인덱스 생성 비용은 IVFFlat보다 큼.
- 파라미터: m(연결도), ef_construction(구축), 검색 시 ef_search.
CREATE INDEX idx_doc_vec_hnsw
ON doc USING hnsw (embedding vector_l2_ops)
WITH (m = 16, ef_construction = 64);
SET hnsw.ef_search = 64; -- 정확도↑ (응답시간은 증가)
거리함수 선택
- vector_l2_ops (유클리드 거리)
- vector_ip_ops (inner product)
- vector_cosine_ops (코사인). 코사인은 정규화(단위 벡터)를 권장합니다.
5. 임베딩 적재 & 검색
5‑1) 적재 예시
INSERT INTO doc (title, body, meta, embedding)
VALUES (
'RAG 소개',
'검색 증강 생성(RAG)은...',
'{"category":"ai","lang":"ko"}',
'[0.012, -0.044, ... , 0.078]'::vector
);
임베딩은 애플리케이션 레이어(파이썬/노드 등)에서 모델 호출 후 저장합니다.
5‑2) k‑NN 질의 (Top‑k)
-- 질의 벡터 q가 주어졌을 때, 가장 가까운 5개 문서
SELECT id, title, category, lang, embedding <-> '[...]'::vector AS dist
FROM doc
WHERE category = 'ai' -- 메타 필터와 결합(하이브리드 검색)
ORDER BY embedding <-> '[...]'::vector
LIMIT 5;
- 연산자 <->는 선택한 거리 함수에 맞는 작을수록 유사한 값.
- 메타 조건과 결합(예: 언어/권한/태그)하면 정확도와 품질이 올라갑니다.
6. RAG(검색 증강 생성) 미니 파이프라인
- 수집/전처리: PDF/문서 → 청크 분할(예: 500~1,000 토큰) + 메타 작성.
- 임베딩: 각 청크 → 임베딩 → doc에 저장.
- 질의 처리: 사용자 질문 → 임베딩 → k‑NN으로 상위 N개 검색.
- 프롬프트 구성: 상위 문서의 본문/요약을 LLM에 컨텍스트로 주입.
-- 청크 테이블로 세분화
CREATE TABLE doc_chunk (
id bigserial PRIMARY KEY,
doc_id bigint REFERENCES doc(id) ON DELETE CASCADE,
chunk_no int,
text text,
emb vector(768)
);
CREATE INDEX ON doc_chunk USING hnsw (emb vector_cosine_ops) WITH (m=16, ef_construction=64);
- 하이브리드 검색: tsvector(전문검색) + 벡터 검색을 합쳐 랭킹을 재조정하면 품질이 더 좋아집니다.
-- 예시: 키워드 점수 + 벡터 거리 가중 합산(간단 점수)
WITH kw AS (
SELECT id, ts_rank_cd(to_tsvector('simple', text), plainto_tsquery('simple', 'RAG')) AS kw_score
FROM doc_chunk
), nn AS (
SELECT id, (1.0 - (emb <-> '[...]'::vector)) AS nn_score -- 코사인 유사도 유사 표현
FROM doc_chunk
ORDER BY emb <-> '[...]'::vector
LIMIT 50
)
SELECT c.id, c.doc_id, (0.6*coalesce(kw.kw_score,0) + 0.4*coalesce(nn.nn_score,0)) AS score
FROM doc_chunk c
LEFT JOIN kw ON kw.id = c.id
LEFT JOIN nn ON nn.id = c.id
ORDER BY score DESC
LIMIT 10;
7. 운영/성능 체크리스트
- 차원/거리 함수를 모델에 맞게 고정했는가? (L2/IP/Cosine)
- 인덱스 타입을 선택했는가? (IVFFlat: 빠른 구축/대용량, HNSW: 고정확도)
- IVFFlat lists/probes, HNSW m/ef_*를 벤치마크로 튜닝했는가?
- 메타 필터(카테고리/언어/권한)를 B‑tree/생성 컬럼으로 최적화했는가?
- 배치 적재 후 ANALYZE/통계 적재, 인덱스 재구성 전략(REINDEX CONCURRENTLY)을 준비했는가?
- 대형 업데이트/삭제 시 파티셔닝과 Autovacuum 상태를 점검하는가?
- PITR/스냅샷/CDC(논리 복제) 등 백업·동기화 전략을 마련했는가?
8. 보안·권한·거버넌스
- 행 수준 보안(RLS)로 테넌트/사용자별 접근 제어.
- 벡터 컬럼도 일반 컬럼과 동일하게 권한을 관리(SELECT 제한 등).
- 임베딩 생성에 사용된 모델/버전/파라미터를 meta에 기록해 재현 가능성 확보.
ALTER TABLE doc ENABLE ROW LEVEL SECURITY;
CREATE POLICY p_doc_tenant ON doc USING ((meta->>'tenant_id') = current_setting('app.tenant', true));
9. 장애/운영 팁
- 인덱스 생성은 오프피크에, CONCURRENTLY 옵션 활용(잠금 완화).
- IVFFlat은 데이터 분포가 바뀌면 REINDEX로 재학습 효과.
- HNSW는 인덱스 크기가 커질 수 있으니 스토리지 여유를 확보.
- 쿼리 플랜 확인: EXPLAIN (ANALYZE, BUFFERS)로 실제 경로/효과 측정.
10. 결론
- PostgreSQL 17 + pgvector는 RAG/의미검색/추천 등 핵심 AI 패턴을 구현하기에 충분한 스택입니다.
- 한 DB에서 정형 + 반정형 + 벡터를 통합 관리할 수 있어 운영 복잡도를 낮출 수 있습니다.
- 인덱스/파라미터 튜닝과 하이브리드 검색(메타/키워드 결합)으로 정확도·성능을 균형 있게 끌어올리세요.
'Database > postgreSQL' 카테고리의 다른 글
| PostgreSQL + pg_partman + pg_cron을 활용한 자동 파티션 관리 (1) | 2025.09.13 |
|---|---|
| PostgreSQL DBA 카탈로그/뷰 치트시트 — pg_user, pg_roles부터 실무 점검 스크립트까지 (1) | 2025.09.05 |
| PostgreSQL에서 DB 구성 전략 — DB vs 스키마 vs 테이블스페이스 (0) | 2025.09.04 |
| PostgreSQL의 jsonb와 인덱스 — 문서 DB처럼 쓰는 법 (MySQL과 비교) (0) | 2025.09.04 |
| PostgreSQL의 VACUUM — MySQL에는 없는 독특한 관리 개념 (0) | 2025.09.04 |