规则引擎的架构设计与系统实现

[未完待续中,后续代码实现优先发布到GitHub]

GitHub - failgoddess/rule: 规则引擎

MVP版本完成可以直接下载

业务规则、配置化编程、政策引擎、规则引擎

目录

ruleEngine

1. 背景

2. 方案考察

2.1. 硬编码:

2.2. Drools:

2.3. Urule:

2.4. 自研规则引擎

3. 能力要求

4. 名词解释

5. 概要设计

5.1. 功能模块划分

5.1.1. 公式推理器Calculator:

5.1.2. 指标解析器FormulaExecuter:

5.1.3. 动作执行器ActionExecuter:

5.1.4. 模型执行器RuleModel:

5.1.5. 模型构建器RuleModelBuilder:

5.1.6. 模型加载器RuleModelLoader:

5.1.7. 交互转换器:

5.2. 系统设计

5.2.1. 指标占位符

5.2.2. JSON出参解析

5.2.3. 关系运算符

5.2.4. 技术选型

5.3. 关键技术说明

5.3.1. 逻辑式编程

5.3.2. 分治策略

5.3.3. 决策树

5.3.4. 括号匹配算法

6. 详细设计

6.1. 数据模型

6.1.1. 规则ER-图

6.1.2. 关系数据库表结构

6.2. 执行逻辑图

6.2.1. 规则执行时序图

6.2.2. 指标解析执行流程

6.3. 缓存对象数据结构

6.4. 枚举值配置


1. 背景

在项目步入成熟期,规则类需求几乎占据了业务所有需求的半边天。一方面规则唯一不变的是“多变”,另一方面开发团队对“规则开发”的感受是乏味、疲惫和缺乏技术含量。如何解决规则开发的效率问题,最大化解放开发团队成为一个新的挑战。

规则底层采用规则引擎来实现。规则引擎是一种嵌入在应用程序中的组件,实现了将业务规则从应用程序代码中分离出来,并使用预定义的规则语义来编写业务规则。规则引擎接受数据输入,解释业务规则,并根据规则执行相应的业务逻辑。一个业务规则包含一组条件和在此条件下执行的操作,它们表示业务规则应用程序的一段业务逻辑。我们在业务中设置一个或者多个条件,当满足这些条件时触发相应的操作,规则引擎设计的初衷是可以将复杂多变的规则从硬编码中解放出来,以规则脚本的形式存放在文件或者数据库中,使得规则的变更不需要修改代码即可使用,做到最大程度的灵活。

2. 方案考察

现在市面上在做业务规则的过程中有多种实现方案:

2.1. 硬编码:

优点:

稳定性较佳:语法级别错误不会出现,由编译系统保证。

当规则较少、变动不频繁时,开发效率最高。

缺点:

规则迭代成本高:对规则的少量改动就需要走全流程(开发、测试、部署)。

规则开发和维护门槛高:规则对业务分析人员不可见。业务分析人员有规则变更需求后无法自助完成开发,需要由开发人员介入开发。

2.2. Drools:

优点:

策略规则和执行逻辑解耦方便维护。

缺点:

业务分析师无法独立完成规则配置:由于规则主体DSL是编程语言(支持Java, Groovy, Python),因此仍然需要开发工程师维护。

规则的语法仅适合扁平的规则,对于嵌套条件语义(then里嵌套when...then子句)的规则只能将条件进行笛卡尔积组合以后进行配置,不利于维护。

2.3. Urule:

优点:

可视化操作完善、功能强大

缺点:

不支持回溯:当前分支没有符合条件的之后不支持回溯

不支持动态加载数据:例如门店有等级、店龄、区域等若干属性,业务规则具体是根据店龄不同给出结果还是根据等级,属于规则的业务范畴,调用方并不关心。要是每次需要将所有可能用于规则判断的数据全部由调用方传入,无疑降低了规则的灵活性。

2.4. 自研规则引擎

在学习机器学习中决策树的算法时可以生成决策树的决策流图。决策树整体分为两个阶段:通过算法计算找出规律将规律构建决策模型、传入新数据基于决策流进行新的决策分析。这一点给我带来了很大的思想启发,配置规则的过程作为决策树的构建阶段,新数据决策为决策树的预测过程。出现多个决策路径组合的为最终结果的场景也可以理解决策森林算法的演化。

3. 能力要求

规则引擎的设计主要分为两部分:一部分是规则的维护,包括规则的创建、修改、删除;一部分是规则的执行。规则的维护部分侧重点是页面,我们需要将用户在页面上的操作转换为内置规则并保存到数据库中。在规则执行的过程中调用方只需要选择规则传入相应的数据即可获得决策结果。结合整体需求,规则引擎应该有可扩展、易维护的特点,先将规则引擎的功能需要实现的功能点总结如下:

指标部分(维护指标、计算执行指标)

模型维护(模型即实体,包括模型的创建以及模型属性的维护)

规则维护(包括对规则的增删改查)

条件维护(对规则条件的增删改查)

指标维护(对规则指标的增删改查)

结果维护(对规则结果的增删改查)

节点维护(包括静态节点和动态节点部分)

基于规则版本的决策记录(基于历史规则查看判定过程记录)

规则的版本控制

根据技术考察和能力要求对我们的规则引擎提出了更为全面的要求:

l 支持可视化的界面配置

l 支持嵌套条件语义

l 支持组合条件

l 支持动态加载

l 支持决策日志

l 支持规则历史版本

l 支持回溯

l 支持决策森林

4. 名词解释

术语及缩略语名词解释
规则每一个需要用于判定的业务场景就是一套规则,例如:可否邮寄判断;规则通常由每一个决策树的判定结果和操作符构成,例如:区域决策树AND(调整价决策树OR年份决策树);规则的本质是分类问题,由决策树和操作符构建的决策森林
节点每一个规则内可能影响决策判定流程和结果的一个影响因素(维度)
结果一个规则中所有决策树中可能返回的结果,也就是一个决策树数的叶子结点,例如:可否邮寄判断的结果集合是是和否
决策树决策树又称为判定树,是规则中的每一条判定路径,这个判定路径是根据不同节点以及条件执行不同分支路径,完整的判定路径分支、节点就是一棵决策树。考虑到不同连接接有同一个下一跳的情况决策树也被称为决策图
操作符条件运算符
分支一个分支包含多个连接是一组连接的集合。
条件条件由被比较值、操作符、比较值构成。名称参考12/6=2 被除数、除数、商
连接连接表示当前分支中一个节点在一组条件下要进入的下一跳,下一跳可以是另外一个连接也可以是结果。主要是达到执行对象切换的作用。同一个分支中的不同连接指向同过个下一跳逻辑关系为或的关系,同一个连接中不同的条件为且的关系。
指标是规则流程执行中的元数据。
判定日志每一次判定结果的日志记录
判定数据用于规则判定时的入参对象
历史规则规则的历史版本控制,每一次规则的修改都会引起一个版本变化,同一时间节点一个规则只会有一个生效的版本

5. 概要设计

5.1. 功能模块划分

5.1.1. 公式推理器Calculator:

用于计算公式例如((18)/9)9572>1008611计算,是指标解析器的底层实现,公式推理器一部分基于规则引擎实现、一部分基于手写运算符计算器实现

5.1.2. 指标解析器FormulaExecuter:

在公式类指标中用于公式的构建例如:目标库存为公式类指标,计算公式为平均周销*周数,由指标解析器将平均周销和周数替换成指定的数值

在传入类指标中用于将调用方的输入值转化成指标项例如目标库存中周数指标

在配置类指标中用于将配置到系统中的参数解析成指定指标

在动作类指标中用于组件构造动作执行器的执行入参并调用动作执行器。

5.1.3. 动作执行器ActionExecuter:

根据动作的类型传入参执行方法或者发送相应的请求,并负责解析返回值;不变型动作的执行可基于动作执行历史记录;

5.1.4. 模型执行器RuleModel:

负责解析规则模型按照深度优先的规则执行决策树,流程树

5.1.5. 模型构建器RuleModelBuilder:

确定一个规则编码负责从数据表中将于这个规则相关的数据加载到程序中,并组装出可以用于执行的规则模型JSON

5.1.6. 模型加载器RuleModelLoader:

负责加载配置好的模型,规则当前版本的加载优先级为Cache —> Redis —>模型构建器,规则历史版本的模型直接加载历史版本中的模型JSON

5.1.7. 交互转换器:

前端页面本着页面友好的原则会采用多种类型的页面展示和实现,前端数据和后端模型的数据会差异比较大所以在前后交互的过程中采用交互转换器进行数据转换,每种样式的展示方式都会有一个相应的转换器。

5.2. 系统设计

5.2.1. 指标占位符

${123}:调用id为123的指标

@{storeCode}:引用入参storeCode的实际值

%{ now()}:系统内置函数的返回值,这个系统特指规则引擎内部

#{123}:引用id为123的节点

["storeCode","1002"]  向被调用者传入参数storeCode为1002 

5.2.2. JSON出参解析

请求型指标会访问一个url发送请求获得非接口返回值是JSON形式的数据,这里采用JsonPath插件对JSON进行解析获取需要的数据。完整语法请参考JsonPath官方文档

Map或对象:$.attr_name

List< Map或对象>$. data[i]. attr_name

i=*或者不配表示 取全部列表每一个item的attr_name逗号隔开

i=5 代表取索引为5 的attr_name

5.2.3. 关系运算符

系统内置操作符用于经销规则的逻辑判断,系统内置的每一条指令都有一个操作符,它表示该指令应进行什么性质的操作。不同的指令用操作符这个字段的不同编码来表示,每一种编码代表一种指令。

操作符布尔不区分字符串字符串数值时间列表
be介于(闭区间)
bed介于(开区间)
nbe不介于(闭区间)
nbed不介于(开区间)
cn包含
ncn不包含
en为空
nn不为空
eq等于
eqd等于(不区分)
neq不等于
neqd不等于(不区分)
ge大于等于
gt大于
in在集合
nin不在集合
le小于等于
lt小于
nre不正则
re正则
and并且
or
not
xor异或
lp左括号
rp右括号
add
sub
mul
div
acm取余

5.2.4. 技术选型

技术选型目前规则引擎领域开源的主要有Drools、IKExpression、Aviator、QLExpress、SimpleEL、Groovy、Fel等,鉴于Fel表达式求值语法简洁。同时其优异的性能表现,规则中心选型Fel。执行100 万次表达式求值的性能表现对比如下图:

5.3. 关键技术说明

本系统会用到:依赖性任务排序的算法(用于指标依赖执行顺序的执行顺序)、决策树算法、分治策略、括号匹配、策略模式、逻辑式编程、JSONPath、DFS算法、Cache、Fel。

5.3.1. 逻辑式编程

算法+数据结构=程序这是Pascal设计者Niklaus Wirth的一本著作的书名,它刻画了过程式尤其是结构化编程的思想。后来Robert Kowalski进一步提出:算法=逻辑+控制。其中逻辑是算法的核心,控制主要用于改进算法的效率。在逻辑式编程中,程序员只需表达逻辑,而控制交给编程语言的解释器或编译器去管理。

本规则引擎采用逻辑式编程的思想,由业务人员提供业务规则,开发负责将业务规则整理转义成解释器可解释执行的配置文件,在交由解释器和编译器解析执行。则可以做到业务只考虑规则构建、开发需表达逻辑、而执行交给解释器或编译器去管理,当调用方选择规则模型传入初始化数据后有加载器加载指定模型、执行器用相关的决策路径来控制执行返回规则结果达到一部分业务流程可配置的目的。

5.3.2. 分治策略

经销规则模块执行器采用分治策略实现深度遍历的决策树。分治策略是对于一个规模为n的问题,若该问题可以容易地解决(比如说规模n较小)则直接解决,否则将其分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。

分治法的基本步骤 分治法在每一层递归上都有三个步骤:

分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;

解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题;

合并:将各个子问题的解合并为原问题的解。

5.3.3. 决策树

决策树机器学习预测方法,主要用于对离散型数据的分类。一个值经过相应的节点测验会跳过假分支进入真分支,所以一组值经过决策树以后,就会形成从树跟到结果节点的一条唯一路径。所以它除了可以对输入进行分类之外,还能给出如此分类的解释。算法实现分为:特征选择、决策树的训练构建决策模型、模型对新数据测预测;

规则引擎的数据维度抽取参考特征选择,也是在硬编码中用于if判断的数据字段;决策树模型的构建采用业务人员在实际工作中的经验规则;传入数据由模型执行类比对模型预测的阶段;

5.3.4. 括号匹配算法

指标的公式是可以嵌套的所以需要来解析公式需要用到括号匹配算法:

123 门店平均销量指标 入参门店编码 sku编码 天数

456 门店可用库存指标 入参门店编码 sku编码

789 门店需求量指标公式为:门店10天的sku需求量=10天门店最近30天平均该sku销量-门店前库存;可表示为 10${123(storeCode:@{storeCode},skuCode:@{skuCode},dayNumber:30)}-${345(storeCode:@{storeCode},skuCode:@{skuCode})}

这个解析的过程是一个采用分治策略的递归解析过程;用到括号匹配算法来解析公式;

原括号匹配算法只是在结构出判断堆栈是否为空用于判断是否成对出现,这里需要做一个改造每一次堆栈为空的时候表示这是一个最大单元也就是整个公式最多可以分为几段 门店需求量就可以分为两段 ${123(storeCode:@{storeCode},skuCode:@{skuCode},dayNumber:30)}和${345(storeCode:@{storeCode},skuCode:@{skuCode})}

在利用分治递归的思想将每一段分别处理

6. 详细设计

6.1. 数据模型

6.1.1. 规则ER-图

6.1.2. 关系数据库表结构

节点表

字段数据类型长度说明
Idint864节点表
rule_idint864所属规则ID
Namevarchar64节点标题
note_typeint432节点数据来源类型:10传入20指标值
note_categoryint432节点类型:1可变、0不可变
Attributevarchar128判定数据对象的字段
note_categoryint432节点类型:1可变、0不可变
value_typeint43210数字20时间30字符串35不区分字符串40列表
parametervarchar255参数用json表示,节点调用指标的参数只能是配置好的固定值或者传入节点的数据值
quota_idint864指标id
Remarkvarchar512备注

结果表

字段数据类型长度说明
Idint864结果表
rule_idint864所属规则ID
Namevarchar64结果标题
Datavarchar128结果数据
result_typeint432结果类型10固定值20节点值30指标值
node_idint864节点ID
quota_idint864指标ID
parametervarchar255参数用json表示
Remarkvarchar512备注

规则表

字段数据类型长度说明
Idint864规则表
Namevarchar64规则名称
Codevarchar64规则编码
Contentvarchar32规则内容
data_typevarchar32结果数据的类型
node_infovarchar32支持的对象节点的描述
node_attributevarchar32支持的对象节点的属性
Remarkvarchar255备注

决策树表

字段数据类型长度说明
Idint864经销商商品授权表
rule_idint864规则ID
codevarchar64决策树编码
first_branch_idint864第一跳ID(分支)
namevarchar64决策树标题
remarkvarchar255备注

运算符表

字段数据类型长度说明
idint864运算符表
codevarchar64编码
operation_typeint432类型:1关系运算符2逻辑运算符3优先级运算符4算数运算符
namevarchar128运算符标题
remarkvarchar255备注

分支表

字段数据类型长度说明
idint864分支表
node_idint864节点ID
node_typeint864节点数据类型
namevarchar64条件名称
operation_idint864操作符ID
thresholdvarchar32阀值
rule_idint864规则ID
tree_idint864决策树ID
remarkvarchar512备注

条件表

字段数据类型长度说明
idint864条件表
link_idint864连接ID
priorityInt464优先级
namevarchar64条件名称
operation_idint864操作符ID
thresholdvarchar32阀值
rule_idint864规则ID
branch_idint864分支ID
threshold_typeInt432阀值类型10固定值20节点值
note_idint864节点ID
remarkvarchar512备注

连接表

字段数据类型长度说明
idint864连接表
namevarchar64连接名称
priorityint464优先级
tree_idint864决策树ID
branch_idint864所属分支ID
next_branch_idint864下一跳分支ID
next_typeint432下一跳类型
next_result_idint864下一跳结果ID
rule_idint864规则ID
remarkvarchar512备注

判定数据表

字段数据类型长度说明
idint864判定数据表
rule_idint864规则ID
rule_versionvarchar128规则版本号
datavarchar128判定数据
resultvarchar64结果(不一定来源于结果)
result_idint864结果ID(为空则表示规则结果为和合成结果)
history_idint864历史ID
factorvarchar128决定因素
remarkvarchar512备注

判定日志表

字段数据类型长度说明
idint864判定数据表
rule_idint864规则ID
rule_versionvarchar128规则版本号
judge_data_idint864判定数据ID
flagbool0是否符合
history_idint864历史ID
node_idint864节点ID
link_idint864连接ID
condition_idint864条件ID
branch_idint864分支ID
remarkvarchar512备注

历史规则表

字段数据类型长度说明
idint864历史规则表
rule_idint864规则ID
rule_versionvarchar128规则版本号
start_timetimestamp64开始时间
end_timetimestamp64结束时间
remarkvarchar512备注

指标表

字段数据类型长度说明
idint864配置表
quota_typeint432指标类型10方法类20请求类30公式类40配置类
namevarchar255指标名称
value_typeint432数据值类型10数字20时间30字符串35不区分字符串40列表
java_methodvarchar25510方法类所配置的方法
request_urlvarchar25520请求类请求路径
request_methodVarchar25520请求类请求方法,目前只支持get、post
formulaVarchar25530公式类计算公式
deployVarchar25540配置类配置
parameterVarchar255参数用json表示
feedback_ruleVarchar255返回值取值规则
necessaryvarchar255必须的入参也就是调用者必传的字段
cache_imevarchar255请求型缓存时间
remarkvarchar512备注

6.2. 执行逻辑图

6.2.1. 规则执行时序图

6.2.2. 指标解析执行流程

6.2.2.1. 公式型指标

10*${123(attr1:12,attr2:${456})}+2

10*

${123(attr1:12,attr2:${456})}

123 的指标

解析123指标需要的入参

attr1=12

attr2=${456}

${456}

456 的指标

456 的指标 执行

123入参构建完成

123 的指标 执行

+2

6.2.2.2. 请求型指标

6.3. 缓存对象数据结构

6.4. 枚举值配置

枚举类型枚举值枚举描述
节点数据来源类型10传入值
20指标值
指标类型10方法类
20请求类
30公式类
40配置类
结果类型10固定值
20节点值
30指标值
下一跳类型1分支
2结果
阀值类型10固定值
20节点值
数据值类型10数值
20时间
30字符串
35不区分大小字符串
40列表

  • 8
    点赞
  • 87
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
drools规则引擎系统概要设计.doc是一份关于drools规则引擎系统概要设计的文档。该文档主要包括系统的整体架构、系统模块设计系统组成部分等内容。 在系统的整体架构中,要明确系统的各个组件和模块之间的关系和作用。例如,可以采用分层架构,将系统分为前端界面、业务逻辑处理、规则引擎等三层。前端界面负责与用户交互,业务逻辑处理层负责处理用户的请求和业务逻辑,规则引擎层则负责管理和执行规则系统模块设计中,应考虑到各个功能模块的划分与实现。例如,可以将规则管理模块、规则编辑模块、规则执行模块等作为系统的主要功能模块。规则管理模块用于对规则进行管理和配置,规则编辑模块用于编辑规则的表达式和条件,规则执行模块则负责根据规则引擎规则执行规则系统组成部分主要指的是系统中的各个组件和技术。例如,可以使用Java语言来开发系统的各个模块,使用Drools来实现规则引擎功能。此外,还可以使用数据库来存储规则和相关数据,使用Spring框架来实现系统的IOC和AOP等功能。 总之,drools规则引擎系统概要设计.doc是一份关于系统整体架构、模块设计系统组成部分的概要设计文档。该文档对系统的整体设计进行了规划和解释,有助于开发团队理解系统设计思路和实现方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值