# BASS Demo - EMR Hive 验证套件

把《数据解析0.2.md》里的 Qoder / QoderWork 打标方案在阿里云 EMR Hive 上跑通的最小可复现实验。

## 一、目录结构

```
sql/
├── 01_ddl.sql         18 张表 + 1 张结果表的 DDL（库 = bass_demo）
├── 02_mock_data.py    本地 mock 数据生成脚本（输出 18 个 CSV 到 ./data/）
├── 02_load.sql        把 CSV 装载进 Hive（提供本地 / OSS 两种姿势）
├── 03_analysis.sql    双画像打分 + 写入 demo_usr_score_target + 落标签
├── 04_verify.sql      6 条核验查询 + 2 段画像偏置对照
├── data/              CSV 输出目录（运行 02_mock_data.py 后填充）
└── README.md          本文件
```

## 二、数据规模

| 类型 | 表数 | 行数 |
| --- | --- | --- |
| 维表 | 5 | 790 |
| 事实表 | 13 | 264,295 |
| **合计** | **18** | **265,085** |

事实表合计约 26.4w 行；如需严格"全部表共 10 万条"，把 `02_mock_data.py` 顶部的 `SCALE = 1.0` 改为 `SCALE ≈ 0.375` 后重跑。注意：维表（合计 790 行）不随 SCALE 缩放，仅事实表按比例缩放，所以并非线性对应（SCALE=0.43 实际约 11.4w 行）。

mock 时刻意制造的偏置：

- 10% 用户构造为 Qoder 程序员画像（IT 集团 + 工作地科技园 + IM/学习/邮件 APP 重度 + 游戏轻 + 高端 5G 终端 + 中高消费 + 中高网龄）
- 15% 用户构造为 QoderWork 白领画像（中高价值 + 商务宽带 + 邮件/IM/办公活跃 + 集团成员 + 4G/5G 智能机 + 工作地 CBD）
- 1500 集团：前 10% 行业 = IT/互联网/通信，紧接 30% 行业 = 金融/政务/咨询/教育

## 三、执行步骤

### 0. 准备

```bash
# 生成脚本仅用 Python 标准库，无需第三方依赖（不装 numpy/pandas 也能跑）
# 关键：固定 PYTHONHASHSEED=0，保证 set 遍历顺序稳定、去重后行数可复现
export PYTHONHASHSEED=0
# Apple Silicon 本机若遇架构问题，可显式 arch -arm64 python3；EMR/Linux 侧直接 python3 即可
```

### 1. 在 Hive 建表

```bash
# 把 01_ddl.sql 上传到 EMR header，或本机直接跑：
beeline -u "jdbc:hive2://emr-header-1:10000/default" -f 01_ddl.sql
```

### 2. 本机生成 mock CSV

```bash
PYTHONHASHSEED=0 python3 sql/02_mock_data.py
# 输出： sql/data/*.csv  共 18 个文件（脚本按自身所在目录写入 ./data/）
```

### 3. 装载 CSV 进 Hive（二选一）

**方式 A — 本地 LOAD（最快，适合 demo）**

```bash
# 把 data/ 目录拷到 EMR header
scp -r sql/data/ root@emr-header-1:/tmp/bass_demo_data
ssh emr-header-1 "beeline -u 'jdbc:hive2://localhost:10000/bass_demo' \
  --hivevar DATA_DIR=/tmp/bass_demo_data \
  -f 02_load.sql"
```

**方式 B — 走 OSS（生产姿势）**

```bash
# 把 CSV 推到 OSS
ossutil cp -r sql/data/ oss://your-bucket/bass_demo/data/

# 在 02_load.sql 里把方式 B 注释块解开，把 ${BUCKET} 替换为实际 bucket
beeline -u "jdbc:hive2://emr-header-1:10000/bass_demo" -f 02_load.sql
```

### 4. 执行打分 + 落标签

```bash
beeline -u "jdbc:hive2://emr-header-1:10000/bass_demo" -f 03_analysis.sql
```

执行完会立刻打印一行汇总：用户总数、Qoder 命中数、QoderWork 命中数、双命中数、平均分。

### 5. 核验

```bash
beeline -u "jdbc:hive2://emr-header-1:10000/bass_demo" -f 04_verify.sql
```

期望结果（以默认 SCALE=1.0 跑完）：

- Q1 各表行数与 mock 报告一致
- Q2 评分分布呈"低分主体 + 高分尾巴"双峰结构
- Q3 Top100 全部命中 Qoder 程序员画像
- Q4 QoderWork 命中群体的集团行业 IT/金融/政务/咨询/教育合计 > 70%
- Q5 5 个高分用户每行的 IMEI 前 4 位都属于 3501/3502/3601，工作地多为科技园
- Q6 `L_QODER_TARGET` ≈ 2,500–3,000；`L_QWORK_TARGET` ≈ 4,000–4,800

## 四、评分公式（与《数据解析0.2.md》一致）

```
Qoder_Score   = 0.35*行业匹配 + 0.25*APP偏好 + 0.15*终端 + 0.10*工作地 + 0.10*消费 + 0.05*网龄
QoderWork_Score = 0.30*中高价值 + 0.20*商务宽带 + 0.20*办公APP + 0.15*集团广义白领 + 0.10*4G/5G智能机 + 0.05*工作地CBD
target = 1 if score >= 0.6
```

阈值 0.6 在 demo 中能平衡命中率与精度；上线前可以拿真实样本做 ROC/Lift 调参。

## 五、迁到真实 BASS 时的字段映射

下面是 demo_xxx 表 → 真实表的对照，把脚本里所有 `demo_` 前缀替换、月份换成你要打标的月份即可：

| demo 表 | 真实表 | 关键字段 |
| --- | --- | --- |
| demo_pers_usr_m | TW_PERS_USR_M | USR_NBR / CUST_ID / PROF_TYP_CD / VPMN_USR_IND / IMEI |
| demo_bass_cust_mo | TW_BASS_CUST_MO | CUST_ID / STAR_LEVEL / BRAND_LAB_CD |
| demo_pers_csnm_m | TW_PERS_CSNM_M | TOT_FEE / CM_AMT_RNK_CD / MH_VALUE_USR_IND |
| demo_pers_4g_usr_m | TW_PERS_4G_USR_M | LTE_4G_TERM_IND / TERM_TYP_CD |
| demo_imei_usr_busi_m | TW_IMEI_USR_BUSI_M | IMEI / CMN_USE_IND |
| demo_pers_homebrb_usr_m | TW_PERS_HOMEBRB_USR_M | PKG_SPEED_CD / CUST_TYP_CD |
| demo_pers_usr_laci_m | TW_PERS_USR_LACI_M | WK_CELL_CD |
| demo_pers_common_app_m | TW_PERS_COMMON_APP_M | IM/EDU/MAIL/GAME 等 23+ 字段 |
| demo_pers_topn_app_d | TW_PERS_TOPN_APP_D | TOP1_APP_CD |
| demo_corp_indapply_useusr | TW_CORP_INDAPPLY_USEUSR | APPL_TYP_NAM |
| demo_bass_vpmn_mbr_mo | TW_BASS_VPMN_MBR_MO | GUSR_ID ↔ USR_NBR |
| demo_bass_gcust_mo | TW_BASS_GCUST_MO | INDUS_TYP2_CD |
| demo_pers_lab_usr_m | TW_PERS_LAB_USR_M | LAB_CD / LAB_SRC_CD |

注：真实环境里 5G 标识、`is_5g` 字段是我在 demo 自加的，对应到生产可能需要 `TW_PERS_4G_USR_M.GPRS_ROAM_FLAG` 或独立的 5G 表，按字典再确认。
