107 lines
4.3 KiB
SQL
107 lines
4.3 KiB
SQL
-- 日内新闻候选与验证持久化结构
|
||
|
||
CREATE TABLE IF NOT EXISTS intraday_news_candidate (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
candidate_date DATE NOT NULL,
|
||
discovered_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
event_type TEXT NOT NULL,
|
||
provider_name TEXT NOT NULL,
|
||
model_name TEXT,
|
||
provider_country TEXT,
|
||
title TEXT NOT NULL,
|
||
summary TEXT,
|
||
candidate_urls JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||
discovery_source TEXT NOT NULL,
|
||
discovery_query TEXT,
|
||
discovery_evidence JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||
normalized_key TEXT NOT NULL,
|
||
status TEXT NOT NULL DEFAULT 'candidate',
|
||
verification_confidence TEXT NOT NULL DEFAULT 'candidate',
|
||
verification_notes TEXT,
|
||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
DO $$
|
||
BEGIN
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM pg_constraint WHERE conname = 'chk_intraday_news_candidate_status'
|
||
) THEN
|
||
ALTER TABLE intraday_news_candidate
|
||
ADD CONSTRAINT chk_intraday_news_candidate_status
|
||
CHECK (status IN ('candidate', 'verifying', 'verified', 'rejected', 'stale'));
|
||
END IF;
|
||
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM pg_constraint WHERE conname = 'chk_intraday_news_candidate_confidence'
|
||
) THEN
|
||
ALTER TABLE intraday_news_candidate
|
||
ADD CONSTRAINT chk_intraday_news_candidate_confidence
|
||
CHECK (verification_confidence IN ('candidate', 'secondary_confirmed', 'official_confirmed'));
|
||
END IF;
|
||
END
|
||
$$;
|
||
|
||
CREATE UNIQUE INDEX IF NOT EXISTS idx_intraday_news_candidate_normalized_key
|
||
ON intraday_news_candidate(normalized_key);
|
||
CREATE INDEX IF NOT EXISTS idx_intraday_news_candidate_date
|
||
ON intraday_news_candidate(candidate_date DESC, discovered_at DESC);
|
||
CREATE INDEX IF NOT EXISTS idx_intraday_news_candidate_status
|
||
ON intraday_news_candidate(status);
|
||
CREATE INDEX IF NOT EXISTS idx_intraday_news_candidate_provider_event
|
||
ON intraday_news_candidate(provider_name, event_type, candidate_date DESC);
|
||
|
||
COMMENT ON TABLE intraday_news_candidate IS '搜索引擎与 LLM 发现的日内新闻候选池,尚未直接进入正式日报事实层';
|
||
COMMENT ON COLUMN intraday_news_candidate.candidate_urls IS '候选来源 URL 数组,按发现层输出原样保留';
|
||
COMMENT ON COLUMN intraday_news_candidate.discovery_evidence IS '发现阶段原始证据 JSONB,例如搜索命中、LLM 归纳结果';
|
||
COMMENT ON COLUMN intraday_news_candidate.normalized_key IS '同日同事件的去重键,避免重复发现候选';
|
||
|
||
CREATE TABLE IF NOT EXISTS intraday_news_verification (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
candidate_id BIGINT NOT NULL REFERENCES intraday_news_candidate(id) ON DELETE CASCADE,
|
||
verified_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
verifier_source TEXT NOT NULL,
|
||
verifier_url TEXT,
|
||
verifier_status TEXT NOT NULL,
|
||
extracted_facts JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||
notes TEXT,
|
||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
DO $$
|
||
BEGIN
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM pg_constraint WHERE conname = 'chk_intraday_news_verification_status'
|
||
) THEN
|
||
ALTER TABLE intraday_news_verification
|
||
ADD CONSTRAINT chk_intraday_news_verification_status
|
||
CHECK (verifier_status IN ('matched', 'contradicted', 'insufficient', 'error'));
|
||
END IF;
|
||
END
|
||
$$;
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_intraday_news_verification_candidate_verified_at
|
||
ON intraday_news_verification(candidate_id, verified_at DESC);
|
||
CREATE INDEX IF NOT EXISTS idx_intraday_news_verification_source
|
||
ON intraday_news_verification(verifier_source);
|
||
CREATE INDEX IF NOT EXISTS idx_intraday_news_verification_status
|
||
ON intraday_news_verification(verifier_status);
|
||
|
||
COMMENT ON TABLE intraday_news_verification IS '日内新闻候选的验证轨迹,记录验证来源、状态和提取事实';
|
||
COMMENT ON COLUMN intraday_news_verification.extracted_facts IS '验证阶段提取出的结构化事实 JSONB';
|
||
|
||
DO $$
|
||
BEGIN
|
||
IF NOT EXISTS (
|
||
SELECT 1
|
||
FROM pg_trigger
|
||
WHERE tgname = 'intraday_news_candidate_updated_at'
|
||
) THEN
|
||
CREATE TRIGGER intraday_news_candidate_updated_at
|
||
BEFORE UPDATE ON intraday_news_candidate
|
||
FOR EACH ROW
|
||
EXECUTE FUNCTION update_updated_at_column();
|
||
END IF;
|
||
END
|
||
$$;
|