Strengthen PostgreSQL consolidation docs

This commit is contained in:
happybell80 2026-03-17 00:13:54 +09:00
parent 8379e9f647
commit 714adeb59a
3 changed files with 100 additions and 0 deletions

View File

@ -20,6 +20,7 @@ tags: [infra, database, postgres, ideas, consolidation]
- 지금 인프라와 서비스 계층에는 `PostgreSQL`, `ChromaDB`, `Neo4j`, 경우에 따라 `Redis/검색 전용 계층`처럼 역할이 나뉘는 구조가 남아 있다.
- 이 구조는 각 역할에 최적화된 장점이 있지만, 운영자 입장에서는 백업, 장애 추적, 권한, 런타임 SSOT, 복구 절차, 데이터 정합성 관리가 분산된다.
- 특히 팀 규모가 작고 서비스 경계가 자주 바뀌는 단계에서는 `DB를 여러 개 운영하는 비용`이 기능 이점보다 더 크게 느껴질 수 있다.
- 이번 아이디어의 직접 대상은 `ChromaDB`, `Neo4j`, 검색 전용 저장소 같은 non-RDB 계층이며, `Redis 전체 캐시 전략`은 지금 문서의 범위에 넣지 않는다.
## 현재상태 -> 기대상태
@ -55,6 +56,7 @@ tags: [infra, database, postgres, ideas, consolidation]
- 서비스 간 데이터 동기화와 이중 저장 부담이 줄어든다.
- `workspace-config`와 런타임 SSOT 해석도 더 직접적이 된다.
- 운영자가 장애 시 봐야 하는 저장소 종류와 복구 절차가 줄어든다.
- `rb8001`, `skill-rag-file` 같은 실제 경로에서 `PostgreSQL만 보면 된다`는 운영 해석이 가능해진다.
## 검증이 필요한 이유
@ -73,6 +75,9 @@ tags: [infra, database, postgres, ideas, consolidation]
- 이 아이디어는 검토 대상이 아니라 현재 방향으로 고정할 수 있다.
- 현 단계 목표는 `전용 DB와 non-RDB 저장소를 유지할 이유를 찾는 것`이 아니라 `PostgreSQL 통일 경로를 설계하는 것`이다.
- 실행 순서와 제거 대상 우선순위는 [non-RDB 계층 PostgreSQL 통일 계획](../plans/260317_nonrdb_계층_postgresql_통일_계획.md)으로 넘긴다.
- 경계도 같이 고정한다.
- 지금 없애는 대상: `ChromaDB`, `Neo4j`, 검색 전용 저장소
- 지금 보류하는 대상: `Redis 전체 캐시 전략`
- 현재 시점의 해석은 아래 문장으로 고정한다.
`인프라의 벡터, 그래프, 검색 계층은 지금부터 PostgreSQL로 통일하는 방향으로 정리하고, 전용 DB는 현 단계에서 제거 대상으로 본다.`

View File

@ -50,6 +50,9 @@ tags: [infra, database, postgres, pgvector, search, graph, plans]
- 벡터 해법은 `pgvector`를 기본으로 하고, 인덱스는 `HNSW`를 우선 후보로 검토한다.
- 전환 우선순위는 `ChromaDB -> 검색 계층 -> Neo4j` 순서로 둔다.
- 이유: 현재 벡터 계층은 이미 임베딩 SSOT와 직접 연결돼 있고, 검색은 PostgreSQL 기능만으로 빠르게 흡수 가능하며, 그래프는 모델 재설계 논의가 가장 많이 필요하다.
- 이번 계획에서 제외하는 경계도 고정한다.
- `Redis 전체 캐시 전략`은 별도 주제로 남긴다.
- 이번 계획의 닫힘은 `ChromaDB`, `Neo4j`, 검색 전용 저장소 제거 기준으로 판단한다.
## 목표 상태
@ -59,18 +62,75 @@ tags: [infra, database, postgres, pgvector, search, graph, plans]
- tenant 분리는 별도 컬렉션이 아니라 `tenant_id` 또는 동등한 범위 키로 관리한다.
- 메타데이터 필터, 최근성, 중요도, 사용자 범위는 SQL 조건으로 함께 평가한다.
#### 벡터 테이블 초안
```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 안에서 결합 가능하도록 정의한다.
#### 검색 테이블 초안
```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` 구문을 우선 사용한다.
#### 그래프 테이블 초안
```sql
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로 확정한다
@ -122,6 +182,22 @@ tags: [infra, database, postgres, pgvector, search, graph, plans]
- 4차: Neo4j 관계 추론 경로
- 각 단계는 `기존 읽기 경로 병행 -> PostgreSQL 결과 비교 -> 읽기 경로 전환 -> 기존 저장소 쓰기 중지 -> 기존 저장소 제거` 순으로 진행한다.
### 4-1. 대표 질의셋을 먼저 고정한다
- 벡터 질의셋:
- 최근 기억 회상
- 사용자별 유사 대화 top-k
- 메타데이터 필터 포함 회상
- 검색 질의셋:
- 정확 키워드
- 두 단어 구문 검색
- 오타 1~2글자 포함 검색
- 태그/metadata 필터 포함 검색
- 그래프 질의셋:
- 사건 -> 감정 -> 결과 연결 조회
- 최근 1년 bounded-depth 관계 회상
- 성공 사건 우선 랭킹
### 5. 운영 기준을 PostgreSQL 중심으로 다시 묶는다
- 백업 기준은 PostgreSQL dump/physical backup을 우선 SSOT로 삼는다.
@ -148,6 +224,7 @@ tags: [infra, database, postgres, pgvector, search, graph, plans]
- 전용 DB 없이도 대표 사용자 시나리오가 재현된다.
- 관련 문서의 아키텍처 설명이 `PostgreSQL + ChromaDB + Neo4j`에서 `PostgreSQL 중심 단일 구조`로 교체된다.
- cut-over 후 worklog가 남고, 전용 DB 제거 또는 비활성화 근거가 기록된다.
- 24 런타임과 배포 문서에서 `ChromaDB`, `Neo4j`, 검색 전용 저장소가 필수 서비스 목록에서 제거된다.
## 리스크와 대응
@ -160,6 +237,12 @@ tags: [infra, database, postgres, pgvector, search, graph, plans]
- 테이블 비대화 가능성:
- tenant key, partial index, partitioning 후보를 초기에 같이 검토한다.
## 롤백 기준
- PostgreSQL 경로가 대표 질의셋에서 기존 결과 품질을 현저히 깨면 읽기 경로를 즉시 기존 저장소로 되돌린다.
- PostgreSQL 전환 후 p95 응답 시간이 합의 기준을 넘기면 쓰기 중지는 유지하되 읽기 cut-over는 보류한다.
- 롤백은 `읽기 경로 restore -> 기존 저장소 쓰기 재개 -> PostgreSQL 비교 로그 보존` 순서로 수행한다.
## 다음 단계로 넘길 결정 항목
- `memory_vectors`, `document_vectors`, `graph_nodes`, `graph_edges`, `search_documents` 같은 실제 테이블 명세

View File

@ -100,18 +100,29 @@ tags: [infra, database, postgres, redis, pgvector, elasticsearch, neo4j, researc
- 로빙 계열 벡터 검색은 메타데이터 필터, 사용자 단위 분리, top-k 검색, 기억 회상, 파일/RAG 결합처럼 관계형 데이터와 함께 움직이는 비중이 크다.
- 이 유형은 별도 벡터 DB보다 `PostgreSQL + pgvector + 관계형 필터`가 오히려 자연스럽다.
- 실제 남는 과제는 `HNSW/IVFFlat 선택`, `ef_search/iterative_scan`, `부분 인덱스/파티셔닝`, `halfvec/압축 여부` 같은 튜닝이지, 기능 부재가 아니다.
- 대표 질의 형태도 이미 PostgreSQL 친화적이다.
- `tenant_id = ? AND category = 'memory' ORDER BY embedding <=> :query LIMIT 10`
- `tenant_id = ? AND created_at >= now() - interval '30 days' ORDER BY embedding <=> :query LIMIT 5`
### 4. 검색은 `FTS + pg_trgm` 조합으로 먼저 닫을 수 있다
- 사용자가 기대하는 검색은 보통 `정확 키워드`, `구문`, `웹검색식 입력`, `오타/부분일치`, `메타데이터 필터`, `랭킹`의 조합이다.
- PostgreSQL은 `phraseto_tsquery`, `websearch_to_tsquery`, `setweight`, `jsonb_to_tsvector`, `pg_trgm` similarity를 모두 공식 기능으로 제공한다.
- 따라서 현재 단계의 검색 통일은 `Elasticsearch 대체 불가 여부`를 묻기보다 `PostgreSQL 안에서 검색 스키마와 인덱스를 어떻게 짤지`를 묻는 단계로 보는 것이 맞다.
- 대표 질의 형태는 아래처럼 바로 그릴 수 있다.
- `WHERE search_tsv @@ websearch_to_tsquery('simple', :q)`
- `ORDER BY ts_rank_cd(search_tsv, websearch_to_tsquery('simple', :q)) DESC, similarity(title, :q) DESC`
- metadata 필터는 `metadata->>'source' = 'companyx'` 같은 SQL 조건으로 결합 가능하다.
### 5. 그래프는 `무제한 자유 탐색`이 아니라 `경계 있는 관계 탐색`으로 재정의하면 PostgreSQL로 수렴시킬 수 있다
- PostgreSQL의 recursive CTE로 그래프성 질의를 구현할 수는 있다.
- `SEARCH``CYCLE` 구문, path array, `ltree` 같은 도구를 쓰면 bounded-depth traversal, 계층형 경로, 관계 추적은 공식 SQL 범위 안에서 구현할 수 있다.
- 현재 로빙 문서에 적힌 Neo4j 용도도 초거대 공개 그래프 탐색이 아니라 `사건-감정-결과 관계 가중치`와 같은 제한된 관계망이므로, 현 단계에서는 PostgreSQL 모델 재설계로 충분히 흡수 가능한 범주에 가깝다.
- 대표 질의도 `3단계 이하 관계 회상`에 가깝다.
- `특정 사건과 감정/결과로 연결된 최근 사건 찾기`
- `사용자별 최근 1년 유사 사건 경로 찾기`
- `성공 결과가 붙은 사건을 우선 랭킹하기`
### 6. 이 아이디어를 닫는 데 남은 미확정은 `가능한가`가 아니라 `어떻게 옮길까`에 가깝다
@ -125,6 +136,7 @@ tags: [infra, database, postgres, redis, pgvector, elasticsearch, neo4j, researc
- `ChromaDB collection -> PostgreSQL table` 매핑 단위를 `tenant per table`, `global table + tenant key`, `partition per tenant` 중 무엇으로 잡을지 결정이 아직 없다.
- Neo4j의 `Event-Emotion-Result` 그래프를 `adjacency table`, `materialized path`, `ltree`, `jsonb edge payload` 중 어떤 방식으로 표현할지 결정이 아직 없다.
- 검색 쪽도 `문서 원문`, `요약문`, `태그`, `metadata jsonb`에 어떤 가중치를 줄지와 `FTS + pg_trgm + vector hybrid rank` 공식을 아직 정하지 않았다.
- 내부 대표 질의셋 10~20개를 무엇으로 고정할지 아직 없다.
- 즉 이 주제의 다음 단계는 추가 일반론 리서치가 아니라 [non-RDB 계층 PostgreSQL 통일 계획](../plans/260317_nonrdb_계층_postgresql_통일_계획.md) 기준의 `스키마/인덱스/랭킹 설계 실행`이다.
## 한 줄 결론