Drools

Drools – Stateful vs Stateless Knowledge Session

In previous chapter we implemented a drools project using KieSession to get stateful session. In this tutorial we will try to understand the difference between drools stateful and stateless session using example. Stateless session that forms the simplest use case, not utilizing inference. A stateless session can be called like a function, passing it some data and then receiving some results back. Stateful sessions are longer lived and allow iterative changes over time. Next we execute the same rule file in stateful and stateless session environment and understand the difference.

Stateless SessionStateful Session
Any changes in the facts while executing rules is not made aware to the rule engine.Any changes in the facts while executing rules is made aware to the rule engine.
dispose() method is called automatically to release the session.dispose() method should be called to release the session to avoid memory leaks.
The engine is caused to fire all rules via a call to one of the execute() methods.
The two variants are; 1) pass a single object/fact, or 2) pass an iterable object
that contains the fact(s) that will be used.
Provide a variety of methods to cause the engine to fire the rules (i.e. execute the consequences of rules scheduled for activation).
fireAllRules()
fireAllRules(AgendaFilter filter)
fireAllRules(AgendaFilter filter, int max)
fireAllRules(int max)
fireUntilHalt()
fireUntilHalt(AgendaFilter filter)
Any changes in the facts while executing rules is not made aware to the rule engine so if any rule is modified no other re-activation of rules will take place.As any changes in facts is available to the rule engine so if a rule is modified for a particular fact, this change will re-activate all the rules and fire the rules that are build on modified fact.

1) Drools Stateful Session

Create the project as follows-

Download Drools Stateful Session
Download counts: 2437
  1. After downloading, unzip the project.
  2. Go to Eclipse IDE -> File -> Import -> Maven -> Existing Maven project -> Select the project.

Create the model class Product as follows-

package com.hi.techpoints.model;

public class Product {

	private int productId;
	private String model;

	public Product(int productId, String model) {
		super();
		this.productId = productId;
		this.model = model;
	}

	public int getProductId() {
		return productId;
	}

	public void setProductId(int productId) {
		this.productId = productId;
	}

	public String getModel() {
		return model;
	}

	public void setModel(String model) {
		this.model = model;
	}

}

The rules.drl file will be as follows-

package rules

import com.hi.techpoints.model.Product

rule "Product count 1"
	when 
		$product: Product()
	then
		System.out.println("Product count there (1) : " + $product.getProductId() + " and the model name is : " + $product.getModel());
	end
	
rule "Product count 2"
	when 
		$product: Product()
		accumulate (Product() ; $cnt : count())
	then
		System.out.println("Product count there (2) : " + $product.getProductId() + " and the model name is : " + $product.getModel()
    +" accumaulated value is " +$cnt);
	end
	
rule "Product count 3" 
	when 
		Product()
	then
		System.out.println("Product count there (3) : ");
	end	

Finally we define RunDrools class. Here load the facts and the rules in the drools working memory and firing all the rules. We make use of stateful session for firing the rules.

package com.hi.techpoints;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import com.hi.techpoints.model.Product;

public class RunDrools {

	public static final void main(String[] args) {
		try {
			KieServices ks = KieServices.Factory.get();
			KieContainer kContainer = ks.getKieClasspathContainer();
			KieSession kSession = kContainer.newKieSession("ksession-rule");

			System.out.println("**** Fire rules after inserting product ****");
			Product product1 = new Product(1, "Pixel");
		    kSession.insert(product1);
			kSession.fireAllRules();
			
			System.out.println("**** Fire rules after inserting product ****");
			Product product2 = new Product(2, "Iphone");
		    kSession.insert(product2);
			kSession.fireAllRules();
	

		} catch (Throwable t) {
			t.printStackTrace();
		}
	}

}

On running the RunDrools class as a java application we get the output as-

We have a stateful session here. Initially when Product1 is inserted and rules fired all three rules get fired. Later we insert Product2 and fire rules again. In this case the execution of rule “Product count 2” changes the value of cnt in working memory.

As this is a stateful session so this rule is again executed for Product1 also as working memory value is changed.

2) Drools Stateless Session

Create the eclipse project as follows-

Download Drools Stateless Session
Download counts: 1835
  1. After downloading, unzip the project.
  2. Go to Eclipse IDE -> File -> Import -> Maven -> Existing Maven project -> Select the project.

Create the model class Product as follows-

package com.hi.techpoints.model;

public class Product {

	private int productId;
	private String model;
    
	public Product(int productId, String model) {
		super();
		this.productId = productId;
		this.model = model;
	}

	public int getProductId() {
		return productId;
	}

	public void setProductId(int productId) {
		this.productId = productId;
	}

	public String getModel() {
		return model;
	}

	public void setModel(String model) {
		this.model = model;
	}

}

The rules.drl file will be as follows –

package rules

import com.hi.techpoints.model.Product

rule "Product count 1"
	when 
		$product: Product()
	then
		System.out.println("Product count there (1) : " + $product.getProductId() + " and the model name is : " + $product.getModel());
	end
	
rule "Product count 2"
	when 
		$product: Product()
		accumulate (Product() ; $cnt : count())
	then
		System.out.println("Product count there (2) : " + $product.getProductId() + " and the model name is : " + $product.getModel()
    +" accumaulated value is " +$cnt);
	end
	
rule "Product count 3" 
	when 
		Product()
	then
		System.out.println("Product count there (3) : ");
	end	

Finally we define RunDrools class. Here load the facts and the rules in the drools working memory and firing all the rules. Here we obtain stateless session and execute the rules.

package com.hi.techpoints;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.StatelessKieSession;

import com.hi.techpoints.model.Product;

public class RunDrools {

	public static final void main(String[] args) {
		try {
			KieServices ks = KieServices.Factory.get();
			KieContainer kContainer = ks.getKieClasspathContainer();
			StatelessKieSession kSession = kContainer.newStatelessKieSession();

			System.out.println("**** Fire rules after inserting product ****");
			Product product1 = new Product(1, "Pixel");
		    kSession.execute(product1);
			
			System.out.println("**** Fire rules after inserting product ****");
			Product product2 = new Product(2, "Iphone");
			kSession.execute(product2);
	

		} catch (Throwable t) {
			t.printStackTrace();
		}
	}

}

On running the RunDrools class as a java application we get the output as –

We have a stateless session here. Initially when product1 is inserted and rules executed. Later we insert product2 and execute rules again. In this case the execution of rule “Product count 2” changes the value of cnt in working memory.
As this is a stateless session each session gets disposed after getting executed.

So execution of product1 and product2 are independent of each other

About the Author: Elavarasan PK

Technical Specialist, Intersoft Data Labs