论坛首页 Java企业应用论坛

规则引擎实现探讨

浏览 43851 次
该帖已经被评为精华帖
作者 正文
   发表时间:2006-09-28  
一、问题
系统要求实现类似如下规则:
积分规则:凭XX信用卡消费1元人民币,即可获得1分的消费积分,
在汽车类商户每消费100元人民币积8分,在房地产类商户每消费100元人民币积6分。
兑奖规则:100分~300分:兑换150元礼品,300分~500分兑换300元礼品,
500分以上兑换400元礼品


因为系统中有大量类似这样的规则,而且规则会经常变动,另外业务上也要求这样的规则最好能由业务人员自己定义和修改,因此一个很自然的考虑是使用规则引擎来实现。

二、现有规则引擎产品分析
最初希望使用商业或开源的规则引擎,但从网上搜索的关于规则引擎的资料来看,现有规则引擎实现这样的应用好象不太合适。

1、如何定义规则?
一般规则引擎中定义规则的方式如下:

if {
	规则
}
then {
	动作
}


但这样的规则“消费1元人民币积1分”使用if...then...该如何定义呢?好象没法定义。

另外感觉这类规则定义就是一系列的if...then...这其中的逻辑和我们在java中的逻辑没有什么区别,
只是换了一种形式而已。这样的规则根本没办法给业务人员使用。

2、如何处理数据库与规则引擎的关系?
再者规则引擎是基于事实进行推演,所以在触发规则引擎计算之前,需要先装入事实。基于JSR94的实现
多使用OO的方式,例如:
loadRules(); // 装入规则
WorkingMemory workingMemory = businessRules.newWorkingMemory();
workingMemory.addEventListener(new DebugWorkingMemoryEventListener());
workingMemory.assertObject(student); // 装入事实
workingMemory.fireAllRules(filter); // 触发计算

摘自http://www.blogchinese.com/06042/201878/archives/2006/200652418217.shtml

这里就有一个问题,如果我的事实是基于数据库记录,那么该如何装入事实?因为规则的定义中条件部分
一般是基于对象的属性,动作部分一般是基于对象的方法,所以如果事实能使用数据记录,那么条件特别是
动作该如何定义?

3、需要Rete算法吗?
只要对规则引擎稍有接触,应该都听说过“Rete算法”,现有的商业或开源的规则引擎多是基于该算法。多数会解决
这样一个问题,就是自动处理动作对事实的反馈,如果一个动作影响了事实,那么会重新针对事实过滤规则,我想这样的反馈
计算可能大大影响了规则引擎的性能,而正Rete算法解决了规则引擎的性能问题。但上述规则并不需要这样的特性,所以性能问题不会表现在这些方面。

因为对这类商业和开源的规则只是有一个泛泛的了解,不知其能否解决这些问题?怎样解决这些问题?

三、方案
终合上述考虑,决定自己实现规则引擎,首要的就是将上述语句表示为规则引擎能识别的规则,自然需要一套语法来定义这样的规则,
结合实现及面向业务人员这样的需求,大略将上述语句转换为如下规则定义:

客户积分 += POS消费总额(商户类型!=汽车类|房地产类) {主体=XX信用卡客户} 
客户积分 += POS消费总额(商户类型=汽车类)/ 100 * 6 {主体=XX信用卡客户} 
客户积分 += POS消费总额(商户类型=房地产类)/ 100 * 8 {主体=XX信用卡客户} 
客户积分 -= 如果(兑换奖品总额>=400,500) {主体=XX信用卡客户,扣减规则=(消费类型=退货)} 
客户积分 -= 如果(兑换奖品总额>=300,300) {主体=XX信用卡客户,扣减规则=(消费类型=退货)} 
客户积分 -= 如果(兑换奖品总额>=150,100) {主体=XX信用卡客户,扣减规则=(消费类型=退货)} 

个人感觉如果能这样定义规则的话业务人员应该很容易就能看懂,也能很容易修改。

针对上述实现,我提出以下要求:
		语法简单,业务人员很容易明白
		必须支持中文规则定义
		必须支持自定函数(我想象的"POS消费总额","如果"都是函数)
		很容易扩展函数
		最好=,>,<之类的符号可以支持全角字符


四、实现
现在考虑如果要用程序实现上述规则,有以下两种方案:
1、使用动态脚本语言实现规则解析,如ruby, groovy,jaskell之类的(好象这就叫DSL吧),但
不知能不能满足我上面提出的要求。
2、使用javacc,antlr定义语法生成解析器。

第二种方案的好处是灵活性足够强,而且能满足“中文定义”的要求,但要权衡,维护和调试一个解析器也不是一件轻松的事。




[color=darkblue][/color]
   发表时间:2006-09-28  
好东西。。。
想过很多次
但从没有总结出来过
有没有人对这个进行一下修定让这个
东西丰富起来
等差不多时出本书。。。。
0 请登录后投票
   发表时间:2006-09-28  
好象内容也没丰富到出书的程度哑,基本已确定了自己写解析器的方案,只是在想还有没有更好的方法。
个人感觉这个案例比较适合拿出来讨论,非常有实际意义。只是好象大家都没什么热情一样,不知怎么回事。
0 请登录后投票
   发表时间:2006-09-28  
对于规则引擎还是一知半解!没研究过,真的好郁闷啊!
0 请登录后投票
   发表时间:2006-09-28  
如果去年这个时候,一堆牛人会冲过来。

翻翻老贴吧!
0 请登录后投票
   发表时间:2006-09-28  
以前关于规则引擎的帖子基本都看过了,但大多是在理论层面的探讨,很少有针对实际应用的讨论。大家都知道规则引擎是个好东西,可为什么没有在实际开发中应用的经验总结呢?就我做银行应用来看,有很多地方都有类似规则引擎这样的需求,但得承认这些名为“规则”的规则,与网上大多关于规则引擎讨论中的“规则”其实不是一码事。现在连SpringSide也集成JBossRules规则引擎,可框架开发人员有没有考虑这些功能应用在什么场景呢?难道我们做框架只管堆彻一大堆知名的框架就行了吗?也许扯远了!
0 请登录后投票
   发表时间:2006-09-28  
银行、保险业的规则引擎应用多了去了。
电信领域,在我的公司里有一个综合服务开通系统,会根据各种情况来决定最后的开通指令。使用规则引擎后那堆破事清晰了不少。

BTW. 此帖精华?鼓励挖坑? 建议先看jboss rules的dsl功能
0 请登录后投票
   发表时间:2006-09-29  
如果业务系统通过规则引擎来实现,而如果业务系统有变化,那么配置规则引擎就可以达到目标,可如果业务相关数据库变化较大怎么办呢?无法在新旧规则中兼容,那是不是不能通过配置就能满足需求的变更啊?
0 请登录后投票
   发表时间:2006-09-29  
江南白衣 写道
银行、保险业的规则引擎应用多了去了。
电信领域,在我的公司里有一个综合服务开通系统,会根据各种情况来决定最后的开通指令。使用规则引擎后那堆破事清晰了不少。

BTW. 此帖精华?鼓励挖坑? 建议先看jboss rules的dsl功能


1、终于有大侠出来说话了,非常感谢。有SpringSide的主力助阵,咱不怕摆不出事实,讲不清道理。何况江南大侠有电信规则引擎的开发背景。

2、江南大侠一眼就看出我没仔细了解过JBossRules,的确好眼力。因为项目关系,虽然之前了解了一些规则引擎方面的知识,但确实只是泛泛地了解,Drools(也即JBossRules前身)的资料虽然看过一些,但确实没有实用过。但凭我那一点粗浅的了解,Drools早已在侯选方案中出局了(原因见主贴分析)。后来看到JBossRules,先是心中一喜,后是心中一凉,喜的是又有一个框架可供选择,凉的是原来JBossRules只是JBoss收购Drools后改了名字的产品,之后便没再深究。既然江南大侠建议我辈了解了解JBossRules的DSL功能,那其中定有什么新鲜东西值得一看。

3、到JBoss网站找到JBossRules的文档,打开一看,标题还是Drools(好象换汤不换药啊?),不管他,直接看DSL一章。终于耐着性子看完了,心中比较失望。继续往上翻,又看了Rule(规则定义)一章。好象没发现什么新意。

这是JBossRules文档中一个关于规则定义的例子:
rule "Approve if not rejected"
  salience -100 
  agenda-group "approval"
    when
        not Rejection() 
        p : Policy(approved == false, policyState:status)
        exists Driver(age > 25)
        Process(status == policyState)
    then
        log("APPROVED: due to no objections."); 
        p.setApproved(true);
end

试问大家第一眼的感觉是什么?“这和java代码有什么区别?”这是我的感觉。
规则的确比较直白,作为程序员,很容易理解。这不就是groovy类的脚本语言吗?哼,把“if”换成了“when”,我就不认识了吗?

Drools的条件部分(LHS)完全基于对象的字段属性进行匹配,其实整个条件表达式完全可以用类似OGNL之类的表达式语言来表示。如果不考虑规则的递归计算,那么可以说Drools就只是一个动态脚本语言,但它的功能与Groovy,JPython之类的脚本语言相比实在差太远了。

再来看看所谓的JBoss Rules DSL是怎样实现的
引用
There is a Cheese with
        -age is less than 42
        -type is 'stilton'

这也是来自Drools文档的一个DSL例子,乍看之下,觉得好强大啊,这完全是自然语言啊!真正的DSL!但别高兴得太早,看看Drools是怎样实现这个DSL的
[when]There is a Cheese with=Cheese()
[when]-age is less than {age}=age<{age}
[when]-type is '{type}'=type=='{type}'
[when]-country equal to '{country}'=country=='{country}'

要让Drools能识别前面的自然语言,还需要上面的Properties文件,大家明白它的作用了吗?是的,它在自然语言与Drools的规则脚本语言之间做一个映射,也就是说,Drools只是做了一个查找替换的工作,将自然语言替换为脚本语言。

这样的DSL的确有其特定的用途,但在我的项目中找不到它的位置。

4、上面哆嗦了一大堆,大家可能觉我在抱怨Drools做得不好。完全没有,只是我手上拿着的这颗钉子,不适合Drools这把锤子而已。网上大家讨论规则引擎讨论得热火朝天,讨论完了大家就在找那颗钉子,可能有的找到了,有的没找到。而我近段时间以来,都是拿着我这颗钉子,想找一把合适的锤子,同样也没找到。

5、江南大侠如果愿意与大家分享,何不详细描述一下你那颗钉子,也好让我辈长长见识。

BTW. 这帖子是大家评为精华的,我也不知JavaEye的大鱼小虾们是不是瞎了眼睛。我只知道这是我这段时间的经验总结,没偷没抢,写此贴也是花了我7000+秒的宝贵时间嘀。江南大侠有什么不满意的话可以多说点理由不?或者也可以到海版投诉,大可不必在此发气。

再BTW. 这个回复又花了我8000+秒的时间,当然包括看Drools文档的时间,不过还是很感谢有机会对Drools有了更深的了解,也许以后我也能幸运地找到那颗钉子呢。

再再BTW. 最后一次了啊!不想再讨论了,也许是问题太具体了,大家在工作中没有碰到类似的问题,也就不愿意多想了,深表理解。
0 请登录后投票
   发表时间:2006-09-29  
我觉得jboss rules的mapping式DSL胜在够简单,完全平民级的东西,比自己javacc,antlr容易多了。
比如:

客户积分 += POS消费总额(商户类型!=汽车类|房地产类) {主体=XX信用卡客户}

只要花时间加强实际处理的类,是完全可以Mapping出来的。

另外,when
        not Rejection()
        p : Policy(approved == false, policyState:status)
        exists Driver(age > 25)
        Process(status == policyState)
    then
        log("APPROVED: due to no objections.");
        p.setApproved(true);

这个语法,在实际应用中,把相关规则集中定义和管理后,加上rete算法,还是比写在代码里好一点的。特别如果规则之间会关联,会互相影响的情况。

drools->jboss rules 不仅是改个名字,2.0用的是XML语法,DSL更是恶梦(自己写XML节点分析器),而3.0的语法已经有点像ilog,DSL也换了这种平民级的Mapping,另外还提供了Eclipse Plugins的IDE,保证客户写DSL的时候不容易写错。

0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics