周口住房和城乡建设网站,企业网站建设费用 珠海,想给公司注册一个网站,视频网站开发价格#x1f44f;作者简介#xff1a;大家好#xff0c;我是爱吃芝士的土豆倪#xff0c;24届校招生Java选手#xff0c;很高兴认识大家#x1f4d5;系列专栏#xff1a;Spring原理、JUC原理、Kafka原理、分布式技术原理、数据库技术#x1f525;如果感觉博主的文章还不错的… 作者简介大家好我是爱吃芝士的土豆倪24届校招生Java选手很高兴认识大家系列专栏Spring原理、JUC原理、Kafka原理、分布式技术原理、数据库技术如果感觉博主的文章还不错的话请三连支持一下博主哦博主正在努力完成2023计划中源码溯源一探究竟联系方式nhs19990716加我进群大家一起学习一起进步一起对抗互联网寒冬 文章目录 设计一个简单的规则引擎问题描述需求设计数据库设计rule_treerule_tree_noderule_tree_node_linerule_tree datarule_tree_node datarule_tree_node_line data 结构设计 核心代码规则管理器推理引擎 最终展示测试结果 设计一个简单的规则引擎
问题描述
何为规则引擎按照gpt的给的定义来解释下
规则引擎是一种计算机软件或系统用于管理和执行特定规则集合。它基于预定义的规则和逻辑对输入数据进行处理、评估和决策。规则引擎通常由两个主要组成部分组成规则管理器和推理引擎。
那么假如说我们需要设计一个简单的规则引擎那么结合上述需要考虑什么呢
比如说我们已知一个人的性别和年龄根据这两个进行规则的判断然后分流到不同的分支怎么实现呢
最简单的方式莫过于几个ifelse就能结果但是假如说后面加入了更多的规则岂不是我们还要重新进去写代码改这个规则
所以需要设计一个动态的规则引擎这样当有新的规则来的时候我们不需要很大的变动就可以完成规则的加入。
需求设计 本质上就是要完成这样的一个规则引擎首先通过性别进行规则判断然后是通过年龄进行规则判断这样一个简单的规则殷勤的雏形就设计好了。
数据库设计
一个好的规则引擎还可以用于将来的扩展所以理论上一些值应该保存在数据库中将来再由一套管理系统进行动态扩展即可。
那么数据库的设计是什么呢
从上图也可以看到这个结构是不是很像一颗二叉树实际上的设计也是基于此库表中其实就是将一颗二叉树抽象进去啦那么这里就需要包括树根、树茎、子叶、果实。在具体的逻辑实现中则需要通过子叶判断走哪个树茎以及最终筛选出一个果实来。
rule_tree
CREATE TABLE rule_tree (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键ID,tree_name varchar(64) DEFAULT NULL COMMENT 规则树NAME,tree_desc varchar(128) DEFAULT NULL COMMENT 规则树描述,tree_root_node_id bigint(20) DEFAULT NULL COMMENT 规则树根ID,create_time datetime DEFAULT NULL COMMENT 创建时间,update_time datetime DEFAULT NULL COMMENT 更新时间,PRIMARY KEY (id)
) ENGINEInnoDB AUTO_INCREMENT10002 DEFAULT CHARSETutf8;rule_tree_node
CREATE TABLE rule_tree_node (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键ID,tree_id int(2) DEFAULT NULL COMMENT 规则树ID,node_type int(2) DEFAULT NULL COMMENT 节点类型1子叶、2果实,node_value varchar(32) DEFAULT NULL COMMENT 节点值[nodeType2]果实值,rule_key varchar(16) DEFAULT NULL COMMENT 规则Key,rule_desc varchar(32) DEFAULT NULL COMMENT 规则描述,PRIMARY KEY (id)
) ENGINEInnoDB AUTO_INCREMENT123 DEFAULT CHARSETutf8;rule_tree_node_line
CREATE TABLE rule_tree_node_line (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键ID,tree_id bigint(20) DEFAULT NULL COMMENT 规则树ID,node_id_from bigint(20) DEFAULT NULL COMMENT 节点From,node_id_to bigint(20) DEFAULT NULL COMMENT 节点To,rule_limit_type int(2) DEFAULT NULL COMMENT 限定类型1:;2:;3:;4:;5;6:enum[枚举范围];7:果实,rule_limit_value varchar(32) DEFAULT NULL COMMENT 限定值,PRIMARY KEY (id)
) ENGINEInnoDB AUTO_INCREMENT7 DEFAULT CHARSETutf8;以上就是表的结构那么将上图中的结构抽象进数据库中数据应该写呢
rule_tree data rule_tree_node data rule_tree_node_line data 以上就是全部的数据库设计啦其实就是将二叉树的结构抽象进数据库中然后为每个分支都加上逻辑判断即可如rule_tree_node_line data 所示。
结构设计
聊完数据库设计再回到问题描述里说的
规则引擎是一种计算机软件或系统用于管理和执行特定规则集合。它基于预定义的规则和逻辑对输入数据进行处理、评估和决策。规则引擎通常由两个主要组成部分组成规则管理器和推理引擎。
总结起来就是一句话规则引擎分为 规则管理器 推理引擎。 核心代码
规则管理器
// 规则过滤器接口
public interface LogicFilter {/*** 逻辑决策器* param matterValue 决策值* param treeNodeLineInfoList 决策节点* return 下一个节点Id*/Long filter(String matterValue, ListTreeNodeLineVO treeNodeLineInfoList);/*** 获取决策值** param decisionMatter 决策物料* return 决策值*/String matterValue(DecisionMatterReq decisionMatter);}filter的核心就是根据当前的决策值返回下一个节点的ID
public abstract class BaseLogic implements LogicFilter {Overridepublic Long filter(String matterValue, ListTreeNodeLineVO treeNodeLineInfoList) {for (TreeNodeLineVO nodeLine : treeNodeLineInfoList) {if (decisionLogic(matterValue, nodeLine)) {return nodeLine.getNodeIdTo();}}return Constants.Global.TREE_NULL_NODE;}/*** 获取规则比对值* param decisionMatter 决策物料* return 比对值*/Overridepublic abstract String matterValue(DecisionMatterReq decisionMatter);private boolean decisionLogic(String matterValue, TreeNodeLineVO nodeLine) {switch (nodeLine.getRuleLimitType()) {case Constants.RuleLimitType.EQUAL:return matterValue.equals(nodeLine.getRuleLimitValue());case Constants.RuleLimitType.GT:return Double.parseDouble(matterValue) Double.parseDouble(nodeLine.getRuleLimitValue());case Constants.RuleLimitType.LT:return Double.parseDouble(matterValue) Double.parseDouble(nodeLine.getRuleLimitValue());case Constants.RuleLimitType.GE:return Double.parseDouble(matterValue) Double.parseDouble(nodeLine.getRuleLimitValue());case Constants.RuleLimitType.LE:return Double.parseDouble(matterValue) Double.parseDouble(nodeLine.getRuleLimitValue());default:return false;}}}以及两个对应的规则
Component
public class UserAgeFilter extends BaseLogic {Overridepublic String matterValue(DecisionMatterReq decisionMatter) {return decisionMatter.getValMap().get(age).toString();}}Component
public class UserGenderFilter extends BaseLogic {Overridepublic String matterValue(DecisionMatterReq decisionMatter) {return decisionMatter.getValMap().get(gender).toString();}}推理引擎
// 规则过滤器引擎
public interface EngineFilter {/*** 规则过滤器接口** param matter 规则决策物料* return 规则决策结果*/EngineResult process(final DecisionMatterReq matter);}// 规则配置
public class EngineConfig {protected static MapString, LogicFilter logicFilterMap new ConcurrentHashMap();Resourceprivate UserAgeFilter userAgeFilter;Resourceprivate UserGenderFilter userGenderFilter;PostConstructpublic void init() {logicFilterMap.put(userAge, userAgeFilter);logicFilterMap.put(userGender, userGenderFilter);}}public abstract class EngineBase extends EngineConfig implements EngineFilter {private Logger logger LoggerFactory.getLogger(EngineBase.class);Overridepublic EngineResult process(DecisionMatterReq matter) {throw new RuntimeException(未实现规则引擎服务);}protected TreeNodeVO engineDecisionMaker(TreeRuleRich treeRuleRich, DecisionMatterReq matter) {TreeRootVO treeRoot treeRuleRich.getTreeRoot();MapLong, TreeNodeVO treeNodeMap treeRuleRich.getTreeNodeMap();// 规则树根IDLong rootNodeId treeRoot.getTreeRootNodeId();TreeNodeVO treeNodeInfo treeNodeMap.get(rootNodeId);// 节点类型[NodeType]1子叶、2果实while (Constants.NodeType.STEM.equals(treeNodeInfo.getNodeType())) {String ruleKey treeNodeInfo.getRuleKey();LogicFilter logicFilter logicFilterMap.get(ruleKey);String matterValue logicFilter.matterValue(matter);Long nextNode logicFilter.filter(matterValue, treeNodeInfo.getTreeNodeLineInfoList());treeNodeInfo treeNodeMap.get(nextNode);logger.info(决策树引擎{} userId{} treeId{} treeNode{} ruleKey{} matterValue{},treeRoot.getTreeName(), matter.getUserId(), matter.getTreeId(), treeNodeInfo.getTreeNodeId(),ruleKey, matterValue);}return treeNodeInfo;}}上述这段代码也是真正的推理引擎的代码来解读一下首先获取到这课规则树然后遍历这颗规则树遍历的时候根据对应节点的规则key从规则管理器中找到对应的规则然后执行规则获取到下一个即将要执行的规则然后在while循环中遍历并且将每一次找到的规则打印即可。
Service(ruleEngineHandle)
public class RuleEngineHandle extends EngineBase {Resourceprivate IRuleRepository ruleRepository;Overridepublic EngineResult process(DecisionMatterReq matter) {// 决策规则树TreeRuleRich treeRuleRich ruleRepository.queryTreeRuleRich(matter.getTreeId());if (null treeRuleRich) {throw new RuntimeException(Tree Rule is null!);}// 决策节点TreeNodeVO treeNodeInfo engineDecisionMaker(treeRuleRich, matter);// 决策结果return new EngineResult(matter.getUserId(), treeNodeInfo.getTreeId(), treeNodeInfo.getTreeNodeId(), treeNodeInfo.getNodeValue());}}最终展示
RunWith(SpringRunner.class)
SpringBootTest
public class RuleTest {private Logger logger LoggerFactory.getLogger(ActivityTest.class);Resourceprivate EngineFilter engineFilter;Testpublic void test_process() {DecisionMatterReq req new DecisionMatterReq();req.setTreeId(2110081902L);req.setUserId(nhs);req.setValMap(new HashMapString, Object() {{put(gender, man);put(age, 25);}});EngineResult res engineFilter.process(req);logger.info(请求参数{}, JSON.toJSONString(req));logger.info(测试结果{}, JSON.toJSONString(res));}}测试结果
09:30:58.874 INFO 53959 --- [ main] c.i.l.d.rule.service.engine.EngineBase : 决策树引擎抽奖活动规则树 userIdfustack treeId2110081902 treeNode11 ruleKeyuserGender matterValueman
09:30:58.874 INFO 53959 --- [ main] c.i.l.d.rule.service.engine.EngineBase : 决策树引擎抽奖活动规则树 userIdfustack treeId2110081902 treeNode112 ruleKeyuserAge matterValue25
09:30:59.349 INFO 53959 --- [ main] c.i.lottery.test.domain.ActivityTest : 请求参数{treeId:2110081902,userId:fustack,valMap:{gender:man,age:25}}
09:30:59.355 INFO 53959 --- [ main] c.i.lottery.test.domain.ActivityTest : 测试结果{nodeId:112,nodeValue:100002,success:true,treeId:2110081902,userId:nhs}