事实数据更改时,Drools 规则触发顺序

Drools Rules Fireing Order when Fact data changes

我是 Drools 的新手,要么我误解了 Drools 的功能,要么我遗漏了一些东西。

我有一个简单的事实class

public class MeterReadTO {

private String status = "";

public String getStatus() {
  return status;
}

public void setStatus(String status) {
   this.status = status;
}

public boolean isInvalid() {
  return status.equals("invalid");
};

}

符合规则

 rule "Rule Invalid"

 dialect "mvel"
 when
     MeterReadTO( isInvalid());
 then
  System.out.println("Rule Invalid Fired");

end

rule "Rule Not Invalid"

 dialect "mvel"
when
   not MeterReadTO(  isInvalid());
then
   System.out.println("Rule Not Invalid Fired");

end

rule "Set Status"

 dialect "mvel"
 when
    $mr: MeterReadTO()
  then
      System.out.println("Rule Set Status Fires");

     modify($mr) {
      setStatus("invalid")
     }
   end

我 运行 规则

@RunWith(SpringRunner.class)
@SpringBootTest
public class Dependancy {


static KieSession ksession;

Logger logger = LoggerFactory.getLogger(Dependancy.class);


MeterReadTO mr;


@BeforeClass
public static void start() {


      KieContainer kieClasspathContainer = KieServices.Factory.get().getKieClasspathContainer();
        ksession = kieClasspathContainer.newKieSession("DependancyTest");
}

@Test
public void contextLoadsAndRetrievesData() {

    MeterReadTO mr = new MeterReadTO();
    mr.setId(50);

    ksession.insert(mr);

    // when
    ksession.fireAllRules();
    ksession.dispose();

    // Then
    System.out.println("After Drools, status is " + mr.getStatus());

}

}

我得到了结果

Rule Not Invalid Fired
Rule Set Status Fires
After Drools, status is invalid

通过使用有状态会话,我希望在 "rule Set Status" 触发后看到 "rule Invalid" 触发。如果我将设置状态规则从规则列表的底部移动到顶部,那么我得到

Rule Set Status Fires
Rule Not Invalid Fired
After Drools, status is invalid

很明显,Drools 并不知道规则集状态中的状态变化。我错过了什么?

此致

跟进。

现在我真的很困惑。如果我在我的规则文件中删除对方法 isInvalid() 的调用并改为引用 getStatus() 方法,那么规则现在看起来像

rule "Rule Invalid"

dialect "mvel"
when
  MeterReadTO( getStatus() == "ïnvalid");
then
  System.out.println("Rule Invalid Fired");

end

rule "Rule Not Invalid"

 dialect "mvel"
 when
   MeterReadTO( getStatus() == "");
 then
    System.out.println("Rule Not Invalid Fired");

end

rule "Set Status"

dialect "mvel"

when
    $mr: MeterReadTO()
  then
      System.out.println("Rule Set Status Fires");

  modify($mr) {
    setStatus("ïnvalid")
  }

   end

然后我得到我期望的输出

Rule Not Invalid Fired
Rule Set Status Fires
Rule Invalid Fired
After Drools, status is ïnvalid  

谁能解释一下这是怎么回事?

基本上,发生的事情是 Drools 无法理解当您更改事实的 status 时,方法 isInvalid() 的结果会受到影响。

当您修改一个事实时,Drools 会尽量减少对规则的重新评估。在您的情况下,Drools 无法在 setStatus()isInvalid() 方法之间建立联系。

在第二种情况下,您在规则中使用 getStatus() 方法,然后 Drools 能够进行连接(通过简单的 POJO 命名约定)。

确保 Drools 理解 setStatus()isInvalid() 之间的联系的一种方法是在您的规则中使用 @watch 注释:

rule "Rule Invalid"
 dialect "mvel"
 when
   MeterReadTO( isInvalid()) @watch(status)
 then
  System.out.println("Rule Invalid Fired");
end

rule "Rule Not Invalid"
dialect "mvel"
when
  not MeterReadTO(  isInvalid()) @watch(status)
then
  System.out.println("Rule Not Invalid Fired");
end

这种方法的问题在于您的规则确实与您的模型相关联。如果你检查一个事实是否无效的方式修改为涉及更多字段,你必须逐条修改@watch注解。

另一种解决方案是使用 @Modifies 注释在模型本身中标记关系:

public class MeterReadTO {
  private String status = "";

  public String getStatus() {
    return status;
  }

  @Modifies( { "invalid" } )
  public void setStatus(String status) {
    this.status = status;
  }

  public boolean isInvalid() {
    return status.equals("invalid");
  };

}

您可以在 Drools' official documentation 中找到有关此主题的更多信息。

希望对您有所帮助,