2021-10-11 规则引擎解决方案

定义
规则引擎是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据业务规则做出业务决策。
规则本质上是一个函数,如y=f(x1,x2,..,xn)
规则引擎由三部分
• 事实(Fact):就是用户输入的已经事实,可以理解为推理前的已知对象。
• LHS(Left Hand Side):可以理解为规则执行需要满足的条件。
• RHS(Right Hand Sike):可以理解为规则执行后的返回对象。
方案模型


image.png

两个重要模块:
• 规则管理:可以理解为逻辑上管理规则,主要涉及规则、事实对象和规则集三个实体。涉及到规则变更时,最好对规则加个版本,可通过规则版本控制,可以平滑灰度地方式改变规则,也便于更有信心在测试规则正确性。
• 规则执行:通过规则库数据,通过规则引擎的规则解析、规则编译将可执行代码缓存起来,避免每次和DB交互,然后每次规则的变更也通过ZK或者DCC实时通知给规则执行器。规则执行器的实现方式,可以多种多样,不依赖于规则库的存储方式,根据需求,这里选用Drools 可以基于ANTLR定制Rules 来作为规则引擎的核心。

规则管理:由于多节点部署,规则主要存放在数据库中进行统一管理。
由于Drools的KieFileSystem需要管理目录的为src/main/resources,所以临时生成的DRL文件可能需要再次编译。
由方案可以得出规则引擎需要的模块有
1.规则生成服务
2.日志系统
3.规则重载
4.规则执行
5.消息系统
6.规则多节点同步
主要需要设计的内容是 规则生成服务。
需要定义不同类型的规则及其生成机制,规则执行的时候可以通过不同的规则类型通过不同的执行器来执行规则。

具体实现:
 业务规则引擎主要包含如下模块

  1. BusinessRuleExecutor 规则引擎配置执行器接口:主要用来定义获取业务规则配置的动作方式。
  2. BusinessRuleExecutorImpl 规则引擎配置加载模块:实现了BusinessRuleExecutor接口。用于动态加载和执行规则。
  3. BusinessRule 业务规则元素:定义业务规则的接口,主要包含:业务规则标识、业务规则内容。
  4. BusinessRuleRunner 业务规则引擎执行器:主要是执行具体的业务规则脚本代码,触发相应的事件判断。
      类图层次结构如下所示
image.png

日志服务在调用接口的时候或者执行规则前后都会打点,根据需要是否持久化存储日志信息。

消息系统功能:
1.在规则执行完后,会根据结果调用外部服务。
2.新生成规则后,根据配置是否需要立即更新规则库,并通知其他节点。

规则体大致可以抽象为4大属性:
名称 描述
trigger 表示场景的触发器,例如时间点、设备属性、设备事件等
condition 表示场景被触发后的过滤条件,例如时间段限制、设备属性限制。一个场景中可以有多个过滤条件,彼此之间是“与”的关系。场景中也可以没有过滤条件,这时场景触发后会不经过滤直接执行相应的动作。
action 表示场景被触发,且满足过滤条件时,所需执行的动作,例如设置设备属性、执行另一个场景。一个场景中可以有多个动作。场景中必须至少有一个动作。
type 表示场景规则的类型
以如下为例,整个规则引擎流程
{
"type":"IFTTT", #为后续扩展,后续扩展不同的规则
"trigger":{
"uri":"trigger/device/event",
"params":{
"productId": "product id",
"deviceId":"iot device code",
"propertyName":"msgType",
"compareType":"equals",
"compareValue":"videoMotion"
}
},
"condition":{
"uri":"logical/and", # 有logical/and
"items":[
{
"uri":"condition/timeRange",
"params":{
"cron":"0 15 10 ? * MON-FRI",
"cronType":"quartz_cron"
}
},
{
"uri":"condition/device/property",
"params":{
"productId":"pkxxxxon",
"deviceId":"txxxxce",
"propertyName":"soxxxxrty",
"compareType":"<",
"compareValue":10
}
}
]
},
"action":[
{
"uri":"action/device/setProperty",
"params":{
"deviceId":"light_iotId",
"propertyName":"onOff",
"propertyValue":"on"
}
}
]
}

首先把不同的trigger 定义成不同的规则放入trigger的规则库,trigger的规则库主要是为了执行action中匹配
condition的 条件,也就是Trigger是为了分发请求到不同的执行器中执行规则。
而condition和action是真正执行规则的when 和then。

规则生成方案

定义规则模板 ruleTemplate
"package com.dahua.rulesengine\n" +
"\n" +
"import\tcom.dahua.rulesengine.model.RuleResult;\n" +
"<rules; separator="\n\n">\n" +
">>\n" +
"\n" +
"ruleValue(condition,action,rule) ::=<<\n" +
"rule "<rule.name>"\n" +
"\tno-loop true\n" +
"\t\twhen\n" +
"\t\t r:RuleResult(<condition.property> <condition.compare> <condition.value>)\n" + " \t\tthen\n" + " modify(r){\n" +
" TODO Action1<if(action)>,\n" +
" TODO Action2<endif>)\n" +
" }\n" +
"end\n" +
">>\n";
参数转换成 规则JSON //这里可以进一步封装成POJO类 映射的时候能更加规范,设置值得时候也不会出错
Map<String, Object> map = new HashMap<>();
//组合Rule部分
Map<String, Object> rule = new HashMap<>();
rule.put("name", name);
map.put("rule", rule);
//组合 规则When部分
Map<String, Object> when = new HashMap<>();
when.put("property","moneySum");
when.put("compare"," >");
when.put("value"," 500");
map.put("condition", when);
//组合 规则Then部分
Map<String, Object> then = new HashMap<>();
then.put("money", money);
map.put("action", then);
//组合规则When And Then 部分
return JSONObject.toJSONString(map);

通过antlr包定制rule
STGroup group = new STGroupString(ruleTemplate);
ST stFile = group.getInstanceOf("wordImport");
ST stRule = group.getInstanceOf("ruleValue");
JSONObject jsonObject = JSONObject.parseObject(json);
JSONObject condition = jsonObject.getJSONObject("condition");
JSONObject action = jsonObject.getJSONObject("action");
JSONObject rule = jsonObject.getJSONObject("rule");
stRule.add("condition", condition);
stRule.add("action", action);
stRule.add("rule", rule);
stFile.add("rules", stRule);
String result = stFile.render();
return result;

在生成规则后获取 rule.hashcode()查询有没有入库
如果已经入库,则给已经入库的规则添加新的condition和action。

若是调用规则执行服务,
通过封装的Facts POJO类 接收参数
调用trigger规则执行器,如果条件触发规则调用,继续执行该trigger业务规则执行器,对比condition 从而执行action(此时会发rpc消息到业务方)
至此 拿到整个规则执行的结果。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容