将'&&'流口水中的'或',“短路”LHS?

时间:2016-03-12 03:35:24

标签: drools

我认为是,但我不太确定。 例如:

class Person {
    int age;
    int salary;
    int bonus;
    //getter and setter

    public int calcIncome () {
        return salary + bonus;
    }
}

DRL:

when 
    $p:Person(age > 30, calcIncome() > 1000)
then
        ...

等于:

    if (person.getAge() > 30 && person.calcIncome() > 1000) {
    ...
    }

所以当人的年龄不大于30时,不会评估calcIncome方法吗?

谢谢!

2 个答案:

答案 0 :(得分:3)

我自己做了一些测试,这是我发现的(至少在6.3版本中)。

始终按顺序评估Drools中特定规则的RETE算法的alpha子网。节点的顺序似乎是约束在它们所属的模式中的顺序。所以,我们可以说存在一种隐含的短路机制。

顺便说一下,我发现逗号的使用没有任何区别,''或&符号&&'在这两种情况下,Drools都将表达式视为2个独立的alpha节点。

这就是我所做的:

模型

public class Person {
    private int age;
    private int salary;
    private int bonus;

    public Person(int age, int salary, int bonus) {
        //set values
    }

    public int calcIncome() {
        throw new IllegalStateException("Expected error here!");
    }

    //getters
}

请注意我是否故意在calcIncome()中抛出异常。

规则A

此规则使用'&&'指示Person模式上的2个约束之间的AND运算。 同样,我使用逗号而不是&符号得到了相同的结果。

DRL

rule "Rule A"
when
    $p:Person(age > 30 && calcIncome() > 1000)
then
    System.out.println("Rule A");
end

RETE网络

先例规则的Rete网络如下所示:

enter image description here

在上图中,我们可以看到2个不同的alpha节点(黄色)。因为alpha节点是按顺序计算的,所以第二个节点只会被评估,在这种情况下,如果我们评估的Person已超过30年。

使用超过30年的Person个实例进行的测试证实了这一点:超过30年的实例抛出了calcIncome()的异常。

规则B

然后,我很好奇当我们使用和/或(||)运算符而不是和。时发生的事情。

DRL

rule "Rule B"
when
    $p:Person(age > 30 || calcIncome() > 1000)
then
    System.out.println("Rule B");
end

RETE网络

有趣的是,此示例的RETE网络解析了单个alpha节点内的OR运算符。

enter image description here

Drools在内部使用的任何机制(我猜是MVEL)来解析这个节点似乎都实现了逻辑短路。我所做的测试表明,只有在使用少于30年的Person个实例时,才会抛出预期的异常。

最后的注释

即使Drools在处理单个Pattern中的约束时似乎短路,但当规则包含多个模式时,情况会有所不同。

根据我的测试,使用启用短路的算法可以解决单个模式的所有约束。这主要依赖于Rete网络中的alpha节点按顺序进行评估的事实。

现在,在处理规则中的多个模式时,无法在编译时预测评估顺序。可以根据特定Rete网络查找特定情况的方式独立评估规则中的每个模式。

希望它有所帮助,

答案 1 :(得分:1)

我认为正确答案是

Person( age > 30 && calcIncome > 1000 )
如果calcIncome,则

不会评估age <= 30

删除了虚假声明“逗号”

Drools文档包含&amp;&amp;并且,运算符具有相同的语义。运算符优先级只有差异,逗号最低。