积累Drools的内部收藏

时间:2018-07-23 01:24:46

标签: drools drools-planner

比方说,我有红色和绿色的篮子,里面装有盒草莓和葡萄:

public class Basket {
    public enum Color { RED, GREEN };

    private Color color;
    private List<FruitBox> fruitBoxes;

    //Assume appropriate constructors, getters exist
}

public class FruitBox {
    public enum Fruit { STRAWBERRY, GRAPE };

    private Fruit fruit;

    //Assume appropriate constructors, getters exist
}

我需要使用Drools来打印以下计算:

  1. 如果篮子中的GRAPE或STRAWBERRY FruitBoxs数量超过两个,则
  2. 按“水果盒”水果和“篮子颜色”分组的“水果盒”总数

我该如何按照简单高效的Drools规则编码(1.)和(2.)?阅读文档后,我提出了以下解决方案:

rule "Two or more of same fruit in any Basket"
    when
        //Bind the contents of each basket
        $Basket : Basket($FruitBoxes : fruitBoxes)

        //Compute A list of the unique fruits in current basket contents
        $fruits : Object() from accumulate( FruitBox($f : fruit) from $FruitBoxes, collectSet($f) )

        //Match and bind each unique fruit one by one
        $fruit : FruitBox.Fruit() from $fruits

        //Find the number of times the unique fruit occurs in this Basket
        $count : Number(intValue >= 2) from accumulate(
            $f : FruitBox(fruit == $fruit) from $FruitBoxes,
            count($f) )
    then
        System.out.println($Basket + " has " + $count + " of the fruit " + $fruit);
end

对于一个测试数据集,成功打印出的输出如下:

com.sample.DroolsTest$Basket@10cd6753 has 4 of the fruit STRAWBERRY
com.sample.DroolsTest$Basket@10cd6753 has 3 of the fruit GRAPE
com.sample.DroolsTest$Basket@2e060819 has 2 of the fruit GRAPE

我担心的是,我的规则漫长而复杂,并且似乎对每个篮子进行了多次迭代(一旦在其中找到独特的水果,然后再对每个水果进行计数)。我怀疑这是我缺乏Drools知识的产物,并且存在更好的解决方案。在纯Java中,我将使用HashMap一次存储每个水果及其数量,这既简单又快速。有什么方法可以重写我的Drools代码以提高性能和可读性?同样的问题也适用于我的第二条规则:

rule "Totals by fruit and by basket color"
    when
        //Calculate the cross product of all fruits and colors
        $fruit : FruitBox.Fruit()
        $color : Basket.Color()

        //Count the number of FruitBoxes of the chosen fruit in Baskets of the chosen color
        $count : Number() from accumulate(
            $fb : FruitBox(fruit == $fruit) 
            and exists Basket(color == $color, fruitBoxes contains $fb),
            count($fb) )
    then
        System.out.println($count + " " + $fruit + " in " + $color + " baskets");
end

哪个会产生如下输出:

5 STRAWBERRY in GREEN baskets
6 STRAWBERRY in RED baskets
6 GRAPE in GREEN baskets
4 GRAPE in RED baskets

但是,不幸的是,看起来它在每个FruitBox的所有篮子中搜索,而在一次遍历篮子的同时计算一个(或全部)种类的FruitBox会更有意义。就性能而言,此规则是否有更好的语法?

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

嗨,第一个问题,我将使用两个单独的规则:

rule "strawberriesInBasket"
dialect "mvel"
when
    $basket : Basket($fruitBoxes : fruitBoxes)
    Number($count : intValue() > 2) from accumulate ($fruitBox : FruitBox(fruit.name == "strawberry") from $fruitBoxes, count($fruitBox)) 
then
    System.out.println("Count of strawberry boxes in basket is: " + $count )
end

rule "grapesInBasket"
dialect "mvel"
when
    $basket : Basket($fruitBoxes : fruitBoxes)
    Number($count : intValue() > 2) from accumulate ($fruitBox : FruitBox(fruit.name == "grape") from $fruitBoxes, count($fruitBox)) 
then
    System.out.println("Count of grape boxes in basket is: " + $count )
end

请注意,我已将枚举水果更改为具有字段名称的数据对象。