8.8 KiB
数据库结构 & 数据完整性
Last updated: 2026-06-21 Reason: Updated fill rates after backfill; added school name matching and cascade backfill references
关联参考
完整审计方法论(含数据质量、JSON 覆盖分析、plan_type 分类优化建议)→ references/database-audit-methodology.md
可复用审计脚本(9 点全面检查,scp 后直接跑)→ scripts/gaokao-audit.py
学校名匹配安全做法(勿用字符串包含匹配!)→ references/school-name-matching.md
数据回填方法论(级联传播,旧名映射)→ references/data-backfill-methodology.md
数据库文件
/www/wwwroot/gaokao/gaokao_henan.db(35MB,SQLite)
不是 gaokao.db 或 schools.db(后两个是空文件,遗留产物)。
两张核心表
schools 表 — 院校投档分(聚合级别)
CREATE TABLE schools (
id INTEGER PRIMARY KEY AUTOINCREMENT,
year INTEGER,
school_name TEXT,
school_code TEXT,
subject TEXT, -- 物理类 / 历史类
batch TEXT, -- 本科批 / 专科批
plan_type TEXT, -- 普通类 / 中外合作办学 / 国家专项 / 地方专项 / 应用工程学院 / 莫动理工学院
subject_group TEXT, -- 专业组代码 (101)(102) 等
subject_req TEXT, -- 选科要求
plan_count INTEGER, -- 招生人数
min_score INTEGER, -- 投档分
min_rank INTEGER, -- 投档位次
batch_diff INTEGER, -- 批次线差
sch_id TEXT, -- 院校代码(从招生章程导入)
tuition TEXT -- 学费(静态推算)
);
2025 年覆盖: 1,437 所学校 / 7,437 条记录 ✅
majors 表 — 分专业录取数据
CREATE TABLE majors (
-- 字段名需通过查阅,列清单:
school_name, major, major_code, subject_group, subject_req,
plan_count, min_score, min_rank, location, school_type,
is_985, is_211, subject, batch, year, major_note
);
2024 年覆盖: 2,244 所学校 ✅(数据源更全) 2025 年覆盖: 830 所学校 / 24,524 条记录 ⚠️ 仅河南招生院校
数据完整性分析
majors 表 2024→2025 数量变化
数据源自河南省教育考试院官方发布的 分专业录取数据。不同年份发布范围不同:
| 年份 | 学校数 | 记录数 | 说明 |
|---|---|---|---|
| 2024 | 2,244 | — | 全国范围较全的院校数据 |
| 2025 | 830 | 24,524 | 仅2025年在河南有招生计划的院校 |
两年交集: 811 所学校同时存在于 2024 和 2025 年。其中:
- 19 所学校 仅 2025 年有(2025 年新招生/新发布)
- 1,433 所学校 仅 2024 年有(2025 年未发布数据)
误区澄清:有些人误以为"2024年2,244所与2025年830所完全无交集",实际并非如此——大部分(811/830)是交叠的。2024 年数据量更大是因为那年的数据源覆盖了更多院校,而非两年之间的学校完全不同。
数据源文件(从用户处获取):
| 文件名 | 用途 | 2025 年数据量 |
|---|---|---|
22-25年全国高校在河南的专业录取分数.xlsx |
majors 表数据源 | 24,524 条 / 830 校 |
22-25年全国高校在河南的院校录取分数.xlsx |
schools 表数据源 | 7,437 条 / 1,437 校 |
22-25年全国高校在河南的招生计划.xlsx |
招生计划(非录取分) | 60,836 条(含学制、学费) |
字段填充率(2026-06-21 级联回填后)
majors 表 is_985 / is_211 / school_type / location
| 年份 | 回填前 | 回填后 | 方法 |
|---|---|---|---|
| 2017-2019 | 44-48% | 96% | 从2024/2025按学校名传播,含59所更名校旧名映射 |
| 2020-2021 | 68-69% | 98% | 同上 |
| 2022-2025 | 100% | 100% | 原始数据完整 |
schools 表关键字段
| 字段 | 回填前 | 回填后 |
|---|---|---|
| school_code | 48.5% | 97.5% |
| tuition | 48.5% | 97.5% |
| batch_diff | 41.5% | 95.4% |
| plan_type | 48.5% | 87.7% |
| sch_id | 47.7% | 86.6% |
school_basic.json 覆盖(2025年 830所学校)
| 匹配方式 | 数量 | 占比 |
|---|---|---|
| 精确匹配 | 816 | 98.3% |
| 括号标准化后匹配(代码层) | 10 | 1.2% |
| 别名映射(校区变体) | 4 | 0.5% |
| 完全无数据 | 0 | 0% |
| 合计覆盖 | 830 | 100% |
更新记录:59所更名校key改为新名+保留old_name,50所新学校补充省份/性质。
字段名陷阱:batch 命名差异(2024 vs 2025)
这是回退查询时的常见陷阱。 河南省高考 2025 年改革前后,数据库中的 batch 字段命名发生了变化:
| 年份 | 本科批次名称 | 说明 |
|---|---|---|
| 2025 及以后 | 本科批 |
新高考合并本科批次 |
| 2024 及以前 | 本科一批 / 本科二批 |
旧高考分批次 |
影响所有回退查询。例如 _get_recommended_majors_for_student 中查询 2024 年数据时:
# 错误:使用当前 batch='本科批' 查 2024 年
conn.execute("SELECT ... FROM majors WHERE year=2024 AND batch=?", (_batch,))
# 返回 0 条,即使有数据
# 正确:同时尝试三种 batch 名称
conn.execute("SELECT ... FROM majors WHERE year=2024 AND (batch='本科一批' OR batch='本科二批' OR batch='本科批')")
学校类型检测策略(v3.1 确立)
school_basic.json 的 type 和 tags 字段不可靠——有民办学校被标为 type='综合'、tags=['双一流'](如武汉东湖学院、河北科技学院)。
正确策略:数据库 majors.school_type 优先。
| 优先级 | 来源 | 覆盖范围 | 可靠性 |
|---|---|---|---|
| 1 | majors 表 school_type |
2,302 所 | 原始数据源 |
| 2 | school_basic.type 公办类型列表 |
后备 | 仅用于推断公办 |
| 3 | description 正则分析 |
后备 | 有历史语境误判 |
_determine_school_type regex 陷阱
基于 description 的学校类型正则容易假阳性:
| 误匹配模式 | 描述原文 | 结果 | 正确 |
|---|---|---|---|
(创办的).{0,30}(民办|私立) |
"孔祥熙创办的私立铭贤学堂"(1907年历史) | 民办 | 公办 |
v3.1 已从正则中移除 创办的|管理的|。仅保留:
(是一所|作为|转设为|批准为|举办的|批准成立的).{0,30}(民办|私立)
验证 batch 命名差异
sqlite3 /www/wwwroot/gaokao/gaokao_henan.db \
"SELECT batch, COUNT(*) as cnt FROM majors \
WHERE school_name='河南科技大学' AND year=2024 AND subject='理科' \
GROUP BY batch ORDER BY cnt DESC LIMIT 5;"
# 预期:本科一批 / 本科二批(不是"本科批")
回退方案(2026-06-20 已实施)
当用户查询 2025 年数据但数据库中没有时:
- school_search API (
gaokao_chat_server_v2.py:1380):优先查 year=2025,无数据回退到MAX(year),返回actual_year+ 每条记录带year字段 - major_search API (
gaokao_chat_server_v2.py:1448):查询指定年份 → 0 条结果 → 自动降级到最近有数据的年份,返回actual_year - school.html 前端:搜索结果上方显示
📅 当前数据来源:2025年(正常)或黄色文字提示回退年份 - major.html 前端:回退时显示黄色提示条
⚠️ 2025年暂无数据,已自动切换到 2024年数据
验证方法
# 按年份检查 schools 表学校数
sqlite3 /www/wwwroot/gaokao/gaokao_henan.db "SELECT year, COUNT(DISTINCT school_name) as schools, COUNT(*) as records FROM schools GROUP BY year ORDER BY year;"
# 按年份检查 majors 表学校数
sqlite3 /www/wwwroot/gaokao/gaokao_henan.db "SELECT year, COUNT(DISTINCT school_name) as schools, COUNT(*) as records FROM majors GROUP BY year ORDER BY year;"
# 检查 2024 与 2025 年 majors 交集(验证是否真无交集)
sqlite3 /www/wwwroot/gaokao/gaokao_henan.db "SELECT COUNT(DISTINCT m1.school_name) FROM majors m1 JOIN majors m2 ON m1.school_name=m2.school_name AND m1.year=2024 AND m2.year=2025;"
# 仅 2025 年有的学校(新招生)
sqlite3 /www/wwwroot/gaokao/gaokao_henan.db "SELECT DISTINCT school_name FROM majors WHERE year=2025 AND school_name NOT IN (SELECT DISTINCT school_name FROM majors WHERE year=2024);"
# 仅 2024 年有的学校(未发布数据)
sqlite3 /www/wwwroot/gaokao/gaokao_henan.db "SELECT COUNT(DISTINCT school_name) FROM majors WHERE year=2024 AND school_name NOT IN (SELECT DISTINCT school_name FROM majors WHERE year=2025);"
# 测试回退
curl -s 'http://127.0.0.1:8080/api/major/search?school=河南科技大学&subject=物理类&year=2025'
# 预期: actual_year=2024, majors 有数据
curl -s 'http://127.0.0.1:8080/api/school/search?q=河南科技大学&subject=物理类'
# 预期: actual_year=2025, 每条记录有 year 字段