migration 101 의 SQL 주석에 '[:200]' 이 들어 있었는데 SQLAlchemy text() 가 :200 을 named bind parameter 로 해석해 init_db() 가 'A value is required for bind parameter 200' 로 실패. fastapi startup 자체가 떨어지는 문제. 주석을 '첫 200자' 로 고쳐서 콜론+숫자/영문 패턴 제거.
58 lines
3.2 KiB
SQL
58 lines
3.2 KiB
SQL
-- Phase 4 Global News Digest
|
||
-- 7일 rolling window 뉴스를 country × topic 2-level로 묶어 매일 새벽 4시 KST 배치 생성
|
||
-- 검색 파이프라인 미사용. documents → clustering → cluster-level LLM summarization → digest
|
||
-- 사용자 결정: country→topic 2-level, cluster-level LLM only, drop 금지 fallback,
|
||
-- adaptive threshold, EMA centroid, time-decay (λ=ln(2)/3 ≈ 0.231)
|
||
|
||
-- 부모 테이블: 하루 단위 digest run 메타데이터
|
||
CREATE TABLE global_digests (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
digest_date DATE NOT NULL, -- KST 기준 생성일
|
||
window_start TIMESTAMPTZ NOT NULL, -- rolling window 시작 (UTC)
|
||
window_end TIMESTAMPTZ NOT NULL, -- 생성 시점 (UTC)
|
||
decay_lambda DOUBLE PRECISION NOT NULL, -- 실제 사용된 time-decay λ
|
||
|
||
total_articles INTEGER NOT NULL DEFAULT 0,
|
||
total_countries INTEGER NOT NULL DEFAULT 0,
|
||
total_topics INTEGER NOT NULL DEFAULT 0,
|
||
|
||
generation_ms INTEGER, -- 워커 실행 시간 (성능 회귀 감지)
|
||
llm_calls INTEGER NOT NULL DEFAULT 0,
|
||
llm_failures INTEGER NOT NULL DEFAULT 0, -- = fallback 사용 횟수
|
||
status VARCHAR(20) NOT NULL DEFAULT 'success', -- success | partial | failed
|
||
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||
|
||
UNIQUE (digest_date) -- idempotency: 같은 날짜 재실행 시 DELETE+INSERT
|
||
);
|
||
|
||
CREATE INDEX idx_global_digests_date ON global_digests (digest_date DESC);
|
||
|
||
-- 자식 테이블: country × topic 단위
|
||
CREATE TABLE digest_topics (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
digest_id BIGINT NOT NULL REFERENCES global_digests(id) ON DELETE CASCADE,
|
||
|
||
country VARCHAR(10) NOT NULL, -- KR | US | JP | CN | FR | DE | ...
|
||
topic_rank INTEGER NOT NULL, -- country 내 1..N (importance_score 내림차순)
|
||
|
||
topic_label TEXT NOT NULL, -- LLM 생성 5~10 단어 한국어 (또는 fallback 시 "주요 뉴스 묶음")
|
||
summary TEXT NOT NULL, -- LLM 생성 1~2 문장 factual (또는 fallback 시 top member ai_summary 첫 200자)
|
||
|
||
article_ids JSONB NOT NULL, -- [doc_id, ...] 코드가 주입 (LLM 생성 금지)
|
||
article_count INTEGER NOT NULL, -- = jsonb_array_length(article_ids)
|
||
|
||
importance_score DOUBLE PRECISION NOT NULL, -- batch 내 country별 0~1 normalized (cross-country 비교)
|
||
raw_weight_sum DOUBLE PRECISION NOT NULL, -- 정규화 전 decay 가중합 (디버그 + day-over-day 트렌드)
|
||
|
||
centroid_sample JSONB, -- 디버그: LLM 입력 doc id 목록 + summary hash
|
||
llm_model VARCHAR(100), -- 사용된 모델 (primary/fallback 추적)
|
||
llm_fallback_used BOOLEAN NOT NULL DEFAULT FALSE, -- LLM 실패 시 minimal fallback 적용 여부
|
||
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||
);
|
||
|
||
CREATE INDEX idx_digest_topics_digest ON digest_topics (digest_id);
|
||
CREATE INDEX idx_digest_topics_country ON digest_topics (country);
|
||
CREATE INDEX idx_digest_topics_rank ON digest_topics (digest_id, country, topic_rank);
|