4. 沙盘环境搭建:模拟风控数据仓库环境、数据表结构设计、模拟脏数据注入规则
沙盘推演的核心在于构建一个“真实但可控”的战场。本章将带领学员从零搭建一套模拟风控数据仓库环境,设计核心数据表结构,并制定一套标准化的脏数据注入规则。这套环境将作为后续所有推演战役的“数据沙盘”,确保每一次优化动作都有据可依、可量化、可复现。
4.1 模拟风控数据仓库环境架构
我们采用经典的“贴源层(ODS)→ 明细层(DWD)→ 汇总层(DWS)→ 应用层(ADS)”四层架构,并针对风控场景进行轻量化改造。环境基于 PostgreSQL 12+ 构建,所有脚本均兼容标准 SQL。
环境规格: 单节点部署,4 vCPU / 16 GB RAM,500 GB SSD。数据库名:
risk_sandbox。Schema 命名规则:ods、dwd、dws、ads。
4.2 核心数据表结构设计
我们聚焦风控最核心的三大实体:用户、订单、支付。每张表都预留了“质量监控字段”,用于后续推演中的数据质量探测。
4.2.1 用户画像表(ods.user_profile)
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| user_id | VARCHAR(32) | PK, NOT NULL | 用户唯一标识 |
| user_name | VARCHAR(64) | NOT NULL | 用户姓名 |
| id_card | VARCHAR(18) | — | 身份证号(模拟) |
| mobile | VARCHAR(11) | — | 手机号 |
| VARCHAR(128) | — | 电子邮箱 | |
| register_time | TIMESTAMP | NOT NULL | 注册时间 |
| user_level | VARCHAR(16) | — | 用户等级(L0/L1/L2) |
| is_blacklisted | BOOLEAN | DEFAULT FALSE | 是否黑名单 |
| etl_time | TIMESTAMP | DEFAULT NOW() | 数据注入时间 |
4.2.2 订单明细表(ods.order_info)
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| order_id | VARCHAR(32) | PK, NOT NULL | 订单唯一标识 |
| user_id | VARCHAR(32) | FK, NOT NULL | 关联用户 |
| merchant_id | VARCHAR(32) | NOT NULL | 商户ID |
| order_amount | DECIMAL(12,2) | NOT NULL | 订单金额 |
| order_status | VARCHAR(16) | — | 状态:PENDING/SUCCESS/FAILED |
| order_time | TIMESTAMP | NOT NULL | 下单时间 |
| ip_address | VARCHAR(45) | — | 下单IP |
| device_fingerprint | VARCHAR(128) | — | 设备指纹 |
| etl_time | TIMESTAMP | DEFAULT NOW() | 数据注入时间 |
4.2.3 支付流水表(ods.payment_log)
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| payment_id | VARCHAR(32) | PK, NOT NULL | 支付流水号 |
| order_id | VARCHAR(32) | FK, NOT NULL | 关联订单 |
| payment_method | VARCHAR(16) | — | 支付方式:WECHAT/ALIPAY/CARD |
| payment_amount | DECIMAL(12,2) | NOT NULL | 支付金额 |
| payment_status | VARCHAR(16) | — | 状态:SUCCESS/FAILED/REFUND |
| payment_time | TIMESTAMP | NOT NULL | 支付时间 |
| channel_fee | DECIMAL(10,4) | — | 渠道手续费 |
| etl_time | TIMESTAMP | DEFAULT NOW() | 数据注入时间 |
4.3 模拟脏数据注入规则
为了真实还原风控数据治理的痛点,我们设计了 6 大类、18 种 脏数据注入规则。这些规则将随机或按比例注入到上述三张核心表中,模拟生产环境中的常见数据质量问题。
推演提示: 脏数据注入比例建议控制在总数据量的 5% ~ 15% 之间,过低无法暴露问题,过高则脱离实际。沙盘默认注入比例为 8%。
4.3.1 脏数据分类与注入规则清单
| 类别 | 规则编号 | 注入描述 | 目标字段 | 注入方式 |
|---|---|---|---|---|
| 完整性缺失 | D01 | 关键字段置 NULL | user_id, order_amount | UPDATE SET = NULL |
| D02 | 外键悬空(孤儿记录) | order_info.user_id | 插入不存在的 user_id | |
| D03 | 必填字段空字符串 | user_name, order_status | UPDATE SET = '' | |
| 格式异常 | D04 | 身份证号位数错误 | id_card | 替换为 15 位或 19 位数字 |
| D05 | 手机号含非法字符 | mobile | 插入 '138-0000-1111' | |
| D06 | 邮箱缺少 @ 符号 | 替换为 'user_at_example.com' | ||
| 逻辑矛盾 | D07 | 订单金额为负数 | order_amount | UPDATE SET = -99.99 |
| D08 | 支付时间早于下单时间 | payment_time | SET = order_time - INTERVAL '1 day' | |
| D09 | 订单状态与支付状态冲突 | order_status | 订单 FAILED 但支付 SUCCESS | |
| 重复数据 | D10 | 主键重复插入 | order_id | INSERT 相同 order_id |
| D11 | 业务含义重复(同人同订单) | user_id + order_time | 完全相同的记录插入两次 | |
| D12 | 部分字段重复 | device_fingerprint | 大量订单共享同一设备指纹 | |
| 值域越界 | D13 | 金额超出合理范围 | order_amount | SET = 99999999.99 |
| D14 | 时间戳为未来时间 | register_time | SET = NOW() + INTERVAL '10 years' | |
| D15 | 枚举值不在定义域内 | user_level | 插入 'L99' | |
| 引用不一致 | D16 | 汇总层与明细层金额不匹配 | dws.user_daily_agg | 汇总金额 ≠ 明细求和 |
| D17 | 跨表关联字段类型不一致 | user_id | ods 为 VARCHAR,dwd 误用 INT | |
| D18 | 编码不一致(GBK vs UTF8) | merchant_id | 混入乱码字符 |
4.4 脏数据注入脚本示例
以下为规则 D01(关键字段置 NULL)和 D07(金额为负数)的 SQL 注入脚本,学员可直接在沙盘环境中执行。
-- 规则 D01:将 5% 的订单金额置为 NULL
UPDATE ods.order_info
SET order_amount = NULL
WHERE order_id IN (
SELECT order_id FROM ods.order_info
TABLESAMPLE BERNOULLI(5)
);
-- 规则 D07:将 3% 的订单金额改为负数
UPDATE ods.order_info
SET order_amount = -ABS(order_amount)
WHERE order_id IN (
SELECT order_id FROM ods.order_info
TABLESAMPLE BERNOULLI(3)
);
-- 规则 D10:主键重复插入(需先关闭主键约束或使用临时表)
INSERT INTO ods.order_info (order_id, user_id, merchant_id, order_amount, order_time)
SELECT order_id, user_id, merchant_id, order_amount, order_time
FROM ods.order_info
WHERE order_id IN (
SELECT order_id FROM ods.order_info
TABLESAMPLE BERNOULLI(2)
);
⚠️ 沙盘操作警告: 注入脏数据前,请务必执行
CREATE TABLE ods.order_info_bak AS SELECT * FROM ods.order_info; 备份原始数据。推演结束后,可通过 TRUNCATE 并重新导入备份来重置沙盘。
4.5 数据质量监控基线
在注入脏数据之前,我们需要建立一套“零污染”基线指标,用于对比脏数据注入后的质量偏差。基线指标将作为后续推演中“数据质量评分卡”的基准值。
4.6 沙盘环境初始化步骤
- 创建数据库与 Schema: 执行
CREATE DATABASE risk_sandbox;并依次创建ods、dwd、dws、ads四个 Schema。 - 执行建表脚本: 按 4.2 节结构创建三张核心表,并添加主键、外键及索引。
- 生成模拟数据: 使用 Python Faker 库或 pgAdmin 的数据生成工具,生成 10 万条用户、50 万条订单、80 万条支付流水。
- 备份基线数据: 执行
CREATE TABLE ... AS SELECT *备份三张表的纯净版本。 - 执行脏数据注入: 按 4.3 节规则,随机选取 8% 的数据执行注入脚本。
- 验证注入效果: 运行数据质量探查 SQL,确认脏数据已成功注入且比例符合预期。