【问题标题】:Drools Rules Fireing Order when Fact data changes当事实数据发生变化时,Drools 规则触发顺序
【发布时间】:2019-03-07 09:52:38
【问题描述】:

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

我有一个简单的 Fact 类

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

通过使用有状态会话,我希望在“规则集状态”触发后看到“规则无效”触发。如果我将 Set Status 规则从规则列表的底部移到顶部,那么我得到

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

很明显 Drools 并没有意识到规则 Set Status 中的状态变化。我错过了什么?

问候

跟进。

现在我真的很困惑。如果我在我的规则文件中删除对方法 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


    【解决方案1】:

    基本上,发生的事情是 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 中找到有关此主题的更多信息。

    希望对你有帮助,

    【讨论】:

    • 作为后续,如果我将状态设置为布尔值并使用 POJO 方法 setStatus() 和 isStatus(),那么一切都会按预期工作
    猜你喜欢
    • 2015-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-14
    • 2019-05-23
    • 1970-01-01
    相关资源
    最近更新 更多