How to Write a Drools Rule (Part 1)

Posted by KimJohn Quinn in guides drools

In Part 1 of our Drools tutorial series, we take a look at how to write a rule for 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 in the body:

when
   // Conditions react to inputs (data or facts)
then
   // Consequences do stuff

Facts

Facts represent the objects in current working memory of Drools. An example might be a Driver fact with age and approved properties.

Facts are added into the rules engine knowledge set before execution, and are made available to the rules. Finally, after execution is finished, the added or modified facts may be retrieved.

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.

Example: If a bank requires loan applicants to be over 21 years of age, then the when condition of an "Underage" rule would be Driver(age < 21).

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.

Example: If a bank requires loan applicants to be over 21 years of age (with a rule condition 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 more sets
  • modify Groups several property set 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.

It is important to note that when you change a fact in the consequence (using *set* or any mutating property) that change updates the fact but does not make the changed data available to other rules. In turn, changes to fact using this approach are not "reactive" and other rules will not be aware of the change unless *update* is called or *modify* is used. Inserted facts, on the other hand, are immediately available to other rules without calling *update*.

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 match a patter were the risk for a Driver was greater than 2 and 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:

guides drools

Subscribe to the Logicdrop Sparks Newsletter

Join hundreds of fellow users for tips, deeps dives, and best practices for implementing business rules and automation.

Try Logicdrop Sparks risk-free for 14 days.

No credit card required. Have questions? Contact us.

closing x