Drools - Grouping multiple dsl conditions in dslr&

2019-09-12 08:29发布

问题:

Am creating a small rule engine and using drools for it. My design is like the developer (that's me :)) will develop dsl and a business user can create rules (dslr).

dsl file

[When]When [Pp]urchase amount is greater than "{Value}" = e : Event(EventAction.isPurchaseGreaterThan(e,{Value}))
[When]If [Cc]ustomer tier equals to "{CustomerTier}"=e1 : Event(EventAction.isCustomerTierEqualTo(e1,"{CustomerTier}")
[Then]Give "{Discount}" Percentage Discount = RewardAction.applyDiscount(e, {Discount});
[Then]Suggest Redemption = System.out.println("Redemption Suggested");

dslr file

rule "Discount For Purchase-1"
    when (When purchase amount is greater than "100") && (If customer tier equals to "Silver")
    then     #Error is thrown in this line
        Give "5" Percentage Discount 
end 

The rest of the java code is similar to the one given in examples. In this code am getting the following error

Error

Line 15:4 mismatched input 'then' in rule "Discount For Purchase-1"

Whereas the below dslr works fine

rule "Discount For Purchase-1"
    when (When purchase amount is greater than "100")
    then
        Give "5" Percentage Discount 
end 

Generated DRL

when (e : Event(EventAction.isPurchaseGreaterThan(e,100))) && (e : Event(EventAction.isCustomerTierEqualTo(e,"Silver"))

Note on this Generated DRL - I might get duplicate variable error for 'e'. That's another problem. But just to sort out this problem i've even tried modifing the second variable to 'e1' in dsl.

And for your information i've tried the below to resolve the error, but noting helped me out

When (When purchase amount is greater than "100" && If customer tier equals to "Silver")
When (When purchase amount is greater than "100" and If customer tier equals to "Silver")
When ((When purchase amount is greater than "100") && (If customer tier equals to "Silver"))
When ((When purchase amount is greater than "100") and (If customer tier equals to "Silver"))
When ((When purchase amount is greater than "100") and (If customer tier equals to "Silver"));
When ((When purchase amount is greater than "100") && (If customer tier equals to "Silver"));

Update :

Generated drl

=== DRL xpanded from DSLR ===
   1  #created on: 5 Oct, 2016
   2  package com.test.loyalty.rules
   3  
   4  #list any import classes here.
   5  import com.test.loyalty.*
   6  import com.test.loyalty.model.*
   7  import com.test.loyalty.util.*
   8  
   9  
  10  
  11  #declare any global variables here
  12  
  13  rule "Discount For Purchase-1"
  14      when 
  15        e : Event(EventAction.isPurchaseGreaterThan(e,100))
  16        e1 : Event(EventAction.isCustomerTierEqualTo(e1,"Silver")
  17      then
  18          System.out.println("Redemption Suggested"); 
  19  end
  20  
  21  rule "Discount For Purchase-2"
  22      when
  23          e : Event(EventAction.isPurchaseGreaterThan(e,100))
  24        e1 : Event(EventAction.isCustomerTierEqualTo(e1,"Gold")
  25      then
  26          System.out.println("Redemption Suggested"); 
  27  end
  28  


=============================
[ERR 102] Line 17:4 mismatched input 'then' in rule "Discount For Purchase-1"
17
[ERR 102] Line 25:4 mismatched input 'then' in rule "Discount For Purchase-2"
25
java.lang.IllegalArgumentException: Could not parse knowledge.
    at com.test.loyalty.LoyaltyTest.readKnowledgeBase(LoyaltyTest.java:124)
    at com.test.loyalty.LoyaltyTest.init(LoyaltyTest.java:104)
    at com.test.loyalty.LoyaltyTest.main(LoyaltyTest.java:38)

can somebody help me with this? Thanks in advance.

回答1:

You are about to combine two patterns (using class EventAction) at top level, so no operator is necessary, and && would be wrong for combining patterns anyway - it is available for constraints within patterns.

rule "Discount For Purchase-1"
when
    When purchase amount is greater than "100"
    If customer tier equals to "Silver"
then    
    Give "5" Percentage Discount 
end 

I wonder whether you have indeed the combination of two Event-s in mind. If not, it's better to combine the constraints within one pattern - although this is a bit tricky. (See the doc.) Alternatively, you can indeed force the identity of another fact bound to a second pattern (of the same class) by using something like this == e in an additional constraint.

Edit Now that you have added the expanded text, it stands out: Event(EventAction.isCustomerTierEqualTo(e1,"Silver") misses a closing parenthesis at the end, same thing in the other rule. Fix the substitution rule in the DSL.

You can use the same variable(s) in any number of rules, but you cannot bind two patterns within the same rule to the same variable. You may have to redesign your DSL a little, e.g.

# creates the Person pattern and binds $person
[condition][]There is a Person with=$person:Person()

# write a comparison using a field reference and a value
[condition][]- his {field} {operator} {value}=
             {field} {operator} {value}

The DSLR becomes:

when
    There is a Person with
    - his call_count is less than 10 or name is equal to "Joe" 
    - his points is greater than 5
then

expands to

when
    $person:Person(call_count  <  10 || name == "Joe", points  >  5)
then

Of course, you'll need the definitions for the operators (or your functions)

[condition][]is greater than=>
[condition][]is equal to===

The initial hyphen is essential, and you need something ("his" or "her") in front of the first parameter ({field}).



回答2:

I think something is wrong with the quotes "" in your value 100. Try rewriting as

When]When [Pp]urchase amount is greater than {Value} = = e : Event(EventAction.isPurchaseGreaterThan(e,"{Value}"));

And when writing your rule there is no need to insert quotes. Of course this is true if your Value is String. If it is an int exclude the quotes. another advice in order to see your rules transated you should insert

/# debug: display result

in the start and in the end of your dsl file.