锁定老帖子 主题:规则引擎实现探讨
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间: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] 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2006-09-28
好东西。。。
想过很多次 但从没有总结出来过 有没有人对这个进行一下修定让这个 东西丰富起来 等差不多时出本书。。。。 |
|
返回顶楼 | |
发表时间:2006-09-28
好象内容也没丰富到出书的程度哑,基本已确定了自己写解析器的方案,只是在想还有没有更好的方法。
个人感觉这个案例比较适合拿出来讨论,非常有实际意义。只是好象大家都没什么热情一样,不知怎么回事。 |
|
返回顶楼 | |
发表时间:2006-09-28
对于规则引擎还是一知半解!没研究过,真的好郁闷啊!
|
|
返回顶楼 | |
发表时间:2006-09-28
如果去年这个时候,一堆牛人会冲过来。
翻翻老贴吧! |
|
返回顶楼 | |
发表时间:2006-09-28
以前关于规则引擎的帖子基本都看过了,但大多是在理论层面的探讨,很少有针对实际应用的讨论。大家都知道规则引擎是个好东西,可为什么没有在实际开发中应用的经验总结呢?就我做银行应用来看,有很多地方都有类似规则引擎这样的需求,但得承认这些名为“规则”的规则,与网上大多关于规则引擎讨论中的“规则”其实不是一码事。现在连SpringSide也集成JBossRules规则引擎,可框架开发人员有没有考虑这些功能应用在什么场景呢?难道我们做框架只管堆彻一大堆知名的框架就行了吗?也许扯远了!
|
|
返回顶楼 | |
发表时间:2006-09-28
银行、保险业的规则引擎应用多了去了。
电信领域,在我的公司里有一个综合服务开通系统,会根据各种情况来决定最后的开通指令。使用规则引擎后那堆破事清晰了不少。 BTW. 此帖精华?鼓励挖坑? 建议先看jboss rules的dsl功能 |
|
返回顶楼 | |
发表时间:2006-09-29
如果业务系统通过规则引擎来实现,而如果业务系统有变化,那么配置规则引擎就可以达到目标,可如果业务相关数据库变化较大怎么办呢?无法在新旧规则中兼容,那是不是不能通过配置就能满足需求的变更啊?
|
|
返回顶楼 | |
发表时间: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. 最后一次了啊!不想再讨论了,也许是问题太具体了,大家在工作中没有碰到类似的问题,也就不愿意多想了,深表理解。 |
|
返回顶楼 | |
发表时间: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的时候不容易写错。 |
|
返回顶楼 | |