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,经历采集、序列化、校验三个环节。下图展示字段在不同环节的填充来源:

交易事件字段填充流程 客户端采集 device_fingerprint geo_location ip_address 服务端生成 transaction_id timestamp merchant_id 业务传入 user_id amount currency Schema 校验 & 字段补全 缺失必选字段 → 拒绝 / 默认值填充 Kafka Topic: trade-events 序列化后写入分区 字段来源分离:设备端采集指纹/位置,服务端生成 ID/时间戳,业务系统传入金额/用户 三者汇聚后统一校验,确保进入 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 注册,从源头避免数据解析失败。