【问题标题】:forall always evaluates to be true [Drools 6.3 final]forall 总是评估为真 [Drools 6.3 final]
【发布时间】:2019-07-13 21:11:05
【问题描述】:

我是 Drools 的新手。想问一个关于条件元素forall的问题。我有一些类,下面的 UML 图显示了这些对象之间的关系: UML diagram

一个订单有一个客户,并且有一个订单行列表。 每个订单行都链接到一个项目。坦率地说,它是一本关于 Drools 的书的示例代码。

我想在订单的客户是SILVER类别并且订单中的所有商品都在高范围(高成本)时触发以下规则,以设置订单的折扣。这是规则:

rule "Silver Customers + High Range Order - 10% Discount -1"
when

    $o: Order( $lines : orderLines.size >= 2, $customer: customer, discount == null )
    $c: Customer( category == Category.SILVER, this == $customer )
    forall( OrderLine( this memberOf $lines,  $item : item)
            Item(this == $item, category == Item.Category.HIGH_RANGE)
    )
then
    $o.setDiscount(new Discount(10.0));
    update($o); 
end

问题是规则总是触发,即使我尝试插入一个包含 5 个低范围项目的订单。

在调试信息中,我发现第一项的类别是 LOW_RANGE,但仍然触发了规则:

==>[BeforeActivationFiredEvent:  getActivation()=[[ Silver Customers +  High Range Order - 10% Discount active=false ] [ null
[fact 0:1:1561745898:141057847:1:DEFAULT:NON_TRAIT:org.drools.devguide.eshop.model.Customer:Customer [id = null, age=null, email=null, name=null, category = SILVER]]
[fact 0:12:1971991758:-345298280:12:DEFAULT:NON_TRAIT:org.drools.devguide.eshop.model.Order:Order [ id = null, customer=Customer [id = null, age=null, email=null, name=null, category = SILVER], date=Fri Oct 21 11:11:38 CST 2016, lines=[OrderLine [item=Item{id=1, name=A, cost=80.0, salePrice=800.0, category=LOW_RANGE}, quantity=1], OrderLine [item=Item{id=1, name=B, cost=800.0, salePrice=850.0, category=HIGH_RANGE}, quantity=2], OrderLine [item=Item{id=1, name=C, cost=800.0, salePrice=850.0, category=HIGH_RANGE}, quantity=3], OrderLine [item=Item{id=1, name=D, cost=800.0, salePrice=850.0, category=HIGH_RANGE}, quantity=4], OrderLine [item=Item{id=1, name=E, cost=800.0, salePrice=850.0, category=HIGH_RANGE}, quantity=5]], state=PENDING, discount=null]] ] ], getKnowledgeRuntime()=KieSession[0]]
-------------------
rule triggered:Silver Customers + High Range Order - 10% Discount
==>[AfterActivationFiredEvent: getActivation()=[[ Silver Customers + High Range Order - 10% Discount active=false ] [ null
[fact 0:1:1561745898:141057847:1:DEFAULT:NON_TRAIT:org.drools.devguide.eshop.model.Customer:Customer [id = null, age=null, email=null, name=null, category = SILVER]]
[fact 0:12:1971991758:-345298280:18:DEFAULT:NON_TRAIT:org.drools.devguide.eshop.model.Order:Order [ id = null, customer=Customer [id = null, age=null, email=null, name=null, category = SILVER], date=Fri Oct 21 11:11:38 CST 2016, lines=[OrderLine [item=Item{id=1, name=A, cost=80.0, salePrice=800.0, category=LOW_RANGE}, quantity=1], OrderLine [item=Item{id=1, name=B, cost=800.0, salePrice=850.0, category=HIGH_RANGE}, quantity=2], OrderLine [item=Item{id=1, name=C, cost=800.0, salePrice=850.0, category=HIGH_RANGE}, quantity=3], OrderLine [item=Item{id=1, name=D, cost=800.0, salePrice=850.0, category=HIGH_RANGE}, quantity=4], OrderLine [item=Item{id=1, name=E, cost=800.0, salePrice=850.0, category=HIGH_RANGE}, quantity=5]], state=PENDING, discount=10.0 % ]] ] ], getKnowledgeRuntime()=KieSession[0]]

我已阅读问题的答案:forall always evaluates to be true [Drools]。我尝试了解决方案,但我得到了另一个错误的结果,即使我使用了包含所有高范围物品的订单,以下规则也不会触发:

rule "Silver Customers + High Range Order - 10% Discount"
when

    $o: Order( $lines : orderLines.size >= 2, discount == null )
    $c: Customer( category == Category.SILVER ) from $o.customer
    forall( OrderLine() from $o.orderLines
            OrderLine( item.category == Item.Category.HIGH_RANGE)
    )
then
    $o.setDiscount(new Discount(10.0));
    update($o);
end

单元测试代码如下:

@Test
public void highRangeOrderDiscountTest() {
    KieSession kSession = createDefaultSession();

    Order o = ModelFactory.getOrderWithFiveHighRangeItems();

    kSession.insert(o.getCustomer());
    kSession.insert(o.getOrderLines().get(0));
    kSession.insert(o.getOrderLines().get(1));
    kSession.insert(o.getOrderLines().get(2));
    kSession.insert(o.getOrderLines().get(3));
    kSession.insert(o.getOrderLines().get(4));
    kSession.insert(o.getOrderLines().get(0).getItem());
    kSession.insert(o.getOrderLines().get(1).getItem());
    kSession.insert(o.getOrderLines().get(2).getItem());
    kSession.insert(o.getOrderLines().get(3).getItem());
    kSession.insert(o.getOrderLines().get(4).getItem());
    kSession.insert(o);

    int fired = kSession.fireAllRules();

    // We have 5 Items that are categorized -> 5 rules were fired
    // We have 1 Customer that needs to be categorized -> 1 rule fired
    // We have just one order with all HIGH RAnge items -> 1 rule fired
    // One Coupon is created for the SILVER Customer -> 1 rule fired
    assertThat(8, is(fired));
    assertThat(o.getCustomer().getCategory(), is(Customer.Category.SILVER));
    assertThat(o.getDiscount(), not(nullValue()));
    assertThat(o.getDiscount().getPercentage(), is(10.0));


}
}

你能告诉我原因或告诉我 forall 的正确用法吗?非常感谢。

【问题讨论】:

    标签: drools


    【解决方案1】:

    这建立了 OrderLine-s 的集合,然后确定所有都属于高范围项目。 (注:未经测试)

    rule "Silver Customers + High Range Order - 10% Discount"
    when
        $c: Customer( category == Category.SILVER )
        $o: Order( $lines : orderLines.size >= 2, customer == $c,
                   discount == null )
        forall( OrderLine( $item : item) from $lines
                Item(this == $item, category == Item.Category.HIGH_RANGE))
    then
        modify( $o ){ setDiscount(new Discount(10.0)) }
    end
    

    所有 Customer 和 Item 对象都必须作为事实插入;对 OrderLine-s 也这样做是合理的。

    【讨论】:

    • 感谢您的回答。我试过你的解决方案仍然触发了低范围物品的规则。
    【解决方案2】:

    书中有一处错误:

    $o: Order($lines: orderLines.size >= 2, customer == $c, discount == null)

    必须是

    $o: Order($lines: orderLines, orderLines.size >= 2, customer == $c, discount == null)

    【讨论】:

      猜你喜欢
      • 2016-10-03
      • 1970-01-01
      • 1970-01-01
      • 2014-05-05
      • 2018-02-24
      • 2016-01-28
      • 2016-08-25
      • 1970-01-01
      • 2018-07-01
      相关资源
      最近更新 更多