How to Write a Drools Business Rule
In Part 1 of our Drools tutorial series, we take a look at the anatomy of a business rule in the Drools rule engine.
What is a business rule?
A rule is a single logic statement comprised of a “when” clause (the condition) and a “then” clause (the consequences when the condition is met). A business rule applies this concept to representing concepts in business, for example when to apply a discount or approve a credit application.
Rules engines allow for executing many rules in tandem to achieve complex logic while keeping individual rules concise and easy to understand.
Now, let’s take a look at what makes up a rule.
Anatomy of a rule
A Rule consists of a condition that triggers it (when) and a consequence that performs actions (then) when it is fired.
Regardless of whether you are hand writing a Drools rule or using a guided designer, rules will always have the below structure:
- Rule header - The rule header declares the name of the rule, and must be unique.
- Attributes - This region may contain optional attributes of the rule to modify the execution behavior, grouping, and add additional information.
- Conditions - This region contains zero or more patterns which will match against the facts in memory. If matching facts are found, the actions are performed.
- Consequences - This region specifies the actions to be performed if the rule’s condition is met.
Conditions (when
)
The “when” part of a rule (also known as the Left Hand Side, or LHS, of the rule) contains the conditions that must be met to execute an action. Conditions consist of a series of stated patterns and constraints based on the available data objects.
Driver(age < 21)
.
Patterns match on “Facts”, where are the objects in current working memory of Drools. An example might be a Driver
fact with age
and height
properties. Facts are added into the rules engine knowledge set before execution, and may also be created and modified by rules as they execute.
Consequences (then
)
The “then” part of the rule (also known as the Right Hand Side, or RHS, of the rule) contains the actions to be performed when the conditional part of the rule has been met.
Driver(age < 21)
) and a loan applicant is under 21 years old, then the action of an "Underage" rule would be setApproved(false)
, declining the loan because the applicant is under age.
The main purpose of consequences (rule actions) are to insert, delete, or modify data (also known as “facts”) throughout the execution process.
Effective rule actions are small, declarative, and readable. If you need to use imperative or conditional code in rule actions, then divide the rule into multiple smaller and more declarative rules.
Actions consist of one or more methods that execute consequences based on the rule conditions and on available data objects.
Next, we will take a look at how to write a rule.
Writing the condition (the When)
To define the conditions for a Drools rule to fire, a special pattern syntax is used:
when
Driver( age < 21 )
then
...
Here the condition can contain patterns (Driver(...)
) which will match facts with the same name. Internally the pattern can contain additional constraints, in this case specifying that age
be less than 21 to match. If a matching pattern is found, the action(s) in the “then” section of the rule will be executed. If no matches are found, no action is taken.
Can we have a rule with an empty condition and no patterns? Absolutely. In this case the rule actions always fire, which can be handy for initializing data:
when
// no conditions
then
...
To declare a more specific condition on our Driver fact, say matching a property gender
to “male”, we can separate then with commas:
when
Driver( age < 21, gender == "male" )
then
...
To match on multiple facts, say the presence of an additional Vehicle
fact, we can add each to a new line in the when:
when
Driver( age < 21, gender == "male" )
Vehicle()
then
...
Note the lack of constraints in the Vehicle
fact condition- this instructs the engine to match the rule if any Vehicle exists. Using this simple syntax, each consequence can be thought as having a logical AND
.
To match a condition that does not exist, we can use the not
keyword:
when
not Vehicle()
then
...
This rule will fire if there are no Vehicle
facts inserted into working memory.
Variables
To capture data from a fact, or the entire fact, for use in the rule actions will we need to create variables. The common convention is to name each variable starting with a ‘$’.
To capture an entire fact as a variable, for example our Driver
fact, prefix it with the name of the variable and a colon:
$d : Driver( age < 21, gender == "male" )
If we only need the age, the same convention applies:
Driver( $age : age < 21, gender == "male" )
Generally, capturing only the specific data needed is preferred.
Writing the consequence (the Then)
At this point, we are able to construct a rule that can fire when certain conditions are met. Now, lets look at how to perform some actions.
Inserting and Modifying Facts
Drools provides specific statements that are used to modify, update, insert, or delete facts during rule execution.
The action methods we will focus on for this example are:
-
set
- Modifies a property of a fact, but does not notify the engine -
update
Notifies the engine that a fact was changed from one or moreset
s -
modify
Groups several propertyset
modifications and notifies the engine in one operation -
insert
Inserts a new fact
Lets look at how to insert an Approval
fact if a Driver
is 21 or older.
when
Driver( age >= 21 )
then
insert( new Approval() )
Note that the syntax of the “Then” area is normal Java. If we wanted to set an additional property on our Approval
object, we could do it like this:
when
Driver( age >= 21 )
then
Approval app = new Approval();
app.setDate = new Date();
insert( app )
Now to look at modifying a fact. If we would like to add 1 to a property risk
on a Driver
if under 21, we could use our captured variable like this:
when
$d : Driver( age >= 21, $risk : risk )
then
$d.setRisk = $risk + 1;
update( $d )
Note the required update
action which tells the Drools engine that this fact was updated.
We could, alternatively, use the modify
action which will automatically perform this update for us:
when
$d : Driver( age >= 21, $risk : risk )
then
modify( $d ) {
setRisk = $risk + 1;
}
Using these combinations of patterns and actions, we can begin to achieve some more powerful logic. For example, a second rule could use a pattern that matches when the risk
for a Driver
is greater than 2
, then insert a Denied
fact. We will look at deeper examples of interacting rules like this in Part 2 of this series.
Conclusion
This has been just a small taste of the power of Drools using some simple examples. Be sure to subscribe to get notified of future guides like this, and of course check out our Sparks Platform which can get you up and running with production Drools in minutes.
For more detailed explanations of the rules and their syntax refer to these links: