Drools generate filters on rule dinamically - drools

New with JBoss Drools :)
I'm working on a PoC where there's a rule where one or multiple filters can exist. I'm using a template to generate that rule dynamically.
template header
effectiveDate
expirationDate
rule
totalPriceValue
package test.template;
import test.domain.ProductDiscountRequest;
template "value discount template"
rule "Value discount on customer_#{row.rowNumber}"
date-effective "#{effectiveDate}"
date-expires "#{expirationDate}"
when
requestObject : ProductDiscountRequest(#{rule} && totalPrice > #{totalPriceValue});
then
requestObject.addDiscount(5.0d);
end
end template
This template, with the correct input, generates a rule like
package test.template;
import test.domain.ProductDiscountRequest;
rule "Value discount on customer_0"
date-effective "25-Jun-2022 16:00"
date-expires "26-Jun-2030 8:00"
when
requestObject : ProductDiscountRequest(customer == 'TestCustomer' && totalPrice > 30);
then
requestObject.addDiscount(5.0d);
end
There are multiple filters available and they can also be combined, so customer == 'TestCustomer' can also be customer == 'TestCustomer' && custGroup == "TestGroup" and so forth.
I see 3 solutions:
Generate the filtering part in the code and only insert it
Create distinct rules per number of filters (1 rule for 1 filter, 1 rule for 2 filters etc)
Send the filters to the template and generate it there directly
I tried some things but I couldn't get #3 to work. Supposing that there's a list of filters, how do I iterate over it and concatenate it to a full condition?
I'm open to other ideas to make this better.

Related

Where can I see if a pattern failed in rule?

I run a rule that contains a few patterns, I want to know which pattern failed:
I've tried to debug the code (drools 7.18.0), and didn't found the relevant place.
rule example:
rule "Trigger"
agenda-group "Trigger"
salience 100
when
$pcase : PCaseMgr()
D1($id: id, type != null, type == "AAA")
D2(aId == $id)
then
$pcase.printAnalyticsRuleLog(">>>>>>>>>>>>>>>>>>> In Trigger");
end
in the example above, if D1 pattern is passed, and D2 pattern is failed, where in the code (of drools 7.18.0) can i see if the pattern was failed?
You can't. Because of the algorithm Drools uses internally, patterns are decomposed into nodes and nodes can be shared among multiple rules in your knowledge base. If you really need to know why a rule was not fire, then you can create other rules that will tell you that. In your example, you could create something like this:
rule "No Trigger because of No D2"
agenda-group "Trigger"
salience 100
when
$pcase : PCaseMgr()
D1($id: id, type != null, type == "AAA")
not D2(aId == $id)
then
$pcase.printAnalyticsRuleLog(">>>>>>>>>>>>>>>>>>> No Trigger because no D2");
end
Hope it helps,

Drools trigger one rule per item in list input for StatelessKieSession

I am using decision tables and would like to trigger one rule per input item.
I am using decision have set the Sequential = true and defined all rules as part of the same ACTIVATION-GROUP.
When I trigger the drools rules engine using below it just evaluates for the first input item and others are ignored. The behavior I want is to evaluate at most 1 rule per input item (rule order defined by the Salience).
kieStatelessSession.execute(inputList)
I can get this working by sending one item at a time to the kieStatelessSession, but would prefer to execute all at once.
I am using Drools verison 6.5.0.FINAL and Java 7.
There is no out of the box support in Drools for what you are trying to achieve. If you want your rules to be evaluated once for each fact, you will need to code it yourself.
One approach could be to have another type of facts to mark when one of the inputs is processed:
declare Marker
fact : Object
end
//Bellow are the rules that should be coming from your decision table.
//Each rule will do whatever it needs to do, and then it will create a
//Marker fact for the fact that was processed.
//These rules now include a "not" Conditional Element to avoid a fact to be
//evaluated more than once.
rule "Rule 1"
salience 100
when
$fact: Object(...) //your conditions
not Marker(fact == $fact)
then
//... Your logic
insert(new Marker($fact));
end
...
rule "Rule 50"
salience 50
when
$fact: Object(...) //your conditions
not Marker(fact == $fact)
then
//... Your logic
insert(new Marker($fact));
end
Hope it helps,

Drools - Running a rule with an empty object

I'm trying to write a rule to calculate prices for an insurance product based on conditions. In the 'when' I'm using an object called AdditionalDriver, which contains the details for drivers other than the policy holder. From this, different prices can be calculated based on whether the additional driver is a parent, friend, spouse etc. See below:
when
AdditionalDriver($relToProp : relationToProposer)
then
String relToProp = $relToProp;
if(!relToProp.equals("P"))
{
//prices
}
end
"P" = parent.
This rule works when an additional driver has been added. However, if there is no additional driver, then the object is empty, and so the rule does not run. What do I need to do to get this rule to run, even when the object is empty?
Thanks in advance.
You should write one rule for each of the relative or acquaintance classes:
when
PolicyHolder( $phid: id )
AdditionalDriver( relationToProposer == "P", belongsTo == $phid )
then
//prices
end
For no additional driver being requested, write a rule
when
PolicyHolder( $phid: id )
not AdditionalDriver( belongsTo == $phid )
then
// cheaper prices
end
Don't use conditional statement in your consequences to further distinguish facts. This is a code smell.

Size and contains methods of List in Drools

Is it possible write conditions on the basis of size of a list using guided editors (either guided decision table or guided rule) and to check if any element is present in the list?
For eg.
User {
List of badges;
}
now I want to apply condition on number of badges and if a specific badge is in user's list of badges.
Also can I compare to objects. For eg. condition on count of badges of two users?
I'm using KIE Drools Workbench
Here's how source code should look like :-
import com.demo.dto.User;
import com.demo.dto.Badges;
rule "Compare two variables"
when
$badge : Badges()
$user : User(name == "Sam", badges.size() >= 9, $badge memberOf badges)
then
$user.setService($user.getService() + $user.getBadges().size());
end

Reuse of conditions (when) in Drool DSL statements

Is it possible to reuse a when/condition statement into another when/condition statement in a DSL file?
For example, I have two conditions:
[condition][]The client is invalid = Client( name == null || email == null )
[condition][]All the clients are invalid = forall( Client( name == null || email == null ) )
Note that the second condition just diff the first for the forall command, but the statement inside is equals. In these case, I want to reuse the first condition into the second.
Is it possible? How?
Thank you.
even the most recent version of drools will only let you substitute values into a template from pojo's or a corresponding map as per their documentation here.
This won't work for your use case though.
Since drool files are simply text files, there is nothing preventing you from considering a more powerful templating toolkit.
Possibilities include Apache Velocity, ANTLR or Scala!