Drools规则引擎调用insert、update、modify、delete函数后重新触发规则匹配的差异及no-loop属性使用
no-loop属性在一个规则当中如果条件满足时对Working Memory当中的某个Fact对象进行了修改,比如使用insert、update、modify、delete操作,这时规则引擎会再次检查所有的规则是否满足条件,如果满足则会再次执行。这样就可能出现死循环,因此引入no-loop属性来解决这个问题,no-loop属性的作用是用来控制已经执行过的规则在条件再次满足时是否再次执行。no-lo
no-loop属性
在一个规则当中如果条件满足时对Working Memory当中的某个Fact对象进行了修改,比如使用insert、update、modify、delete操作,这时规则引擎会再次检查所有的规则是否满足条件,如果满足则会再次执行。这样就可能出现死循环,因此引入no-loop属性来解决这个问题,no-loop属性的作用是用来控制已经执行过的规则在条件再次满足时是否再次执行。
no-loop属性是一个布尔类型,默认值为false,如果为true,则表示该规则只会被引擎检查一次,满足LHS部分,就会执行RHS部分。
insert插入
函数insert的作用与外面在Java类调用KieSession对象的insert方法的作用相同,都是用来将一个Fact对象插入到当前的Working Memory当中。
格式如下
insert( new <object> );
insert引起死循环的表现
Java代码
package org.drools.examples.test;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
public class TestPerson {
public static void main(final String[] args) {
KieContainer kc = KieServices.Factory.get().getKieClasspathContainer();
execute(kc);
}
public static void execute(KieContainer kc) {
KieSession ksession = kc.newKieSession("TestPersonKS");
ksession.insert(new Person("张三", 50));
ksession.fireAllRules();
ksession.dispose();
}
public static class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
}
}
}
drl文件
package org.drools.examples.test
import org.drools.examples.test.TestPerson.Person;
import java.util.Date;
import java.util.ArrayList;
dialect "mvel"
rule ruleStartLog
salience 10
when
then
System.out.println("ruleStartLog======"+new Date()+"=========");
end
rule ruleEndLog
salience 1
when
then
System.out.println("ruleEndLog======"+new Date()+"=========");
end
rule rule_insert
salience 2
//no-loop true
when
$person:Person(name == "张三",age < 60)
then
//insert会重新触发该规则
Person $p = new Person("张三",$person.age + 1);
insert($p);
System.out.println("rule1=====insert====="+$p.toString);
end
说明:这里有ruleStartLog、ruleEndLog两个规则,ruleStartLog优先级是10,高于rule_insert、ruleEndLog优先级是1,小于rule_insert,所以正常的执行顺序是ruleStartLog、rule_insert、ruleEndLog
这里主要观察rule_insert规则中的insert对整个规则集合的执行的影响情况,为了便于观察,没有让rule_insert一直循环执行。
最后执行结果
ruleStartLog======Sat Jul 25 22:38:07 CST 2020=========
rule1=====insert=====Person{name='张三', age=51}
rule1=====insert=====Person{name='张三', age=52}
rule1=====insert=====Person{name='张三', age=53}
rule1=====insert=====Person{name='张三', age=54}
rule1=====insert=====Person{name='张三', age=55}
rule1=====insert=====Person{name='张三', age=56}
rule1=====insert=====Person{name='张三', age=57}
rule1=====insert=====Person{name='张三', age=58}
rule1=====insert=====Person{name='张三', age=59}
rule1=====insert=====Person{name='张三', age=60}
ruleEndLog======Sat Jul 25 22:38:07 CST 2020=========
给rule_insert添加上no-loop true后执行结果
ruleStartLog======Sat Jul 25 23:01:10 CST 2020=========
rule1=====insert=====Person{name='张三', age=51}
ruleEndLog======Sat Jul 25 23:01:10 CST 2020=========
update/modify更新
update/modify用来实现对当前Working Memory当中的Fact进行更新,update宏函数的作用与StatefulSession对象的update方法的作用基本相同,用来告诉当前Working Memory该Fact对象已经发生了变化。
格式如下
modify ( <fact-expression> ) {
<expression>,
<expression>,
...
}
update ( <object> )
update/modify引起死循环的表现
java代码与insert中的完全一样
drl文件
package org.drools.examples.test
import org.drools.examples.test.TestPerson.Person;
import java.util.Date;
import java.util.ArrayList;
dialect "mvel"
rule ruleStartLog
salience 10
when
then
System.out.println("ruleStartLog======"+new Date()+"=========");
end
rule ruleEndLog
salience 1
when
then
System.out.println("ruleEndLog======"+new Date()+"=========");
end
rule rule_update
salience 2
//no-loop true
when
//$person:Person(name == "张三",age < 60)
$person:Person(name == "张三")
then
//modify没有重新触发该规则,而是先触发其他规则,如果其他规则再重新触发规则并且该规则匹配,则执行
modify($person){
age += 1,
//只要修改了LHS中判断的属性中任何一个属性的值,就会重新触发该规则,如在LHS中同时判断name和age,这样只要修改了其中任何一个值都会重新触发该规则
//name = "张三";
};
System.out.println("rule_update=====modify====="+$person.toString);
//update没有重新触发该规则,而是先触发其他规则,如果其他规则再重新触发规则并且该规则匹配,则执行
//$person.setAge($person.getAge() + 1);
//只要修改了LHS中判断的属性中任何一个属性的值,就会重新触发该规则,如在LHS中同时判断name和age,这样只要修改了其中任何一个值都会重新触发该规则
//$person.setName("张三");
//update($person);
//System.out.println("rule_update=====update====="+$person.toString);
end
我们会觉的rule_update会一直被触发,知道age>=60了,我们看下真实的执行结果
ruleStartLog======Sun Jul 26 12:11:32 CST 2020=========
rule_update=====modify=====Person{name='张三', age=51}
ruleEndLog======Sun Jul 26 12:11:32 CST 2020=========
结果是rule_update只执行了一次,但是我们并没有设置no-loop 属性值为true
原因就在于rule_update的LHS的条件部分和RHS的操作部分,在LHS的条件部分只通过name进行了过滤,即$person:Person(name == "张三")
在RHS部分只修改了age的值,使其值+1,并没有修改name的值。
通过这里我们发现,只有在RHS部分修改了LHS中作为判断过滤的属性值时,才会重新触发该规则,这是其与insert不同的,也就是说在RHS部分只有更新了LHS中判断逻辑使用到的属性,就会重新触发该规则。
例如在when中,我们这样写$person:Person(name == "张三",age < 60),看下执行结果
ruleStartLog======Sun Jul 26 12:18:18 CST 2020=========
rule_update=====modify=====Person{name='张三', age=51}
rule_update=====modify=====Person{name='张三', age=52}
rule_update=====modify=====Person{name='张三', age=53}
rule_update=====modify=====Person{name='张三', age=54}
rule_update=====modify=====Person{name='张三', age=55}
rule_update=====modify=====Person{name='张三', age=56}
rule_update=====modify=====Person{name='张三', age=57}
rule_update=====modify=====Person{name='张三', age=58}
rule_update=====modify=====Person{name='张三', age=59}
rule_update=====modify=====Person{name='张三', age=60}
ruleEndLog======Sun Jul 26 12:18:19 CST 2020=========
在下面的情况中,即使规则设置了no-loop true,也会出现死循环
rule rule_update
salience 5
no-loop true
when
$person:Person(name == "张三")
then
//modify没有重新触发该规则,而是先触发其他规则,如果其他规则再重新触发规则并且该规则匹配,则执行
modify($person){
age += 1,
};
System.out.println("rule_update=====modify====="+$person.toString);
end
rule rule_update2
salience 3
no-loop true
when
$person:Person(age < 60)
then
modify($person){
name = "张三";
};
System.out.println("rule_update2======"+new Date()+"========="+$person.toString);
end
执行结果
ruleStartLog======Sun Jul 26 12:37:46 CST 2020=========
rule_update=====modify=====Person{name='张三', age=51}
rule_update2======Sun Jul 26 12:37:46 CST 2020=========Person{name='张三', age=51}
rule_update=====modify=====Person{name='张三', age=52}
rule_update2======Sun Jul 26 12:37:46 CST 2020=========Person{name='张三', age=52}
rule_update=====modify=====Person{name='张三', age=53}
rule_update2======Sun Jul 26 12:37:46 CST 2020=========Person{name='张三', age=53}
rule_update=====modify=====Person{name='张三', age=54}
rule_update2======Sun Jul 26 12:37:46 CST 2020=========Person{name='张三', age=54}
rule_update=====modify=====Person{name='张三', age=55}
rule_update2======Sun Jul 26 12:37:46 CST 2020=========Person{name='张三', age=55}
rule_update=====modify=====Person{name='张三', age=56}
rule_update2======Sun Jul 26 12:37:46 CST 2020=========Person{name='张三', age=56}
rule_update=====modify=====Person{name='张三', age=57}
rule_update2======Sun Jul 26 12:37:46 CST 2020=========Person{name='张三', age=57}
rule_update=====modify=====Person{name='张三', age=58}
rule_update2======Sun Jul 26 12:37:46 CST 2020=========Person{name='张三', age=58}
rule_update=====modify=====Person{name='张三', age=59}
rule_update2======Sun Jul 26 12:37:46 CST 2020=========Person{name='张三', age=59}
rule_update=====modify=====Person{name='张三', age=60}
ruleEndLog======Sun Jul 26 12:37:46 CST 2020=========
delete/retract删除
和kession的retract/delete方法一样,宏函数retract/delete也是用来将Working Memory当中某个Fact对象从Working Memory当中删除。
格式如下
delete( <object> );
java代码
java代码我们修改了一些,插入三个对象,其他保持不变
ksession.insert(new Person("张三", 50));
ksession.insert(new Person("张三", 40));
ksession.insert(new Person("张三", 40));
drl文件
package org.drools.examples.test
import org.drools.examples.test.TestPerson.Person;
import java.util.Date;
import java.util.ArrayList;
dialect "mvel"
rule ruleStartLog
salience 10
when
then
System.out.println("ruleStartLog======"+new Date()+"=========");
end
rule ruleEndLog
salience 1
when
then
System.out.println("ruleEndLog======"+new Date()+"=========");
end
rule rule_delete
salience 2
//no-loop true
when
$person:Person(name == "张三",age == 50)
$p:Person(name == "张三",age == 40)
then
//retract会重新触发该规则
retract($p);
System.out.println("rule1=====delete=====");
end
执行结果
ruleStartLog======Sun Jul 26 12:25:52 CST 2020=========
rule1=====delete=====
rule1=====delete=====
ruleEndLog======Sun Jul 26 12:25:52 CST 2020=========
更多推荐
所有评论(0)