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(검색 증강 생성) 미니 파이프라인

  1. 수집/전처리: PDF/문서 → 청크 분할(예: 500~1,000 토큰) + 메타 작성.
  2. 임베딩: 각 청크 → 임베딩 → doc에 저장.
  3. 질의 처리: 사용자 질문 → 임베딩 → k‑NN으로 상위 N개 검색.
  4. 프롬프트 구성: 상위 문서의 본문/요약을 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에서 정형 + 반정형 + 벡터를 통합 관리할 수 있어 운영 복잡도를 낮출 수 있습니다.
  • 인덱스/파라미터 튜닝과 하이브리드 검색(메타/키워드 결합)으로 정확도·성능을 균형 있게 끌어올리세요.

 

+ Recent posts