3. 交易数据模型设计:原始交易日志字段定义、用户画像与设备指纹、标签体系设计(正常/异常)
交易数据模型是异常检测系统的数据基石。一个完整的数据模型需要覆盖三个层次:原始交易日志(描述“发生了什么”)、用户画像与设备指纹(描述“谁在操作”)、标签体系(描述“结果是什么”)。本章将逐层定义字段结构,并给出 Flink 作业可直接引用的数据模型。
3.1 原始交易日志字段定义
原始交易日志是风控系统最上游的数据源,通常由支付网关、收单系统或核心账务系统实时推送。每条日志记录一笔交易的完整上下文。下表定义了标准化的 20 个核心字段:
| 字段名 | 类型 | 长度/精度 | 说明 | 示例值 |
|---|---|---|---|---|
transaction_id |
String | 64 | 全局唯一交易流水号 | TXN2025032112345678 |
user_id |
String | 32 | 用户登录 ID 或会员号 | U10008642 |
account_id |
String | 32 | 交易发起账户号 | ACC6228480012345678 |
trans_type |
String | 16 | 交易类型:消费/转账/提现/充值 | CONSUME |
amount |
Decimal | 18,2 | 交易金额(元) | 4999.00 |
currency |
String | 3 | 币种 ISO 代码 | CNY |
trans_time |
Timestamp | — | 交易发生时间(UTC+8) | 2025-03-21 14:30:00 |
merchant_id |
String | 16 | 商户编号 | M10086 |
terminal_type |
String | 16 | 终端类型:WEB/APP/POS/API | APP |
ip_address |
String | 45 | 客户端 IP(支持 IPv6) | 192.168.1.100 |
device_id |
String | 128 | 设备指纹 ID | DF_A1B2C3D4E5F6 |
location_lat |
Double | — | GPS 纬度 | 39.9042 |
location_lng |
Double | — | GPS 经度 | 116.4074 |
channel |
String | 16 | 渠道编码:支付宝/微信/银联/银行卡 | ALIPAY |
risk_score |
Integer | — | 上游风控预评分(0-100) | 35 |
is_first_transaction |
Boolean | — | 是否该用户首笔交易 | false |
order_id |
String | 64 | 关联订单号 | ORD20250321001 |
product_category |
String | 32 | 商品类目 | 电子产品 |
remark |
String | 256 | 备注/扩展信息(JSON) | {"coupon":"DISCOUNT50"} |
etl_timestamp |
Timestamp | — | 数据入湖时间 | 2025-03-21 14:30:05 |
Flink 建模提示: 在 Flink SQL 中建议将
trans_time 定义为 TIMESTAMP(3) 并声明为事件时间属性(WATERMARK FOR trans_time AS trans_time - INTERVAL '5' SECOND),以便后续做滑动窗口聚合与延迟数据容忍。
3.2 用户画像与设备指纹
仅靠单笔日志字段无法识别团伙欺诈或账户盗用。必须引入用户画像(描述用户长期行为特征)和设备指纹(描述设备环境与关联关系)。这两类数据通常存储在 HBase/Redis 中,Flink 通过异步 I/O 或维表 JOIN 实时关联。
3.2.1 用户画像核心维度
| 维度类别 | 字段 | 类型 | 说明 |
|---|---|---|---|
| 基础属性 | user_reg_time |
Timestamp | 注册时间 |
user_level |
Integer | 会员等级(1-5) | |
real_name_verified |
Boolean | 是否实名认证 | |
| 行为统计 | avg_daily_amount_7d |
Decimal | 近7天日均交易金额 |
trans_count_1h |
Integer | 过去1小时交易笔数 | |
city_set_30d |
String | 近30天常驻城市列表(JSON) | |
| 风险标签 | blacklist_flag |
Boolean | 是否命中黑名单 |
risk_tag_list |
String | 风控标签列表(逗号分隔) |
3.2.2 设备指纹关键字段
| 字段 | 类型 | 说明 |
|---|---|---|
device_id |
String | 设备唯一标识(通过 canvas/webgl/IMEI 等生成) |
os_type |
String | 操作系统:iOS / Android / Windows / macOS |
browser_fingerprint |
String | 浏览器指纹哈希 |
screen_resolution |
String | 屏幕分辨率 |
is_rooted_or_jailbroken |
Boolean | 是否越狱/root |
associated_user_count |
Integer | 该设备关联过的用户数 |
first_seen_time |
Timestamp | 设备首次出现时间 |
设备指纹关联风险: 若
associated_user_count > 5 且 is_rooted_or_jailbroken = true,该设备极可能是“猫池”或模拟器设备,应直接提升交易风险等级。
3.3 标签体系设计:正常 / 异常
标签体系是监督学习与规则评估的“标准答案”。我们将标签分为三个层级:最终标签(业务决策结果)、过程标签(中间判定)、细分类别(异常类型)。
3.3.1 标签定义表
| 标签层级 | 标签字段 | 取值 | 含义 |
|---|---|---|---|
| 最终标签 | final_label |
0 / 1 | 0=正常,1=异常(最终审核结果) |
label_source |
RULE / MODEL / MANUAL | 标签来源:规则/模型/人工 | |
| 过程标签 | rule_hit_list |
String | 命中规则 ID 列表(逗号分隔) |
model_score |
Double [0,1] | 模型输出异常概率 | |
manual_review_result |
PASS / REJECT / REVIEW | 人工审核结果 | |
review_comment |
String | 审核备注 | |
| 细分类别 | abnormal_type |
String | 异常大类:FRAUD / MONEY_LAUNDERING / ACCOUNT_TAKEOVER / CREDIT_CARD_SCAM / OTHERS |
fraud_subtype |
String | 欺诈子类:PHISHING / SOCIAL_ENGINEERING / BRUTE_FORCE | |
ml_subtype |
String | 洗钱子类:SMURFING / STRUCTURING / TRADE_BASED | |
ato_subtype |
String | 盗号子类:CREDENTIAL_STUFFING / SESSION_HIJACK | |
severity |
LOW / MEDIUM / HIGH / CRITICAL | 异常严重等级 |
3.3.2 标签生成流程
标签并非一次性写入,而是经过多阶段管道逐步丰富:
- 规则引擎打标:Flink CEP 或 Drools 规则命中后,写入
rule_hit_list与model_score(初始值 0.0)。 - 模型推理:XGBoost/DeepFM 模型输出
model_score,若 > 0.7 则临时标记为异常。 - 人工审核:高风险交易进入人工审核队列,审核员填写
manual_review_result与abnormal_type。 - 最终标签生成:综合规则、模型、人工结果,由仲裁逻辑输出
final_label。
标签一致性注意: 在 Flink 流处理中,
final_label 可能延迟到达(人工审核耗时数分钟)。建议设计“标签版本号”字段,Flink 作业以 upsert 模式更新标签,避免覆盖早期人工标注。
3.4 数据模型整体架构
下图展示了原始日志、用户画像、设备指纹、标签体系四层数据在 Flink 实时风控架构中的关联关系:
3.5 Flink 数据模型代码示例
在 Flink 中,我们使用 Java POJO 或 Flink SQL 的 CREATE TABLE 语句来定义数据模型。以下是一个完整的交易事件 POJO 示例:
// TransactionEvent.java — 原始交易日志 POJO
public class TransactionEvent implements Serializable {
public String transactionId;
public String userId;
public String accountId;
public String transType;
public BigDecimal amount;
public String currency;
public Long transTime; // 事件时间(毫秒时间戳)
public String merchantId;
public String terminalType;
public String ipAddress;
public String deviceId;
public Double locationLat;
public Double locationLng;
public String channel;
public Integer riskScore;
public Boolean isFirstTransaction;
public String orderId;
public String productCategory;
public String remark;
public Long etlTimestamp;
// 无参构造器(Flink 要求)
public TransactionEvent() {}
// 全参构造器、getter/setter 省略(实际生产使用 Lombok @Data)
}
// TransactionLabel.java — 标签 POJO
public class TransactionLabel implements Serializable {
public String transactionId;
public Integer finalLabel; // 0:正常 1:异常
public String labelSource; // RULE/MODEL/MANUAL
public String ruleHitList;
public Double modelScore;
public String manualReviewResult;
public String abnormalType;
public String severity;
public Long labelUpdateTime;
}
Flink SQL 建表语句(Kafka 源表):
CREATE TABLE transaction_log ( transaction_id STRING, user_id STRING, amount DECIMAL(18,2), trans_time TIMESTAMP(3) METADATA FROM 'timestamp', WATERMARK FOR trans_time AS trans_time - INTERVAL '5' SECOND, proctime AS PROCTIME()) WITH ( 'connector' = 'kafka', 'topic' = 'raw_transaction', 'format' = 'json');
3.6 数据模型设计检查清单
- 完整性:是否覆盖了交易标识、用户、金额、时间、位置、设备、渠道、标签等全部必要维度?
- 可扩展性:
remark字段是否预留 JSON 扩展空间?标签体系是否支持新增异常子类? - 时间语义:是否明确区分事件时间(
trans_time)与处理时间(etl_timestamp)? - 关联效率:用户画像与设备指纹是否设计了 JOIN KEY(
user_id/device_id)?是否考虑异步 I/O 或广播维表? - 标签版本:是否包含
label_update_time或版本号,以支持标签的流式更新?