본문 바로가기
C.W.K.
Stream
Lesson 05 of 05 · published

이전, 재임베딩, 무중단 전환

~20 min · pgvector, operations, migrations

Level 0Scout
0 XP0/41 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

pgvector 운영에서 구분할 두 상황

  1. 스키마 이전 — 벡터 컬럼이 있는 테이블에도 Alembic, dbmate, sqlx 같은 기존 이전 도구를 그대로 쓸 수 있어. 다만 데이터가 이미 든 테이블에 vector(N) NOT NULL 컬럼을 추가하려면 기존 값을 채울 계획이 필요해.
  2. 재임베딩 — 모델을 바꾸면서 차원이 달라지면 ALTER COLUMN으로 해결할 수 없어. 새 컬럼이나 새 테이블을 추가해야 해.

중단 없이 재임베딩하는 절차

  1. ALTER TABLE chunks ADD COLUMN embedding_v2 vector(1024) NULL;을 실행해.
  2. 텍스트를 읽어 임베딩한 뒤 embedding_v2가 NULL인 행을 배치로 채워.
  3. v2 인덱스를 만들어.
  4. 코드가 embedding_v2를 읽도록 전환해.
  5. 일주일 뒤 기존 embedding 컬럼을 삭제해.

백업

pg_dump와 특정 시점 복구는 평소처럼 작동해. 벡터 컬럼은 기본적으로 긴 텍스트로 직렬화되므로 매우 큰 테이블에서는 논리 덤프보다 기본 백업과 WAL 보관을 선호해.

Code

새 vector 컬럼을 나란히 추가하기·sql
ALTER TABLE chunks ADD COLUMN embedding_v2 vector(1024);

-- 옵션: backfill 끝날 때까지 partial 인덱스
CREATE INDEX chunks_embedding_v2_hnsw
    ON chunks USING hnsw (embedding_v2 vector_cosine_ops)
    WHERE embedding_v2 IS NOT NULL;
파이썬에서 배치로 기존 값 채우기·python
from itertools import islice

BATCH = 500
with conn.cursor() as cur:
    while True:
        cur.execute(
            'SELECT id, text FROM chunks WHERE embedding_v2 IS NULL LIMIT %s',
            (BATCH,),
        )
        rows = cur.fetchall()
        if not rows:
            break
        ids   = [r[0] for r in rows]
        texts = [r[1] for r in rows]
        new_vecs = new_model.encode(texts, normalize_embeddings=True).tolist()
        cur.executemany(
            'UPDATE chunks SET embedding_v2 = %s WHERE id = %s',
            list(zip(new_vecs, ids)),
        )
        conn.commit()
        print(f'backfilled {len(ids)} rows')

External links

Exercise

행 1만 개가 든 테스트 테이블에 새 vector 컬럼을 추가하고 500개씩 기존 값을 채워. v2 인덱스를 만든 뒤 코드의 읽기를 전환하고 v1 컬럼을 삭제해. 전체 소요 시간과 발생한 오류를 모두 기록하면 실제 서비스 이전 절차서의 바탕이 돼.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.