EqualsIgnoreCase on Drools - drools

I am trying to rewrite my drl from using regex to equalsIgnoreCase as I think its faster. I am not sure its faster though. However, drools doesn't like it for some reason and I get unknown error.
The one on top works, but the one using equalsIgnoreCase doesn't
rule "name"
salience 0
activation-group "flow"
dialect "mvel"
no-loop true
when
$vurderinger: Vurderinger(vurdering1909 != null &&
vurdering1909.verdi matches "(?i)^FOO$")
then
modify( $vurderinger ) { setVurdering1913(new DroolsType("SHOW")) }
end
rule "name"
salience 0
activation-group "flow"
dialect "mvel"
no-loop true
when
$vurderinger: Vurderinger(vurdering1909 != null &&
eval("FOO".equalsIgnoreCase(vurdering1909.verdi)))
then
modify( $vurderinger ) { setVurdering1913(new DroolsType("SHOW")) }
end
Can anyone spot the mistake?

Within eval, stick to Java: refer to bound variables, use getter.
when
$vurderinger: Vurderinger($v: vurdering1909 != null &&
eval("FOO".equalsIgnoreCase($v.getVerdi())))
then
Edit Not knowing the class definition, the error and the version, I advise using eval/Java, to be on the safe side, no matter what the Drools version is. For 6.3.0, you can omit eval, and it works.
when
$vurderinger: Vurderinger(vurdering1909 != null &&
"FOO".equalsIgnoreCase(vurdering1909.verdi))
then

I have given solution for decision table i.e:
javaObject.getRisk().equalsIgnoreCase("$param")
for drools rules
rule "Rule To Check String Contains"
when
Pojo(name.contains("Loans"))
then
System.out.println(drools.getRule().getName());
end
rule "Rule To Check String Equals"
when
Pojo(name.equals("Personal Loans, Insuarnce"))
then
System.out.println(drools.getRule().getName());
end
rule "Rule To Check String EqualsIgnoreCase"
when
Pojo(name.equalsIgnoreCase("Personal loans, insuarnce"))
then
System.out.println(drools.getRule().getName());
end```

Related

How to control rule evaluation (or rule execution) stages in Drools?

I know that "salience" in Drools provides control under rule execution sequence. But above is an example of the problem when "saliences" cannot help anymore that I've faced with.
Here I have three rules being executed one after another:
rule "Rule 1"
salience 30
when
then
Resource resource1 = new Resource();
resource1.setName("Resource 1");
resource1.setAmount("5");
insert(resource1);
System.out.println("First");
end
rule "Rule 2"
salience 20
//no-loop (interesting, it doesn't lead to a loop)
when
$resource1: Resource(name == "Resource 1")
then
modify($resource1) {setAmount("20")};
System.out.println("Second");
end
rule "Rule 3"
salience 10
when
$resource1: Resource(name == "Resource 1",
Double.parseDouble(amount) > 10)
then
System.out.println("Rule is fired");
end
I expected the third rule is fired and there's a "Rule is fired" line in the console, but it is not executed.
As I understand the issue is with rules evaluation stage when all three rules are evaluated at once before execution and only then are executed according to their "salience" turn.
And on the moment of evaluation $resource1.amount is 5, that is why third rule wasn't fired. If you put a number more than 10 in the first rule the 3d rule will fire. And if you don't set amount at all - it leads to exception.
How can I solve this issue so that the 3d rule fires?
My guess is that Drools doesn't understand that the expression Double.parseDouble(amount) > 10 must be re-evaluated when you change the amount of your fact. The problem is related with the way you are writing your expression.
You can take a look at my answer in this other question. Take a look at the "Another solution" part.
What I would suggest you to do is to modify your model and add a getAmountAsDouble() method to you class so the conversion happens inside it. You will also need to annotate the setAmount() method to let Drools know that it modifies the value returned by getAmountAsDouble():
public class Resource {
private String amount;
#Modifies( { "amountAsDouble" } )
private void setAmount(String amount){
this.amount = amount;
}
private String getAmount(){
return this.amount;
}
private String getAmountAsDouble(){
return Double.parseDouble(this.amount);
}
}
Now your rule can be rewritten as:
rule "Rule 3"
salience 10
when
$resource1: Resource(name == "Resource 1",
amountAsDouble > 10)
then
System.out.println("Rule is fired");
end
Hope it helps,
Look in the docs for Agenda/activation Groups, you can control the execution of rule groups using that concept
So it was a bug and now it is fixed in one of last updates.
Here is the issue: https://issues.jboss.org/browse/DROOLS-3972
I tested the code, and rule3 is fired
drools.version 7.32.0.Final

How to break the loops in Drools, Mvel dialect?

In the below rule the logic in then-part is getting executed for all Child-objects which pass the given condition, I want to break the loop after the logic
in then-part is executed only once, how to do this
rule "test"
when
Parent( $childList : childList != null, childList.empty == false)
Child('testing'.equalsIgnoreCase(attribute)) from $childList
then
// testLogic
end
If you don't need a reference to the Child object (or any of its attributes) in the RHS, then you can use an exists operator:
rule "test"
when
Parent( $childList : childList != null, childList.empty == false)
exists Child('testing'.equalsIgnoreCase(attribute)) from $childList
then
// testLogic
end
If for some reason you do need the Child object or any of its attributes you can do something like this (although is not very nice):
rule "test"
when
Parent( $childList : childList != null, childList.empty == false)
$c: Child('testing'.equalsIgnoreCase(attribute)) from $childList.get(0)
then
// testLogic
end
Hope it helps,
Reason for infinite loop should be known by identifying whether it is self-loop or complex-loop.
Fact modification within the rule activates the same rule (Self)
Fact modification within the rule activates the different rule (complex) and it activates the original rule.
You can use 'no-loop', next to rule name as no-loop true
You can also restrict by using agenda-group, by checking conditions or like a flag. It depends upon your complexity.

Drools Instanceof with Inheritance

I have 5 fact types: BaseFact, AFact, BFact, CFact and DFact.
AFact, BFact, CFact and DFact all inherit from BaseFact.
I have some rules that run on BaseFacts, that I can no longer run on CFacts or DFacts.
What is the best way to modify my BaseFact rules so that they only run on BaseFacts, AFacts and BFacts.
Is there some sort of instanceOf function I can check, like the following?
rule "BaseRule"
when
fact : BaseFact(this instanceOf AFact || this instanceOf BFact)
...
then
...
end
Or do I need to split this rule into 2 new rules, for AFact and BFact?
Even if there is no instanceOf operator, there are several ways to achieve what you are looking for.
These are some ideas:
rule "BaseRule"
when
fact : BaseFact(class == AFact.class || == BFact.class)
...
then
//note that the variable fact is still of type BaseFact
...
end
A nastier version:
rule "BaseRule"
when
fact : BaseFact()
not CFact(this == fact)
not DFact(this == fact)
...
then
//note that the variable fact is still of type BaseFact
...
end
Or:
rule "BaseRule"
when
AFact() OR
BFact()
...
then
//note you can't bind a variable to AFact or BFact
...
end
If you only have 2 concrete types you want to match, then having 2 individual rules doesn't sound like a bad idea either.
Hope it helps,
Quick update: I was also able to use:
rule "MyRow"
dialect "mvel"
when
f1 : Wrapper( eval( nestedProperty#MyNestedClass ), ... )
then
...
end
Which is handy for testing classes of (nested) properties.

Get LHS in drools 6.5 to show in taskform

We have a situation where if rule fails, we need to show what condition is failed. For that I need to show LHS of a particular rule. How can we do that in drools6.5. I am using it in jbpm6.5. Please help.
import java.lang.Number;
rule "parent"
#author(rupesh)
dialect "mvel"
ruleflow-group "grp"
when
obj : Player( totalWinnings >= 10.0 )
then
System.out.println(drools.getRule().getMetaData());
System.out.println(drools.getRule().getMetaAttributes());
System.out.println(drools.getRule());
end
I am not able to get LHS in sysout.
I am assuming that you want to see the LHS values when a rule is not activated to understand why it happened.
To do that, create a function like this:
function boolean debug(double x) {
System.out.println("lhs_debug(): "+x);
return true;
}
and then modify the rule to use it, like this:
rule "parent"
when
obj : Player( debug(totalWinnings), totalWinnings >= 10.0 )
then
System.out.println("activated: "+obj.totalWinnings);
//do something
end
This will show you all attempts to activate the rule and will help you debug when it was not activated.
Please note that it will be very verbose and time consuming, so it should be removed after debugging.

Using declare statement in drl files

I am declaring a SensorMode object in the DRL file
declare SensorMode
modeOffset: Integer
end
I have set the value to modeOffset using
FactType factType=kbase.getFactType("com.yob.pestway.
valueobjects", "SensorMode");
Object nc = factType.newInstance();
factType.set(nc, "modeOffset",sensorDataVO.getModeOffset());
I need to use the modeOffset in the following rule,It gives me an error saying $mode.modeOffset is not visible.
rule "Difference in offsets"
dialect "java"
no-loop true
when
$mode:SensorMode();
$snrData : SensorDataVO(getWeightOffset().size()>0,
$initOffset:getInitialOffset());
then
System.out.println("---modeOffset---"+$mode.modeOffset);
update($snrData);
end
Can you please suggest
Two alternatives:
rule "Difference in offsets"
dialect "java"
no-loop true
when
$mode:SensorMode( $mo: modeOffset );
//...
then
System.out.println("---modeOffset---"+ $mo);
//...
end
Or:
rule "Difference in offsets"
dialect "java"
no-loop true
when
$mode:SensorMode();
//...
then
System.out.println("---modeOffset---"+ $mode.getModeOffset() );
//...
end
It's possible that dialect "mvel" is a third option, but this may depend on the Drools version you are using.