风控逻辑利器 --- 规则引擎
前言
规则引擎的定义
规则引擎的执行方式
转转风控规则引擎
总结
前言
风控的职责是为了控制业务的风险。在识别风险过程中,要根据大量的用户行为和用户信息去做逻辑判断,最终给出决策结果。在决策过程中,大量的逻辑判断需要开发和维护,如果以传统的方式去开发和维护,需要付出巨大的时间成本并且隐藏着毁灭性的事故隐患。所以将业务代码和复杂的逻辑代码剥离显得迫在眉睫。
规则引擎的定义
规则引擎由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据业务规则做出业务决策。
下图是规则引擎的组成部分:
1)特征集合:表示当前传入的数据(例如:用户对象 zzuser)。
2)条件: 逻辑判断。
3)规则: 对特征进行逻辑判断,得出结论。
4)规则集:多条规则组合成规则集。
规则引擎推理方式分为两种:
正向链接推理:这是一种基于“数据驱动”的形式,基于用户的行为信息和基本信息,得出结论。
反向链接推理:这是一种基于“目标驱动”的推理形式,与正向链接相反,以假设的结论出发,推断用户的哪些行为信息和基本信息符合假设的结论。
规则引擎的执行方式
(1) 解释执行
一般会有自己的规则解释器,规则解释器解释执行。
(2) 动态编译
规则会动态的编译成字节码并执行。
规则编译成字节码的步骤
a.文法分析
b.语法解析
c.生成字节码
(3) 自定义解释规则
早期在没有引入表达式引擎的时候,就是通过自定义实现的表达式解析。
举个例子
特征 a、特征 b、特征 c => 求特征 d
d = (a+b)/ c 这是一个简单的四则运算表达式。
这个表达式对于人的思维方式来说非常的简单,但是计算机识别起来就非常的困难。所以要将常规的表达式转换成计算机方便计算的表达式(逆波兰表达式)。
上面的表达式转换成逆波兰表达式为: ab+c/
这样计算机就可以比较简单的求出表达式的值。
逆波兰表达式的转换算法感兴趣的可以自行百度。
转转风控规则引擎
转转风控规则引擎是一种正向链接推理的规则引擎,以数据为驱动,去推断相应的结论。比如说,业务要识别违禁品,可以根据图片模型分数大于 0.9 来推断出用户违规。
特 征: 模型分数。
操作符号: 大于
阈 值: 0.9
这三部分构成了一个规则。
转转规则引擎的发展阶段
第一阶段:硬编码阶段,此阶段所有的规则都是通过代码写死的,维护性和扩展性极差。
第二阶段:规则引擎阶段,通过抽象业务,开发规则配置平台,可以非常方便的运营规则,增加了规则的机动性。
下图是规则运行的一个用例图:
特征(按类型划分)
用户特征 : 用户的昵称、年龄、注册时间等。
商品特征 : 商品内容、标题等。
订单特征 : 订单金额、订单的品类等。
操作符号
规则引擎操作符:大于、小于、等于、敏感词匹配、用户标记等
结果
命中规则 或者 不命中规则
下图是实际的一个规则配置(商品的当前价格是否小于等于 30000):
第三阶段:完善特征工程阶段,减少特征的开发上线。
表达式引擎的引入
表达式引擎的选择
两者性能差不多,最终选择了 aviator,因为 aviator 社区活跃度和 jar 包大小要优于 Fel。
aviator 表达式功能简介
(1) 支持绝大多数运算操作符,包括算术操作符、关系运算符、逻辑操作符、位运算符、正则匹配操作符(=~)、三元表达式(?:)
(2) 支持操作符优先级和括号强制设定优先级。
(3) 支持赋值。
(4) 逻辑运算符支持短路运算。
(5) 支持丰富类型,例如 nil、整数和浮点数、字符串、正则表达式、日期、变量等,支持自动类型转换。
(6) 支持 lambda 匿名函数和闭包。
(7) 内置一套强大的常用函数库
(8) 可自定义函数,易于扩展
(9) 可重载操作符
(10) 支持大数运算(BigInteger)和高精度运算(BigDecimal)。
(11) 小巧并性能优秀
aviator 表达式引擎在特征工程的实践
(1) 基本特征取值
比如说,订单价格特征(orderFeture.price)、商品标题特征(infoFeature.title)、用户昵称特征(userFeature.nickname)。(注:orderFeture,infoFeature,userFeature 是系统中的一个实体对象)
(2) 特征的基本运算
比如说,已有手机分类商品数特征(infoFeature.phoneTotalCount)、全部商品总数特征(infoFeature.totalInfoCount),想要一个手机商品数在商品总数中的占比特征,就可以直接通过四则运算获取到:long(infoFeature.phoneTotalCount)*100/long(infoFeature.totalInfoCount)
(3) 内置函数
aviator 提供了大量的内置函数,可以通过它的内置函数获取想要的配置结果。比如说,商品标题长度特征 string.length(infoFeature.title),应用了求字符串长度的函数 string.length。
(4) 自定义函数
aviator 除了内置的函数,还支持自定义函数,可以根据需求自定义函数。比如说,想通过配置获取 redis 里的值,就可以开发一个获取 redis 的函数(函数名字是 jodisFeature)。
jodisFeature('price_median', infoFeature.cateChildId)。这个特征配置就是为了获取 redis key 为 price_median 的值。特征的代表的含义是:分类价格的中位数,当然这些数据已经提前计算好存储在 redis 里面了。
(5) Lambda 表达式
个人感觉 Lambda 表达式的引入是一个质的飞跃,这样就可以操作集合,只要有源数据,就可以转换出任何想要的特征。比如说,已有订单流水 list(orderFeature.orderFlow),通过 lambda 表达式就可以转换成特征(发货时间到确认收货时间):seq.get(map(filter(orderFeature.orderFlow,lambda(x)->(x.status==5)end),lambda(y)->y.latestOpTime end),0)- order.deliverTime
总之,表达式引擎还有各种各样的玩法,感兴趣的可以自行尝试。
特征数据源
引入表达式引擎之后,可以通过各种函数转换获取想要的特征,特征的转换依赖数据源。由于数据源的获取需要开发上线,给特征配置化带来极大的不便。因此,数据源的获取成了特征配置的瓶颈。数据源哪里来呢?两种方式:一种是业务请求携带的参数数据,另一种是调用服务方获取的数据。第一种对应的解决方案是特征映射,第二种对应的解决方案是服务配置。
1. 特征映射
特征映射是为了将业务方的参数转换成需要的特征。业务方通过两种方式调用,一种是同步调用,另一种是异步调用(异步调用采用的是消息队列的形式)。为了将业务的数据源统一收拢,跟业务约定将参数放到 map 里面,规则需要什么数据就可以通过 map 去获取。 为了方便特征配置,开发了一个获取业务参数的自定义函数(函数名:paramget)。例子:paramget('uid')代表的意思就是获取用户的 uid。
在实际开发过程中,MQ 异步调用的方式遇到了一些困难。由于各个业务系统的 MQ 消息体字段名称不一致,导致配置兼容比较多。比如说,同样都是 uid 的特征,有的业务 MQ 中用 uid 字段表示,有的用 userId 字段表示。为了控制字段兼容对规则的侵入性,在 MQ 消息和风控特征数据源之间做了一层映射,这层映射解决了字段对应偏差的问题。
2. 服务配置
服务配置是为了解决风控调用业务获取数据源的问题,每个接口只要传入相应的参数,就会返回相应的结果。这个问题可以抽象概括,只需要根据不同的业务方配置不同的参数,就可以获取相应的数据源。比如说,我们新接入一个 zzuser 的接口,通过配置表就可以获取用户 unionid 关联的账户数。下图是配置表的信息:
配置表里包含:服务名、类的全限定名、接口名、接口参数、接口参数值
返回结果:{"code":0,"body":3}
图中表达式中,13 代表了配置表的 id=13,commonfeature 函数获取 getCountByUnionId 接口的返回信息({"code":0,"body":3}),jsongain 函数获取 json 数据中 key 是“body“的信息 3。
由于服务间的通信是 rpc 调用的,要实现服务间通用的规则调用需要底层的支持。正好,架构部提供了服务的泛化调用,完美地解决了通用的调用问题。
总结
本文介绍了规则引擎的定义和执行方式,并且详细介绍了规则引擎在风控的落地。利用规则引擎辅助风控控制业务风险,实现业务数据源可配置、风控逻辑可配置,极大的降低了开发规则和维护规则的成本。
> 转转研发中心及业界小伙伴们的技术学习交流平台,定期分享一线的实战经验及业界前沿的技术话题。
> 关注公众号「转转技术」(综合性)、「大转转 FE」(专注于 FE)、「转转 QA」(专注于 QA),更多干货实践,欢迎交流分享~
评论