DOCS/journey/plans/260317_nonrdb_계층_postgresql_통일_계획.md

13 KiB

tags
tags
infra
database
postgres
pgvector
search
graph
plans

260317 non-RDB 계층 PostgreSQL 통일 계획

상태: closed

상위 원칙

관련 문서

문제 정의

  • 현재 운영 구조는 관계형 데이터는 PostgreSQL, 벡터는 ChromaDB, 관계 추론은 Neo4j, 검색은 별도 전용 계층 가능성을 함께 열어 둔 하이브리드 상태다.
  • 이 구조는 기능 분화 측면에서는 설명 가능하지만, 운영 기준으로는 백업, 복구, 권한, 런타임 SSOT, 장애 추적, 데이터 정합성 경로를 여러 저장소에 분산시킨다.
  • 이번 계획의 목표는 벡터, 검색, 그래프 계층을 PostgreSQL로 통일하고, 현 단계의 전용 DB를 제거 가능한 상태까지 실제 실행 순서를 고정하는 것이다.

범위

포함

  • ChromaDB가 맡고 있는 벡터/메모리/RAG 저장 구조를 PostgreSQL pgvector 기반으로 재설계
  • Neo4j가 맡고 있거나 맡을 예정인 관계 추론 구조를 PostgreSQL 관계 모델 + WITH RECURSIVE 중심으로 재설계
  • 검색 전용 계층 후보를 PostgreSQL FTS + pg_trgm + jsonb_to_tsvector 구조로 흡수
  • 운영 기준 SSOT를 PostgreSQL 중심 백업/복구/모니터링 구조로 재정렬

제외

  • 지금 단계에서 Redis까지 함께 없애는 캐시 전략 전체 재설계
  • 대규모 분산 클러스터링, 샤딩, 멀티리전 설계
  • 구현 완료 보고와 성능 확정 수치 기록

결정

  • 기본 저장소 전략은 PostgreSQL only until proven otherwise로 고정한다.
  • 현 단계의 non-RDB 기능은 전용 DB 존치를 기본값으로 두지 않고 PostgreSQL 흡수를 기본값으로 둔다.
  • 검색 해법은 FTS + pg_trgm + metadata filter + vector hybrid rank 조합을 기본으로 한다.
  • 그래프 해법은 adjacency table + recursive query를 기본 모델로 삼고, 필요 시 ltree를 보조 선택지로 쓴다.
  • 벡터 해법은 pgvector를 기본으로 하고, 인덱스는 HNSW를 우선 후보로 검토한다.
  • 전환 우선순위는 ChromaDB -> 검색 계층 -> Neo4j 순서로 둔다.
    • 이유: 현재 벡터 계층은 이미 임베딩 SSOT와 직접 연결돼 있고, 검색은 PostgreSQL 기능만으로 빠르게 흡수 가능하며, 그래프는 모델 재설계 논의가 가장 많이 필요하다.
  • 이번 계획에서 제외하는 경계도 고정한다.
    • Redis 전체 캐시 전략은 별도 주제로 남긴다.
    • 이번 계획의 닫힘은 ChromaDB, Neo4j, 검색 전용 저장소 제거 기준으로 판단한다.

목표 상태

1. 벡터

  • 문서/메모리/질의 임베딩은 PostgreSQL pgvector(768) 컬럼으로 저장한다.
  • tenant 분리는 별도 컬렉션이 아니라 tenant_id 또는 동등한 범위 키로 관리한다.
  • 메타데이터 필터, 최근성, 중요도, 사용자 범위는 SQL 조건으로 함께 평가한다.

벡터 테이블 초안

create table memory_vectors (
  id uuid primary key,
  tenant_id uuid not null,
  source_type text not null,
  source_id uuid not null,
  content text not null,
  embedding vector(768) not null,
  metadata jsonb not null default '{}'::jsonb,
  importance numeric(6,3),
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now()
);

2. 검색

  • 문서 본문, 요약, 태그, metadata jsonb는 PostgreSQL 내부에서 색인한다.
  • 정확 키워드/구문은 FTS, 오타/부분일치는 pg_trgm, 의미 유사도는 pgvector로 처리한다.
  • 최종 검색 랭킹은 SQL 안에서 결합 가능하도록 정의한다.

검색 테이블 초안

create table search_documents (
  id uuid primary key,
  tenant_id uuid not null,
  title text,
  content text not null,
  summary text,
  tags text[] not null default '{}',
  metadata jsonb not null default '{}'::jsonb,
  search_tsv tsvector,
  embedding vector(768),
  created_at timestamptz not null default now()
);

3. 그래프

  • 사건, 감정, 결과, 참여자 관계는 PostgreSQL 테이블과 edge 구조로 저장한다.
  • 관계 점수 계산은 SQL 또는 DB 인접 계층 서비스 로직으로 계산하되 저장소는 PostgreSQL 하나로 고정한다.
  • bounded-depth traversal과 cycle 방지는 WITH RECURSIVE, SEARCH, CYCLE 구문을 우선 사용한다.

그래프 테이블 초안

create table graph_nodes (
  node_id uuid primary key,
  tenant_id uuid not null,
  node_type text not null,
  payload jsonb not null default '{}'::jsonb,
  created_at timestamptz not null default now()
);

create table graph_edges (
  edge_id uuid primary key,
  tenant_id uuid not null,
  src_node_id uuid not null references graph_nodes(node_id),
  dst_node_id uuid not null references graph_nodes(node_id),
  edge_type text not null,
  weight numeric(6,3) not null default 1.0,
  payload jsonb not null default '{}'::jsonb,
  created_at timestamptz not null default now()
);

실행 순서

1. 벡터 저장 구조를 먼저 PostgreSQL로 확정한다

  • Chroma collection의 공통 속성을 추출한다.
    • tenant_id
    • document_id
    • content
    • embedding vector(768)
    • metadata jsonb
    • created_at
    • updated_at
  • 저장 전략은 global table + tenant key를 기본값으로 둔다.
  • 인덱스 초안은 아래를 기본으로 둔다.
    • embedding용 HNSW
    • tenant_id, created_at, 주요 metadata key용 btree 또는 표현식 인덱스
    • 필요 시 tenant 또는 도메인 단위 partition

2. 검색 스키마와 랭킹 공식을 고정한다

  • 검색 대상 테이블은 document_search 같은 단일 검색 뷰 또는 검색 전용 테이블로 수렴시킨다.
  • 색인 필드는 최소 아래를 포함한다.
    • title
    • content
    • summary
    • tags
    • metadata jsonb
  • 랭킹은 아래 순서로 결합한다.
    • ts_rank_cd(weighted_tsvector, query)
    • pg_trgm similarity
    • 필요 시 vector distance
    • 최신성 또는 중요도 가중치
  • 이 결합은 SQL 함수 또는 view로 감싼다.

3. 그래프 구조를 PostgreSQL 관계 모델로 재작성한다

  • 기본 구조는 아래 두 테이블 계열로 시작한다.
    • graph_nodes(node_id, node_type, payload jsonb, tenant_id, created_at)
    • graph_edges(edge_id, src_node_id, dst_node_id, edge_type, weight, payload jsonb, tenant_id, created_at)
  • 사건-감정-결과 관계는 edge_type으로 표준화한다.
  • 회상과 추론은 bounded-depth recursive query로 먼저 구현한다.
  • 계층형 경로나 고정 깊이 탐색이 반복되면 ltree 또는 materialized path를 보조 채택한다.

4. 이관 단위를 서비스별로 나눈다

  • 1차: rb8001 메모리 벡터와 recall
  • 2차: skill-rag-file 문서 벡터와 검색
  • 3차: 검색 전용 API 또는 검색 보조 기능
  • 4차: Neo4j 관계 추론 경로
  • 각 단계는 기존 읽기 경로 병행 -> PostgreSQL 결과 비교 -> 읽기 경로 전환 -> 기존 저장소 쓰기 중지 -> 기존 저장소 제거 순으로 진행한다.

4-1. 대표 질의셋을 먼저 고정한다

  • 벡터 질의셋:
    • 최근 기억 회상
    • 사용자별 유사 대화 top-k
    • 메타데이터 필터 포함 회상
  • 검색 질의셋:
    • 정확 키워드
    • 두 단어 구문 검색
    • 오타 1~2글자 포함 검색
    • 태그/metadata 필터 포함 검색
  • 그래프 질의셋:
    • 사건 -> 감정 -> 결과 연결 조회
    • 최근 1년 bounded-depth 관계 회상
    • 성공 사건 우선 랭킹

5. 운영 기준을 PostgreSQL 중심으로 다시 묶는다

  • 백업 기준은 PostgreSQL dump/physical backup을 우선 SSOT로 삼는다.
  • 모니터링은 pg_stat_statements, 인덱스 크기, bloat, query latency, vacuum 상태를 중심으로 본다.
  • 장애 복구 문서도 Chroma/Neo4j 복구가 아니라 PostgreSQL 스키마/인덱스/데이터 복구 중심으로 재작성한다.

검증 기준

기능 검증

  • ChromaDB가 제공하던 top-k 벡터 검색이 PostgreSQL pgvector에서 동일 tenant 범위로 재현된다.
  • 기존 검색 대표 질의셋이 FTS + pg_trgm 경로에서 허용 가능한 품질로 재현된다.
  • Neo4j에서 표현하던 사건-감정-결과 관계 질의가 PostgreSQL recursive query로 재현된다.

운영 검증

  • 백업/복구 절차가 PostgreSQL 기준 1세트로 단순화된다.
  • 런타임 env와 문서 SSOT에서 ChromaDB, Neo4j, 검색 전용 저장소를 필수 의존성으로 더 이상 요구하지 않는다.
  • 서비스 로그에 전용 DB 연결 실패가 핵심 경로 장애 원인으로 남지 않는다.

닫힘 조건

  • rb8001, skill-rag-file 기준 주요 벡터·검색·관계 기능이 PostgreSQL 경로로 동작한다.
  • 전용 DB 없이도 대표 사용자 시나리오가 재현된다.
  • 관련 문서의 아키텍처 설명이 PostgreSQL + ChromaDB + Neo4j에서 PostgreSQL 중심 단일 구조로 교체된다.
  • cut-over 후 worklog가 남고, 전용 DB 제거 또는 비활성화 근거가 기록된다.
  • 24 런타임과 배포 문서에서 ChromaDB, Neo4j, 검색 전용 저장소가 필수 서비스 목록에서 제거된다.

리스크와 대응

  • 벡터 검색 품질 저하 가능성:
    • 동일 질의셋으로 ChromaDB와 PostgreSQL 결과를 병렬 비교한다.
  • 검색 랭킹 불안정 가능성:
    • 가중치 조정용 대표 질의셋을 먼저 고정한다.
  • 그래프 질의 복잡성 증가 가능성:
    • 무제한 탐색을 허용하지 않고 bounded-depth 시나리오만 먼저 지원한다.
  • 테이블 비대화 가능성:
    • tenant key, partial index, partitioning 후보를 초기에 같이 검토한다.

롤백 기준

  • PostgreSQL 경로가 대표 질의셋에서 기존 결과 품질을 현저히 깨면 읽기 경로를 즉시 기존 저장소로 되돌린다.
  • PostgreSQL 전환 후 p95 응답 시간이 합의 기준을 넘기면 쓰기 중지는 유지하되 읽기 cut-over는 보류한다.
  • 롤백은 읽기 경로 restore -> 기존 저장소 쓰기 재개 -> PostgreSQL 비교 로그 보존 순서로 수행한다.

다음 단계로 넘길 결정 항목

  • memory_vectors, document_vectors, graph_nodes, graph_edges, search_documents 같은 실제 테이블 명세
  • HNSW 파라미터와 vacuum/maintenance 기준
  • hybrid rank 공식
  • 서비스별 cut-over 순서와 rollback 기준

실행 결과

  • 1차: rb8001 메모리 벡터와 recall은 PostgreSQL memory_vectors, memory_graph_nodes, memory_graph_edges로 전환 완료.
  • 2차: skill-rag-file 문서 벡터와 검색은 PostgreSQL team_document_chunk + pgvector(768)로 전환 완료.
  • 3차: rb8001의 잔여 Neo4j 런타임 경로였던 coldmail memory, startup valuation comparable prior, valuation premia recalculation도 PostgreSQL 경로로 전환 완료.
  • 24 배포는 rb8001 Gitea Actions와 skill-rag-file 실배포 검증으로 반영됐고, 컨테이너 헬스체크와 실제 저장/검색/재계산 결과로 확인됐다.
  • 이 계획의 닫힘 조건은 non-RDB 계층 PostgreSQL 통일 1차 실행 완료에서 충족 증거를 남겼다.

한 줄 결론

  • 이번 계획의 핵심은 전용 DB를 유지할 이유를 찾는 것이 아니라, 벡터 -> 검색 -> 그래프 순서로 non-RDB 계층을 PostgreSQL 하나로 흡수하는 실제 전환 순서를 고정하는 것이다.