Drools dynamic salience - drools

global Integer rank1;
global Integer rank2;
rule "Data"
salience 10
when
req : Requests(status == "ON")
then
drools.getWorkingMemory().setGlobal("rank1", 8);
drools.getWorkingMemory().setGlobal("rank2", 6);
end
rule "1" extends "Data"
salience 8
when
req1 : Requests()
then
System.out.print("1");
end
rule "2" extends "Data"
salience 6
when
req2 : Requests()
then
System.out.print("2");
end
Here rank1 and rank2 are initialised as 0 in java code.
the output is 11112222.
i want the same output but instead of using static salience, i want it dynamic.
rule "1" extends "Data"
salience rank1
.......
but the code output is 21212121.

You need to set the globals before you insert the facts. Globals are not evaluated dynamically.
If you really need a more dynamic salience you should create a class
class Salience {
private int rank1;
private int rank2;
// ...
}
and insert a fact with appropriate values and change them as required. You'll then need the pattern added to the root rule:
rule "Data"
when
Salience( $rank1: rank1, $rank2: rank2 )
Requests(...)
then
and you can use $rank1 and $rank2 in salience attributes.
Note: Almost certainly there is a solution to your problem that can be expressed in logic and without salience, the usage which is almost always a design flaw.

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

Don'ing a Trait Looses the Map-Based Fact it Proxys

We are running into an issue with Drools when we try to "don" a trait to a map-based model.
It appears that after don'ing the trait the map-based fact it is proxying disappears (or gets retracted).
There does not seem to be any issue using the trait properties to get to the model properties.
In the scenario below the expectation is:
A populated map-based fact is supplied to the engine.
We modify the map-based fact based on constraints in a rule.
We check the constraints against the map fact and apply the trait.
We use the trait and the model in subsequent rules.
In rule 5, regardless of whether I add a 'bmi' property to the trait and try to set that and/or put the property in the map-based fact, it still does not even get to this rule (or anything after rule 3).
We are trying to use the model, mostly for constraints and updates, then within the rules apply and use traits to give us a stronger-typed fact and easier rule constraining.
Test Case:
public class TraitDonningTest extends CommonTestMethodBase
{
#Test
public void should_see_map_after_don() throws IOException
{
final String rule = Files.asCharSource(new File("src/test/resources/rules/traits.drl"), Charset.defaultCharset())
.read();
KieSession ks = loadKnowledgeBaseFromString(rule).newKieSession();
TraitFactory.setMode(VirtualPropertyMode.MAP, ks.getKieBase());
MyModel model = new MyModel();
model.put("weight", 1.0);
ks.insert(model);
ks.fireAllRules();
//We should have an updated BMI here
assertEquals(3.0, model.get("bmi"));
}
/**
* The real model based off of a map
*/
public static class MyModel extends HashMap<String, Object>
{
}
}
Rules:
package drools
import TraitDonningTest.MyModel
declare MyModel
#Traitable
end
declare trait MyTrait
#PropertyReactive
height : Double
weight : Double
end
rule "1 - Update Model"
when
$model: MyModel(
this['weight'] != null,
this['height'] == null )
then
modify($model) {
put('height', 2.0)};
System.out.println("Rule 1");
end
rule "2 - Apply Trait"
dialect "mvel"
no-loop
when
$model: MyModel(
this['weight'] != null,
this['height'] != null)
then
System.out.println("Rule 2A: " + $model.get('weight') + " (before don)");
MyTrait trait = don($model, MyTrait.class);
System.out.println("Rule 2B: " + $model.get('weight') + " (after don)");
System.out.println("Rule 2C: " + trait.weight );
end
rule "3 - Check Trait"
dialect "mvel"
when
$trait : MyTrait()
then
System.out.println("Rule 3: " + $trait.weight);
end
rule "4 - Check Model"
dialect "mvel"
when
MyTrait()
$model: MyModel()
then
System.out.println("Rule 4A: " + $model.get('height'));
System.out.println("Rule 4B: " + $model.get('weight'));
end
rule "5 - Compute Map"
when
$model : MyModel()
MyTrait(
$height : height,
$weight : weight)
then
double compute = $height + $weight;
modify($model) {
put('bmi', compute)};
System.out.println("Rule 5: " + $model.get('bmi'));
end
rule "6 - Summarize Results"
when
$a: Number() from accumulate( MyModel(), count(1) )
$b: Number() from accumulate( MyTrait(), count(1) )
then
System.out.println("Model: " + $a);
System.out.println("Trait: " + $b);
end
Output:
Rule 1
Rule 2A: 1.0 (before don)
Rule 2B: 1.0 (after don)
Rule 2C: 1.0
Rule 3: 1.0
Model: 0
Trait: 1
More details and testing...
I tried a few different scenarios using a strong-typed class as the fact rather than the map.
If I replace the map-based fact with a strong-typed fact the output is what I would expect:
Rule 1
Rule 2A: 1.0 (before don)
Rule 2B: 1.0 (after don)
Rule 2C: 1.0
Rule 3: 1.0
Rule 4A: 2.0
Rule 4B: 1.0
Rule 5: 3.0
Model: 1
Trait: 1
If I make the strong-typed fact (class) extend HashMap, even though I have the properties in the trait, it reverts back to the non-working result set.
Rule 1
Rule 2A: 1.0 (before don)
Rule 2B: 1.0 (after don)
Rule 2C: null
Rule 3: null
Model: 0
Trait: 1

EqualsIgnoreCase on 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```

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.

Unable to get data in an object in .drl file

I have two rules in my .drl file
rule "Monitor"
when
s : Test1( type == Test1.X )
n : Test123()
then
n.monitor();
drools.setFocus("Rules");
end
rule "Utilization"
agenda-group "Rules"
when
s : Test1( type == Test1.X , newValue > oldValue )
n : Test123()
then
//Do something
end
monitor() is a method in the class Test123, and this method sets values to some variables in the class Test1, by using Getters and Setters. And this method returns an object 'object'. In my second rule I want to compare values (newValue > oldValue) in the object 'object'. How can I perform this operation.
You can save the old value in global variable and compare with it in second rule.