ai_member_xiaoban/output/用户学情数据导出_数据表与业务逻辑.md
2026-06-04 08:00:01 +08:00

288 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 用户学情数据导出 — 数据表与业务逻辑
> 整理日期2026-06-03 | 基于 `export-user-data` 技能 v1.5
---
## 一、数据源总览
该技能跨 **4 个数据源**ES + PostgreSQL + 2 个 MySQL 库),共涉及 **17+ 张表/索引**
| 序号 | 数据源 | 库/索引 | 表名 | 用途 |
|------|--------|---------|------|------|
| 1 | ES Online | `user-audio` | — | 用户全部音频数据 |
| 2 | ES Online | `llm_asr_log` | — | ASR 识别结果回填(按 makee_id 关联) |
| 3 | PG Online | `vala` | `user_component_play_record_0` ~ `user_component_play_record_7` | 互动组件学习记录8 张分表) |
| 4 | PG Online | `vala` | `user_unit_review_question_result` | 课程巩固记录 |
| 5 | PG Online | `vala` | `user_unit_challenge_question_result` | 单元挑战记录 |
| 6 | PG Online | `vala` | `user_unit_summary_km_result` | 单元总结记录 |
| 7 | MySQL Test | `vala_test` | `vala_game_info` | story_id → unit_id 映射表 |
| 8 | MySQL Test | `vala_test` | `vala_game_chapter` | chapter_id → lesson_id 映射表 |
| 9 | MySQL Test | `vala_test` | `middle_interaction_component` | 中互动组件配置mid_* 类型) |
| 10 | MySQL Test | `vala_test` | `core_interaction_component` | 核心互动组件配置core_* 类型) |
| 11 | MySQL Online | `vala_user` | `vala_app_character` | 账户 ID → 角色 ID 映射 |
---
## 二、各数据源详细说明
### 2.1 ES `user-audio` 索引 — 全部音频数据
**查询条件:** `userId == 目标角色ID`,最多返回 10000 条,按时间倒序排列。
**输出字段:**
| 字段 | 说明 |
|------|------|
| `userId` | 角色 ID |
| `userMsg` | 用户消息ASR 识别结果或原始 JSON |
| `userName` | 用户名 |
| `soeData` | 语音评测数据 |
| `audioUrl` | 音频文件地址 |
| `asrStatus` | ASR 识别状态 |
| `componentId` | 关联的组件 ID |
| `componentType` | 组件类型 |
| `dataVersion` | 数据版本号 |
| `timeStr` | 时间字符串 |
| `source` | 数据来源(仅当命中 makee_id 回填时有值) |
**特殊逻辑v1.2 — makee_id 回填):**
`userMsg` 字段内容包含 `makee_id` 时:
1.`userMsg` 中提取 `makee_id` 的值(支持 JSON 解析 + 正则兜底)
2.`makee_id` 去 ES `llm_asr_log` 索引查询对应记录
3. 将查询到的 `result_text` 回填到 `userMsg` 字段
4.`source` 字段输出到 `source`
如果 `userMsg` 不包含 `makee_id`,保持原始逻辑不变。
---
### 2.2 PG `user_component_play_record_0~7` — 互动组件学习记录
**表结构:** 8 张分表,需 `UNION ALL` 合并查询。
**查询条件:** `user_id == 目标角色ID`,按 `updated_at` 倒序。
**输出字段:**
| 字段 | 来源 | 说明 |
|------|------|------|
| `user_id` | PG 原始字段 | 角色 ID |
| `component_unique_code` | PG 原始字段 | 组件唯一标识 |
| `session_id` | PG 原始字段 | 会话 ID |
| `c_type` | PG 原始字段 | 组件类型编码(如 `mid_vocab_item` |
| `c_id` | PG 原始字段 | 组件 ID |
| `互动组件名称` | MySQL 映射 | 根据 c_type 查组件配置表映射 |
| `组件标题` | MySQL 映射 | 组件配置中的 `title` |
| `组件配置摘要` | MySQL 映射 | mid 取 `question`core 取 `taskInfo` |
| `知识点` | MySQL 映射 | 组件配置中的 `kp_relation_info` |
| `play_result` | PG 原始字段 | 答题结果Perfect/Good/Failed/Pass/Oops |
| `user_behavior_info` | PG 原始字段 | 用户行为信息 JSON |
| `updated_at` | PG 原始字段 | 更新时间 |
#### 组件名称映射规则v1.5
**中互动组件c_type 以 `mid_` 开头)→ 查 `middle_interaction_component` 表:**
| c_type | 互动组件名称 |
|--------|-------------|
| `mid_vocab_item` | 物品互动 |
| `mid_vocab_image` | 图片互动 |
| `mid_vocab_fillBlank` | 填词互动 |
| `mid_vocab_instruction` | 指令互动 |
| `mid_sentence_dialogue` + `mode=express` | 对话互动-表达 |
| `mid_sentence_dialogue` + `mode=read` | 对话互动-朗读 |
| `mid_sentence_voice` | 语音互动 |
| `mid_sentence_material` | 材料互动 |
| `mid_sentence_makeSentence` | 造句互动 |
| `mid_grammar_cloze` | 挖空互动 |
| `mid_grammar_sentence` | 组句互动 |
| `mid_pron_pron` | 发音互动 |
**核心互动组件c_type 以 `core_` 开头)→ 查 `core_interaction_component` 表:**
| c_type | 互动组件名称 |
|--------|-------------|
| `core_speaking_reply` | 口语快答 |
| `core_speaking_inquiry` | 口语妙问 |
| `core_speaking_explore` | 口语探讨 |
| `core_speaking_monologue` | 口语独白 |
| `core_reading_order` | 合作阅读 |
| `core_listening_order` | 合作听力 |
| `core_writing_imgMakeSentence` | 看图组句 |
| `core_writing_imgWrite` | 看图撰写 |
| `core_writing_questionMakeSentence` | 问题组句 |
| `core_writing_questionWrite` | 问题撰写 |
**组件配置摘要取值规则:**
- `mid_*`:取 `component_config` 中的 `question` 字段
- `core_*`:取 `component_config` 中的 `taskInfo` 字段
**知识点取值:** 直接取 `kp_relation_info` 字段JSON 数组格式,每个元素含 `kpId`、`kpType`、`kpTitle`、`kpSkill`、`kpSkillName`
---
### 2.3 PG `user_unit_review_question_result` — 课程巩固记录
**查询条件:** `user_id == 目标角色ID`,按 `updated_at` 倒序。
**输出字段:**
| 字段 | 来源 | 说明 |
|------|------|------|
| `user_id` | PG 原始字段 | 角色 ID |
| `unit_id` | story_id 映射 | 通过 `vala_game_info` 表将 `story_id` 映射为 `unit_id` |
| `lesson_id` | chapter_id 映射 | 通过 `vala_game_chapter` 表将 `chapter_id` 映射为 `lesson_id` |
| `question_list` | PG 原始字段 | 题目列表 JSON |
| `正确率` | 计算字段 | `isRight==true 的数量 / 总题数 × 100%` |
| `updated_at` | PG 原始字段 | 更新时间 |
**正确率计算逻辑:** 解析 `question_list` JSON 数组,统计其中 `isRight == true` 的题目数,除以总题数,结果以百分比展示。
---
### 2.4 PG `user_unit_challenge_question_result` — 单元挑战记录
**查询条件:** `user_id == 目标角色ID`,按 `updated_at` 倒序。
**输出字段:**
| 字段 | 来源 | 说明 |
|------|------|------|
| `user_id` | PG 原始字段 | 角色 ID |
| `unit_id` | story_id 映射 | 通过 `vala_game_info` 表映射 |
| `category` | PG 原始字段 | 挑战类别 |
| `score_text` | PG 原始字段 | 得分文本 |
| `question_list` | PG 原始字段 | 题目列表 JSON |
| `updated_at` | PG 原始字段 | 更新时间 |
---
### 2.5 PG `user_unit_summary_km_result` — 单元总结记录
**查询条件:** `user_id == 目标角色ID`,按 `updated_at` 倒序。
**输出字段:**
| 字段 | 来源 | 说明 |
|------|------|------|
| `id` | PG 原始字段 | 记录 ID |
| `user_id` | PG 原始字段 | 角色 ID |
| `unit_id` | story_id 映射 | 通过 `vala_game_info` 表映射 |
| `updated_at` | PG 原始字段 | 更新时间 |
| `km_id` | PG 原始字段 | 知识点 ID |
| `km_type` | PG 原始字段 | 知识点类型 |
| `play_time_seconds` | 计算字段 | 播放时长(原始毫秒值 ÷ 1000 |
---
### 2.6 MySQL 映射表
#### `vala_game_info` — story_id → unit_id 映射
**查询逻辑:** `SELECT id, story_id FROM vala_game_info ORDER BY season_package_id ASC, index ASC`
**映射规则:** 查询结果按排序后的索引位置(从 1 开始)作为 `unit_id`
#### `vala_game_chapter` — chapter_id → lesson_id 映射
**查询逻辑:** `SELECT id, chapter_id, index FROM vala_game_chapter`
**映射规则:** `chapter.index` 字段值即为 `lesson_id`
#### `vala_app_character` — 账户 ID → 角色 ID 映射
**查询逻辑:** `SELECT id FROM vala_app_character WHERE account_id = <账户ID>`
**使用场景:** 当使用 `--account-ids` 模式时,先查此表获取该账户下所有角色 ID再逐个导出。
---
## 三、Excel 输出结构8 个 Sheet
| Sheet 序号 | Sheet 名称 | 数据来源 |
|-----------|-----------|---------|
| 1 | 全部音频数据 | ES `user-audio` 索引 |
| 2 | 互动组件学习记录 | PG 8 张分表 + MySQL 组件配置 |
| 3 | 课程巩固记录 | PG `user_unit_review_question_result` |
| 4 | 单元挑战记录 | PG `user_unit_challenge_question_result` |
| 5 | 单元总结记录 | PG `user_unit_summary_km_result` |
| 6 | 统计-互动组件通过情况 | 基于 Sheet 2 聚合,按组件名称统计 Perfect/Good/Failed/Pass/Oops 数量及比例 |
| 7 | 统计-知识点通过情况 | 基于 Sheet 2 聚合按知识点kpId + kpType + kpTitle统计通过情况 |
| 8 | 统计-单元总结时长 | 基于 Sheet 5 聚合,按 unit_id 累加 play_time_seconds并转换为分钟取整 |
---
## 四、执行方式
### 脚本位置
- **Wrapper 脚本:** `scripts/export_user_data.sh`
- **核心 Python 脚本:** `git_repos/llm_offline_production/config_user_data_extract_and_analyze/export_user_id_data.py`
### 命令参数
```bash
# 单角色导出
./scripts/export_user_data.sh --user-id 33123
# 多角色批量导出
./scripts/export_user_data.sh --user-ids 33123,33124,33125
# 按账户批量导出(自动查该账户下所有角色)
./scripts/export_user_data.sh --account-ids 2148,2149
# 指定输出目录
./scripts/export_user_data.sh --user-id 33123 --output-dir /tmp/my_output/
```
三种模式(`--user-id` / `--user-ids` / `--account-ids`)互斥,只能传一种。
### 输出文件命名
- 角色模式:`角色id_{ID}_导出时间_{YYYYMMDD}.xlsx`
- 账户模式:`账户id_{账户ID}_角色id_{角色ID}_导出时间_{YYYYMMDD}.xlsx`
### Python 依赖
`python3`, `pymysql`, `psycopg2`, `pandas`, `openpyxl`, `requests`
---
## 五、所需环境变量
| 环境变量 | 对应数据源 | 说明 |
|---------|-----------|------|
| `ES_HOST` | ES Online | Elasticsearch 地址 |
| `ES_PORT` | ES Online | ES 端口9200 |
| `ES_SCHEME` | ES Online | 协议https |
| `ES_USER` | ES Online | ES 用户名 |
| `ES_PASSWORD` | ES Online | ES 密码 |
| `PG_DB_HOST` | PG Online | PostgreSQL 地址 |
| `PG_DB_PORT` | PG Online | PG 端口28591 |
| `PG_DB_USER` | PG Online | PG 用户名 |
| `PG_DB_PASSWORD` | PG Online | PG 密码 |
| `PG_DB_DATABASE` | PG Online | PG 数据库名vala |
| `MYSQL_HOST` | MySQL Test | MySQL 测试库地址 |
| `MYSQL_PORT` | MySQL Test | MySQL 测试库端口25413 |
| `MYSQL_USERNAME` | MySQL Test | MySQL 测试库用户名 |
| `MYSQL_PASSWORD` | MySQL Test | MySQL 测试库密码 |
| `MYSQL_HOST_online` | MySQL Online | MySQL 线上库地址 |
| `MYSQL_PORT_online` | MySQL Online | MySQL 线上库端口27751 |
| `MYSQL_USERNAME_online` | MySQL Online | MySQL 线上库用户名 |
| `MYSQL_PASSWORD_online` | MySQL Online | MySQL 线上库密码 |
> 凭证具体值见 `secrets.md`wrapper 脚本 `export_user_data.sh` 已内置默认值。
---
## 六、注意事项
1. **所有数据库连接均为只读账号**,不会产生写操作
2. ES 查询使用 HTTPS + 自签证书,脚本已处理 `verify=False`
3. PG 返回的 `updated_at` 带时区信息,脚本会自动去除时区避免 Excel 写入报错
4. `play_result` 支持两种格式:纯字符串(`"Perfect"`)或 JSON`{"result": "Perfect"}`
5. 导出大批量角色时建议分批执行,避免单次耗时过长
6. 脚本默认输出到 `output/` 目录