.net开源项目nxbre中flow engine的研究报告
上周刚刚看完了nxbre,写了一个ppt给项目组评审,用来拟定我们GSP中的规则引擎的实现需求。
不知为什么我上传不了文件,只好把ppt的内容贴出来给大家共享。大家如果这个开源项目感兴趣,可以留言索取。ppt中不可能把细节讲的很清楚,而且由于时间关系,只写了其中的flow engine,请见谅。
Nxbre的简介
Nxbre包括interface engine和flow engine
两种引擎的区别
the Flow Engine, which uses XML as a way to control process flow for an application in an external entity. It is basically a wrapper on C#, as it offers all its flow control commands (if/then/else, while, foreach), plus a context of business objects and results.
the Inference Engine, which is a forward-chaining (data driven) deduction engine and that supports concepts like Facts, Queries and Implications (as defined in RuleML 0.86 Datalog) and like Rule Priority, Mutual Exclusion and Precondition(as found in many commercial engines). It is designed in a way that encourages the separation of roles between the expert who designs the business rules and the programmer who binds them to the business objects.
两种引擎使用的场景
1. the Inference Engine supports priority, mutual exclusions and pre-conditions,
2. the Inference Engine uses a "standard" rule format (RuleML),
3. the Inference Engine has an elaborated memory model with support for isolated deduction space.
4. Interface Engine 更适合于知识库或专家系统,因为在这样的系统中,facts必须被保持
5. Flow Engine 只是对一段逻辑进行了解析,并根据结果去做action
6. The Flow Engine is really an instantaneous traversal of logical branches using transient data for evaluations of boolean expressions.
选择的理由
1. 在我们的GSP系统中,没有对fact保持的需求,没有通过规则优先级、互斥和前置条件的判断来选择规则
2. Flow Engine 相对简单,易于维护
所以,应该Flow Engine是一个合适的选择
Flow Engine的介绍
加载和卸载规则集的API (BREImpl)
Init
Reset
数据操作的API(IBRERuleContext)
SetObject
GetObject
引擎执行的API (BREImpl)
Process
Stop
规则引擎基本遵循以下5个典型的步骤
1. 创建规则引擎对象
2. 向引擎中加载规则集或更换规则集
3. 向引擎提交需要被规则集处理的数据对象集合
4. 命令引擎执行
5. 导出引擎执行结果,从引擎中撤出处理过的数据
Flow Engine中的规则文件
规则语言一般分为两类:
“面向程序技术”的规则语言,使用者是技术人员。在Flow Engine中是.bre文件(结构是businessRule.xsd规定的) ,引擎真正解析的也是这个文件。
“面向业务”的规则语言,使用者是业务人员。规则定制器应该生成这份文档。在Flow Engine中是.xbre文件(结构是businessRule.xsd规定的) 。
两种Schema的转换是由transformXRules.xsl文件规定的。
Flow Engine为加载规则文件提供了以下的类:IRulesDriver,AbstractRuelsDriver,BusinessRulesFileDriver,XSLTRulesFileDriver,XBusinessRulesFileDriver, XBusinessRulesStreamDriver, XBusinessRulesStringDriver
Flow Engine中的规则上下文
规则上下文中包含如下四块:
1. RuleFactory集(hashtable),包含rule的解决方法,可以是默认的,也可以是自定义的
2. Operator集(hashtable),包含可用的比较操作符,如:==,<,>等
3. Result集(hashtable),包含result和用户初始的数据,lookupobject就是在result集中查找数据对象。每条<rule>都会产生一条result,每条result又会包含metadata和结果数据。metadata中包含产生这条result的rule的factory和param
4. CallStack(stack),目前没发现有什么用,只是在往Result集中添加result的同时也往此中添加
支持上下文的主要类型:IBRERuleContext,AbstractBRERuleContext,BRERuleContextImpl
Flow Engine创建规则引擎对象
构建BREFactoryConsole对象,他负责构建BREImpl对象,并向外发布引擎中出现的log和exception
构建BREImp对象之前,必须首先构建BREFactory,他负责将log和exception的代理挂到BREImp对象中的相应event上去
用IRuleDriver初始化BREImp对象
相关的类型: BREFactoryConsole,BREFactory,BREImp
Flow Engine加载规则集
在Flow Engine中rule(在.bre文件中用<rule>标签标识的部分)是一些用id唯一标识的对象。加载这些rule的方式有两种:
1. 在引擎初始的时候,先从规则文件中查找<factory>标签,找到需要加载的RuleFactory。通过反射的方式,创建该类型的实例(引擎默认的rule)
2. 在引擎的运行时,外部需要对规则文件中定义的rule有特殊的处理,必须在外部环境中构造BRERuleFactory对象,并以一个代理作为它的参数,在代理的方法中实现对rule的处理
讨论:是否还需要第三种方式,因为使用第二种方式扩展系统时,外部环境开发者不得不很了解目前使用的规则文件中到底使用了哪些扩展的rule,并为这些rule些处理方法。当我们修改了规则文件,并添加了一些扩展rule时,外部环境的开发者不得不修改他们的程序,以适应新的规则文件。
我们现在想要的是像使用默认的rule一样方式来使用扩展rule,这就需要我们用一种注册的方式,在引擎加载rule之前,将扩展的rule注册进系统。
所有的rule都必须通过引擎上下文(IBRERuleContext)的SetFactory方法注册进引擎上下文中
IBRERuleFactory中有ExecuteRule方法,这就是处理默认rule的方法
支持规则集的相关类型:IBRERuleFactory,BRERuleFactory(主要是为自定义的rule设计的,他的ExecuteRule中只是调用了代理)
在写代理方法的时候注意,引擎调用代理的时候,可以提供上下文和相关的参数,这是我们极其需要的
Flow Engine加载操作符
很简单,在BREImpl的init()方法中,用反射的方式从当前Assembly中查找所有实现IBREOperator接口的类型,创建实例,加入上下文中。
这里的操作符只是if语句中判断大小用的,而+,-,*,/,或其他数学函数,我认为可以作为默认的rule来对待
支持的相关类型:IBRERuleOperator,实现他的类其实就是实现一个compare的strategy
讨论:这一块是不是能满足需求
Flow Engine中提交数据对象
如前所述,数据对象在系统中是被当成result来处理的,封装他的BRERuleObject类继承于AbstractBRERuleResult,会被插入上下文的result集中。数据对象被封装到BRERuleObject的Result属性中。
具体的,在外部环境中,通过上下文的SetObject(id,object),就可以将数据对象添加到上下文中了。
同样,获取数据对象的时候用上下文的GetObject(id)。
Flow Engine中命令引擎执行
在启动引擎之前,要注意必须执行BREImpl的Reset()方法,清空留在上下文中的上一次的Result集和CallStack清空,否则,可能会干扰本次的执行。这有一次表明了Flow Engine是一个对逻辑分支的瞬时遍历,他不能保存结果,也不能用于以往知识对执行实例有影响的系统中。
要执行引擎,只需调用BREImpl的process()方法,引擎就会根据规则文件中指定的逻辑来执行了。
更具体的,processxml()方法判断XPathNavigator当前节点的类型,跳转到特定的处理程序中。
如果当前节点有子节点,那么调用DoRecursion()来进行迭代。
执行的方式是先深的遍历。
Flow Engine中导出结果
很简单,通过上下文的GetResult(id),就能导出运行的结果。Id与该条rule的id相同。
真正结果封装在AbstractBRERuleResult的result属性中
Flow Engine中的log和Exception处理
提供了丰富的向外部暴露内部运行情况的接口
还指定了log和exception的级别,用于向不同的终端暴露信息
内部使用DispatchLog(message,level),DispatchException(message,level)