简体   繁体   English

Drools 规则的执行次数超过预期

[英]Drools rule gets executed more times than expected

I'm new to Drools and am following along the book: Mastering JBoss Drools 6我是 Drools 的新手,正在阅读这本书: Mastering JBoss Drools 6

Chapter 2 shows an example where we create a Customer and Order , classify customers based on their order size, give discounts and generate Coupon s.第 2 章展示了一个示例,我们创建了一个CustomerOrder ,根据订单大小对客户进行分类,提供折扣并生成Coupon

The example mentions:该示例提到:

  • A customer一个客户
  • The customer has an order with 5 items and therefore classified as a SILVER customer客户有一个包含 5 件商品的订单,因此被归类为SILVER客户
  • Each item costs more than 500, so it is classified as a HIGH_RANGE item每件商品的价格都超过 500,因此被归类为HIGH_RANGE商品
  • The customer is a SILVER customer therefore a Coupon is created客户是SILVER客户,因此创建了Coupon
  • Give a discount of 10% for each SILVER customer with orders with more than 2 items为每位SILVER级客户提供超过 2 件订单的 10% 折扣

Here are the Drools rules:以下是 Drools 规则:

add-discount.drl添加折扣.drl

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

classify-customer-rules.drl分类客户规则.drl

rule "Classify Customer by order size"
    when
        $o: Order( orderLines.size >= 5, $customer: customer )
        $c: Customer(this == $customer, category == Customer.Category.NA)
    then
        modify($c){
            setCategory(Customer.Category.SILVER)
        }
end

classify-items-rules.drl分类-items-rules.drl

rule "Classify Item - Low Range"
    when
        $i: Item(cost < 200, category == Category.NA)
    then
        $i.setCategory(Category.LOW_RANGE);
        update($i);
end

rule "Classify Item - Mid Range"
    when
        $i: Item(cost > 200 && cost < 500, category == Category.NA)
    then
        $i.setCategory(Category.MID_RANGE);
        update($i);
end

rule "Classify Item - High Range"
    when
        $i: Item(cost >= 500, category == Category.NA)
    then
        $i.setCategory(Category.HIGH_RANGE);
        update($i);
end

coupons-creation.drl优惠券-creation.drl

rule "Create Coupons for silver customer"
    when
        $o: Order($customer: customer)
        $c: Customer(this == $customer, category == Customer.Category.SILVER)
    then
        Coupon x = new Coupon($c, $o, Coupon.CouponType.POINTS);
        System.out.println(x);
        insert(x);
end

The number of rules executed should be 8. 5 items to classify (5 rules) + 1 customer to classify (1 rule) + 1 discount to add (1 rule) + 1 coupon to create (1 rule)执行的规则数应为 8。5 个要分类的项目(5 个规则)+ 1 个要分类的客户(1 个规则)+ 1 个要添加的折扣(1 个规则)+ 1 个要创建的优惠券(1 个规则)

But the actual number of rules fired is 9. Here is the test I used to check.但实际触发的规则数是 9。 是我用来检查的测试。 The coupon creation rule is fired twice.优惠券创建规则被触发两次。 I do not understand why.我不明白为什么。 I checked the number of coupons created after firing the rule like so:我检查了触发规则后创建的优惠券数量,如下所示:

Collection<Coupon> coupons = Util.getFactsFromSession(kieSession, Coupon.class);
coupons.forEach(x -> System.out.println(x));

and I also have a print statement in the coupon creation rule.我在优惠券创建规则中也有打印声明。

This is what I get:这就是我得到的:

12:54:47.607 [main] DEBUG org.drools.core.impl.KnowledgeBaseImpl - Starting Engine in PHREAK mode
12:54:47.730 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is nw FIRING_ALL_RULES
12:54:47.732 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
12:54:47.795 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
Coupon created com.example.droolstut.model.Coupon@b14cb989
12:54:47.797 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
12:54:47.797 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
12:54:47.799 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
12:54:47.806 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
Coupon created com.example.droolstut.model.Coupon@424f842a
12:54:47.806 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
12:54:47.806 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
12:54:47.806 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is nw HALTING
12:54:47.806 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is nw INACTIVE
Coupon found: com.example.droolstut.model.Coupon@424f842a
Coupon found: com.example.droolstut.model.Coupon@424f842a

So, it looks like the rule is executed twice, but only the second coupon is found post execution.因此,看起来规则执行了两次,但执行后只找到了第二张优惠券。

But, when I run the test in debug mode, the coupon rule is executed only once, and the total number of rules fired is 8 too.但是,当我在调试模式下运行测试时,优惠券规则只执行一次,触发的规则总数也是 8。

Did I miss something?我错过了什么? I'd appreciate any help.我将不胜感激任何帮助。

By the time a book on Drools gets published, it's out of date.当一本关于 Drools 的书出版时,它已经过时了。 Drools has fantastic documentation that you should be using as your primary source, not a very old book on a very old version of Drools. Drools 有很棒的文档,您应该将其用作您的主要来源,而不是一本关于非常旧版本的 Drools 的非常古老的书。 (Current version of Drools is Drools 8. Your book is for Drools 6.) (Drools 的当前版本是 Drools 8。您的书适用于 Drools 6。)

The other reason I recommend people not use books is because they tend to be awful.我建议人们不要使用书籍的另一个原因是它们往往很糟糕。 This one is no exception这个也不例外


The reason you're firing more rules than you think is because both "High Range order - 10% discount" forces a reevaluation of working memory, and "Create Coupons for silver customer" doesn't have anything to stop it from triggering multiple times.你触发比你想象的更多规则的原因是因为“高范围订单 - 10% 折扣”强制重新评估工作 memory,而“为白银客户创建优惠券”没有任何东西可以阻止它多次触发.

"High Range..." calls 'modify' which re-fires all rules with the modified item. “High Range...”调用“修改”,它会使用修改后的项目重新触发所有规则。 Since "Create Coupon..." remains valid to fire, it will trigger twice.由于“Create Coupon...”仍然有效,因此它会触发两次。 (It'll fire once, and then once "High Range..." forces the reevaluation of working memory, it'll fire a second time.) You'll also see that there's twice as many coupons in working memory as you'd expect -- there will be 2 coupons instead of one because you fired the coupon rule twice. (它会触发一次,然后一旦“High Range...”强制重新评估 working memory,它就会触发第二次。)你还会看到 working memory 的优惠券数量是你的两倍。 d expect -- 将有 2 张优惠券而不是一张,因为您触发了优惠券规则两次。

To keep this from happening, you need to make "Create Coupon..." not valid to fire twice.为了防止这种情况发生,您需要使“创建优惠券...”无效以触发两次。 (That is, once it's fired, it can't be triggered again.) You can do this, for example, by not allowing two of the same coupon. (也就是说,一旦触发,就不能再次触发。)例如,您可以通过不允许使用两张相同的优惠券来做到这一点。 Or you could do this by only allowing one coupon.或者您可以只允许一张优惠券来做到这一点。 Depends on your use case.取决于您的用例。

One way might be:一种方法可能是:

rule "Create Coupons for silver customer"
when
  $o: Order($customer: customer)
  $c: Customer(category == Customer.Category.SILVER)

  // don't fire if this coupon already exists; I guessed on the variable names
  not( Coupon( customer == $c, order == $o, type == Coupon.CouponType.POINTS) )
then
  Coupon x = new Coupon($c, $o, Coupon.CouponType.POINTS);
  insert(x);
end

In the Real World, you want to keep your rules simple.在现实世界中,您希望规则简单。 Don't stick the entire kitchen sink into a single KieBase.不要将整个厨房水槽粘在一个 KieBase 中。 The single responsibility principle is key here.单一职责原则是这里的关键。 Your "Item classification" rules should be fired separately from your customer classification rules should be fired separately from your discount rules.您的“项目分类”规则应该与您的客户分类规则分开触发,应该与您的折扣规则分开触发。

Also calling update is a great way to get yourself into infinite loops and greatly increase your memory/cpu overhead.调用update也是让自己陷入无限循环并大大增加内存/CPU 开销的好方法。 At my last company it was considered not only a code smell and bad practice, but actually outright banned (we checked for it in code reviews.)在我上一家公司,它不仅被认为是一种代码味道和不良做法,而且实际上被彻底禁止(我们在代码审查中检查过它。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 一个流口水规则没有间歇性地执行 - One drools rule not executed Intermittently 流口水:仅在执行另一个规则后执行规则 - Drools: Execute a rule only after another was executed 流口水-规则触发时并非所有动作都会执行 - Drools - Not all actions are executed when rule fires 流口水:简单规则在无状态会话中执行了两次 - Drools: simple rule executed twice in a stateless session Drools在议程过滤器之外的规则上获取NullPointerException - Drools gets NullPointerException on rule outside of Agenda Filter Drools:触发了不止一个规则,我想打印结论(然后是部分),这可能吗? 如果不是,你有什么建议? - Drools: more than one rule are fired and I want the conclusion to be printed (then part), is it possible? if not what do you suggest? 单独的流口水统治者还是后果更严重? - Separate Drools rule or have more if in the consequence? Drools:AfterMatchFiringEvent为具有OR条件的同一规则多次触发? - Drools: AfterMatchFiringEvent triggering multiple times for the same rule with OR conditions? 使用状态会话,Drools BRMS火灾和警报规则无法按预期工作 - Drools BRMS Fire and Alarm rule not working as expected using statefulsession 以 n 为单位执行语句的次数 - number of times a statement gets executed in terms of n
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM