Drools Albuquerque

From Training Material
Jump to navigation Jump to search

Basic

EX1

rule "01. Select all Salgrade facts"
when 
 $s : Salgrade()
then    
  System.out.println(
     $s.grade + "\t" +
     $s.losal + "\t" +
     $s.hisal);
end

EX2

rule "2 - Select shown data about employees who earn between 1000 and 2000."
//	enabled false
	when
		$e : Emp( sal>=1000, sal<=2000 )
	then
		System.out.println(
			$e.id + " " + 
			$e.name + " " +
			$e.job + " " + 
			$e.mgr + " " +
			$e.hiredate + " " +
			$e.sal + " " +
			$e.deptno);
end

EX3

rule "Clerks in 20"
enabled true
when 
 $e : Emp($e.getJob() == "CLERK" , $e.getDeptno() == 20)
then    
  System.out.println($e.getId() + " " + $e.getName() + "\t" + $e.getJob() 
      + "\t" + $e.getMgr() + " " + $e.getHiredate() + " " + $e.getSal() + " " + $e.getDeptno())
end

EX4

rule "04. Select employees who have a boss."
when 
 //$e : Emp( job in ('SALESMEN', 'CLERK', 'ANALYST'))
 $e : Emp( job not in ('PRESIDENT', 'MANAGER'))
then    
  System.out.println($e.id + " " +
  					 $e.name + " " +
  					 $e.job + " " + 
  					 $e.mgr + " " +
  					 $e.hiredate + " " +
  					 $e.sal + " " +
  					 $e.deptno);
end

EX5

/*
7566 PUTIN	MANAGER   	7839	1981 35700 20
7782 MERKEL	MANAGER   	7839	1981 29400 10
7698 BLAIR	MANAGER   	7839	1981 34200 30
*/
rule "05. Select manager's annual remuneration"
enabled true
when 
 $e : Emp(job == "MANAGER")
then    
  System.out.println($e.id + "\t" 
  			+ $e.name + "\t" 
  			+ $e.job + "\t" 
  			+ $e.mgr + "\t" 
  			+ $e.hiredate + "\t" 
  			+ ($e.sal*12) + "\t" 
                        + $e.deptno)
 end

EX6

/*Expected Output
+-------+
| name |
+-------+
| BLAIR |
+-------+
*/
rule "employees with second letter “L” and third “A”"
when 
 $e : Emp(name matches ".LA.*")
then    
  System.out.println("| " + $e.name + " |")
end

EX7

rule "7 - Find employees whose name ends with N and contains T."
//	enabled false
	when
		$e : Emp( name matches ".*T.*N" )
	then
		System.out.println($e.name);
end

EX8

/* EXPECTED OUTPUT:
+--------+-----------+--------+
| ename  | job       | deptno |
+--------+-----------+--------+
| BUSH   | PRESIDENT | 10     |
| BLAIR  | MANAGER   | 30     |
| PUTIN  | MANAGER   | 20     |
| ELISON | CLERK     | 10     |
+--------+-----------+--------+
*/

rule "08. Find employees who either work as managers or work in department no 10, but not both."
enabled true
when 
 $e : Emp( (job == "MANAGER" && deptno != 10) || 
           (job != "MANAGER" && deptno == 10) )
then    
  System.out.println("+--------+-----------+--------+");
  System.out.printf("| %-6s | %-9s | %-6s |\n", $e.name, $e.job, $e.deptno );

end

Advanced

EX31

rule "31 - Select the name of the employee and the city (LOC column in DEPT table) in which they work"
//	enabled false
	when
		$e : Emp()
		$d : Dept( deptno == $e.deptno )
	then
		System.out.println($e.name + "\t" + $d.loc);
end

EX32

rule "Select the names of the employees, and the name and number of their department"
enabled true
when 
 $e : Emp()
 $d : Dept($e.deptno == deptno)
then    
  System.out.println($e.name + "\t" + $d.dname + "\t" + $d.deptno) 
end

EX33

/* 33. EXPECTED OUTPUT:
+----------+---------+-------+
| ename    | sal     | grade |
+----------+---------+-------+
| BUSH     | 5000.00 | 5     |
| BLAIR    | 2850.00 | 4     |
| MERKEL   | 2450.00 | 4     |
| PUTIN    | 2975.00 | 4     |
| TOOSK    | 3000.00 | 4     |
| CARNEGIE | 3000.00 | 4     |
+----------+---------+-------+
*/

rule "33. Select the names of the employees, their salary and salary grade, but only those whose salary is more than 2000."
enabled false
when 
	e : Emp( sal > 2000 )
	s : Salgrade(e.sal >= losal && e.sal <= hisal)
then    
	System.out.printf("| %-8s | %-4s.00 | %-9s |\n", e.name, e.sal, s.grade );
end

EX34

rule 'London employees'
enabled true
when
	$e : Emp()
	$d : Dept($e.deptno == deptno && loc == 'LONDON')
then
	System.out.println($e.name + '\t' + $d.loc);
end

EX35

rule "35. Select employees and their salary grades except those from London."
enabled true
when
    $d : Dept(loc != "LONDON")
	$e : Emp(deptno == $d.deptno)
	$s : Salgrade(losal <= $e.sal && $e.sal <= hisal)
then
	System.out.println($e.name + "\t" 
  			+ $d.loc + "\t"
  			+ $s.grade)
end

EX36

/* Expected Output
OPERATIONS
*/
rule "Find departments without employees"
enabled true
when 
	d :Dept()
	not (Emp(deptno == d.deptno))    
then
	System.out.println(d.dname)
end

EX37

rule "#37 Employee and their boss"
// enable false
when
   $e :Emp()
   $m :Emp(id == $e.mgr)
then    
  System.out.println($m.name + " manages " + $e.name)
end

EX38

/* 38. EXPECTED OUTPUT:
BUSH
*/
rule "38. Select employees who doesn't have a boss. "
enabled true
when 
	e : Emp()
	not (Emp(e.mgr == id))
then    
	System.out.println(e.name);
end

EX39

rule "39 - Show all employees who have no subordinates"
//	enabled false
	when
		$e: Emp()
		not ( Emp( mgr==$e.id ) )
	then
		System.out.println($e.name);
end

EX41

// Exercise 41
rule "Select employees hired earlier than their bosses"
enabled true
when 
 $e :Emp()
 $m :Emp($e.mgr == $m.id , $e.hiredate < $m.hiredate) 
then    
  System.out.println($e.name + " was hired in " + $e.hiredate
      + " the boss " + $m.name + " was hired in " + $m.hiredate) 
end

EX44

rule "44 - Find jobs which are in department 10 but not in department 20."
//	enabled false
	when
		$e1: Emp( deptno==10 )
		not (Emp( deptno==20, job==$e1.job ))
//		NOTE: this isn't the most stable:
//			If two employees, both in department 10, have the same job, and that job is not in department 20, it will be printed twice.
//			But we can do no better with what we've learned up until this point in the course.
	then
		System.out.println($e1.job);
end

EX23

// Exercise 23 
rule "Find the minimal, maximal and average salaries of people employed in 1981"
enabled true
when
  accumulate (e :Emp(hiredate == 1981), 
  	$avg : average(e.sal),
  	$min : min(e.sal),
  	$max : max(e.sal)
  	) 
then    
  System.out.println( 
   "Average salary: " + $avg + "\n" +
  "Min salary: " + $min + "\n" +
  "Max salary: " + $max + "\n" 
  )
end

EX24

rule "Ex 24. Find the difference between maximal and minimal salary."
when 
	accumulate (e :Emp(), 
  		$min : min(e.sal),
  		$max : max(e.sal)
  	) 
 then    
  System.out.println("Salary range: " + ($max-$min) + ".");
end

EX26

rule "How many managers work for the company?"
enabled true
when 
	 accumulate (e :Emp(job == "MANAGER"), numMgrs : count(e))
then
	System.out.println("Company has " + numMgrs + " managers")
end

EX25

 +-----------+-------------+
 | job       | Average     |
 +-----------+-------------+
 | ANALYST   | 3000.000000 |
 | CLERK     | 1037.500000 |
 | MANAGER   | 2758.333333 |
 | PRESIDENT | 5000.000000 |
 | SALESMAN  | 1400.000000 |
 +-----------+-------------+

declare SalByJob
   job : String
end

rule "#25 - Find the average salary for every post."
//enabled true
when
   Emp(j: job) and
   not SalByJob(j == job)
   accumulate (e :Emp(job == j), $avg : average(e.sal)) 
then    
   System.out.println("Position " + j + " has average salary: " + $avg + "." )
   insert(new SalByJob(j))
end

EX27

/* 27. EXPECTED OUTPUT:
+--------+-----------------+
| deptno | Annual Salaries |
+--------+-----------------+
| 10     | 35000.000000    |
| 20     | 26100.000000    |
| 30     | 18800.000000    |
+--------+-----------------+
*/
declare Deps
   dn : int
end
rule "27. Find the average annual salaries in departments."
enabled true
when
   Emp( d : deptno ) and not Deps( d == dn )
   accumulate ( 
     e : Emp( d == deptno ),
     avg : average((e.sal * 12))   	
   ) 
then    
   System.out.printf("| %s | %.2f |\n", d, avg);
   insert(new Deps(d))
end

EX43

declare AlreadyFiredRule43
	job : String
end
rule "43 - Find post filled in 1982 and 1983."
//	enabled false
	when
		Emp( $post: job, hiredate==1982)
			and not AlreadyFiredRule43( job==$post )
		Emp( job==$post, hiredate==1983)
	then
		System.out.println($post);
		insert(new AlreadyFiredRule43($post));
end
rule "43+"
when
	e1 : Emp(hiredate == 1982)
	e2 : Emp(hiredate == 1983)
	exists (Emp(e1.job == job, e2.job == job))
then
   System.out.println( e1.job)
end

EX28

/* 28. EXPECTED OUTPUT:
+--------+----------+
| deptno | count(*) |
+--------+----------+
| 20     | 5        |
| 30     | 6        |
+--------+----------+
*/  
rule "28. Find departments with more than 3 workers."
enabled true
when
   Dept( d : deptno )
   accumulate ( 
     e : Emp(d == deptno),
     c : count(e)   	
   ) 
   Number(doubleValue > 3) from c
then    
   System.out.printf("| %s | %s |\n", d, c);
end

EX45

rule "45 - Find employees earning more than the manager's (job=='MANAGER') average."
//	enabled false
	when
		accumulate(
			$m : Emp ( job=="MANAGER", $ss: sal ),
			$avg : average($ss)
		)
		$e: Emp( $s: sal>$avg.doubleValue(), $n: name )
	then
		System.out.println($n + " " + $s);
end

EX46

solution 1

/* 46. EXPECTED OUTPUT:
+----------+-----------+---------+
| ename    | job       | sal     |
+----------+-----------+---------+
| ELISON   | CLERK     | 1300.00 |
| BAROSSO  | SALESMAN  | 1600.00 |
| PUTIN    | MANAGER   | 2975.00 |
| TOOSK    | ANALYST   | 3000.00 |
| CARNEGIE | ANALYST   | 3000.00 |
| BUSH     | PRESIDENT | 5000.00 |
+----------+-----------+---------+
*/  
rule "46. Select employees earning the maximum salaries in their positions (jobs). "
enabled false
when
   e : Emp()
   Number(max_sal : longValue) from accumulate (Emp(s: sal, job == e.job), max(s))
   Number(doubleValue == e.sal) from max_sal
then    
   System.out.printf("| %-9s | %-10s | %s.00 |\n", e.name, e.job, e.sal);
end

solution 2 - doesn't work

declare RichJobs
	job: String
	name: String
end
//Example 46
rule "Select employees earning the maximum salaries in their positions (jobs). "
when
	Emp($job: job, $name: name, $sal: sal) and not RichJobs($job == job, $name == name)
	accumulate (
		$e: Emp(job == $job),
		$max: max($e.sal)
	)
	Number($sal == $max) from $max
then
	System.out.println(
  		$name + " | " + $job + " | " + $max + "\n"
  	)
  	insert(new RichJobs($job, $name))
end

EX51

rule "51. Find employees earning more than the average salary in their department."
enabled true
when
	e : Emp()
    Number(longValue < e.sal) from accumulate (Emp(s : sal, deptno == e.deptno), average(s))
then    
   System.out.println(e.name + " " + e.sal + " " + e.deptno);
end

EX55

solution 1

declare AvgDep
	deptno: int
	avg: long
end
 
rule "55.a *Exercise Find the maximum average salary of departments. " enabled true
when 
		$dept : Dept($deptno:deptno,$dname:dname)
		Number($avg : longValue) from accumulate (Emp(deptno==$deptno,  $s: sal),average($s))
then    
  insert(new AvgDep($deptno,$avg))
end
 
rule "55.b " enabled true
when 
		Number($max : longValue) from accumulate (AvgDep($avg: avg),max($avg))
		AvgDep(avg==$max,$deptno:deptno)
		$d: Dept(deptno==$deptno)
then    
  System.out.println($d.dname+' '+$d.deptno+' '+ $max)
end

solution 2

/* 55. EXPECTED OUTPUT:
10     2916.666667
*/  
rule "55. Find the maximum average salary of departments."
enabled true
when
  Number(max_val : doubleValue) from accumulate (
    Dept( d : deptno )
    and
    Number(avg_val : doubleValue) from accumulate (
      Emp(s: sal, deptno == d), average(s)
    ), max(avg_val)
  )
   	
then    
   System.out.printf("%f\n", max_val);
end


insertLogical

Rules

package _30_mvel
import com.nobleprog.FactModel.*
dialect "mvel" 

declare AccessToSecretFile
    emp : Emp
end

rule "Grant access to employees of Dept. 10"
when 
    e : Emp( deptno == 10 )
then    
    insertLogical( new AccessToSecretFile(e) )
end

jUnit test

package com.nobleprog;

import org.junit.Test;
import org.kie.api.KieServices;
import org.kie.api.event.KieRuntimeEventManager;
import org.kie.api.logger.KieRuntimeLogger;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;
import org.kie.internal.logger.KnowledgeRuntimeLoggerFactory;

import com.nobleprog.FactModel.*;

public class Test01 {
        @Test
        public void test1() {
                KieServices ks = KieServices.Factory.get();
                KieContainer kContainer = ks.getKieClasspathContainer();
                KieSession ksession = kContainer.newKieSession("ksession-rules");

                /**
                 * Prepare Data
                 */
                ksession.insert(new Emp(7839, "BUSH", "PRESIDENT", 0, 1981, 5000, 10));
                ksession.insert(new Emp(7782, "MERKEL", "MANAGER", 7839, 1981, 2450, 10));
                ksession.insert(new Emp(7566, "PUTIN", "MANAGER", 7839, 1981, 2975, 20));
                ksession.insert(new Emp(7654, "CHIRACK", "SALESMAN", 7698, 1981, 1250,30));
                ksession.insert(new Emp(7499, "BAROSSO", "SALESMAN", 7698, 1981, 1600,30));
                ksession.insert(new Emp(7844, "GATES", "SALESMAN", 7698, 1981, 1500, 30));
                ksession.insert(new Emp(7900, "BUFFETT", "CLERK", 7698, 1981, 950, 30));
                ksession.insert(new Emp(7521, "WALTON", "SALESMAN", 7698, 1981, 1250,30));
                ksession.insert(new Emp(7902, "TOOSK", "ANALYST", 7566, 1981, 3000, 20));
                ksession.insert(new Emp(7369, "THATCHER", "CLERK", 7902, 1980, 800, 20));
                ksession.insert(new Emp(7788, "CARNEGIE", "ANALYST", 7566, 1982, 3000,20));
                ksession.insert(new Emp(7876, "FORD", "CLERK", 7788, 1983, 1100, 20));
                ksession.insert(new Emp(7934, "ELISON", "CLERK", 7782, 1982, 1300, 10));
                ksession.insert(new Emp(7698, "BLAIR", "MANAGER", 7839, 1981, 2850, 30));

        Emp elison = new Emp(7934, "ELISON", "CLERK", 7782, 1982, 1300, 10);
        FactHandle elisonFH = ksession.insert(elison);
        
                KieRuntimeLogger logger =
                                KnowledgeRuntimeLoggerFactory.newFileLogger((KieRuntimeEventManager) ksession, "/tmp/logicalinsert_exercise");

        ksession.fireAllRules();
        elison.setDeptno(20);
        ksession.update(elisonFH, elison);
        ksession.fireAllRules();
        
                logger.close();
        }
}

DSL

EX1

package rules1
import com.nobleprog.FactModel.*;
import java.lang.Math
dialect "mvel" 

expander  Exercise01.dsl

rule "Rule 1"
 
when
 There are employees earning more than 2000
then
 Show name and salary

end
[condition][]There (is (a|an)|are) {o} {cond}=$e: {o}( {cond} )
[consequence][]Show {f1} and {f2}=System.out.println($e.{f1} + ", " + $e.{f2});
[keyword][Emp]salary=sal
[keyword][]employees?=Emp
[keyword][Emp]earning more than {amt}=sal>{amt}

EX2

[condition][]There is a department which:=d:Dept()
[consequence][]Show department name=System.out.println(d.dname)
[condition][]has at least {c} employees working in it=accumulate(e:Emp(deptno == d.deptno), $countOfEmployees : count(e)) && Number(intValue >= {c}) from $countOfEmployees
[condition][]average salary is greater than {sal}=accumulate(e2:Emp(deptno == d.deptno), $avgSal: average(e2.sal)) &&  Number(doubleValue > {sal}) from $avgSal
package rules2
import com.nobleprog.FactModel.*;
import java.lang.Math
dialect "mvel" 

expander  Exercise02.dsl

rule "Rule 2"
when
 There is a department which:
   has at least 3 employees working in it
   average salary is greater than 2000
then
 Show department name
end

EX3

package rules3
import com.nobleprog.FactModel.*;
import java.lang.Math
dialect "mvel" 

expander Exercise03.dsl


rule "Rule 3"
when
// Make sure that the rule will work for both cases
// There are departments where:
  There is a department where:
//	there are analysts working in 
    there is an analyst working in it
then
 Show department name
 
end
[condition][]There (is a|are) departments? where:=$d :Dept()
[condition][]there (is an|are) analysts? working in( it)?=exists Emp($d.deptno == deptno , job == "ANALYST")
[consequence][]Show department name=System.out.println($d.dname)


Shopping Example

Fact Model

package newpack;

public class FactModel {
	
	public static class Customer {
		
		@Override
		public String toString() {
			return "Customer [name=" + name + ", discount=" + discount + "]";
		}
		public Customer(String name, double discount) {
			super();
			this.name = name;
			this.discount = discount;
		}
		
		private String name;
		private double discount;
		
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public double getDiscount() {
			return discount;
		}
		public void setDiscount(double discount) {
			this.discount = discount;
		}
	}
	
	public static class Purchase {
		@Override
		public String toString() {
			return "Purchase [cust=" + cust + ", prod=" + prod + "]";
		}
		public Purchase(Customer cust, Product prod) {
			super();
			this.cust = cust;
			this.prod = prod;
		}
		private Customer cust;
		private Product prod;
		public Customer getCust() {
			return cust;
		}
		public void setCust(Customer cust) {
			this.cust = cust;
		}
		public Product getProd() {
			return prod;
		}
		public void setProd(Product prod) {
			this.prod = prod;
		}
	}
	
	public static class Discount {
		@Override
		public String toString() {
			return "Discount [cust=" + cust + ", discount=" + discount + "]";
		}
		public Discount(Customer cust, double discount) {
			super();
			this.cust = cust;
			this.discount = discount;
		}
		private Customer cust;
		private double discount;
		public Customer getCust() {
			return cust;
		}
		public void setCust(Customer cust) {
			this.cust = cust;
		}
		public double getDiscount() {
			return discount;
		}
		public void setDiscount(double discount) {
			this.discount = discount;
		}
	
	}
	
	public static class Product {
		public Product(String name, double price) {
			super();
			this.name = name;
			this.price = price;
		}
		@Override
		public String toString() {
			return "Product [name=" + name + ", price=" + price + "]";
		}
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public double getPrice() {
			return price;
		}
		public void setPrice(double price) {
			this.price = price;
		}
		private String name;
		private double price;
	}
}

rules

//created on: Aug 26, 2016
package rules
import newpack.FactModel.*
import java.lang.Math
import java.util.ArrayList
dialect "mvel" 

rule "Notify of purchase"
    when
        p : Purchase()
    then
        System.out.printf("New purchase made: %s\n", p);

end

declare AlreadyFoundCust
   customer : Customer
end 
rule "Set discount for total purchase over 1000"
    when
        c : Customer() and not AlreadyFoundCust(c == customer)
        accumulate( Purchase(product : prod && c == cust), total : sum(product.price))
    then
        System.out.printf("Total: %s\n", total);  
        insert(new AlreadyFoundCust(c))      
end

jUnit

package newpack;

import static org.junit.Assert.*;

import org.junit.Test;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

import newpack.FactModel.*;
@SuppressWarnings("unused")
public class TestSCRules {

	@Test
	public void test() {
		KieServices ks = KieServices.Factory.get();
		KieContainer kContainer = ks.getKieClasspathContainer();
		KieSession ksession = kContainer.newKieSession("ksession-rules");

		/**
		 * Prepare Data
		 */
		Customer cust = new Customer("John", 0.0);
		ksession.insert(cust);
		
		Product prod1 = new Product("Foo", 600);
		ksession.insert(prod1);
		Product prod2 = new Product("Bar", 600);
		ksession.insert(prod2);
		Product prod3 = new Product("Baz", 600);
		ksession.insert(prod3);
		
		Purchase pur1 = new Purchase(cust, prod1);
		ksession.insert(pur1);
		Purchase pur2 = new Purchase(cust, prod2);
		ksession.insert(pur2);
		
		ksession.fireAllRules();
	}

}