Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Learn Drools (Part 4): Inferences

DZone's Guide to

Learn Drools (Part 4): Inferences

Learn how you can set up inferences in Drools to create more modular rules that can be changed on the go.

· Java Zone
Free Resource

Learn how to troubleshoot and diagnose some of the most common performance issues in Java today. Brought to you in partnership with AppDynamics.

As per the dictionary, inference means, "An assumption or conclusion that is rationally and logically made, based on the given facts or circumstances."

An inference is based off of facts, so the reasoning for the conclusion is often logical.

Example: According to a technical interview, we can make an assumption that a candidate is good, bad, or moderate. The thing to notice here is that we don’t know how good the candidate is, as we do not work with them, but according the candidate's answers (facts), we can logically judge and come to a conclusion.

So, how do Drools' inferences work?

Let's try to understand it with a problem statement.

We want to give a laptop to those people who are in IT department whose designation is the manager.

When we get this problem statement, we will try to solve it with a Drools rule. Inputting the logic, we use Ifdepertment=="IT" and isManager=true, then we print "Give laptop."

As simple as that.

Solution

rule "give Laptop"
  when
     $dept: Department(name=="IT");
     $emp: Employee(dept == $dept,manager==true);

  then
  $emp.setMessage("Give Laptop");
  System.out.println($emp.getName()+ ": "+$emp.getDept().getName()+ ":"+$emp.getMessage());
end

Is this an elegant way to solve this problem?

The answer depends. If this IT Manager condition check (depertment=="IT" and isManager=true) is used in several rules, then it is not an elegant way to implement it. We can do it better, and here's the potential where we can use Inference.

On other hand, if this condition used only one or in a few rules and no future changes will be needed, then make it simple. The above rule is just fine, as I am a big follower of YAGNI (You aren't gonna need it).

Why is the above not a judicious way to define the rules where the same condition is used in several of them?

Let's say the IT manager condition is used in 100 different rules, and based on that condition, we will take different actions. So far, the condition has not changed, so our design is good. But think about if the condition requirements are changed — now the client wants (department=="IT" and isManager=true and experience>15). Now this experience factor is set to greater than 15, and that has to be taken into account.

So, we need to change the condition in 100 rules. A simple change is then hard to implement because the condition has been duplicated over 100 time.

It would be nice if could we design in a such a way that we can define the condition in one place and use that reference in other places — like soft link in Unix or environment variables in Windows.

By doing that , we can use the reference to the condition in every rule. We set JAVA_HOME="C;//java"; and use JAVA_HOME anywhere to declare a Java path, so in case we change the Java path to c://javaone, that will be reflected everywhere.

Fortunately, we can do the same thing in Drools via an Inference. Let's see how to do it step by step.

Step 1

Create a rule where we define the condition  and create a reference to that in the "then" part, so we can use this reference in other rules.

rule "IT Manager Inference"
   when
      $dept: Department(name=="IT");
      $emp: Employee(dept == $dept,manager==true);
   then
   insert(new ITManager($emp));
end


Please note the then part of the rule, where we insert a Java object called ITManager, which takes the employee reference. With this statement, we instruct Drools to insert an ITManager object into the KnowledgeFactory, which holds the "when" parts. It acts as a reference, like the JAVA_HOME key.

Step 2

Let's create other rules where we use this IT Manager reference.

rule "give Manager Laptop"
   when
      $emp: Employee();
      $itManager: ITManager(emp == $emp);

   then
   $emp.setMessage("Give Laptop");
   System.out.println($emp.getName()+ ": "+$emp.getDept().getName()+ ":"+$emp.getMessage());
end


Pay attention to the "when" part here. We check to see if the current employee is matching the  ITManager condition. Here, Drools replaces ITManger with the actual "when" condition stated in the ITManager inference rule.

Step 3

Let's look at our complete Drools rule file.

package com.rules

import com.example.droolsExample.pojo.Employee
import com.example.droolsExample.pojo.Department
import com.example.droolsExample.pojo.ITManager

rule "IT Manager Inference"
   when
      $dept: Department(name=="IT");
      $emp: Employee(dept == $dept,manager==true);
   then
   insert(new ITManager($emp));
end
rule "give Manager Laptop"
   when
      $emp: Employee();
      $itManager: ITManager(emp == $emp);

   then
   $emp.setMessage("Give Laptop");
   System.out.println($emp.getName()+ ": "+$emp.getDept().getName()+ ":"+$emp.getMessage());
end


This setup ensures any changes in we made will be automatically reflected in our "Give Laptop" rule.

Step 4: Java Objects

Employee.java

package com.example.droolsExample.pojo;

public class Employee {

   String name;
   boolean manager;
   String message;
   Department dept;
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public boolean isManager() {
      return manager;
   }
   public void setManager(boolean manager) {
      this.manager = manager;
   }
   public String getMessage() {
      return message;
   }
   public void setMessage(String message) {
      this.message = message;
   }
   public Department getDept() {
      return dept;
   }
   public void setDept(Department dept) {
      this.dept = dept;
   }
}


ITManager.java

package com.example.droolsExample.pojo;

public class ITManager {

   private Employee emp;
   public ITManager(Employee emp)
   {
      this.emp=emp;
   }


   public Employee getEmp() {
      return emp;
   }

   public void setEmp(Employee emp) {
      this.emp = emp;
   }
}


Department.java

package com.example.droolsExample.pojo;

public class Department {

   String name;

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }
}


DroolTest.java

package com.example.droolsExample;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;

import org.drools.compiler.compiler.DroolsParserException;
import org.drools.compiler.compiler.PackageBuilder;
import org.drools.core.RuleBase;
import org.drools.core.RuleBaseFactory;
import org.drools.core.WorkingMemory;

import com.example.droolsExample.pojo.Department;
import com.example.droolsExample.pojo.Employee;



public class DroolsTest {

   public static void main(String[] args) throws DroolsParserException,
          IOException {
      DroolsTest droolsTest = new DroolsTest();
      droolsTest.executeDroolsEmployee("/com/rules/employeeInfernce.drl");
   }

      public void executeDroolsEmployee(String ruleFile) throws DroolsParserException, IOException {

      PackageBuilder packageBuilder = new PackageBuilder();

      InputStream resourceAsStream = getClass().getResourceAsStream(ruleFile);

      Reader reader = new InputStreamReader(resourceAsStream);
      packageBuilder.addPackageFromDrl(reader);
      org.drools.core.rule.Package rulesPackage = packageBuilder.getPackage();
      RuleBase ruleBase = RuleBaseFactory.newRuleBase();
      ruleBase.addPackage(rulesPackage);

      WorkingMemory workingMemory = ruleBase.newStatefulSession();

      Department dep = new Department();
      dep.setName("Civil");

      Department dep1 = new Department();
      dep1.setName("IT");

      Employee emp = new Employee();
      emp.setName("Shamik Mitra");
      emp.setManager(true);
      emp.setDept(dep1);

      Employee emp1 = new Employee();
      emp1.setName("Samir Mitra");
      emp1.setManager(true);
      emp1.setDept(dep);

      workingMemory.insert(dep);
      workingMemory.insert(dep1);
      workingMemory.insert(emp);
      workingMemory.insert(emp1);
      workingMemory.fireAllRules();

   }

}


Step 5: Output

Shamik Mitra: IT:Give Laptop


And that's it! Congratulations, you've set up an inference.

Understand the needs and benefits around implementing the right monitoring solution for a growing containerized market. Brought to you in partnership with AppDynamics.

Topics:
java ,drools ,inference ,rules

Published at DZone with permission of Shamik Mitra, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}