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=========

 

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐