跳转至

数据模型

三层定义保持一致:本体 schema(src/kg/ontology.py::build_schema(),驱动 /ontology 页与 RDF 导出)↔ SQLite 实例库(data/xgb_wiki.db,§1–§6)↔ RDF 导出(src/kg/rdf_export.py)。本页按 SQLite 实际表结构(2026-09-05 实测)整理。 另有派生库 知识图谱(data/graph.db,§7)与镜像库 staging(data/staging.db,见 staging-schema.md)。 概念含义见 名词解释;模型取舍的设计动机见 设计方案 §2。

1. 实体表(8 张)

chain 产业链

列 类型 说明
id TEXT PK 链标识(slug),即本体 chainId
name TEXT 如"AI算力"
description TEXT

segment 环节

列 类型 说明
id TEXT PK 环节标识,即本体 segmentId
chain_id TEXT 所属链(→ chain.id,segment_part_of_chain)
name TEXT 自由命名,用研报原文词汇
segment_type TEXT 角色类型,开放字典(默认六类,见 §3)
stage_tag TEXT 派生粗分组(上游/中游/下游/配套)
order_no INTEGER 链内顺序(工序型链有意义)
is_bottleneck INTEGER 卡脖子标记 0/1

theme 题材

列 类型 说明
plate_id INTEGER PK 板块 ID,即本体 plateId
name TEXT NOT NULL
classification TEXT 概念 / 行业 / 风格(+ 待审核/未知)
occurrence_count INTEGER 出现次数(全库聚合)
first_seen_at / last_seen_at TEXT 首次/最近提及
decay_score REAL 衰减热度(见设计方案 §2.4)
cnt_5d / cnt_10d / cnt_20d / cnt_30d INTEGER 滚动时间窗出现次数(自然日口径,截至最新研报日;src/content/trends.py 重算)
streak_days INTEGER 后端指标(已不用于展示):从最后一次提及往前数的连续数据日数。页面口径已改为活跃天数=所选窗口内出现过的数据日数(src/trends.theme_active_days 现算,不落列)

theme_daily 每日题材(时间轴基础表)

列 类型 说明
day + theme_id PK 数据日(YYYY-MM-DD)× 题材
cnt INTEGER 当日提及篇数
core_cnt INTEGER 当日强证据提及数(is_core=1)

任意时间窗(非仅 5/10/20/30)与逐日时间轴视图均由本表现算;scripts/sync/refresh_trends.py 可脱离 MySQL 单独重算。

report_section 观点单元(每日简报基础表)

列 类型 说明
report_id + seq PK 所属研报 × 小节序号(枚举位置;live/兜底单卡 seq=0)
heading TEXT 小节标题(digest 正文编号小节;live 为空)
viewpoint TEXT 观点句(≤70 字:信号句 → 首句 → 标题兜底)
evidence TEXT 小节正文摘录(≤300 字,截去文末引用块)
reason_type TEXT 催化类型(同 report_stock 口径,开放字典)
is_core INTEGER 命中 is_core=1 提及(强股/编辑打标)时为 1
broker_name / source_title TEXT 可选增强:券商名出现在节内文本时归属,否则为空

配套关联表 section_stock(report_id, seq, stock_code) / section_theme(report_id, seq, theme_id)。 口径:个股/题材以小节内文本匹配为主源(report_stock/report_theme 是编辑打标口径,"关注"清单入库率仅 20%); live 研报为单卡(标题即观点),个股/题材取编辑打标作交叉引用。由 src/content/daily.py 解析, 同步管线自动回填(近 7 日,幂等);存量回填用 python scripts/sync/refresh_daily.py。实现细节表,不入本体 schema。

stock 个股

列 类型 说明
code TEXT PK 股票代码
name TEXT

broker 券商

列 类型 说明
id INTEGER PK 自增 即本体 brokerId
name TEXT UNIQUE 如"东吴证券"

report 研报

列 类型 说明
id TEXT PK "{src_type}-{src_id}" 组合,即本体 reportId
src_type TEXT NOT NULL live / digest(两源合一表)
src_id INTEGER NOT NULL 源表主键
column_name TEXT 栏目(config.py 栏目字典映射)
title / summary / display_time TEXT 标题/摘要/展示时间
is_premium INTEGER APP 端标记(库里存全文,仅存档用)
content TEXT 正文 HTML(渲染原文页用)

rating_event 评级事件

列 类型 说明
id INTEGER PK 自增 即本体 eventId
event_type TEXT 开放字典(见 §3)
event_date TEXT 评级行动日期(来源块日期)
analyst_name / analyst_license TEXT 分析师姓名 / S 开头执业编号
broker_id INTEGER 发出方(→ broker.id,rating_event_issued_by_broker)
stock_code / stock_name TEXT 针对标的(stock_code 关联 stock.code,stock_name 为冗余显示名)
source_title TEXT 原始研报标题(事件识别依据)
report_id TEXT 引用自哪篇脱水研报(→ report.id)

注:评级事件的三条关系(targets/issuedBy/citedIn)以本表外键列物化,不再建关联表。

image_asset 图片

列 类型 说明
id TEXT PK URL 哈希,即本体 imageId
url TEXT UNIQUE image.xuangubao.cn 直链
context_text TEXT 正文上下文(前后各 100 字)
parse_status TEXT unparsed / pending / parsed / failed
parsed_type TEXT 解析归类:产业链图 / 数据图表 / 其他
parsed_content TEXT 解析文本结果
parsed_at TEXT 解析时间(运维字段,不进本体 schema)

2. 关系表(8 张 + 3 条物化)

全库关联总览(实体只列主键/外键与识别列,全量字段见 §1;多对多边的标签即中间表名,边上的关系属性见下方表格):

erDiagram
    chain {
        TEXT id PK "链 slug"
        TEXT name "如 AI算力"
    }
    segment {
        TEXT id PK
        TEXT chain_id FK
        TEXT segment_type "开放字典 §3"
    }
    theme {
        INTEGER plate_id PK
        TEXT name
        TEXT classification "概念/行业/风格"
    }
    theme_daily {
        TEXT day PK "数据日"
        INTEGER theme_id PK
    }
    stock {
        TEXT code PK
        TEXT name
    }
    broker {
        INTEGER id PK
        TEXT name
    }
    report {
        TEXT id PK "live-或digest-前缀"
        TEXT src_type "live / digest"
        INTEGER src_id "源表主键"
    }
    report_section {
        TEXT report_id PK
        INTEGER seq PK "小节序号"
        TEXT viewpoint "观点句"
    }
    report_tag {
        TEXT report_id PK
        INTEGER tag_id PK "栏目字典 config"
    }
    rating_event {
        INTEGER id PK
        TEXT event_type "开放字典 §3"
        INTEGER broker_id FK
        TEXT stock_code FK
        TEXT report_id FK
    }
    image_asset {
        TEXT id PK "URL 哈希"
        TEXT url "image.xuangubao.cn 直链"
    }

    chain ||--o{ segment : segment_part_of_chain
    theme }o--o{ segment : theme_segment
    theme }o--o{ stock : theme_stock
    report }o--o{ theme : report_theme
    report }o--o{ stock : report_stock 推荐个股
    report }o--o{ broker : report_broker
    report ||--o{ image_asset : report_image
    image_asset }o--o{ theme : image_theme
    broker ||--o{ rating_event : issued_by
    stock ||--o{ rating_event : targets
    report ||--o{ rating_event : cited_in
    report ||--o{ report_section : 正文分节
    report_section }o--o{ stock : section_stock
    report_section }o--o{ theme : section_theme
    report ||--o{ report_tag : 栏目标签
    theme ||--o{ theme_daily : 每日题材
本体关系 SQLite 表 基数 关系属性
segment_part_of_chain segment.chain_id 列 多对一 —
theme_located_at_segment theme_segment 多对多 evidence(来源出处)
theme_associates_stock theme_stock 多对多 occurrence_count, first_seen_at, last_seen_at, decay_score, core_count(核心提及数)
report_mentions_theme report_theme 多对多 reason, reason_type, evidence_quote, is_core, weight
report_mentions_stock report_stock 多对多 同上
report_cites_broker report_broker 多对多 analyst_name, analyst_license, source_title, cited_date
rating_event_targets_stock rating_event.stock_code 列 多对一 —
rating_event_issued_by_broker rating_event.broker_id 列 多对一 —
rating_event_cited_in_report rating_event.report_id 列 多对一 —
report_cites_image report_image 一对多 —
image_depicts_theme image_theme 多对多 —
report_has_column_tag report_tag 一对多 tag_id → LIVE_TAG_COLUMNS / DIGEST_TAG_COLUMNS 栏目字典(吸收自 2_xuangubao 分类口径,REPORT_NAV 三组导航)

提及关系(report_theme / report_stock)即推荐观点记录:一行 = "某研报在某时间以某原因提及某标的"。weight 为该次提及的热度权重(核心 1.0 / 共现 0.3,写库时由 config 固化),is_core 保留原始证据强度供重新加权。

辅助表 etl_meta(key, value):built_at(构建时间)、ref_date(源数据基准时间)、 wm_live_id / wm_digest_id(增量同步进度标记 = 源表主键最大 id,含已删除行;旧库缺失时按 report.MAX(src_id) 自动引导)。

同步日志表 sync_log(src/pipeline/sync.py 写入,每次同步一条,含失败记录): started_at/finished_at/mode(full|incremental)/status(success|env_failed|failed_rolled_back)/ duration_s/new_live/new_digest/deleted_live/reports_before/reports_after/wm_before/wm_after/ warnings/errors。同名文件日志 data/xgb_wiki.sync.log(gitignore)同步追加,库不可写时仍留存。

3. 开放字典(data/*.json)

三个字典同构:types 为已转正类型(有序,键即枚举值),_pending 为待审区。

// data/segment_types.json —— 额外带 stageTag 映射与展示方式
{
  "types": {
    "material":       {"label": "材料资源", "stageTag": "上游", "display": "group"},
    "process":        {"label": "工艺制造", "stageTag": "中游", "display": "flow"},
    "component":      {"label": "核心部件", "stageTag": "中游", "display": "group"},
    "infrastructure": {"label": "配套设施", "stageTag": "配套", "display": "group"},
    "service":        {"label": "服务",     "stageTag": "配套", "display": "group"},
    "application":    {"label": "下游应用", "stageTag": "下游", "display": "group"}
  },
  "_pending": {}
}

// data/reason_types.json —— 催化类型:业绩/订单/政策/技术进展/供需价格/产能/事件催化/资金动向
// data/event_types.json —— 评级事件:首次覆盖/上调/下调/目标价/增持/维持
//   两者条目格式:{"types": {"<值>": {"label": "<中文名>"}}, "_pending": {}}

display: flow 的类型按 orderNo 排横向流程带;group 类型按 stageTag 分组卡片。字典修改后:/ontology 页与 RDF 导出的枚举实时跟随,存量数据需重跑 build_wiki.py 重新归类。

4. 链映射文件(data/chain_map.json)

{
  "磷化铟": {                          // 键 = 题材名
    "chain": "AI算力",                 // 链名(slugs 化后入 chain.id)
    "segment": "上游材料",             // 环节名(原文词汇)
    "segmentType": "material",         // 角色类型(对齐开放字典)
    "order": 1, "isBottleneck": true,
    "manual": true,                    // 人工确认位:重跑 LLM 不覆盖
    "evidence": [ {"reportId": 4342, "quote": "最上游的铟,95%以上是锌矿冶炼的副产品…"} ]
  }
}

当前 300 个题材已映射,全部 manual: true;ETL 载入时据此生成 chain / segment 实例与 theme_segment 关联。

5. 本体 ↔ 存储对照要点

  • 本体标识属性 → SQLite 主键一一对应(chainId→chain.id、plateId→theme.plate_id 等)
  • 实体/关系显示名中文化(name="产业链"/"提及题材"…),技术 id 保留英文(chain、report_mentions_theme);SQLite 表名、RDF 类名、代码引用均走英文 id
  • 本体 enum → SQLite TEXT 存字符串(加类型零迁移),枚举值在渲染时从字典读取
  • 本体关系属性 → 关联表列(提及关系的观点五属性 + weight)
  • image_asset.parsed_at、rating_event.stock_name、etl_meta 为实现细节,不在本体 schema 中暴露
  • RDF 导出(data/output/xgb-a-chain/)只含 schema 层(类/属性/关系定义),实例数据不导出——实例由 Flask Web 展示(两层的分工见 设计方案 §5)

6. 源库 → 本地映射(ETL 入库口径)

选股宝脱水研报源库(内网 MySQL xuangubao,只读)库内共 42 张表(上游文档口径),同步管线只读其中 5 张,结构与连接关系如下(实线 = SQL JOIN,虚线 = 字符串内 ID 的逻辑关联):

erDiagram
    live_tuoshui_news {
        BIGINT id PK "同步进度标记 wm_live_id"
        BIGINT msg_id "消息ID 接标签表"
        VARCHAR title "研报标题"
        MEDIUMTEXT summary "摘要"
        MEDIUMTEXT content "正文 HTML"
        VARCHAR stocks "推荐个股 代码,名称;…"
        VARCHAR plates "题材 板块ID,名称;…"
        TINYINT is_deleted "1=源端已删除"
        DATETIME msg_display_time "展示时间"
    }
    live_tuoshui_tag_related {
        BIGINT live_msg_id "= live_tuoshui_news.msg_id"
        BIGINT tag_id "栏目 LIVE_TAG_COLUMNS"
    }
    tuoshui_msgs {
        BIGINT id PK "同步进度标记 wm_digest_id"
        BIGINT msg_id "消息ID 接标签表"
        VARCHAR title "研报标题"
        TEXT summary "摘要"
        TEXT content "正文 HTML"
        VARCHAR related_stocks "推荐个股 代码,名称;…"
        VARCHAR plates "题材 板块ID,名称;…"
        TINYINT is_premium "APP 端付费标记"
        DATETIME msg_created_at "创建时间"
    }
    tuoshui_tag_related {
        BIGINT msg_id "= tuoshui_msgs.msg_id"
        BIGINT tag_id "栏目 DIGEST_TAG_COLUMNS"
    }
    plate_rank_infos {
        BIGINT plate_id PK "即本地 theme.plate_id"
        VARCHAR plate_name "题材名"
        VARCHAR classification "概念/行业/风格"
    }

    live_tuoshui_news ||--o{ live_tuoshui_tag_related : "n.msg_id = t.live_msg_id 取栏目"
    tuoshui_msgs ||--o{ tuoshui_tag_related : "m.msg_id = t.msg_id 取栏目"
    live_tuoshui_news }o..o{ plate_rank_infos : "plates 内板块 ID 逻辑关联"
    tuoshui_msgs }o..o{ plate_rank_infos : "plates 内板块 ID 逻辑关联"

要点:

  • 字段口径:同步依赖列以 src/pipeline/sync.py::REQUIRED_MYSQL_COLUMNS 为准——每次同步启动前对 information_schema 做存在性校验(最近一次通过 2026-09-03);连接关系按 src/pipeline/etl.py 的 LIVE_SQL / DIGEST_SQL 实际 JOIN 绘制,两处标签表均经 msg_id 关联(不是主键 id)。
  • stocks / plates 是分隔符字符串("代码,名称;…" / "板块ID,名称;…"),源库无个股/题材外键——实体与关系由 ETL 解析字符串后落库,plate_rank_infos 提供 plate_id → 名称/分类的主数据。
  • ⚠️ 上游 2_xuangubao 项目《脱水研报数据库Wiki文档》部分列名已过时:其写 live_tuoshui_tag_related.news_id、tuoshui_tag_related.tuoshui_id、tuoshui_msgs.stocks,实际为 live_msg_id、msg_id、related_stocks(且缺 is_premium)。参考该文档时以本节同步校验口径为准。
  • messages、original_msgs 等其余表本管线不读取。

各表如何落到本地 SQLite——取数 SQL 与解析在 src/pipeline/etl.py(LIVE_SQL / DIGEST_SQL / apply_live_deletions),同步前置校验所需列清单在 src/pipeline/sync.py::REQUIRED_MYSQL_COLUMNS:

源(MySQL xuangubao) → 本地(SQLite) 说明
live_tuoshui_news(is_deleted=0)⨝ live_tuoshui_tag_related(经 msg_id,tag_id→栏目字典 LIVE_TAG_COLUMNS) report(src_type='live') display_time 取 msg_display_time;tag_id 缺省按未分类
live_tuoshui_tag_related ⨝ live_tuoshui_news、tuoshui_tag_related ⨝ tuoshui_msgs(etl.sync_tags 每次同步全量重建) report_tag 栏目 tag 完整映射(一篇可多 tag);report.column_name 仅存 JOIN 末行的单栏目,多 tag 会互相覆盖,/reports 栏目浏览以 report_tag 为准
tuoshui_msgs ⨝ tuoshui_tag_related(经 msg_id,tag_id→DIGEST_TAG_COLUMNS) report(src_type='digest') is_premium 直传;display_time 取 msg_created_at
live_tuoshui_news.stocks / tuoshui_msgs.related_stocks(解析 "代码,名称;…") stock + report_stock(is_core=0, weight=0.3) 编辑打标"关注"清单,入库率约 20%
digest 每日强股结构段(tag_id=4,正文解析) report_stock(is_core=1, weight=1.0, evidence_quote) 强证据推荐
*.plates(解析 "ID,名称;…")+ plate_rank_infos(plate_id→name/classification) theme + report_theme(is_core=0, weight=0.3) 题材主数据来自 plate_rank_infos
研报标题正则(extract_title_broker) broker + report_broker 券商引用
正文图片直链(extract_images) image_asset + report_image 待解析队列
正文评级段解析 rating_event 事件日期/分析师/券商
正文分节 + 提及原因提取(src/content/daily.py 分节、src/llm/viewpoint.py 归因;同步自动回填近 7 日,幂等;全量 python scripts/sync/refresh_daily.py) report_section + section_stock + section_theme,并 UPDATE report_stock / report_theme 的 reason/reason_type 观点单元口径,正文文本匹配为主源
live_tuoshui_news.is_deleted=1 删除本地对应 report(连同 report_theme/stock/broker/image/tag、rating_event、report_section、section_stock/theme) 增量同步检测源端删除
—(本地派生/配置,无源表) theme_stock 聚合与 theme.occurrence_count/decay_score(src/pipeline/etl.py 重算);theme_daily、theme.cnt_*(src/content/trends.py);chain/segment/theme_segment(data/chain_map.json);etl_meta(同步进度标记);sync_log(同步日志) 聚合、链映射配置与运维字段

7. 知识图谱库(data/graph.db)

从 xgb_wiki.db 的 report 正文抽取的三元组库(scripts/kg/build_graph.py 构建,移植自 2_xuangubao 云端 v0.5.0)。2026-10-01 实测口径:7351 实体 / 18556 边 / 18883 提及。行业/概念名入图前经 src/kg/kg_schema.py 的 SYNONYMS 同义词表归一化(如"硅烷/CPO/大储"并入规范名)。

entity 实体表(7351 行)

列 类型 说明
id INTEGER PK 实体 ID,edge 两端引用
type TEXT company 公司 / industry 行业(题材) / segment 产业链环节 / report 研报 / rating_event 评级事件
name TEXT 实体名(industry 已归一化为规范名)
meta TEXT 附加属性 JSON

edge 关系表(18556 行)

列 类型 说明
id INTEGER PK 边 ID,mention 引用
src_id / dst_id INTEGER → entity.id(有向边)
rel_type TEXT mentioned_in 提及于研报 / company_in_segment 公司属环节 / has_segment 链含环节 / rating_action 评级动作
attrs TEXT 关系属性 JSON

mention 提及事件表(18883 行)

列 类型 说明
edge_id INTEGER → edge.id
report_id + report_type INTEGER/TEXT 指回 xgb_wiki.db 的 report(src_type=live/digest)
t TEXT 提及时间(数据日)——衰减热度计算的源数据,weight 不落盘、查询时按 90 天半衰期动态算(GRAPH_HALF_LIFE_DAYS 可调)

cluster 主题群表(254 行)

scripts/kg/kg_recluster.py 产出(重建后图谱查询缓存失效):cluster_name 群名 / industry_name 成员行业(→ entity.name)/ rank_in_cluster 群内排序。

extraction_log 抽取进度表(1196 行)

report_type + report_id + status + extracted_at——图谱增量构建的依据(已抽篇目不重复处理;无可抽内容的报告计 fail,属正常跳过)。

image 图片资产表(2583 行)

研报图片证据:report 关联(report_type + report_id)、url / local_path(缓存路径)、status、las_task_id / las_status(LAS 云端解析任务状态)——与图片解析队列(scripts/sync/parse_queue.py)并发写库(连接带 busy_timeout)。