Drools attributes- Salience, update and no-loop | JavaInUse






Drools Tutorials- Understanding attributes salience, update statement and no-loop using Simple Example



Overview

In previous chapter we implemented a drools project to understand backward chaining. In this tutorial we will try to understand the attributes salience, update statement and no-loop.
  • Salience is a prioritization value. Drools uses it in order figure out which drool to fire first when it is the case that the constraints for more than one rule are satisfied.
  • Using update makes the rules engine aware that a fact has been modified. This may cause other depending rules to get fired again.In some scenarios as shown below it cause indefinite looping.
  • Indefinite looping can be avoided using the no-loop attribute as shown in below example.

JBoss Drools - Table of Contents

JBoss Drools Hello World JBoss Drools Hello World-Stateful Knowledge Session using KieSession JBoss Drools- Understanding Drools Decision Table using Simple Example Understand Drools Stateful vs Stateless Knowledge Session Drools Tutorials- Backward Chaining simple example Drools Tutorials- Understanding attributes salience, update statement and no-loop using Simple Example Drools Tutorials- Understanding Execution Control in Drools using Simple Example Drools Tutorials- Integration with Spring MVC Drools Tutorials- Integration with Spring Boot

Video

This tutorial is explained in the below Youtube Video.

Lets Begin

Understanding Salience attribute

For our example here we will use the example of jewellery shop we used before. We will be modifying the files as follows-
In the product class we add an additional field event.
package com.javainuse.model;

public class Product {

	private String type;
	private int discount;
	private String event;

	public String getEvent() {
		return event;
	}

	public void setEvent(String event) {
		this.event = event;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public int getDiscount() {
		return discount;
	}

	public void setDiscount(int discount) {
		this.discount = discount;
	}

}

In the drl file we add the salience attribute.
package com.rule

import com.javainuse.model.Product

rule "Offer for Diamond"
	when 
		productObject: Product(type=="diamond")
	then
		productObject.setDiscount(15);
	end
rule "Offer for Gold"
salience 2
	when 
		productObject: Product(type=="gold")
	then
		productObject.setDiscount(productObject.getDiscount() + 5);
		System.out.println("Offer for Gold");
	end
rule "Offer for Gold on Festival"
salience 3
	when 
		productObject: Product(type=="gold") && Product(event=="sale")
	then
		productObject.setDiscount(productObject.getDiscount() + 5);
		System.out.println("Offer for Gold on Festival");
	end
Both the rules "offer for gold" and "offer for gold on sale" have condition product type=gold. So in this scenario which rule should applied first for gold jewellery? For this we use Salience attribute. The rule with higher salience value will be executed first. So here the rule "offer for gold on sale" will be executed first.
package com.javainuse.main;

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.javainuse.model.Product;

public class DroolsTest {

	public static void main(String[] args) throws DroolsParserException,
			IOException {
		DroolsTest droolsTest = new DroolsTest();
		droolsTest.executeDrools();
	}

	public void executeDrools() throws DroolsParserException, IOException {

		PackageBuilder packageBuilder = new PackageBuilder();

		String ruleFile = "/com/rule/Rules.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();

		Product product = new Product();
		product.setType("gold");
		product.setEvent("sale");
		workingMemory.insert(product);
		workingMemory.fireAllRules();

		System.out.println("The discount for the jewellery product "
				+ product.getType() + " is " + product.getDiscount());
	}

}

Get the output as-
So the discounts of both rules "Offer for Gold on Festival" and "Offer for Gold" get applied in sequence..

Understanding Update attribute

In the product class we add an additional field buyer.
package com.javainuse.model;

public class Product {

	private String type;
	private int discount;
	private String event;
	private String buyer;

	public String getBuyer() {
		return buyer;
	}

	public void setBuyer(String buyer) {
		this.buyer = buyer;
	}

	public String getEvent() {
		return event;
	}

	public void setEvent(String event) {
		this.event = event;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public int getDiscount() {
		return discount;
	}

	public void setDiscount(int discount) {
		this.discount = discount;
	}

}

In drl file we add an additional rule "if customer is platinum". The salience for this rule is 1 which is lower than the salience for other rules. So this rule gets executed last. In this rule we check if the buyer is a platinum customer then an update will be called. This will cause the other two discount rules to be applied again so the discount will be doubled. However we have not used a no-loop attribute here so the rule "if customer is platinum" will get applied indefinitely.
	package com.rule

import com.javainuse.model.Product

rule "Offer for Diamond"
	when 
		productObject: Product(type=="diamond")
	then
		productObject.setDiscount(15);
	end
rule "Offer for Gold"
salience 2
	when 
		productObject: Product(type=="gold")
	then
		productObject.setDiscount(productObject.getDiscount() + 5);
		System.out.println("Offer for Gold");
	end
rule "Offer for Gold on Festival"
salience 3
	when 
		productObject: Product(type=="gold") && Product(event=="sale")
	then
		productObject.setDiscount(productObject.getDiscount() + 5);
		System.out.println("Offer for Gold on Festival");
	end
rule "if customer is platinum"
salience 1
	when 
		productObject: Product(buyer == "platinum")
	then
		System.out.println("This is platinum customer double the discount");
		update(productObject)
	end	
package com.javainuse.main;

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.javainuse.model.Product;

public class DroolsTest {

	public static void main(String[] args) throws DroolsParserException,
			IOException {
		DroolsTest droolsTest = new DroolsTest();
		droolsTest.executeDrools();
	}

	public void executeDrools() throws DroolsParserException, IOException {

		PackageBuilder packageBuilder = new PackageBuilder();

		String ruleFile = "/com/rule/Rules.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();

		Product product = new Product();
		product.setType("gold");
		product.setEvent("sale");
		workingMemory.insert(product);
		product.setBuyer("platinum");
		workingMemory.fireAllRules();

		System.out.println("The discount for the jewellery product "
				+ product.getType() + " is " + product.getDiscount());
	}

}

Get the output as-

Understanding no loop attribute


In drl file we add an attribute no-loop for rule "if customer is platinum". This avoids our rule getting executed indefinitely and gets executed only once.
	package com.rule

import com.javainuse.model.Product

rule "Offer for Diamond"
	when 
		productObject: Product(type=="diamond")
	then
		productObject.setDiscount(15);
	end
rule "Offer for Gold"
salience 2
	when 
		productObject: Product(type=="gold")
	then
		productObject.setDiscount(productObject.getDiscount() + 5);
		System.out.println("Offer for Gold");
	end
rule "Offer for Gold on Festival"
salience 3
	when 
		productObject: Product(type=="gold") && Product(event=="sale")
	then
		productObject.setDiscount(productObject.getDiscount() + 5);
		System.out.println("Offer for Gold on Festival");
	end
rule "if customer is platinum"
salience 1
no-loop true
	when 
		productObject: Product(buyer == "platinum")
	then
		System.out.println("This is platinum customer double the discount");
		update(productObject)
	end	
package com.javainuse.main;

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.javainuse.model.Product;

public class DroolsTest {

	public static void main(String[] args) throws DroolsParserException,
			IOException {
		DroolsTest droolsTest = new DroolsTest();
		droolsTest.executeDrools();
	}

	public void executeDrools() throws DroolsParserException, IOException {

		PackageBuilder packageBuilder = new PackageBuilder();

		String ruleFile = "/com/rule/Rules.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();

		Product product = new Product();
		product.setType("gold");
		product.setEvent("sale");
		product.setBuyer("platinum");
		workingMemory.insert(product);
		workingMemory.fireAllRules();

		System.out.println("The discount for the jewellery product "
				+ product.getType() + " is " + product.getDiscount());
	}

}

Get the output as-
If the buyer is not a platinum customer only the rules "Offer for Gold" and "Offer for Gold on Festival" will get applied once. If the buyer is a platinum customer the rules "Offer for Gold" and "Offer for Gold on Festival" will get applied twice, once before the update call and once after the update call.So the discount gets applied twice if the customer is a platinum customer.

Download Source Code

Download it - Drools attributes example
JBoss Drools Hello World
JBoss Drools Hello World-Stateful Knowledge Session using KieSession
JBoss Drools- Understanding Drools Decision Table using Simple Example
Understand Drools Stateful vs Stateless Knowledge Session
Drools Tutorials- Backward Chaining simple example
Drools Tutorials- Understanding Execution Control in Drools using Simple Example
Drools Tutorials- Integration with Spring
Drools Interview Questions
Drools-Main Menu.