项目:CodeQ 代码大模型训练语料质量评估平台

开发模块:SparkJobService ETL 任务编排、QualityReportController 报告保存接口、全链路自动化闭环

当前进度:Spark ETL 子进程调度、任务状态跟踪、自动触发 AI 评估、质量报告 JPA 持久化全部完成,全自动化链路代码层面验证通过。


一、任务与目标

在此之前,ETL 数据采集、AI 评估、报告写入是三个独立的手动步骤。本次目标是实现一条 /api/etl/submit?layer=all 请求触发从数据采集到报告入库的全自动流程,同时解决一个关键技术问题——中文文本通过外部管道写入 MySQL 出现乱码。


二、SparkJobService 任务编排

核心设计是"父进程调度子进程"模式:backend-api 收到 ETL 请求后,通过 ProcessBuilder 启动 fat jar 子进程执行 Spark ETL,并在子进程退出后自动触发 AI 评估。

任务生命周期管理 :

public enum JobStatus { SUBMITTED, RUNNING, SUCCEEDED, FAILED, UNKNOWN }

每个任务分配唯一 UUID jobId,状态存储在 ConcurrentHashMap 中,支持通过 /api/etl/status/{jobId} 实时轮询。

子进程启动逻辑 :

List<String> cmd = new ArrayList<>();
cmd.add("java");
cmd.add("-jar");
cmd.add(resolvedJar);
cmd.add("--layer");
cmd.add(info.layer);
cmd.add("--limit");
cmd.add("10");
cmd.add("--max-size-mb");
cmd.add("500");

ProcessBuilder pb = new ProcessBuilder(cmd);
Map<String, String> env = pb.environment();
env.put("GITHUB_TOKEN", githubToken);
env.put("MYSQL_PASSWORD", mysqlPassword);
pb.redirectErrorStream(true);

关键设计决策:

- --limit 10 --max-size-mb 500 :默认只扫描 3 个仓库、限制 100MB 会导致热门 Java 仓库(如 hello-algo 453MB)全部被跳过。放宽参数保证代码解析步骤能实际产出数据。
- 环境变量注入 :GITHUB_TOKEN 和 MYSQL_PASSWORD 从父进程环境传递给子进程,避免硬编码。
- stderr 合并到 stdout : redirectErrorStream(true) 确保错误日志能完整捕获到 errorLog 字段。


成功后自动触发 AI ( triggerAgentAnalysis 方法):

1. 查询最新 analysis_task 记录
2. 从 metric_result 读取汇总指标
3. 从 file_metric 读取文件级详情(Top 5 高复杂度文件)
4. 调用 llmService.evaluateRepository() 生成评估
5. 通过 JPA 写入 quality_report 表


三、QualityReportController POST 保存接口

新增 POST /api/quality-report/save 接口,接收完整报告 JSON:

@PostMapping("/save")
public R<QualityReport> save(@RequestBody QualityReport report) {
    return R.success(qualityReportService.save(report));
}

这个接口解决了一个隐蔽但关键的问题——中文写入 MySQL 出现乱码。

问题定位过程 :

- 测试阶段通过 PowerShell mysql -e "INSERT ..." 管道写入含中文的 quality_report
- DBeaver 查询显示所有中文字符变为 ?
- HEX 检查确认每个中文字节都被替换为 3F ( ? 的 ASCII 码)
- 多次尝试设置 [Console]::OutputEncoding = UTF8 、 charset utf8mb4 均无效
根本原因 :Windows PowerShell 的管道机制在处理非 ASCII 字符时,会将字节流按照当前控制台编码(通常是 GBK)重新解释,导致 UTF-8 中文被破坏。

解决方案 :不经过外部管道,由 backend-api 的 JPA(Hibernate)直接连接 MySQL 执行 INSERT。Spring Boot + Hibernate 的 JDBC 连接默认使用 UTF-8 编码,与数据库的 utf8mb4 字符集一致,中文传输路径完全在 Java 进程内,不经过 Shell。

验证结果——HEX 对比:

错误(管道):5B42 3F ...             → [B?
正确(JPA):5B42 E7BAA7 ...          → [B级

四、全链路数据流

完整的自动化流程:

POST /api/etl/submit?layer=all
  ↓
SparkJobService.submitJob()
  ↓ ProcessBuilder 启动子进程
java -jar fat.jar --layer all --limit 10 --max-size-mb 500
  ↓ [1/7] GitHub API 采集 → ods_github_api_raw
  ↓ [2/7] JSON 解析 → dwd_repo_detail
  ↓ [3/7] 贡献者采集
  ↓ [4/7] Issue 采集
  ↓ [5/7] 代码解析 → dwd_file_metric_detail
  ↓ [6/7] DWS 聚合 → metric_result
  ↓ [7/7] ADS 评分 → file_metric
  ↓ exitCode = 0
SparkJobService.triggerAgentAnalysis()
  ↓ 读取 metric_result + file_metric
  ↓ 调用 LLM API(带重试)
  ↓ JPA 写入 quality_report(中文无乱码)

五、接口测试与验证

启动 backend-api 后执行测试:

POST /api/etl/submit?layer=all
→ jobId: c41b4acb, status: SUBMITTED

GET /api/etl/status/c41b4acb
→ status: SUCCEEDED

查询 quality_report 表:
→ 中文完整显示:summary = "[B级 | Medium | 78分] Arthas 是高影响力..."
→ advantages = ["高 star 数量,广泛行业认可", ...]
→ problems = ["文档得分极低,严重缺乏说明", ...]
→ suggestions = ["立即启动文档重构", ...]

六、技术理解

本次全链路自动化开发的几个关键收获:

1. 父进程调度子进程 是独立模块间协作的经典模式——backend-api 不需要引入 Spark 依赖,只需管理进程生命周期和退出码判断。
2. 编码问题往往不是数据库的问题 。MySQL 的 utf8mb4 完全能存储中文,问题出在传输路径上(Shell 管道 vs JPA 直连)。
3. 后端自动化逻辑的判断应该保守 ——ETL exit code != 0 时不触发 AI、metric_result 为空时跳过评估,避免产生误导性报告。
4. 状态机设计要简单 :SUBMITTED → RUNNING → SUCCEEDED/FAILED,没有过度设计的状态转换,用 ConcurrentHashMap 做内存存储足够。


七、当前项目进度

- SparkJobService 完整实现(子进程调度 + 状态跟踪)
- --limit 10 --max-size-mb 500 参数传递修复
- ETL 成功后自动触发 AI 评估
- QualityReportController 新增 POST /save 接口
- 中文质量报告 JPA 写入无乱码
- 全链路自动化代码层面打通

Logo

脑启社区是一个专注类脑智能领域的开发者社区。欢迎加入社区,共建类脑智能生态。社区为开发者提供了丰富的开源类脑工具软件、类脑算法模型及数据集、类脑知识库、类脑技术培训课程以及类脑应用案例等资源。

更多推荐