[rules-users] rules for promotional offers

Sandeep Bandela gibsosmat at gmail.com
Mon Sep 12 11:25:26 EDT 2011


wolfgang,
I didnt get it, so does that mean that all CE will be re-evaluated on every
change of workingmemory no matter which rule fired? even when executing RHS.
I didnt test it with copy of list yet. I will do it and see.

On Sun, Sep 11, 2011 at 11:28 AM, Wolfgang Laun <wolfgang.laun at gmail.com>wrote:

> The result of the collect CE is changed due to the modify. You have to
> copy the list and use the copy in the loop.
> -W
>
> 2011/9/9 Sandeep Bandela <gibsosmat at gmail.com>:
> > Thanks wolfgang, for the info and that workaround.
> > I think there is some off by one error in for loop, or may be some
> mistake
> > that I didnt notice in my code. the following rule with 3 objects gives
> > index out of bound error. I am attaching java & drl file (package
> > com.example.drools.testing). I am using 5.2.0 final release.
> >
> > rule "Buy X units of Product A and Get Y units of Product B Free"
> >     when
> >         $itemsA : ArrayList( $a : size >= 2 ) from collect( CartItem(
> > productId == "A", processed == false) )
> >         $itemsB : ArrayList( $b : size >= 1 ) from collect( CartItem(
> > productId == "B", processed == false) )
> >         $m : RuleMessage()
> >  then
> >          $m.addMessage("sizes- A="+$a + " B="+$b);
> >          int $x = 2;
> >         int $y = 1;
> >         $m.addMessage("sizes- X="+$x + " Y="+$y);
> >         for(int i=0 ; i < $x ; i++){
> >              CartItem $ci = (CartItem) $itemsA.get(i);
> >              $m.addMessage( $ci.getId()+")Found item:
> "+$ci.getProductId());
> >              modify((CartItem)$ci){
> >                 setProcessed(true),
> >                 setPromoItemDiscount(0D),
> >                 setPromoId("2"),
> >                 setBundleId(bundler.getId()),
> >                 setAggregatorId(1)
> >             };
> >          };
> >          for(int i=0 ; i < $y  ; i++){
> >          CartItem $ci = (CartItem) $itemsB.get(i);
> >              $m.addMessage( $ci.getId()+")Found item:
> "+$ci.getProductId());
> >              modify((CartItem)$ci){
> >                 setProcessed(true),
> >                 setPromoItemDiscount($ci.getPrice()),
> >                 setPromoId("2"),
> >                 setBundleId(bundler.getId()),
> >                 setAggregatorId(2)
> >             };
> >          };
> >         bundler.increment();
> > end
> >
> >
> > error
> > Exception in thread "main" org.drools.runtime.rule.ConsequenceException:
> > rule: Buy X units of Product A and Get Y units of Product B Free
> >
> >     at
> >
> org.drools.runtime.rule.impl.DefaultConsequenceExceptionHandler.handleException(DefaultConsequenceExceptionHandler.java:39)
> >     at
> > org.drools.common.DefaultAgenda.fireActivation(DefaultAgenda.java:916)
> >     at
> org.drools.common.DefaultAgenda.fireNextItem(DefaultAgenda.java:845)
> >     at
> org.drools.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:1056)
> >     at
> >
> org.drools.common.AbstractWorkingMemory.fireAllRules(AbstractWorkingMemory.java:733)
> >     at
> >
> org.drools.common.AbstractWorkingMemory.fireAllRules(AbstractWorkingMemory.java:699)
> >     at
> >
> org.drools.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:218)
> >     at com.example.drools.testing.Main.main(Main.java:52)
> > Caused by: java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
> >     at java.util.ArrayList.RangeCheck(ArrayList.java:547)
> >     at java.util.ArrayList.get(ArrayList.java:322)
> >     at
> >
> com.example.drools.testing.Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.defaultConsequence(Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java:12)
> >     at
> >
> com.example.drools.testing.Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0DefaultConsequenceInvoker.evaluate(Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0DefaultConsequenceInvoker.java:44)
> >     at
> > org.drools.common.DefaultAgenda.fireActivation(DefaultAgenda.java:906)
> >     ... 6 more
> >
> >
> > 2011/9/9 Wolfgang Laun <wolfgang.laun at gmail.com>
> >>
> >> If the declared type of productId and getProductId() is String, it
> should
> >> be compared to a string literal. (A conversion might be made, but don't
> rely
> >> on that.)
> >>
> >> You cannot access components of a global in RHS code using the
> simplified
> >> notation (not unless you use "mvel" - but don't do that.) Here, all
> accesses
> >> should be written the usual Java way, with getter and setter calls.
> >>
> >> The problem you have with modify(ci) is a bug (fixed for 5.3.0). As a
> >> workaround,use
> >>
> >> modify( (CartItem)ci ){ ... }
> >>
> >> -W
> >>
> >>
> >> 2011/9/9 Sandeep Bandela <gibsosmat at gmail.com>
> >>>
> >>> some more info for the modify() problem, the CartItem is an interface
> and
> >>> the implementation is CartItemImpl. if this info leads to some clues.
> >>>
> >>>
> >>> On Fri, Sep 9, 2011 at 1:28 PM, Sandeep Bandela <gibsosmat at gmail.com>
> >>> wrote:
> >>>>
> >>>> Hi here is the same thing converted to mvl
> >>>>
> >>>> // this Bundler.java has integer member that keeps incrementing
> >>>> global Bundler bundler
> >>>>
> >>>> rule "Apply 10% discount if you purchase 2 items"
> >>>>     when
> >>>>         $s1 : CartItem( productId == 219759, processed == false)
> >>>>         $s2 : CartItem( this != $s1, productId == $s1.productId,
> >>>> processed == false)
> >>>>         $m : RuleMessage()
> >>>>  then
> >>>>         $m.addMessage("Found item1: " + $s1.getName() + " id:
> >>>> "+$s1.getId());
> >>>>         $m.addMessage("Found item2: " + $s2.getName() + " id:
> >>>> "+$s2.getId());
> >>>>         modify($s1){
> >>>>         setProcessed(true),
> >>>>         setPromoItemDiscount($s1.getPrice() * 0.1),
> >>>>         setPromoId("1"),
> >>>>         setBundleId(bundler.getId()),
> >>>>         setAggrigatorId(1)
> >>>>         };
> >>>>         modify($s2){
> >>>>         setProcessed(true),
> >>>>         setPromoItemDiscount($s2.getPrice() * 0.1),
> >>>>         setPromoId("1"),
> >>>>         setBundleId(bundler.getId()),
> >>>>         setAggrigatorId(1)
> >>>>         };
> >>>>         $m.addMessage("bundled ["+bundler.getId()+"]
> >>>> "+$s1.getId()+","+$s2.getId());
> >>>>         bundler.increment();
> >>>> end
> >>>>
> >>>> the above rule dosent fire, but if I change the highlighter to
> >>>> getProductId() == 219759, or use productId == "219759", may be this is
> some
> >>>> edge case but it took long time for me to figure it out productId is
> String.
> >>>> now consider the bundler.getId(), if I use bundler.id I get
> compilation
> >>>> error.
> >>>>
> >>>> Rule Compilation error : [Rule name='Apply 10% discount if you
> purchase
> >>>> 2 items']
> >>>>
> >>>>
> com/example/promotions/promotionEngine/Rule_Apply_10__discount_if_you_purchase_2_items_0.java
> >>>> (23:1592) : The field Bundler.id is not visible
> >>>> 2011-09-09 13:18:39,863  INFO [STDOUT] - 2011-09-09 13:18:39,863  INFO
> >>>> [PromotionsManager] - ksession initialized
> >>>> 2011-09-09 13:18:39,863  INFO [STDOUT] - 2011-09-09 13:18:39,863  INFO
> >>>> [PromotionsManager] - Exploding items and inserting cart
> >>>> 2011-09-09 13:18:39,864  INFO [STDOUT] - 2011-09-09 13:18:39,863 ERROR
> >>>> [CheckOutBasedUtilities] - Failed to apply promo offers
> >>>> java.lang.RuntimeException: Unexpected global [bundler]
> >>>>     at
> >>>>
> org.drools.common.AbstractWorkingMemory.setGlobal(AbstractWorkingMemory.java:613)
> >>>>     at
> >>>>
> org.drools.impl.StatefulKnowledgeSessionImpl.setGlobal(StatefulKnowledgeSessionImpl.java:332)
> >>>>     at
> >>>>
> com.example.promotions.promotionEngine.PromotionsManager.applyOffers(PromotionsManager.java:154)
> >>>>     at
> >>>>
> com.example.promotions.promotionEngine.PromotionsManager.shuffleForOffers(PromotionsManager.java:61)`
> >>>>
> >>>> lastly my actual problem that I am looking for a solution lets say we
> >>>> have "Buy X items of A and get Y Items of B". X=5 & Y=4 from the
> original
> >>>> problem I want to template the rule and load the values of X,A,Y,B
> from
> >>>> database or excel etc. if I use modify the error is as follows
> >>>>
> >>>> my rule
> >>>>
> >>>>
> >>>> rule "Buy X units of Product A and Get Y units of Product B Free"
> >>>>     when
> >>>>         $itemsX : ArrayList( size == 2 ) from collect( CartItem(
> >>>> getProductId() == 24257, !isProcessed()))
> >>>>         $itemsY : ArrayList( size == 1) from collect(CartItem(
> >>>> getProductId() == 24260, !isProcessed()))
> >>>>         $m : RuleMessage()
> >>>>  then
> >>>>          for(Object item : $itemsX){
> >>>>              CartItem ci = (CartItem) item;
> >>>>              $m.addMessage( ci.getId()+")Found item:
> "+ci.getItemId()+"
> >>>> name: "+ci.getName());
> >>>>              modify(ci){
> >>>>                 setProcessed(true),
> >>>>                 setPromoItemDiscount(0),
> >>>>                 setPromoId("2"),
> >>>>                 setBundleId(bundler.getId()),
> >>>>                 setAggrigatorId(1)
> >>>>             };
> >>>>          }
> >>>>          for(Object item : $itemsY){
> >>>>          CartItem ci = (CartItem) item;
> >>>>              $m.addMessage( ci.getId()+")Found item:
> "+ci.getItemId()+"
> >>>> name: "+ci.getName());
> >>>>              modify(ci){
> >>>>                 setProcessed(true),
> >>>>                 setPromoItemDiscount(ci.getPrice()),
> >>>>                 setPromoId("2"),
> >>>>                 setBundleId(bundler.getId()),
> >>>>                 setAggrigatorId(2)
> >>>>             };
> >>>>          }
> >>>>         bundler.increment();
> >>>> end
> >>>>
> >>>> Rule Compilation error : [Rule name='Buy X units of Product A and Get
> Y
> >>>> units of Product B Free']
> >>>>
> >>>>
> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
> >>>> (11:1236) : The method setProcessed(boolean) is undefined for the type
> >>>> Object
> >>>>
> >>>>
> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
> >>>> (12:1265) : The method setPromoItemDiscount(int) is undefined for the
> type
> >>>> Object
> >>>>
> >>>>
> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
> >>>> (13:1299) : The method setPromoId(String) is undefined for the type
> Object
> >>>>
> >>>>
> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
> >>>> (14:1325) : The method setBundleId(Integer) is undefined for the type
> Object
> >>>>
> >>>>
> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
> >>>> (15:1364) : The method setAggrigatorId(int) is undefined for the type
> Object
> >>>>
> >>>>
> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
> >>>> (22:1702) : The method setProcessed(boolean) is undefined for the type
> >>>> Object
> >>>>
> >>>>
> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
> >>>> (23:1731) : The method setPromoItemDiscount(Double) is undefined for
> the
> >>>> type Object
> >>>>
> >>>>
> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
> >>>> (24:1777) : The method setPromoId(String) is undefined for the type
> Object
> >>>>
> >>>>
> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
> >>>> (25:1803) : The method setBundleId(Integer) is undefined for the type
> Object
> >>>>
> >>>>
> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
> >>>> (26:1842) : The method setAggrigatorId(int) is undefined for the type
> Object
> >>>>
> >>>> Rule Compilation error : [Rule name='Apply 10% discount if you
> purchase
> >>>> 2 items']
> >>>>
> >>>>
> com/example/promotions/promotionEngine/Rule_Apply_10__discount_if_you_purchase_2_items_0.java
> >>>> (23:1592) : The field Bundler.id is not visible
> >>>>
> >>>>
> >>>> On Fri, Sep 9, 2011 at 12:40 PM, Sandeep Bandela <gibsosmat at gmail.com
> >
> >>>> wrote:
> >>>>>
> >>>>> Hi Wolfgang,
> >>>>> This is what I did initially but for product > 2 I didnt find a
> generic
> >>>>> way to do this. following is my first rule. I didnt use field names
> because
> >>>>> it was giving error that member is not accessible. I will attach the
> errors
> >>>>> of each case in a few mins.
> >>>>>
> >>>>> rule "Apply 10% discount if you purchase 2 items"
> >>>>>     dialect "java"
> >>>>>     when
> >>>>>         $s1 : CartItem( getProductId() == 236061, !isProcessed())
> >>>>>         $s2 : CartItem( getProductId() == 236061, getId() !=
> >>>>> $s1.getId(), !isProcessed())
> >>>>>         $m : RuleMessage()
> >>>>>  then
> >>>>>         $m.addMessage("Found item1: " + $s1.getName() + " id:
> >>>>> "+$s1.getId());
> >>>>>         $m.addMessage("Found item2: " + $s2.getName() + " id:
> >>>>> "+$s2.getId());
> >>>>>         modify($s1){
> >>>>>         setProcessed(true),
> >>>>>         setPromoItemDiscount($s1.getPrice() * 0.1),
> >>>>>         setPromoId("1"),
> >>>>>         setBundleId(bundler.getId()),
> >>>>>         setAggrigatorId(1)
> >>>>>         };
> >>>>>         modify($s2){
> >>>>>         setProcessed(true),
> >>>>>         setPromoItemDiscount($s2.getPrice() * 0.1),
> >>>>>         setPromoId("1"),
> >>>>>         setBundleId(bundler.getId()),
> >>>>>         setAggrigatorId(1)
> >>>>>         };
> >>>>>         bundler.increment();
> >>>>> end
> >>>>>
> >>>>> 2011/9/9 Wolfgang Laun <wolfgang.laun at gmail.com>
> >>>>>>
> >>>>>> Your rule exhibits procedural thinking. (For an aspiring rule
> >>>>>> programmer his is typical teething troubles.)
> >>>>>>
> >>>>>> There's no need to collect all A's and B's in order to determine
> their
> >>>>>> number being greater than one or two - this is achieved
> automatically by a
> >>>>>> simple triple match rule. Consider
> >>>>>>
> >>>>>> rule "2A - 1B"
> >>>>>> when
> >>>>>>    $a1: CartItem( productId == "A", processed == false )
> >>>>>>    $a2: CartItem( this != $a1, productId == "A", processed == false
> )
> >>>>>>    $b: CartItem( productId == "B", processed == false )
> >>>>>> then
> >>>>>>    modify( $a1 ){...}
> >>>>>>    modify( $a2 ){...}
> >>>>>>    modify( $b ){...}
> >>>>>> end
> >>>>>>
> >>>>>> Note:
> >>>>>>
> >>>>>> The modify is essential. (When you say "doesn't work", always
> provide
> >>>>>> details.)
> >>>>>> Use the field name rather than the getter call - it improves
> >>>>>> readability.
> >>>>>> I'm not sure whether 5.2.0 final handles boolean fields correctly -
> >>>>>> IIRC, there were some issues. It's possible that CartItem(...,
> !processed)
> >>>>>> works.
> >>>>>>
> >>>>>> -W
> >>>>>>
> >>>>>> 2011/9/8 Sandeep Bandela <gibsosmat at gmail.com>
> >>>>>>>
> >>>>>>> Hi,
> >>>>>>> I am new to rules engine, after going through the examples shipped
> >>>>>>> (shopping.drl, petstore.drl)
> >>>>>>> I am trying to implement promotional discounting using drools 5.2.0
> >>>>>>> final, stateful session. assume cart has all the items that
> customer wants
> >>>>>>> to buy,
> >>>>>>> I am trying to bundle them together with the existing offers
> >>>>>>>
> >>>>>>> rule "Buy X units of Product A and Get Y units of Product B Free"
> >>>>>>>     dialect "java"
> >>>>>>> when
> >>>>>>>     $itemsA : ArrayList( size >= 2) from collect( CartItem(
> >>>>>>> getProductId() == "A", !isProcessed()))
> >>>>>>>     $itemsB : ArrayList( size >= 1) from collect( CartItem(
> >>>>>>> getProductId() == "B", !isProcessed()))
> >>>>>>> then
> >>>>>>>     // current scenario buy 2*A and get 1*B
> >>>>>>>     int x = 2;
> >>>>>>>     int y = 1;
> >>>>>>>     for(int i=0 ; i < x ; i++){
> >>>>>>>         CartItem $ci = (CartItem) $itemsA.get(i);
> >>>>>>>         // modify($ci){setProcessed(true) ... } dosent work
> >>>>>>>         $ci.setProcessed(true);
> >>>>>>>         $ci.setItemDiscount(0.0);
> >>>>>>>         $ci.setBundleId(bundler.getId());
> >>>>>>>     }
> >>>>>>>
> >>>>>>>     for(int i=0 ; i < y  ; i++){
> >>>>>>>         CartItem $ci = (CartItem) $itemsB.get(i);
> >>>>>>>         $ci.setProcessed(true);
> >>>>>>>         $ci.setItemDiscount($ci.getPrice());
> >>>>>>>         $ci.setBundleId(bundler.getId());
> >>>>>>>     }
> >>>>>>>     // global counter to identify bundled items
> >>>>>>>     bundler.increment();
> >>>>>>> end
> >>>>>>>
> >>>>>>> the above rule calculates only for 1 set of offer i.e first 2*A &
> 1*B
> >>>>>>> are considered, rest in the cart are not bundled.
> >>>>>>> if customer buys 4*A + 2*B it dosent consider it. am I missing
> >>>>>>> anything? is this the right way to do it?
> >>>>>>> any feedback is appreciated.
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> --
> >>>>>>> Regards,
> >>>>>>> Sandeep Bandela.
> >>>>>>>
> >>>>>>>
> >>>>>>> _______________________________________________
> >>>>>>> rules-users mailing list
> >>>>>>> rules-users at lists.jboss.org
> >>>>>>> https://lists.jboss.org/mailman/listinfo/rules-users
> >>>>>>>
> >>>>>>
> >>>>>>
> >>>>>> _______________________________________________
> >>>>>> rules-users mailing list
> >>>>>> rules-users at lists.jboss.org
> >>>>>> https://lists.jboss.org/mailman/listinfo/rules-users
> >>>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>> --
> >>>>> Regards,
> >>>>> Sandeep Bandela.
> >>>>>
> >>>>
> >>>>
> >>>>
> >>>> --
> >>>> Regards,
> >>>> Sandeep Bandela.
> >>>>
> >>>
> >>>
> >>>
> >>> --
> >>> Regards,
> >>> Sandeep Bandela.
> >>>
> >>>
> >>> _______________________________________________
> >>> rules-users mailing list
> >>> rules-users at lists.jboss.org
> >>> https://lists.jboss.org/mailman/listinfo/rules-users
> >>>
> >>
> >>
> >> _______________________________________________
> >> rules-users mailing list
> >> rules-users at lists.jboss.org
> >> https://lists.jboss.org/mailman/listinfo/rules-users
> >>
> >
> >
> >
> > --
> > Regards,
> > Sandeep Bandela.
> >
> >
> > _______________________________________________
> > rules-users mailing list
> > rules-users at lists.jboss.org
> > https://lists.jboss.org/mailman/listinfo/rules-users
> >
> >
>
> _______________________________________________
> rules-users mailing list
> rules-users at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-users
>



-- 
Regards,
Sandeep Bandela.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/rules-users/attachments/20110912/bdd67dae/attachment.html 


More information about the rules-users mailing list