4. 交易数据模型设计:标准交易事件 JSON Schema
实时风控系统的核心是数据。如果进入 Kafka 的交易事件字段缺失、格式混乱或语义模糊,下游的规则引擎、特征计算和模型推理都将失去准心。本章定义一套标准化的交易事件 JSON Schema,覆盖风控场景最关键的 6 个必选字段与 4 个扩展字段,确保数据从产生到消费的全链路可解析、可追溯、可计算。
4.1 字段全景:从交易 ID 到设备指纹
标准交易事件采用 JSON 格式,以 transaction_id 作为全局唯一标识。下表列出核心字段及其风控语义:
| 字段名 | 类型 | 必选 | 风控用途 |
|---|---|---|---|
transaction_id |
string (UUID) | 是 | 全局去重、幂等消费、链路追踪 |
user_id |
string | 是 | 用户画像、黑名单、行为序列 |
amount |
number (decimal) | 是 | 金额阈值、累计限额、异常波动 |
currency |
string (ISO 4217) | 是 | 汇率转换、跨境风控 |
timestamp |
long (epoch ms) | 是 | 时间窗口、频次控制、时序异常 |
device_fingerprint |
string | 是 | 设备关联、模拟器检测、设备簇 |
geo_location |
object | 否 | 地理位置漂移、异地登录检测 |
ip_address |
string | 否 | IP 信誉、代理检测、地域解析 |
merchant_id |
string | 否 | 商户分级、行业风控 |
extras |
object | 否 | 业务自定义扩展字段 |
设计原则:必选字段保证基础风控能力,可选字段提供扩展性。生产环境中建议至少保证 6 个必选字段完整填充,缺失字段应使用
null 而非空字符串,便于下游做空值判断。
4.2 完整 JSON Schema 定义
以下为符合 JSON Schema Draft-07 的标准定义,可直接用于 Kafka Schema Registry 或代码校验:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "TransactionEvent",
"type": "object",
"required": [
"transaction_id",
"user_id",
"amount",
"currency",
"timestamp",
"device_fingerprint"
],
"properties": {
"transaction_id": {
"type": "string",
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
"description": "全局唯一交易ID,UUID v4"
},
"user_id": {
"type": "string",
"minLength": 1,
"maxLength": 64,
"description": "用户标识,支持手机号/邮箱/用户ID"
},
"amount": {
"type": "number",
"minimum": 0,
"description": "交易金额,单位:元,保留两位小数"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$",
"description": "ISO 4217 货币代码,如 CNY、USD"
},
"timestamp": {
"type": "integer",
"minimum": 1000000000000,
"description": "事件发生时间,Unix 毫秒时间戳"
},
"device_fingerprint": {
"type": "string",
"minLength": 16,
"maxLength": 128,
"description": "设备指纹,由SDK采集生成"
},
"geo_location": {
"type": "object",
"properties": {
"lat": { "type": "number", "minimum": -90, "maximum": 90 },
"lon": { "type": "number", "minimum": -180, "maximum": 180 }
},
"required": ["lat", "lon"],
"description": "GPS 经纬度坐标"
},
"ip_address": {
"type": "string",
"oneOf": [
{ "format": "ipv4" },
{ "format": "ipv6" }
],
"description": "客户端 IP 地址"
},
"merchant_id": {
"type": "string",
"description": "商户编号"
},
"extras": {
"type": "object",
"description": "业务自定义扩展字段,如优惠券ID、分期期数"
}
}
}
4.3 数据流与字段填充关系
交易事件从客户端产生到进入 Kafka,经历采集、序列化、校验三个环节。下图展示字段在不同环节的填充来源:
4.4 字段设计要点与避坑
- transaction_id 必须全局唯一:推荐 UUID v4,避免使用自增 ID 或时间戳拼接,防止 Kafka 分区内重复消费导致统计偏差。
- amount 使用 decimal 而非 float:浮点数精度丢失会导致金额计算错误。生产环境建议以“分”为单位存储整型,或使用字符串传递保留两位小数。
- timestamp 统一为 epoch 毫秒:避免时区歧义。客户端采集时建议使用设备本地时间,服务端收到后以 NTP 校准时间覆盖,防止设备时间篡改。
- device_fingerprint 长度限制:指纹通常由 SDK 生成,长度在 32~64 字符之间。设置
minLength: 16可过滤掉测试环境产生的无效短指纹。 - geo_location 可选但重要:对于移动端交易,GPS 坐标是判断“人地分离”的关键特征。缺失时可用 IP 地址反查经纬度作为降级方案。
常见错误:将
timestamp 设计为字符串格式(如 "2025-03-21T10:30:00Z")。虽然可读性好,但风控窗口计算(如 5 秒内交易次数)需要数值比较,字符串解析会引入性能开销。始终使用 Long 型毫秒时间戳。
4.5 示例事件:完整 JSON 报文
以下是一个符合上述 Schema 的真实交易事件示例:
{
"transaction_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"user_id": "user_10086",
"amount": 2999.00,
"currency": "CNY",
"timestamp": 1742544000000,
"device_fingerprint": "fp_abc123def456ghi789jkl",
"geo_location": {
"lat": 39.9042,
"lon": 116.4074
},
"ip_address": "192.168.1.100",
"merchant_id": "merchant_888",
"extras": {
"coupon_id": "coupon_2025",
"installments": 3
}
}
生产建议:在 Kafka Producer 端使用 Avro 或 Protobuf 序列化替代纯 JSON,可减少 30%~50% 的传输体积,并强制 Schema 兼容性检查。JSON Schema 主要用于 API 网关校验和调试阶段。
4.6 Schema 版本管理策略
风控业务迭代频繁,字段增减不可避免。推荐以下版本管理规则:
| 变更类型 | 兼容性 | 操作方式 |
|---|---|---|
| 新增可选字段 | 向前兼容 | 直接添加,旧消费者忽略新字段 |
| 新增必选字段 | 破坏性变更 | 升级 Schema 版本号,通知所有消费者适配 |
| 删除字段 | 破坏性变更 | 先标记为 deprecated,两个版本后再删除 |
| 修改字段类型 | 破坏性变更 | 必须新建字段,旧字段保留并标记废弃 |
在 Kafka 生态中,建议使用 Schema Registry 管理 Avro/Protobuf Schema,设置 COMPATIBILITY=BACKWARD 或 FORWARD,自动阻止不兼容的 Schema 注册,从源头避免数据解析失败。