手把手教你搭建轻量级电商风控平台-风险特征平台篇

416 阅读27分钟

引言

通过上一篇文章规则引擎篇,大家对规则引擎的产品功能、结构划分以及技术实现细节有了一定的了解。我们也通过了一个又一个案例讲解,了解到每个功能在实际的业务中所扮演的角色。

就像我们了解到的,规则引擎识别风险是离不开数据的支持。没有数据作支撑,规则引擎就只是一个低代码的工具,其价值也就大大缩水了。那么这一篇文章,我会重点讲述一下负责为规则引擎提供数据汇总指标加工风险特征平台,是如何高效的为上游服务提供数据支持的。

一、什么是风险特征平台

风险特征平台是一种用于识别、评估和管理风险的技术系统,主要用于电商、金融、保险、网络安全、信贷评估等领域。其核心价值在于将原始数据转化为可操作的风险洞察,帮助平台提前识别潜在问题并采取预防措施。通常包括大数据处理框架、机器学习算法、实时计算引擎、可视化工具等组件,能够处理结构化和非结构化数据,并提供API接口与其他系统集成。

其主要功能有:

数据整合:汇集来自多个来源的数据(交易记录、用户行为、外部数据库等)

特征提取:识别和计算与风险相关的关键指标(如信用评分、欺诈概率等)

风险评估:使用算法和模型评估风险水平

实时监控:持续跟踪风险指标的变化

预警系统:当风险超过阈值时发出警报

决策支持:为风险管理人员提供数据支持

二、技术选型

MYSQL

针对B端场景的功能以及C端风险指标的实现(数据落地 + 数据加工)。

MONGO

用于风险画像快照及其历史版本功能实现和C端风险指标的实现(数据落地 + 数据加工)。

选择MONGO主要基于以下4点考虑:

1、没有事务的需求。

2、读写性能优于MYSQL,复杂条件查询优于REDIS。

3、非结构化存储,完美的解决了不同业务场景,对于不同业务字段的存储问题。极大的节省了开发成本。

4、自带分库分表能力,不同业务场景可以根据风险事件自动拆分集合,无需引入第三方分库分表的插件。不同业务场景的数据天然的隔离,极大的方便了开发人员性能调优。

ROCKET MQ

用于系统模块与模块之间的解耦。

REDIS

用于无复杂查询需求的读写场景和临时数据缓存场景,例如:指标级缓存、分布式锁等。

三、产品功能划分

我们先来看一下功能清单,如下图:

风险特征平台功能清单.jpg

1、风险指标计算

1.1、通用指标模型

1.1.1、概念讲解:

在风险特征平台中,我们把所有对数据的加工请求,都统一抽象成风险指标。这样做有以下几点好处:

1、通用的API接口,输入格式和输出格式标准化,可以满足各个业务方对数据加工的需求,无需个性化定制。

2、标准化的技术文档,方便各个业务方接入。

3、统一数据源管理,避免多个业务线重复对接,节约开发成本。

4、统一缓存管理,多个业务线共享缓存资源,节约服务器成本。

1.1.2、案例讲解:

风险指标定义:

指标名称指标编码数据类型默认值是否开启缓存缓存时间(秒)缓存键生成规则必填入参数据源
商户注册归属省merchantProvince字符串未知60 * 60 * 24{商户ID}_{指标编码}商户IDCRM-商户信息查询接口
交易IP归属省ipProvince字符串未知60 * 60 * 24{交易IP}_{指标编码}交易IP第三方产品-IP信息解析接口
最近X小时内商户成功交易数量merchantSuccessTradeNumInXhour整数型0--商户ID、时间滑块阈值本地-交易信息表
最近X小时内用户成功交易数量customerSuccessTradeNumInXhour整数型0--用户手机号、时间滑块阈值本地-交易信息表
腾讯天域分tencentScore整数型-160 * 60 * 24 * 7{用户手机号}_{指标编码}用户手机号腾讯-天域分查询接口

输入参数定义:

参数含义参数名称参数类型是否必填默认值参数说明
请求唯一标识bizRequestIdString-上游业务用于区分请求数据,多用于并行请求。
指标编码indexCodeListList<String>-需要计算的风险指标集合。
指标编码对应的扩展参数indexConditionMapMap<String, List<JSONObject>>-Map的key对应的是【指标编码】,value是指标自定义的扩展参数。一般用于相同计算逻辑但计算条件参数不一样的情况。
业务扩展参数paramsMapMap<String, Object>-当次请求的业务参数,如交易场景,订单号、交易金额、支付金额等。
忽略指标缓存ignoreCacheboolean false通过此参数可跳过缓存强制执行指标计算逻辑。
忽略源数据保存ignoreInsertbooleanfalse通过此参数可不记录当次请求的源数据。

返回参数定义:

参数含义参数名称参数类型是否必填默认值参数说明
响应编码codeString000000-
响应信息msgString--
响应体dataMap<String, JSONObject>-Map的key为输入参数中【请求唯一标识】,value是计算好的指标名称以及对应的指标值。

1.2、指标加工流程

1.2.1、概念讲解:

每一个风险指标都会被提前定义好,并且映射到一个worker。worker是实际处理指标加工逻辑的一个最小单位,他会在系统启动时被spring容器加载,加载的同时也会生成一个指标编码与worker的数据字典。为了提升指标加工的性能,我们会把同一类(相同数据源)风险指标放在一个worker中实现,每一个worker都会对应他独有的数据源。也就是说,一个worker对应一个数据源和多个风险指标

如图所示:

风险特征平台-风险指标映射.jpg

在收到指标加工请求时,风险特征平台会从数据字典中拿到风险指标的相关信息(是否开启缓存、缓存键生成规则等)。若有缓存类的指标,优先从缓存中读取数据(这里我们用的是redis缓存),然后再调用指标对应的worker进行数据加工得到指标值。若有缓存类的指标,则添加到缓存中。最后将数据汇总统一返回。

如图所示:

风险特征平台-指标加工流程.jpg

1.2.2、案例讲解:

业务场景以交易风控审核为例。规则引擎执行风控策略时,同步请求风险特征平台获取指标数据,然后带入规则中执行并得出风控审核结果。

规则集配置:

风险事件应用策略规则集名称模板类型执行条件规则配置
线下扫码支付策略A异地大额交易条件模板满足以下所有条件【交易IP归属省】 不等于 【商户注册归属省】
线下扫码支付策略A异地大额交易条件模板满足以下所有条件【腾讯天域分】 大于 【100】
线下扫码支付策略A异地大额交易条件模板满足以下所有条件【最近2小时内用户成功交易数量】 大于 【20】

风险指标加工-输入参数:

{
    "bizRequestId": "HAHA_123",
    "indexCodeList": [
        "merchantProvince",
        "requestProvince",
        "customerSuccessTradeNumInXhour",
        "tencentScore"
    ],
    "indexConditionMap": {
        "customerSuccessTradeNumInXhour": {
            "timeSliderThreshold": 2,
            "timeSliderUnit": "hour"
        }
    },
    "paramsMap": {
        "requestIp": "10.53.55.123",
        "customerId": "123",
        "merchantId": "456",
        "customerPhone": "13512365742",
        "orderAmount": 500.60,
        "payAmount": 500.60
    },
    "ignoreCache": false,
    "ignoreInsert": false
}

风险指标加工-输出参数:

{
    "code": "000000",
    "msg": "请求成功",
    "data": {
        "HAHA_123": {
            "merchantProvince": "上海市",
            "requestProvince": "苏州市",
            "customerSuccessTradeNumInXhour": 21,
            "tencentScore": 300
        }
    }
}

规则集执行:

风险事件应用策略规则集名称模板类型执行条件规则配置规则执行规则命中
线下扫码支付策略A异地大额交易条件模板满足以下所有条件【交易IP归属省】 不等于 【商户注册归属省】苏州市 != 上海市命中
线下扫码支付策略A异地大额交易条件模板满足以下所有条件【腾讯天域分】 大于 【100】300 > 100命中
线下扫码支付策略A异地大额交易条件模板满足以下所有条件【最近2小时内用户成功交易数量】 大于 【20】21 > 20命中

1.3、指标加工性能优化

1.3.1、概念讲解
1.3.1.1、本地轻量级指标

本地轻量级指标相对来说风险可控,不会受到外部系统的影响,计算逻辑和复杂度都比较简单。除了在数据库(mysql、mongo)索引层面的优化外,还需要支持串行计算和并行计算两种方式。

在多个指标加工请求的情况下,串行计算的时间复杂度是O(n),并行计算的时间复杂度是O(1)。为了满足一些业务场景对低延迟的需求,我们可以采取用空间换时间的方式,但同时服务的资源利用率会变高。在选择计算方式时,需要根据实际业务需要选择合适的计算方式。还需要针对不同业务场景自定义配置熔断时间,防止极端情况下接口请求超时。

在多个指标读取和写入redis缓存时,可以采用pipeline的方式合并发送操作指令,这样可以减少网络开销,指标数量越多性能提升越明显。

1.3.1.2、三方实时指标

第三方指标加工成本相对本地指标会大很多。其中包含两个方面的问题,接口调用成本和接口稳定性。

接口调用成本:

采购第三方产品都会产生调用成本,不同的产品计费策略也不一样。有预购套餐的,也有先使用后付费的。为了节约成本,通常我们会把第三方返回给我们的结果持久化到本地数据库(具体持久化策略视不同产品而定)。这样既可以节约调用成本(相同用户或商户只调用一次),也可以提升指标加工的响应速度(优先读取本地数据库)。

接口稳定性:

调用第三方产品API通常都需要通过外网访问。由于网络原因、第三方服务原因等一些不确定的因素,接口调用的成功率和响应时间相对内部服务都会有较大的波动,直接影响到了指标加工的性能。为了最大程度的减少外部服务对我们的影响,我们做出如下几点优化。

失败重试机制: 通过http协议调用第三方接口时,需要设置超时熔断时间和最大失败重试次数。接口请求超时熔断后进行重试,如果超过最大重试次数还没有请求成功则放弃这一次任务,请求失败。

本地缓存机制: 调用成功后持久化保存到本地数据库,若有重复请求则优先读取本地数据库。

预加载机制: 针对一些可以提前加工的指标,可以选择在业务前置环节提前异步触发指标加工。这样在真正需要同步请求指标加工的时候就可以直接命中指标级别的缓存,可以极大程度的提升系统性能。

降级机制: 若第三方接口调用失败,则使用指标定义的默认值兜底。

1.3.1.3、本地重量级指标

重量级指标他们的特点是计算复杂度较高、统计周期较长,无法在短时间内快速响应。这一类的指标通常我们会采用异步触发计算,计算完成之后本地持久化数据快照。在实际业务中,会有两种场景用到重量级指标,离线风控审核任务和实时风控审核任务(对指标数据的时效性无要求,可以接受最近一次加工的快照数据)。

数据快照:

用户手机号指标名称指标编码指标值最新更新时间
13634854931芝麻分zhimaScore4602025-04-11 0:11:31
13634854931风险分riskScore3002025-04-11 0:11:31

数据历史记录:

用户手机号指标名称指标编码指标值创建时间
13634854931芝麻分zhimaScore4602025-04-11 0:11:31
13634854931芝麻分zhimaScore4302025-03-11 0:11:31
13634854931芝麻分zhimaScore4102025-02-11 0:11:31
13634854931风险分riskScore3002025-04-11 0:11:31
13634854931风险分riskScore2602025-03-11 0:11:31
13634854931风险分riskScore2002025-02-11 0:11:31
1.3.2、案例讲解
1.3.2.1、串行请求与并行请求对比

我们先来看一下串行请求和并行请求的差异,如图所示。

串行请求: 风控特征平台-串行请求.jpg

并行请求: 风控特征平台-并行请求.jpg

从图中我们就可以很直观的找到差异点,串行请求是由主线程直接去完成指标加工的工作,并行请求是由线程池作为代理去完成指标加工的工作,那么效果是显而易见的。

假设tradeWorker执行耗时15毫秒,ipWorker执行耗时50毫秒,tencentWorker执行耗时70毫秒。

串行请求的总耗时为全部worker执行耗时的总和(15+50+70),也就是135毫秒。

并行请求的总耗时为全部worker执行耗时的最高值(70>50>15),也就是70毫秒。

参与计算的worker越多两种计算方式的差异也就越大。当然提升响应时间的代价就是消耗更多的系统资源。需要注意的一点,由于这个场景对响应时间的要求较高,所有请求都需要被立刻执行。所以我们选择的是无缓冲队列和最大线程数无上限。

ThreadPoolExecutor executorService = new ThreadPoolExecutor(100, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
1.3.2.2、三方指标加工

我们假设业务场景为交易风控审核触发的IP归属地解析,先看一下三方指标加工的流程,如图所示。

风险特征平台-第三方服务diaoyong.jpg

在交易审核同步触发IP归属地解析,如果本地没有数据的话,要同步请求三方服务,响应时间不可控。那么我们换个思路,在发起交易的前置环节(这里我们选择的是跳转收银台页面),跳过规则引擎直接异步触发IP归属地解析的相关指标计算。这样的话,在发起交易审核时,就可以直接命中指标级别的缓存,可以极大程度的提升响应速度。如图所示。

风险特征平台-指标预处理流程.jpg

1.3.2.3、离线指标加工

我们假设业务场景为交易风控审核,判断交易金额是否在当前商户交易金额中位数的合理区间范围内。这里我们先定义一个风险指标-商户交易金额中位数

指标名称指标编码数据类型默认值是否开启缓存缓存时间(秒)缓存键生成规则必填入参数据源计算逻辑
商户交易金额中位数merchantOrderMiddleAmount浮点型-160 * 60 * 24{商户ID}_{指标编码}商户ID本地-商户画像最近3个月该商户所有成功交易的金额取中位数,不足3个月的向前推直至90天直至第一笔交易记录那天。

由于该指标统计的时间范围较大(3个月),需要统计的商户量又很多,所以我们采用异步的方式对每个商户分别进行统计并生成数据快照,每天更新一个版本。指标加工时则直接去最近生成的数据快照。这样就可以满足这个风险指标的加工需求,但有一个前提是需要和业务方沟通好对指标时效性的要求。如图所示。

风险特征平台-异步数据统计.jpg

数据快照:

商户编号指标名称指标编码指标值最新更新时间
123商户交易金额中位数merchantOrderMiddleAmount20002025-04-11 0:11:31

数据历史记录:

商户编号指标名称指标编码指标值创建时间
123商户交易金额中位数merchantOrderMiddleAmount20002025-04-11 0:11:31
123商户交易金额中位数merchantOrderMiddleAmount18802025-04-10 0:11:31
123商户交易金额中位数merchantOrderMiddleAmount17802025-04-09 0:11:31

2、风险画像

风险画像是一个数据集中营,包含两种类别数据,静态信息动态信息数据采集的渠道越多,数据统计的维度越多,风险画像也就越清晰。

风险画像可以帮助各个业务线的运营人员提升工作效率,也可以作为运营人员做决策的依据。不同的业务场景切入的角度各自不同。例如风控运营更关注商户和用户的一些高风险行为,营销运营更关注用户对商品的偏好等等。

技术实现上,由于我们的数据量级还没有到海量的级别,所以我们没有选择对接大数据而是在应用层面实现。数据存储方面,由于风险画像的统计维度的不确定性,在我们考虑之后,最终决定放弃mysql选择mongo,因为mongo在面对不规则结构体的表现是优于mysql的。

数据库读性能写性能分库分表扩展性
MYSQL引入三方插件,不同业务场景以风险事件命名 + 固定名称,手动建表。添加字段需要执行脚本,若此时数据量较大,执行耗时会很长。
MONGO无需三方插件,不同业务场景以风险事件命名 + 固定名称,自动建集合。添加字段无需执行脚本,程序端直接写入数据即可。

风险画像划分为商户画像用户画像

2.1、商户画像

商户画像是以商户编号作为统计维度,汇总了一系列商户的静态信息动态信息

静态信息:

商户编号商户名称商户状态法人姓名法人手机号入网时间商户类型
1上海哈哈少儿有限公司运营中哈哈少儿135127338232025-04-12线上商城
2上海马格雷迪有限公司运营中格雷迪136746187322025-03-22线上商城
3上海林二数字哥有限公司已注销林二哥131783746312025-01-15线下店铺

动态信息:

基础信息

商户编号商户名称交易中位数单笔交易限额单日交易限额商户评分其他动态指标
1上海哈哈少儿有限公司30001500200000900……
2上海马格雷迪有限公司20001200200000890……
3上海林二数字哥有限公司150058050000250……

交易形态

商户编号商户名称当日活跃用户数近7日活跃用户数近7日交易天数近7日交易笔数近7日交易金额其他动态指标
1上海哈哈少儿有限公司120015007180020000……
2上海马格雷迪有限公司100012007120014000……
3上海林二数字哥有限公司058038008000……

交易分布

商户编号商户名称近7日交易归属省数量近7日交易归市数量近7日跨省交易数量占比近7日跨市交易数量占比近7日跨省交易金额占比近7日跨市交易金额占比其他动态指标
1上海哈哈少儿有限公司5820%15%30%10%……
2上海马格雷迪有限公司3610%5%10%4%……
3上海林二数字哥有限公司275%1%4%9%……

风险系数

商户编号商户名称近3日交易拦截占比近7日交易拦截占比近15日交易拦截占比近30日交易拦截占比近90日交易拦截占比其他动态指标
1上海哈哈少儿有限公司20%20%20%20%20%……
2上海马格雷迪有限公司20%20%20%20%20%……
3上海林二数字哥有限公司20%20%20%20%20%……

2.2、用户画像

用户画像是以商户编号作为统计维度,汇总了一系列用户的静态信息动态信息

静态信息:

用户编号用户昵称用户手机号注册时间
1哈哈少儿135127338232025-04-12
2马格雷迪136746187322025-03-22
3林二哥131783746312025-01-15

动态信息:

交易形态

用户编号常用设备号(微信小程序)常用设备号(支付宝小程序)openID(微信小程序)openID(支付宝小程序)常驻省常驻省手机号归属省手机号归属市消费客单价(元)最近成功消费时间
1obHbp4vxXhq9Z9sVbcPsi-x8xQs02088422453936255obHbp4vxXhq9Z9sVbcPsi-x8xQs02088422453936255上海市上海市上海市上海市1502025-04-12 21:53:00
2obHbp4vxXhq9Z9sVbcPsi-x8xQs12088422453936244obHbp4vxXhq9Z9sVbcPsi-x8xQs12088422453936244上海市上海市上海市上海市1502025-04-12 21:53:00
3obHbp4vxXhq9Z9sVbcPsi-x8xQs22088422453936233obHbp4vxXhq9Z9sVbcPsi-x8xQs22088422453936233上海市上海市上海市上海市1502025-04-12 21:53:00

交易行为

用户编号最近3天交易天数最近3天交易笔数最近3天交易金额(元)最近3天交易省份最近3天交易城市最近3天风险交易笔数占比最近3天风险交易金额占比
13500035000上海市、北京市上海市、北京市0%0%
23500035000上海市上海市2%5%
33500035000上海市上海市10%20%

2.3、自定义标签

标签是一种用于分类、组织和检索数据的结构化方法,通过对数据(如用户、商品、内容、行为等)添加特定的标签(Tags),使其更容易被识别、管理和分析。标签系统广泛应用于数据管理、用户画像、推荐系统、风险控制等领域。

2.3.1、标签的核心功能:

分类与组织:通过标签对数据进行分类,提高管理效率。

检索与查询:支持基于标签的快速筛选和查找。

数据分析:结合标签进行数据统计、挖掘和可视化分析。

个性化推荐:在电商、内容平台中,利用标签实现精准推荐。

风险管理:在风控系统中,通过标签标记高风险用户或行为。

2.3.2、标签类型:

静态标签

基于固定的属性或规则生成,如:

用户:性别、年龄、职业、会员等级。

商品:品类、品牌、价格区间。

风控:黑名单、白名单、灰名单。

动态标签

基于实时行为或计算模型动态更新,如:

用户:最近活跃度、消费偏好

风控:异常登录、频繁交易

内容:热门话题、趋势标签

规则标签

通过预定义的规则生成,如:

近30天交易金额超过10000元的用户 → 高价值用户

近30天交易金额超过1000000元的商户 → 大KA

近30天交易金额是100的整数倍上下浮动3% → 贴整交易

2.3.3、案例讲解:

假设业务场景为交易审核场景,先来看一下规则配置风险指标定义

规则集配置:

风险事件应用策略规则集名称模板类型执行条件规则配置
线下扫码支付策略A用户刷单条件模板满足以下所有条件【近90天用户满足所有贴整交易规则的成功交易笔数】 > 200

风险指标定义:

指标名称指标编码数据类型默认值是否开启缓存缓存时间(秒)缓存键生成规则统计条件数据源
近90天用户满足所有贴整交易规则的成功交易笔数customerTieZhengTradeSuccessNumIn90Days整数型-1--用户ID,时间滑块范围,交易状态,交易金额满足贴整交易规则本地-交易数据源

由于指标统计时间范围比较大,而且需要对每一笔交易的金额做一次贴整交易的规则匹配,单个用户需要执行N笔交易 * X条贴整交易规则次计算,实时统计的性能肯定是非常差的。如图所示。

风险特征平台-复杂逻辑统计(未使用标签).jpg

所以我们决定采用实时指标加工 + 异步打标的方式来解决这个问题。

标签定义:

标签名称标签编码标签规则定义
贴整交易1tiezheng1交易金额是100的倍数上下浮动1%
贴整交易2tiezheng2交易金额是100的倍数上下浮动2%
贴整交易3tiezheng3交易金额是100的倍数上下浮动3%
贴整交易4tiezheng4交易金额是1000的倍数上下浮动1%
贴整交易5tiezheng5交易金额是1000的倍数上下浮动2%
贴整交易6tiezheng6交易金额是1000的倍数上下浮动3%
贴整交易XtiezhengX交易金额是X的倍数上下浮动Y%

交易记录打标:

风险特征平台-复杂逻辑统计(使用标签).jpg

2.4、自定义人群

自定义人群指基于某些特定规则或标签数据,从海量群体(用户或者商户)中筛选出符合要求的目标群体。通常用于营销、风控、产品运营等场景,支持精细化运营。其业务具备以下特征。

灵活定义:可基于用户属性、行为、交易等维度组合筛选。

动态更新:部分系统支持实时或定时更新人群数据。

多场景适用:如广告投放、个性化推荐、风险监控等。

人群名称人群编码人群定义
高风险用户群customerHighRiskLevel【用户最近90天夜间交易笔数】> 200 and 【用户最近90天交易金额大于5000元的笔数】> 200 and【用户最近90天交易归属省个数】> 8
高风险商户群merchantHighRiskLevel【商户最近90天夜间交易笔数】> 2000 and 【商户最近90天交易金额大于5000元的笔数】> 2000 and【商户最近90天交易归属省个数】> 8
高价值用户群customerHighVable【用户最近30天成功交易数】> 300 or 【用户最近30天成功交易额】> 50000 or【用户标签】in(高价值,高潜力,高转化率)

2.5、自定义圈人

2.5.1、概念讲解

"圈人"是业务中的通俗说法,指通过某些特定规则或标签数据从海量群体(用户或者商户)中"圈定"目标人群的过程,本质与"自定义人群"相同,自定义人群强调定义,但圈人则更强调动作。

通常业务上会预先定义好人群,然后以任务的形式触发,基于人群定义的匹配规则在对应的数据源中检索出符合条件的数据。

2.5.2、案例讲解

我们先看一下流程图。

风险特征平台-人群&圈人.jpg

接下来是圈人任务。

任务编号任务开始时间任务结束时间任务状态任务归属人群任务检索总数任务创建人任务创建时间操作
202504140000012025-04-14 00:10:412025-04-14 01:10:41执行完成高风险用户群120哈哈少儿2025-04-13 15:31:59查看明细
202504140000022025-04-14 03:10:412025-04-14 05:10:41执行完成高风险商户群8哈哈少儿2025-04-13 15:31:59查看明细
202504140000032025-04-14 14:10:412025-04-14 18:10:41执行完成高价值用户群860哈哈少儿2025-04-13 15:31:59查看明细

总结

到这里,风险特征平台的内容就介绍完了。通过这篇文章,我们了解了风险特征平台的系统构成以及如何对外提供指标加工能力。业务人员是如何通过风险特征平台来提升他们的工具效率。

我们可以先停下脚步,尝试着去完成一个同步机器审核的demo。如果还有不清楚的地方,可以私信我,我会抽空回复大家的问题。

那么接下来一篇文章,我会分享一下流量回访系统(离线风控审核),它是基于实时风控审核系统实现的,在阅读它之前需要把前面几篇文章都阅读完并理解至少80%。那我们下期再见(* ̄︶ ̄)。