- 新增 report_db 包: MySQL 连接/建表/幂等写入 (news_report/news_event, myquant 库) - 新增 report_import 包: 历史 178 份日报 HTML 解析入库, 表头驱动列映射 - reporter.py 完全切换: generate_report 结构化入库, 不再生成/上传 HTML - CLI: 新增 report-import 子命令 - 依赖: uv add pymysql; 配置: NEWS_DB_* / REPORT_HISTORY_DIR - 文档: docs/report_db_design.md(实现逻辑), docs/db_schema.md(表结构供 API/前端) - 测试: 24 个单测通过 (parser/builder/models/importer)
5.2 KiB
5.2 KiB
日报结构化入库:数据库表结构与数据契约
版本:v1.0 | 2026-08-03 用途:供 API / 前端对接读取日报数据。表位于 MySQL
myquant库,表前缀news_。 连接:192.168.1.10:13306(pi 上 autossh 隧道 → doorcome.cn:3306 MariaDB 10.11),用户myquant(密码在服务器.env的NEWS_DB_PASSWORD)。
1. 表结构
1.1 news_report(日报主表,一行 = 一份日报)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | BIGINT UNSIGNED PK | 自增主键 |
| report_date | DATE | 日报日期 |
| report_type | VARCHAR(16) | finance=A 股日报 / intl=国际财经日报 |
| file_name | VARCHAR(160) | 历史文件源文件名;新生成日报为空字符串 "" |
| generated_at | DATETIME | 生成时间 |
| ai_summary | TEXT | AI 摘要全文(含换行,按条目分行) |
| stats | JSON | 数据总览统计快照(见第 3 节),可为 NULL |
| created_at | DATETIME | 入库时间 |
唯一键:(report_date, report_type, file_name) —— 历史同一天多次生成(intl 一日 3 次)保留多行;新生成日报 file_name='' 每天每类型仅一行,重复生成覆盖。
1.2 news_event(日报事件明细,一行 = 一条事件)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | BIGINT UNSIGNED PK | 自增主键 |
| report_id | BIGINT UNSIGNED | FK → news_report.id |
| section | VARCHAR(16) | 板块:xwlb=新闻联播 / news=财经新闻 / cninfo=公告调研 / intl=国际重要事件 |
| rank | INT | 板块内序号(1 起) |
| importance | INT NULL | 重要度 1-5 |
| event_type | VARCHAR(64) NULL | 事件类型(如 宏观经济/地缘政治/新闻联播/公告) |
| title | VARCHAR(512) | 标题 |
| summary | TEXT NULL | 摘要/正文 |
| sentiment | VARCHAR(8) NULL | positive / negative / neutral |
| source | VARCHAR(64) NULL | 来源(如 cls、investinglive.com) |
| url | VARCHAR(512) NULL | 原文链接(新闻联播为空) |
| created_at | DATETIME | 入库时间 |
索引:idx_report_section (report_id, section)。
2. 数据契约
- 幂等语义:同一
(report_date, report_type, file_name)重复写入会覆盖主表并全量替换事件(DELETE + INSERT),不会产生重复行。 - 取最新:同一天存在多份时(历史 intl 一日 3 次),前端按
generated_at取最新;新日报file_name=''每天唯一。 - 板块差异:finance 日报含
xwlb+news+cninfo三板块;intl 日报仅intl板块。前端按section过滤展示。 - 历史覆盖范围:2026-06-16 ~ 2026-08-03,共 177 行(finance 49 + intl 128;finance 少 1 因为两个目录存在同名文件被幂等合并)。事件总计 4222 条。
3. stats JSON 结构
news_report.stats 为数据总览快照,前端自行解析。finance 与 intl 的 key 集合不同:
| key | finance | intl | 内容 |
|---|---|---|---|
pipeline |
✅ | ✅ | M1→M6 管道各环节数量:{label: 数量} |
sources |
✅ | — | 各新闻源文章数:{源名: 数量} |
news |
✅ | — | 新闻统计:{total, hi_threshold, sentiments, importances, event_types} |
cninfo |
✅ | — | 公告调研统计:{total, hi_threshold, by_day, announcement, research, irm} |
xwlb |
✅ | — | 联播统计:{total, date}(有数据时才有) |
sentiment |
✅ | ✅ | 情绪分布(历史文件为图例文本列表;新生成在 news.sentiments) |
importance |
✅ | ✅ | 重要度分布:[{重要度, 数量}, ...] |
event_types |
✅ | ✅ | 事件类型 TOP:[{事件类型, 数量}, ...] |
source_dist |
— | ✅ | 文章来源分布:[{来源, 文章数}, ...] |
历史文件与新生成日报的 stats 结构存在差异(历史为 HTML 解析快照,新生成为结构化组装),前端建议按 key 防御性读取。
4. 常用查询示例(API 实现参考)
-- 某类型日报列表(取每天最新一份)
SELECT r.* FROM news_report r
JOIN (
SELECT report_date, report_type, MAX(generated_at) AS g
FROM news_report GROUP BY report_date, report_type
) t ON r.report_date = t.report_date AND r.report_type = t.report_type
AND r.generated_at = t.g
WHERE r.report_type = 'finance' AND r.report_date >= '2026-07-01'
ORDER BY r.report_date DESC;
-- 某日报的全部事件(按板块)
SELECT section, rank, importance, event_type, title, summary, sentiment, source, url
FROM news_event WHERE report_id = ? ORDER BY section, rank;
-- 最近 N 天重要事件聚合(跨日报检索)
SELECT e.* FROM news_event e
JOIN news_report r ON r.id = e.report_id
WHERE r.report_date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
AND e.importance >= 4
ORDER BY e.importance DESC, r.report_date DESC;
5. 相关命令(数据生产侧)
uv run a-share report --date YYYYMMDD # 生成当日日报并入库(finance)
uv run a-share report-import # 历史 HTML 全量解析入库(幂等)
uv run a-share report-import --date YYYYMMDD --type intl
代码:report_db/(连接/写入)、report_import/(历史解析/导入)、scheduler/reporter.py(日报生成)。