规则引擎实现探讨

来源:百度文库 编辑:神马文学网 时间:2024/05/13 20:48:02
规则引擎实现探讨2007-01-10 21:58

最近在处理自定义表单时,需要自定义业务规则,最终在网上看到jxb8901先生的文章,和我的部分想法类似,特别是对于表达式的要求上,非常赞赏。区别在于我需要的表达式是基于组件的。原文如下:

一、问题 
系统要求实现类似如下规则: 

代码
  1. 积分规则:凭XX信用卡消费1元人民币,即可获得1分的消费积分,  
  2. 在汽车类商户每消费100元人民币积8分,在房地产类商户每消费100元人民币积6分。  
  3. 兑奖规则:100分~300分:兑换150元礼品,300分~500分兑换300元礼品,  
  4. 500分以上兑换400元礼品  

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

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

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

 

代码
  1. if {  
  2.     规则  
  3. }  
  4. then {  
  5.     动作  
  6. }  

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

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

2、如何处理数据库与规则引擎的关系? 
再者规则引擎是基于事实进行推演,所以在触发规则引擎计算之前,需要先装入事实。基于JSR94的实现 
多使用OO的方式,例如: 

代码
  1. loadRules(); // 装入规则  
  2. WorkingMemory workingMemory = businessRules.newWorkingMemory();  
  3. workingMemory.addEventListener(new DebugWorkingMemoryEventListener());  
  4. workingMemory.assertObject(student); // 装入事实  
  5. workingMemory.fireAllRules(filter); // 触发计算  

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

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

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

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

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

 

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

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

针对上述实现,我提出以下要求: 

代码
  1. 语法简单,业务人员很容易明白  
  2. 必须支持中文规则定义  
  3. 必须支持自定函数(我想象的"POS消费总额","如果"都是函数)  
  4. 很容易扩展函数  
  5. 最好=,>,<之类的符号可以支持全角字符  

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

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

原文出处:http://www.javaeye.com/article/25215?page=3