文档章节

规则引擎开发

lateron
 lateron
发布于 2013/05/06 15:36
字数 1824
阅读 746
收藏 22

最近两个月以来,一直在开发公司的规则引擎系统,起初是想把引擎用到CRM系统中,后来经过多次讨论、多次变更,领导决定把这个规则引擎做成中间件,在平台的高度来使用他。做成中间件,对规则引擎的要求更高了,这需要引擎具备高灵活性和伸缩性,来适应不同的业务系统。下面我来谈谈开发过程中我的一些经验。

曾经听板桥先生说过,架构设计需要从事物外部(通过与其他同类事物比较)和深入事物内部两种方式来进行,实际就是“做什么”和“怎么做”分离。首先,我需要技术选型,在众多的规则引擎中,适合java项目的有ILog、Jess、Mandarax、Drools,由于ILog和Jess不是开源的,所以这两个提前出局。剩下Mandarax和Drools,这两个开源项目各有千秋,但是我比较了一下,Mandarax最近几年都没有过更新,并且文档不全、社区不活跃,而Droos在google一搜,有很多的mail list供我参考,所以我很倾向于使用Drools。在一篇Mandarax的入门文档的评论里,我看到一个朋友在业务的角度来比较他们俩,看完后,我更加确定Drools是最适合我的。

接下来,我开始了解需求,初步规划规则引擎,在了解完各个系统的业务需求后,我大致定了下规则引擎要做的事情以及引擎与其他系统的边界。由于各个系统之间差异比较大,要让引擎高可扩展,需要对需求进一步抽象,业务系统与规则引擎之间是通过模型来交互的,所以我们单独将模型抽象出来,在引擎中可以对模型进行管理。另外一个需要抽象的地方就是规则的动作部分,由于每个系统数据库、业务的差异性,动作是不可能统一的,将动作抽象为动作类型,并可以单独管理,当有新系统接入引擎时,我们为其定义新的动作类型即可。

引擎有了初步规划后,我开始了解Drools,结合Drools的特点进一步规划引擎。Drools的官方文档上提供了很详细的例子来供我们入门,这里不再赘述入门级别的代码。我需要列举一下自己的引擎中需要实现的功能并在Drools中找到解决方案:

1.规则有效期

Drools中的date-effective和date-expires生来就是干这个的。

2.基于Cron的定时任务

Drools中的timer可以实现,并且官方例子很详细。

3.规则返回结果

Drools中的globle很适合。

4.规则优先级

可以使用salience来解决。

5.计算类的属性

对于一些需要预处理的属性,我们可以不定义字段,而是直接定义一个无参数的方法,具体可以参考这篇文章的4.8.3.1.1.1节。

6.规则的与或关系

这是Drools天生就支持的,并且是完美支持。

掌握了基本的技术点后,我开始设计规则的创建页面,整个规则引擎大致的思路是:把前端用户输入的语言(通俗易懂的白话语言)作为输入,经过一系列处理转换后,保存到数据库(我们特殊处理的语言)。在规则执行的时候,我们再从数据库拿出保存在数据库的“语言”,然后转换为Drools语言。只所以不把前端用户的输入直接转换为Drools语言,是因为我们的场景、属性、动作类型都是可以灵活变动的,如果创建之初就进行转换,会导致之后的扩展异常困难。

规则的创建页面包含规则的名称、有效期、条件信息和动作信息等,条件部分我们允许用户选择实体(模型)属性并可以对属性做四则运算或者与或关系,这样在保证引擎的强大之时却不失简单之美。为了保证条件的正确性,系统需要在保存规则之前对用户输入的条件进行正确性检验。动作的创建首先是需要选择动作类型,然后根据定义好的动作类型去输入相应的内容,这块还涉及到一些其他知识,比如静态变量和动态变量,这里不再展开细说。

说到页面了,那就接着来,由于是后台的管理界面,所以我毫不犹豫的选择了DWZ。选择DWZ有这几个考虑:一是我对他熟悉,上手快。二是他的速度还可以,并且对常用的浏览器都有较好的支持。关于DWZ的一些使用经验我都零零碎碎分享到了博客里,供以后参考。

上面说了,引擎的核心工作其实就是转换。我们需要把自己的语言转换为Drools语言,这里面就涉及到很多字符串的拼装,接下来我谈谈这部分工作的经验:

1.使用StringBuilder进行拼装,并且注意对拼装规则进行格式化(比如在每行后面换行,这样方便我们调试与排错)。

2.巧用正则表达式,比如我们要得到两个@之间的字符串,可以使用下面的代码:

Matcher m=Pattern.compile("\\#(.*?)\\#").matcher(str);
		List<String> list = new ArrayList<String>();
		while(m.find()){
			list.add(m.group(1));
		}

3.以Drools规则语言的标准来组织程序,做到有条不紊。在代码关键部分多打log,方便调试。

完成引擎的解析工作后,剩下的部分就容易多了,无非是一些CRUD的工作,比如对场景的管理、场景中实体的管理、角色的管理等等。

引擎开发工作持续了将近一个月,接下来进入测试阶段。我们需要根据压测结果对引擎核心代码进行优化重构,这部分我主要借助VisualVM和JConsole,在压测的同时使用VisualVM进行CPU采样,然后进行分析。经过几轮的测试,我发现之前自己的代码中有很多的不严谨之处,比如:

1.使用StatefulKnowledgeSession后没有调用dispose方法去释放内存资源,这一错误会让引擎不停的内存溢出。

2.没有对KnowledgeBase进行缓存,而是对字符串进行缓存。由于没有对KnowledgeBase进行缓存,每次请求到来之时都需要重新编译规则,而规则编译的成本相当高,没有对代码修正之前,给引擎300左右的并发CPU负载就到了10,而修正后,300的并发CPU负载没有超过1。

3.没有关闭Reader流,这个就太粗心了,幸好及时发现。

再剩下就是一些其他方面的优化,比如tomcat、mysql等,和主题无关,我留在心里。

© 著作权归作者所有

lateron

lateron

粉丝 172
博文 57
码字总数 44492
作品 1
海淀
私信 提问
加载中

评论(2)

瞎闹13
规则引擎项目还能顶住吗
神是到着念
神是到着念
good
规则引擎-BRMS在企业开发中的应用

1. 什么是规则 复杂企业级项目的开发以及其中随外部条件不断变化的业务规则(business logic),迫切需要分离商业决策者的商业决策逻辑和应用开发者的技术决策,并把这些商业决策放在中心数据库...

lifetragedy
2016/10/17
0
0
Java规则引擎与其API(JSR-94)

复杂企业级项目的开发以及其中随外部条件 不断变化的业务规则(business logic),迫切需要分离商业决策者的商业决策逻辑和应用开发者的技术决策,并把这些商业决策放在中心数据库或其他统一的地...

银月光海
2016/02/18
208
0
360数据处理平台的架构演进及优化实践

本次要分享的是360大数据中心数据处理平台Titan的架构演进,以及一些具体的实践过程。 一、背景介绍 在当今的大数据时代,大数据计算引擎已经从原先最早的Hadoop生态系统演变到了第三代甚至是...

技术小能手
2018/07/12
0
0
外部系统调用规则引擎接口

外部系统调用规则引擎接口 规则包:新建一个hello规则包,此规则包接受一个参数(用户姓名),如果姓名不为空,则返回欢迎词“Hello”+姓名,如果姓名为空,则返回欢迎词“Hello World”。 ...

flagleader
2013/08/23
482
0
漫话规则引擎(4): Java规则引擎规范:JSR94

1 概述 JSR-94是JCP(Java Community Process)制定的关于Java规则引擎API的规范,包括接口定义和示例代码。于2004年8月发布。 JSR-94定义了javax.rules和javax.rules.admin,前者包含了Java规则...

银月光海
2016/02/18
232
0

没有更多内容

加载失败,请刷新页面

加载更多

iOS苹果应用IPA一键签名工具及重签教程

开心签名工具,是一款跨平台ios签名和重签名工具。 同时支持在windows、linux、mac运行,数据同步,方便使用及管理! 开心重签名工具官网 功能特点 1、支持图形界面及命令行重签(部署到服务...

tintong
6分钟前
2
0
2.4G有源卡核心芯片供应商

有源2.4G RFID的防盗标签,在与无源标签相比较,通信距离远,通信时效高。我司的SI24R2E这颗芯片专门为2.4G有源标签而设计,具有低功耗,发送距离远,厂商设计简单等优势;广泛应用于现在城市...

文刀石
12分钟前
2
0
设置Ubuntu16.04启动为命令行界面

1. 修改/etc/default/grub文件,将GRUB_CMDLINE_LINUX_DEFAULT设置成”quiet splash 3” 2. 使用命令update-grub使得在/boot下重新生成GRUB2配置文件。 3. 重启...

JosiahMg
12分钟前
2
0
C++基础知识点

计算机语言 计算机不能理解高级语言,只能理解机器语言,必须要将高级语言翻译成机器语言,翻译的方式有两种,一种是编译,一种是解释 解释型语言,在运行程序时进行翻译,每个语句在执行时逐...

大瑞清_liurq
18分钟前
2
0
EFCore 多条数据更新不能同时savechanges()的解决方法

1 在ModelContext定义下增加var transaction = ctx.Database.BeginTransaction(); 1.2 在最后一个SaveChanges()后增加transaction.Commit(); 3 在finally的if (sMsgCode != "")分支中增加tra......

_Somuns
22分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部