drools 为什么写了no-sql loop循环还会循环

Drools语法详解
Drools语法详解
一个典型的DRL文件:
①package com.sample 包名,不可以与关键字冲突。一个包通过名称空间描绘,这样很好的保持了一组规则的独立性。 ②import 标记就像java中的含义一样。对于任何要用在规则中的对象,你需要指定完整的路径和类型名。Drools从同名的java包中自动导入类。 ③global 如果多个包定义了同样名称的全局变量,它们必须使用同样的类型,并且全部指向同一个全局值。全部变量通常用来返回数据,获得提供数据或服务给规则使用。为了使用全局变量,你必须: 在规则文件中声明全局变量并使用它,如: global java.util.List myGlobalL rule "Using a global" when &&& eval( true ) then &&& myGlobalList.add( "Hello World" ); end 在working memory上设置全局变量的值。最好是在将fact插入working memory之前设置完所有全局变量,如: List list = new ArrayList(); WorkingMemory wm = rulebase.newStatefulSession(); wm.setGlobal( "myGlobalList", list ); ④function 相对于正常的java类,函数是在你的规则代码中放置语言代码的方法。它们不可能做任何超过你可以在帮助类(在java中定义,被设置入规则的Working Memory中的类)中做到的事情。使用函数的优点是可以将逻辑保存在一个地方,并且你可以在需要的时候改变函数(这样做各有优缺点)。函数最大的用处是被规则的推论(then)部分中的行为所调用,特别是当一个行为操作需要反复被调用时(将公用代码抽取出来成为一个函数)。 ⑤rule 名称可以在“”下取任何名字。 属性列表: 属性 类型 默认值 功能描述 no-loop Boolean false 设置no-loop为true可以阻止该规则被再次激活。 salience integer 0 优先级数字高的规则会比优先级低的规则先执行。 agenda-group String MAIN 只有在具有焦点的agenda group中的规则才能够激发。 auto-focus Boolean false 如果该规则符合激活条件,则该规则所在agenda-group自动获得焦点,允许规则激发。 activation-group String N/A 在同名activation-group中的规则将以互斥的方式激发 dialect String "java" or "mvel" 指定在LHS代码表达式或RHS代码块中使用的语言。 date-effective String, 包含日期/时间定义 N/A 规则只能在date-effective指定的日期和时间之后激活。 date-exptires String, 包含日期/时间定义 N/A 如果当前时间在date-expires指定的时间之后,规则不能激活。 duration long N/A 指出规则将在指定的一段时间后激发,如果那个时候规则的激活条件还是处于true的情况下。 ⑥& LHS (when) 条件元素 为了能够引用匹配的对象,使用一个模式绑定变量如‘$c’。变量的前缀使用的$是可选的,但是在复杂的规则中它会很方便用来区别变量与字段的不同。 $c : Cheese( type == "stilton", price & 10, age == "mature" ) && 和|| 约束连接符 Cheese( type == "stilton" && price & 10, age == "mature" ) Cheese( type == "stilton" || price & 10, age == "mature" ) 第一个有两个约束而第二个组有一个约束,可以通过圆括号来改变求值的顺序。 单值约束 Matches 操作 Cheese( type matches "(Buffalo)?\S*Mozerella" ) Cheese( type not matches "(Buffulo)?\S*Mozerella" ) Contains 操作 CheeseCounter( cheeses contains "stilton" ) CheeseCounter( cheeses not contains "cheddar" ) memberof操作 CheeseCounter( cheese memberof $matureCheeses ) CheeseCounter( cheese not memberof $matureCheeses ) 字符串约束 字符串约束是最简单的约束格式,将字段与指定的字符串求值:数值,日期,string或者boolean。 Cheese( quantity == 5 ) Cheese( bestBefore & "27-Oct-2007" ) Cheese( type == "stilton" ) Cheese( smelly == true ) 绑定变量约束 变量可以绑定到Fact和它们的字段,然后在后面的字段约束中使用。绑定变量被称为声明。有效的操作符由被约束的字段类型决定;在那里会进行强制转换。绑定变量约束使用'=='操作符,因为能够使用hash索引,因此提供非常快的执行速度。 Person( likes : favouriteCheese ) Cheese( type == likes ) 返回值约束 返回值约束可以使用任何有效的Java元数据类型或对象。要避免使用任何Drools关键字作为声明标识。在返回值约束中使用的函数必须返回静态常量(time constant)结果。之前声明的绑定可以用在表达式中。 Person( girlAge : age, sex == "F" ) Person( age == ( girlAge + 2) ), sex == 'M' ) 复合值约束 复合值约束用在可能有多个允许值的时候,当前只支持'in' 和'not in'两个操作。这些操作使用圆括号包含用逗号分开的值的列表,它可以是变量,字符串,返回值或限定标识符。'in' 和'not in'运算式实际上被语法分析器重写成多个!= and ==组成的多重约束。 Person( $cheese : favouriteCheese ) Cheese( type in ( "stilton", "cheddar", $cheese ) 多重约束 多重约束允许你对一个字段通过使用'&&' 或者'||'约束连接符进行多个约束条件的判断。允许使用圆括号分组,它会让这种约束看起来更自然。 Person( age ( (& 30 && & 40) || (& 20 && & 25) ) ) Person( age & 30 && & 40 || location == "london" ) 内联的Eval约束 eval约束可以使用任何有效的语言表达式,只要它最终能被求值为boolean元数据类型。表达式必须是静态常量(time constant)。任何在当前模式之前定义的变量都可以使用,自动代入(autovivification)机制用来自动建立字段绑定变量。当构建器发现标识不是当前定义的变量名是,它将尝试将它作为对象的字段来访问,这种情况下,构建器自动在inline-eval中建立该字段的同名变量。 Person( girlAge : age, sex = "F" ) Person( eval( girlAge == boyAge + 2 ), sex = 'M' ) ⑦RHS (then) 执行操作 这部分应当包含一系列需要执行的操作。规则的RHS部分应该保持简短的,这保持它是声明性和可读性的。如果你发现你需要在RHS中使用命令式或and/or条件代码,那你可能需要将规则拆分为多个规则。RHS的主要目的是插入,删除修改working memory数据。 "update(object, handle);" 将告诉引擎对象已经改变(已经被绑定到LHS中的那一个),并且规则需要重新检查。 "insert(new Something());" 将在working memory中放置一个你新建的对象。 "insertLogical(new Something());" 与insert类似,但是当没有更多的fact支持当前激发规则的真值状态时,对象自动删除。 "retract(handle);" removes an object from working memory. ⑧ Query 查询中仅仅包含规则LHS部分的结构(不用指定when或then)。它提供了查询working memory 中符合约束条件的对象的一个简单办法。 query "people over the age of 30" &&& person : Person( age & 30 ) end 通过在返回的查询结果(QueryResults)上进行标准的for循环遍历,每一行将返回一个QueryResult,该对象可以用来存取组元中的每一个Column。这些Column可以通过声明的名称或索引位置存取。 QueryResults results = workingMemory.getQueryResults( "people over the age of 30" ); for ( Iterator it = results. it.hasNext(); ) { &&& QueryResult result = ( QueryResult ) it.next(); &&& Person person = ( Person ) result.get( "person" ); &&& }
发表评论:1.drools是什么
Drools是为Java量身定制的基于Charles& Forgy的RETE算法的规则引擎的实现。具有了OO接口的RETE,使得商业规则有了更自然的表达。
Rule是什么呢?
一条规则是对商业知识的编码。一条规则有&attributes&,一个&Left Hand Side&(&LHS&)和一个&Right Hand Side&(&RHS&)。Drools&允许下列几种&attributes&:&salience&,&agenda-group&,&no-loop&,&auto-focus&,&duration&,&activation-group&&。
规则的&LHS&由一个或多个条件(&Conditions&)组成。当所有的条件(&Conditions&)都满足并为真时,&RHS&将被执行。&RHS&被称为结果(&Consequence&)。&LHS&和&RHS&类似于
if(&LHS&){
下面介绍几个术语:
对新的数据和被修改的数据进行规则的匹配称为模式匹配(&Pattern Matching&)。进行匹配的引擎称为推理机(&Inference Engine&)。被访问的规则称为&ProductionMemory&,被推理机进行匹配的数据称为&WorkingMemory&。&Agenda&管理被匹配规则的执行。推理机所采用的模式匹配算法有下列几种:&Linear&,&RETE&,&Treat&,&Leaps&。这里注意加红的地方,对数据的修改也会触发重新匹配,即对 WorkingMemory中的数据进行了修改。
然后规则引擎大概是这个样子的:
这个图也很好理解,就是推理机拿到数据和规则后,进行匹配,然后把匹配的规则和数据传递给Agenda。
规则引擎实现了数据同逻辑的完全解耦。规则并不能被直接调用,因为它们不是方法或函数,规则的激发是对&WorkingMemory&中数据变化的响应。结果(&Consequence&,即&RHS&)作为&LHS events&完全匹配的&Listener&。
数据被&assert&进&WorkingMemory&后,和&RuleBase&中的&rule&进行匹配(确切的说应该是&rule&的&LHS&),如果匹配成功这条&rule&连同和它匹配的数据(此时就叫做&Activation&)一起被放入&Agenda&,等待&Agenda&来负责安排激发&Activation&(其实就是执行&rule&的&RHS&),上图中的菱形部分就是在&Agenda&中来执行的,&Agenda&就会根据冲突解决策略来安排&Activation&的执行顺序。
下面附上drools规则引擎的执行过程
2.rete算法
参考链接:
rete在拉丁文里是net network的意思,这个算法由&Charles Forgy &博士在他的博士论文里提到。
这个算法可以分为两个部分,一个是如何编译规则,一个是如何执行。原话(The Rete algorithm can be broken into 2 parts: rule compilation and runtime execution.)
rule compilation 就是如何通过对所有规则进行处理,生成一个有效的辨别网络。而一个辨别网络,则对数据进行过滤,使数据一步步往下传送。数据刚进入网络,有很多的匹配条件,这里可以理解为:逻辑表达式为true or false,然后在网络里往下传递的时候,匹配的条件越来越少,最后到达一个终止节点。
在这个论文里Dr Charles描述了这么几个节点,Node:
2.rete算法
参考链接:
rete在拉丁文里是net network的意思,这个算法由&Charles Forgy &博士在他的博士论文里提到。
这个算法可以分为两个部分,一个是如何编译规则,一个是如何执行。原话(The Rete algorithm can be broken into 2 parts: rule compilation and runtime execution.)
rule compilation 就是如何通过对所有规则进行处理,生成一个有效的辨别网络。而一个辨别网络,则对数据进行过滤,使数据一步步往下传送。数据刚进入网络,有很多的匹配条件,这里可以理解为:逻辑表达式为true or false,然后在网络里往下传递的时候,匹配的条件越来越少,最后到达一个终止节点。
在这个论文里Dr Charles描述了这么几个节点,Node:
这里对其中的几个节点做一下简单介绍,另外说一下如何运作的。
首先,root node是所有的对象都可以进入的节点,也是辨别网络的一个入口,这个可以理解为一个虚节点,其实可能并不存在。
然后立马进入到ObjectTypeNode节点,这是一个对象类型节点。很明显,这里承载的是一个对象,可以理解为是java中的某个new Object(),在这个算法里,这个节点的作用就是为了保证不做一些无用功,什么无用功呢,就是不是对每个规则,进入的对象都要去辨别一遍,而是确定的对象类型,去做跟他相关的辨别,其实就是match。那么怎么做到呢?这里用到了一个hashMap,每次进入网络的对象,都会在这个map中通过hash,找到一个对应的辨别路径去辨别,即match。附上英文原文:(
Drools extends Rete by optimizing the propagation from ObjectTypeNode to AlphaNode using hashing. Each time an AlphaNode is added to an ObjectTypeNode it adds the literal value as a key to the HashMap with the AlphaNode as the value. When a new instance enters the ObjectType node, rather than propagating to each AlphaNode, it can instead retrieve the correct AlphaNode from the HashMap,thereby avoiding unnecessary literal checks.)
一个图来说明:
所有经过ObjectTypeNode的对象都会走到下一个节点,下一个节点可以是下面的几种:AlphaNodes, LeftInputAdapterNodes and BetaNodes。后面两个节点是AlphaNodes节点的一些变种,AlphaNodes节点是用来判断一些条件的。可以理解为一些逻辑表达式的计算。下面开始上图:
这个图就是传递进一个Cheese对象,然后依次判断是否满足条件:1.判断name是否是&cheddar&,2.如果判断1通过了,继续判断strength是否是strong。这是最简单了一种情况了,这里附上对应的规则描述,后面会继续讲解:rule "cheessRule" when$cheese:Cheese(name == "cheddar" && strength == "strong")then......end
3.maven依赖
这里列了一些后面的一些例子需要用到的maven依赖
&!--kie api 构建kie虚拟文件系统,关联decisiontable和drl文件,很关键 --&
&dependency&
&groupId&org.kie&/groupId&
&artifactId&kie-api&/artifactId&&/dependency&&!-- 规则引擎核心包,里面包含了RETE引擎和LEAPS 引擎--&&dependency&
&groupId&org.drools&/groupId&
&artifactId&drools-core&/artifactId&&/dependency&&dependency&
&groupId&org.drools&/groupId&
&artifactId&drools-compiler&/artifactId&&/dependency&&!-- 决策表依赖--&&dependency&
&groupId&org.drools&/groupId&
&artifactId&drools-decisiontables&/artifactId&&/dependency&&dependency&
&groupId&org.drools&/groupId&
&artifactId&drools-templates&/artifactId&&/dependency&
4.规则文件:.drl or xls
我们一般用到的也就这两种形式,一个是drl文件,是drools规则引擎提供的最原生的方式,语法很简单,具体语法见
还有一个是决策表,决策表可以是xls也可以是csv,我们一般用xls比较多。而且好理解。xls就是一个excel文件。ps:在使用的过程中,遇到很多坑,其中一个最大的坑是mac系统的问题,这里后面会安利。
首先来看下drl文件,这个在第2条讲解node的时候已经提到过了。举例:
package com.sankuai.meituan.maxtse.drools.testimport com.sankuai.meituan.maxtse.drools.po.Studentrule "ageUp12" when&$student: Student(age & 2)
then&$student.ageUp12();
endrule "nameMax" when&$student: Student(name == "max")
then&$student.nameMax();
retract($student);
简单说明:以第一个rule为例
package 定义了规则文件的一个命名空间,和java中的package无关。
import 这里可以有多个,就是在规则文件里引用到的java类。
rule 用来定义一个规则,这里名字不可重复,后面跟一个when关键字,翻译过来就是,规则 名ageUp12,当满足......
when 和then之间是逻辑表达式,也就是辨别条件,其中$student:Student(age &2)这里其实包含了两个意思,一个是满足age&2的Student对象,一个是把这个对象赋值给$student变量,这样后面就可以引用这个变量了。逻辑表达式写在小括号里,如果是多个条件,可以用逗号分隔,如$sutdent :Student(age & 2,name=="max")
then和end之间来定义action,即当满足age&2的时候,做什么操作,这里可以像在java方法里一样,调用任何一个java类的方法,只要import了这个类且在前面定义了这个变量
第二个例子可以看到有个retract($student),这里是用到了drools内部提供的一个函数,具体见后续关于drools语法介绍的博客
决策表(decisiontable)
决策表就是一个excel文件,可以是xls(xlsx暂不支持)或者csv是个表格,看上去也很直观,即便是不懂代码的人看了也能看懂,不像drl文件那么多语法。关键的一点是:decisiontable也是最终转成drl文件来让drools规则引擎来解析执行的。*.xls到*.drl的转换这个在后面的wiki会说到。
直接上图吧
这里可以暂时忽略那些背景色,只是为了好区分没个模块的作用
这里忽略文件开始的空行,从有数据的第一行开始解释说明:
第一行,第一列:RuleSet 第二列com.sankuai.meituan.maxtse.drools.test。这里RuleSet可以省略的,累似drl文件中的package
第二行,第一列:Import 第二列具体的java类,这里和drl文件里的Improt相对应,多个引用类用逗号分隔
第三行,是个对这个决策表的说明
第四行,第一列:RuleTable FirstDecisionTable 这一行很关键 指明这是一个决策表,并且下面的几行都是具体的规则,就好比上面几行是一些准备条件,下面才是真正干活的地方,这里来个说明
第五行,CONDITION行,这一行可以有两种列名:CONDITION ACTION。CONDITION列就是drl里的辨别条件, &ACTION则是具体的操作,即满足前面几列的CONDITION的条件后,会执行什么操作,这里CONDITION一定在ACTION前面,ACTION可以有多个列, 单个ACTION里的多个操作用逗号分隔,末尾要加分号结尾这里很重要,不然会有解析错误
第六行,紧挨着CONDITION的一行,可以在这里声明下面要用的到对象,对应drl文件里的$student:Student()
第七行,是辨别条件逻辑表达式,如:student.getAge()==$param则对应drl里的age==12这里$param是对应列每个单元格的值,然后这里需要特别说明下,针对于非字符串,如整数,小数等,可以直接使用$param,但是如果单元格里是字符串,则需要加双引号。(ps:mac里的双引号是斜的,一定要保证是竖着"的)另外,如果有多个值,可以用逗号隔开,然后可以用$1,$2提取变量值,如第一个ACTION里的student.doAction1($1,"$2")
第八行仍然是注释行,可以添加每一个CONDITON ACTION列的说明。
下面的每一行就是对应的某些条件的取值了。
阅读(...) 评论()应用drools规则引擎做产生式规则不确定性推理
优势和做法
drools规则引擎,能以rete算法为核心进行高效的规则匹配。我们可以借助其高效的匹配能力,完成产生式规则的推理工作。
rete网在首次加载完成之后,其加载和推理的时间随着规则的增加,仅有很小幅度的增加。
推理需要连续的匹配动作,所以我们要控制drools循环不断地进行规则匹配,并记录每一步过程。每次匹配成功,都做相应的记录,并将该规则的后件加入事实库,同时关闭该规则。再用现有的事实库寻求下一个能成功匹配的规则,直至没有规则可以匹配,获得我们的记录,就获得了推理链。至于匹配过程中同时有多条规则可以匹配的问题,由agenda机构处理,我们不用过多担心。
产生式规则的不确定性推理,我们要考虑到规则前件的可信度,前件的权重,和规则的可信度,这些相关的计算和处理,都可以在每次匹配成功后做相应记录的时候完成。
我做了一个实现的[Demo],托管在[我的github]。其中实现了上述的推理能力。想要的可以找我要。
我们可以在控制台输入相应的事实,就可以得到根据我们给定的规则获得的推理链。由于我手里没有能拿来公开演示的真实规则,所以Demo中只是用了并没有实际意义的名称和字母组成的规则,只是作为示例。
//规则编号
salience 4
//配合循环控制规则
no-loop true
//防止规则重复执行
$message10 : Message(a == 10)
//规则前件匹配元素10、15
$message15 : Message(a == 15)
$assistant : Assistant()
//获取记录推理链的辅助类
//System.out.println(7);
Map&Integer, Double& factAndWeight = new HashMap&Integer, Double&();
factAndWeight.put(10, 0.6);
//前件元素10,占前件权重60%
factAndWeight.put(15, 0.4);
//前件元素15,占前件权重40%
$assistant.inferenceOneStep(26, factAndWeight, 95);
//后件元素26,规则可信度95%
insert(new Message(0));
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1576次
排名:千里之外
(2)(1)(2)(5)Drools 规则文件 ——语法属性
Drools 规则文件 ——语法属性
1.salience&
功能:设置规制执行的优先级
值:数字(数字越大执行优先级越高)
rule "rule1"&
& salience 1&
eval(true)&
System.out.println("rule1");
功能:控制已经执行的规则条件再次满足是否再次执行
值:true/false
rule "rule1"&
& no-loop true&
& $customer:Customer(name=="张三")&
& &update($customer);&
& System.out.println("customer name:"+$customer.getName());&
3.activation-group
功能:若干个规则划分成一个组
值:分组名称
rule "rule2"
&activation-group "test"
&salience 10&
& eval(true)
& & System.out.println("rule2 execute");
&rule "rule1"
&activation-group "test"
&salience 9
&eval(true)
&System.out.println("rule1 execute");
如果同一组规则,谁的salience高就执行谁,没有则按顺序执行最后同组最后那个规则
Drools除了可以接受用户在外部向 WorkingMemory当中插入现成的
Fact对象,还允许用户在规则文件当中定义一个新的 Fact对象。
declare Address
熟悉名 : 类型
package com.demo.fact
declare Address
city : String
addressName : String
rule "rule1"
salience 2
eval(true);
Address add = new Address();
add.setCity("中国上海");
add.setAddressName("中国上海松江区");
insert(add);
5.date-expires
功能:当系统时间&=date-expires后才会触发
值:日期默认格式为dd-MMM-yyyy
可以设置其它时间格式如yyyy-MM-dd,需在代码设置系统时间格式System.setProperty("drools.dateformat", "yyyy-MM-dd");
rule "rule1"&
& date-expires ""&
& eval(true);&
& System.out.println("rule1 is execution!"); &
发表评论:
TA的最新馆藏[转]&

我要回帖

更多关于 sql loop循环 的文章

 

随机推荐