likes
comments
collection

风控逻辑利器---规则引擎

作者站长头像
站长
· 阅读数 15
  • 前言

  • 规则引擎的定义

  • 规则引擎的执行方式

  • 转转风控规则引擎

  • 总结

前言

风控的职责是为了控制业务的风险。在识别风险过程中,要根据大量的用户行为和用户信息去做逻辑判断,最终给出决策结果。在决策过程中,大量的逻辑判断需要开发和维护,如果以传统的方式去开发和维护,需要付出巨大的时间成本并且隐藏着毁灭性的事故隐患。所以将业务代码和复杂的逻辑代码剥离显得迫在眉睫。

规则引擎的定义

规则引擎由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据业务规则做出业务决策。

下图是规则引擎的组成部分:

风控逻辑利器---规则引擎

1)特征集合:表示当前传入的数据(例如:用户对象zzuser)。

2)条件: 逻辑判断。

3)规则: 对特征进行逻辑判断,得出结论。

4)规则集:多条规则组合成规则集。

规则引擎推理方式分为两种:

正向链接推理:这是一种基于“数据驱动”的形式,基于用户的行为信息和基本信息,得出结论。

反向链接推理:这是一种基于“目标驱动”的推理形式,与正向链接相反,以假设的结论出发,推断用户的哪些行为信息和基本信息符合假设的结论。

规则引擎的执行方式

  1. 解释执行

    一般会有自己的规则解释器,规则解释器解释执行。

  2. 动态编译

    规则会动态的编译成字节码并执行。

    规则编译成字节码的步骤:

    • 文法分析
    • 语法解析
    • 生成字节码
  3. 自定义解释规则

    早期在没有引入表达式引擎的时候,就是通过自定义实现的表达式解析。

    举个例子:

    特征a、特征b、特征c => 求特征d

    d = (a+b)/ c 这是一个简单的四则运算表达式。

    这个表达式对于人的思维方式来说非常的简单,但是计算机识别起来就非常的困难。所以要将常规的表达式转换成计算机方便计算的表达式(逆波兰表达式)。

    上面的表达式转换成逆波兰表达式为: ab+c/

    风控逻辑利器---规则引擎

    这样计算机就可以比较简单的求出表达式的值。

    逆波兰表达式的转换算法感兴趣的可以自行百度。

转转风控规则引擎

转转风控规则引擎是一种正向链接推理的规则引擎,以数据为驱动,去推断相应的结论。比如说,业务要识别违禁品,可以根据图片模型分数大于0.9来推断出用户违规。

特 征: 模型分数。

操作符号: 大于

阈 值: 0.9

这三部分构成了一个规则。

风控逻辑利器---规则引擎

转转规则引擎的发展阶段

第一阶段:硬编码阶段,此阶段所有的规则都是通过代码写死的,维护性和扩展性极差。

第二阶段:规则引擎阶段,通过抽象业务,开发规则配置平台,可以非常方便的运营规则,增加了规则的机动性。

下图是规则运行的一个用例图:

风控逻辑利器---规则引擎

  • 特征(按类型划分)

    1. 用户特征 : 用户的昵称、年龄、注册时间等。
    2. 商品特征 : 商品内容、标题等。
    3. 订单特征 : 订单金额、订单的品类等。
  • 操作符号

    规则引擎操作符:大于、小于、等于、敏感词匹配、用户标记等

  • 结果

    命中规则 或者 不命中规则

下图是实际的一个规则配置(商品的当前价格是否小于等于30000):

风控逻辑利器---规则引擎

第三阶段:完善特征工程阶段,减少特征的开发上线。

  • 表达式引擎的引入

  1. 表达式引擎的选择
    AviatorFel
    执行速度
    jar包的大小70kB200kB
    社区活跃度非常活跃一般
    执行方式动态编译/解释执行动态编译/解释执行

    两者性能差不多,最终选择了aviator,因为aviator社区活跃度和jar包大小要优于Fel。

  2. aviator表达式功能简介
    • 支持绝大多数运算操作符,包括算术操作符、关系运算符、逻辑操作符、位运算符、正则匹配操作符(=~)、三元表达式(?:)
    • 支持操作符优先级和括号强制设定优先级。
    • 支持赋值。
    • 逻辑运算符支持短路运算。
    • 支持丰富类型,例如nil、整数和浮点数、字符串、正则表达式、日期、变量等,支持自动类型转换。
    • 支持 lambda 匿名函数和闭包。
    • 内置一套强大的常用函数库
    • 可自定义函数,易于扩展
    • 可重载操作符
    • 支持大数运算(BigInteger)和高精度运算(BigDecimal)。
    • 小巧并性能优秀
  3. aviator表达式引擎在特征工程的实践
    • 基本特征取值

      比如说,订单价格特征(orderFeture.price)、商品标题特征(infoFeature.title)、用户昵称特征(userFeature.nickname)。(注:orderFeture,infoFeature,userFeature是系统中的一个实体对象)

    • 特征的基本运算

      比如说,已有手机分类商品数特征(infoFeature.phoneTotalCount)、全部商品总数特征(infoFeature.totalInfoCount),想要一个手机商品数在商品总数中的占比特征,就可以直接通过四则运算获取到:long(infoFeature.phoneTotalCount)*100/long(infoFeature.totalInfoCount)

    • 内置函数

      aviator提供了大量的内置函数,可以通过它的内置函数获取想要的配置结果。比如说,商品标题长度特征string.length(infoFeature.title),应用了求字符串长度的函数string.length。

    • 自定义函数

      aviator除了内置的函数,还支持自定义函数,可以根据需求自定义函数。比如说,想通过配置获取redis里的值,就可以开发一个获取redis的函数(函数名字是jodisFeature)。

      jodisFeature('price_median', infoFeature.cateChildId)。这个特征配置就是为了获取redis key为price_median的值。特征的代表的含义是:分类价格的中位数,当然这些数据已经提前计算好存储在redis里面了。

    • 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(微信id)关联的账户数。下图是配置表的信息: 风控逻辑利器---规则引擎

      配置表里包含:服务名、类的全限定名、接口名、接口参数、接口参数值

      返回结果:{"code":0,"body":3}

      图中表达式中,13代表了配置表的id=13,commonfeature函数获取getCountByUnionId接口的返回信息({"code":0,"body":3}),jsongain函数获取json数据中key是"body"的信息 3。

      由于服务间的通信是rpc调用的,要实现服务间通用的规则调用需要底层的支持。正好,架构部提供了rpc的泛化调用,完美的解决了通用的调用问题。但是数据类型的校验涉及编译原理底层的知识,实现成本较高,所以调用参数类型不支持自定义输入,只能用系统中已有的实体进行配置。

总结

本文介绍了规则引擎的定义和执行方式,并且详细介绍了规则引擎在风控的落地。利用规则引擎辅助风控控制业务风险,实现业务数据源可配置、风控逻辑可配置,极大的降低了开发规则和维护规则的成本。

> 转转研发中心及业界小伙伴们的技术学习交流平台,定期分享一线的实战经验及业界前沿的技术话题。

> 关注公众号「转转技术」(综合性)、「大转转FE」(专注于FE)、「转转QA」(专注于QA),更多干货实践,欢迎交流分享~