Learn Drools:Part VII Salience

salience in drools:Part VII


One thing is pretty clear to us that How Drools works?

Let's summarize How it works.

Rules are written on the drl files. And facts or POJOs are inserted in Knowledge Base, Rules are applied on each fact, If When part of this rule satisfies with a fact, Then part will execute.

Having said that One question is just pop up my mind

If multiple rules are matched on a fact then which order those rules will be fired ?

The Answer is they will fire arbitrary, There is no sequence for Rules execution.  So if we need a sequence or we want that a rule will fire at first, how we can achieve this?

In Drools we can achieve it through Salience, Salience is a keyword in the .drl file and we can assign a positive or negative number to salience.


This number denotes the priority, Higher number means higher priority, Rule with higher salience number will be executed first by Drools engine.

So If Rule 1 has salience 10 ,Rule 2 has 1 and Rule 3 has 5. Order of execution should be

Rule 1>Rule 3>Rule 2.

By default, the value of salience is 0. So if we do not mention the salience, all rules got the default salience 0.

If multiple rules have same salience , the there will be no order among them but Drools guarantee that they will execute at the same level.

So
So If Rule 1 has salience 10 ,Rule 2 has 10 and Rule 3 has 5. Then

Rule 1 or 2 will be executed first then Rule 3. We can not say which sequence  Rule 1 or Rule 2 will be executed as they have same salience value but we can say that they will execute before Rule 3.

So Execution order will be
Either

Rule 1>Rule 2>Rule 3

Or

Rule 2>Rule 1>Rule 3

It is possible to assign negative value in Salience. But the question is why and when we use a negative value.

The answer is very simple if we want a rule will be fired at last  we provide a negative value as a default value of salience is 0. If salience only accepts positive value then to execute a rule, at last, we have to provide the least value and we know default value of salience is 0. So in this case we have to change salience of all rules, think if a .drl file has 500 entries then we have to provide positive salience for each rule. But as negative value is accepted we just define the rule with negative salience in order to execute at last.


Let see How to use Salience in a problem context.

Say we will give a laptop to that manager who belongs to IT department?

One way to approach this problem is to write Rule in when part check if the department is IT and designation is Manager the give him a laptop. But this is not efficient as every fact execute this irrespective of the department. So if there is a huge number of facts it will execute for each fact .

But we can view this problem in another way, we can filter out fact based on department first then based on designation then give a laptop to remaining facts .

So first give a higher salience to Rule which filter department, here we will check is department is IT . Then give medium salience to designation rule where we check designation is manager after that we give lease/default salience to give laptop rule so it fired last and give the laptop to only filtered facts.

Example:

  1. Drools file employeeSalience.drl

    package com.rules

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

    rule "Not IT" salience 10
    lock-on-active
       when
          $emp: Employee("IT" != dept.getName());
       then
       System.out.println("filter Dept ::" + $emp.getName());
       $emp.setFilter(true);
       update($emp);
    end
    rule "Not Manager" salience 5
    lock-on-active
       when
          $emp: Employee(manager==false);
       then
       System.out.println("filter Manger ::" + $emp.getName());
       $emp.setFilter(true);
       update($emp);
    end
    rule "give Manager Laptop"

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


    2. Employee Object.

    package com.example.droolsExample.pojo;

    public class Employee {
       
       String name;
       boolean manager;
       String message;
       Department dept;
       boolean filter;
       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;
       }
       
       
       public boolean isFilter() {
          return filter;
       }
       public void setFilter(boolean filter) {
          this.filter = filter;
       }
       @Override
       public String toString() {
          return "Employee [name=" + name + ", manager=" + manager + ", message="
                  + message + ", dept=" + dept + "]";
       }
       
       
       
       
       

    }

    3. Department Object:

    package com.example.droolsExample.pojo;

    public class Department {
       
       String name;

       public String getName() {
          return name;
       }

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

    }

    4. DroolsTest.java

    package com.example.droolsExample;

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

    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 org.drools.core.event.AgendaEventListener;
    import com.example.drools.listener.TrackingRuleFiredEventListener;
    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.executeDrools();
          droolsTest.executeDroolsEmployee("/com/rules/employeeSalience.drl");
       }


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

          PackageBuilder packageBuilder = new PackageBuilder();

          //String ruleFile = "/com/rules/employee.drl";
          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 emp2 = new Employee();
          emp2.setName("Swastika Mitra");
          emp2.setManager(false);
          emp2.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.insert(emp2);
          workingMemory.fireAllRules();
         
         
         
       }

    }


    5. Output:

    filter Dept ::Samir Mitra
    filter Manager ::Swastika Mitra
    Shamik Mitra: IT:Give Laptop