Drools does support "global variables" -- called globals -- but you can't write rules against them. They're generally discouraged, but back in the day it's how you'd usually go about returning values from your rule set.
Here's a simple example with a List
as a global:
global java.util.List result;
rule "All people whose name starts with 'M' will attend"
when
$person: Person( name str[startsWith] "M" )
then
result.add($person);
end
List<Person> attendees = new ArrayList<>();
KieSession session = this.getSession();
session.insert(person);
session.insert(person1);
session.insert(person2);
session.insert(person3);
session.insert(person4);
session.setGlobal("result", attendees);
session.fireAllRules();
// at this point, 'attendees' is populated with the result of the rules
This won't work for you, though because you can't interact with these globals on the left hand side ("when").
What you need, instead, is an intermediate object to haul around your intermediate calculations. Usually I'd suggest storing these values on the objects themselves, but if you have truly derived data, there's nowhere appropriate to store it on your models.
Here's another simple example. Here I track some results in an adhoc object, so I can key off of them in a subsequent rule.
declare Calculations {
intermediateValue1: int
intermediateValue2: double
}
rule "Create tracker object"
when
not(Calculations())
then
insert(new Calculations())
end
rule "Calculate some intermediate value 1"
when
$calc: Calculations()
// some other conditions
then
modify($calc) {
setIntermediateValue1( 42 )
}
end
rule "Calculate some other value using value 1 when > 20"
when
$calc: Calculations( $value1: intermediateValue1 > 20 )
// other conditions
then
modify( $calc ) {
setIntermediateValue2( $value1 * 3 )
}
end
rule "Final calculation"
when
$calc: Calculation( $value1: intermediateValue1 > 0,
$value2: intermediateValue2 > 0 )
// other conditions
then
// do the final calculation
end
The declare
keyword is used to define, effectively, a lightweight class within the DRL itself. It doesn't exist outside of the DRL and can't be referenced in Java. Since we're just tracking intermediate values, that's ok.
The first rule looks to see if we have an instance of our calculated results present in working memory. If it's not, it inserts one.
The inserts
keyword is critical here. It tells Drools that there's new data in its working memory, and that it needs to reevaluate any subsequent rules to determine if they're now valid to fire.
The middle two rules interact with the results object and modify values. Note that instead of just calling the setter (eg. $calc.setIntermediateValue1( 42 )
) I instead use modify
. Similar to insert
, this lets Drools know that this particular object in working memory has been modified, so it reevaluates any rules that rely on this object and determine if it's now valid to execute.
The last rule takes all of the intermediate calculated values and (presumably) does something with them to figure out the 'final' calculated value.
This other answer of mine talks a bit about the different operations (insert
, etc.) that make data changes visible to other rules.