风控系统之通用规则条件设计,算术单元/逻辑单元/函数式接口
个人博客:无奈何杨(wnhyang)
个人语雀:wnhyang
共享语雀:在线知识共享
Github:wnhyang - Overview
简介
前面有风控系统之普通规则条件,使用LiteFlow实现,介绍了普通规则条件,并给出简单的示例实现。
这篇就此进行扩展,介绍其他规则条件。
说白了,规则条件就是条件,而且并不局限于规则之中,简单讲就是if()
括号里的内容,用于判断规则是否需要执行,是规则极其重要的部分。
规则条件有很多种,他们看似相同,却又不同。作为程序员,应该具备逻辑抽象的思维,通过设计将其统一整合起来。
普通条件
前文讲过,普通规则条件就是常规的比较,类同于代码中各种运算符。
这也是最简单最基础的,先看原来的设计。
create table de_condition
(
id bigint auto_increment comment '主键' primary key,
field_name varchar(32) default '' not null comment '字段名',
operate_type varchar(32) default 'null' not null comment '操作类型',
expect_type varchar(32) default 'input' not null comment '期望值类型',
expect_value varchar(32) default '' not null comment '期望值',
description varchar(64) charset utf8mb4 default '' null comment '描述',
creator varchar(64) charset utf8mb4 default '' null comment '创建者',
create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
updater varchar(64) charset utf8mb4 default '' null comment '更新者',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
deleted bit default b'0' not null comment '是否删除'
) comment '规则条件表';
举例说明一下
field_name | operate_type | expect_type | expect_value |
---|---|---|---|
N_S_appName | eq | input | phone |
N_F_money | gte | context | N_F_balance |
第一个条件:判断系统字段N_S_appName
是否等于phone
这个字符串。
第二个条件:判断系统字段N_F_money
是否大于等于系统字段N_F_balance
。
看似挺简单的,但这还涉及到系统字段的类型问题,之前文章有将字段进行如下划分。
/**
* @author wnhyang
* @date 2024/3/13
**/
@AllArgsConstructor
@Getter
public enum FieldType {
/**
* 字符型,支持【等于、不等于、包含、不包含、前缀、非前缀、后缀、非后缀、为空、不为空、存在于、不存在于】
*/
STRING("S"),
/**
* 整数型,支持【等于、不等于、大于、小于、大于等于、小于等于、为空、不为空、存在于,不存在于】
*/
NUMBER("N"),
/**
* 小数型,支持【等于、不等于、大于、小于、大于等于、小于等于、为空、不为空】
*/
FLOAT("F"),
/**
* 日期型,支持【等于、不等于、大于、小于、大于等于、小于等于、为空、不为空】
*/
DATE("D"),
/**
* 枚举型,支持【等于、不等于、为空、不为空】
*/
ENUM("E"),
/**
* 布尔型,支持【等于、不等于、为空、不为空】
*/
BOOLEAN("B");
private final String type;
public static FieldType getByType(String type) {
for (FieldType value : values()) {
if (value.getType().equals(type)) {
return value;
}
}
return null;
}
public static FieldType getByFieldName(String fieldName) {
if (fieldName.length() >= 3) {
String sub = StrUtil.sub(fieldName, 2, 3);
return getByType(sub);
}
return null;
}
}
与其相对应的操作类型有下。
/**
* @author wnhyang
* @date 2024/4/3
**/
@AllArgsConstructor
@Getter
public enum OperateType {
NULL("null"),
NOT_NULL("not_null"),
EQ("eq"),
NOT_EQ("not_eq"),
GT("gt"),
GTE("gte"),
LT("lt"),
LTE("lte"),
CONTAINS("contains"),
NOT_CONTAINS("not_contains"),
PREFIX("prefix"),
NOT_PREFIX("not_prefix"),
SUFFIX("suffix"),
NOT_SUFFIX("not_suffix");
private final String type;
public static OperateType getByType(String type) {
for (OperateType operateType : OperateType.values()) {
if (operateType.getType().equals(type)) {
return operateType;
}
}
return null;
}
}
普通条件就可表示如下,因为左边,只有${字段}
所以表设计的也简单,是field_name
没有区分,而中间操作也只有这些,也是固定的operate_type
,右边因为有变量${字段}
和常量的区别,设计了expect_type
和expect_value
。
指标条件
作为风控系统,指标是非常重要的存在,它与字段有很多相似之处。
数据类型差不多,有字符、数字、时间,毕竟它就是通过字段计算出来的嘛。
操作和右边也是一样,所以指标条件需要在左边加上${指标}
就够用了。
正则条件
我们都知道正则运算一般就是match(表达式,content)
,其实也是左运算右的模式。不过正则条件要加上一些属性。
1、是否匹配(是/否)
2、忽略大小写(是/否)
四则条件
四则运算,必要条件是数字类型,包括整数类型和小数类型,而且不局限于系统,还包含指标。
运算模式大概是下面这样。
不过这还不是条件,这只是运算,结果为数字类型,还需要加上判断才能成为条件。
如下,四则运算整体作为左边进行判断才构成了四则条件。
名单条件
名单条件有点类似普通条件的包含于,不多不是字符串那种包含于,而是数组类似的包含于。
时间条件
时间条件针对的是时间类型的字段。
时间差
顾名思义,时间A-时间B的差。
时间范围
对于流式数据时间不可能局限于准确的时间点,应当是类似于cron
。
位置条件
针对经纬度相关信息进行判断。
距离计算
顾名思义,位置A到位置B距离。
设备条件
关于设备可以算是新的安全领域,关系客户端。
主要风险包含有:越狱、代理、vpn、root、模拟器、双开、调试、注入攻击、DNS劫持等等。
通常需要配合客户端sdk
来识别,本质上也是风控因子(系统字段)的收集与判断。
脚本条件
脚本条件是最灵活、最不可控的条件,灵活容易理解,毕竟都是直接写代码作为条件了;不可控制就是代码不可控,只有熟悉本系统了解怎么编写的才能正确的使用脚本条件,不然就是各种问题了。
总结
以上基本梳理了通用的规则条件,可以了解到,所有条件无非是boolean condition(left, operate, right);
函数。
operate
是常用的操作,是固定的运算流程。
left
和right
是两个不同于condition
的逻辑单元,condition
返回值是boolean
,他们俩需要的是T arithmetic(T leftValue, arithmeticOperate, T rightValue);
这样的运算单元。
是不是有点编译原理的意思了!虽然当时我上那门课的时候也是各种懵逼,但是有些思想和方法论确实很有价值。
读万卷书也要行万里路啊!
所以可以将其拆分开为condition
和arithmetic
。
首先是T arithmetic(T leftValue, arithmeticOperate, T rightValue);
boolean condition(arithmetic(l1,m1,r1) right, logicOperation, arithmetic(l2,m2,r2) right);
根据如上的算术单元和逻辑单元可以结合Java
的函数式接口使编码更加优雅,就先到这吧!
抛砖引玉啦!
写在最后
拙作艰辛,字句心血,望诸君垂青,多予支持,不胜感激。
个人博客:无奈何杨(wnhyang)
个人语雀:wnhyang
共享语雀:在线知识共享
Github:wnhyang - Overview
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)