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

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

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


博士升:

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


是否等于:

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


因此,当一个人的年龄不大于30岁时,calcIncome方法将不会被评估?

谢谢!

最佳答案

我自己做了一些测试,这就是我发现的(至少在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运算。
同样,通过使用逗号而不是“&”号也得到了相同的结果。

博士升

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


RETE网络

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

drools - 会在流口水LHS中“&&”或“,”“短路”吗?-LMLPHP

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

使用具有超过30年且少于30年的Person实例进行的测试证实了这一点:具有30年以上的实例会引发calcIncome()的异常。



规则B

然后,我很好奇当我们使用and或(||)运算符而不是and时会发生什么。

博士升

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


RETE网络

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

drools - 会在流口水LHS中“&&”或“,”“短路”吗?-LMLPHP

Drools内部使用了什么机制(我想是MVEL)来解决该节点,似乎实现了逻辑短路。我所做的测试表明,仅当使用少于30年的Person实例时才会引发预期的异常。



最后说明

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

根据我的测试,将使用短路启用算法来解决单个模式的所有约束。这主要取决于Rete网络中的alpha节点是按顺序评估的。

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

希望能帮助到你,

关于drools - 会在流口水LHS中“&&”或“,”“短路”吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35953447/

10-11 20:42