Mvel

Facts used during course

Emp

id name job mgr hiredate sal deptno
7839 BUSH PRESIDENT 0 1981 5000.00 10
7698 BLAIR MANAGER 7839 1981 2850.00 30
7782 MERKEL MANAGER 7839 1981 2450.00 10
7566 PUTIN MANAGER 7839 1981 2975.00 20
7654 CHIRACK SALESMAN 7698 1981 1250.00 30
7499 BAROSSO SALESMAN 7698 1981 1600.00 30
7844 GATES SALESMAN 7698 1981 1500.00 30
7900 BUFFETT CLERK 7698 1981 950.00 30
7521 WALTON SALESMAN 7698 1981 1250.00 30
7902 TOOSK ANALYST 7566 1981 3000.00 20
7369 THATCHER CLERK 7902 1980 800.00 20
7788 CARNEGIE ANALYST 7566 1982 3000.00 20
7876 FORD CLERK 7788 1983 1100.00 20
7934 ELISON CLERK 7782 1982 1300.00 10

Dept

deptno dname loc
10 ACCOUNTING NEW YORK
20 RESEARCH LONDON
30 SALES PARIS
40 OPERATIONS BERLIN

Salgrade

+-------+-------+-------+ | grade | losal | hisal | +-------+-------+-------+ | 1 | 700 | 1200 | | 2 | 1201 | 1400 | | 3 | 1401 | 2000 | | 4 | 2001 | 3000 | | 5 | 3001 | 9999 | +-------+-------+-------+

Filtering

根据Fact Type过滤

Find all facts of Emp type

when
	e : Emp()
then    
    System.out.println(
       e.id + " " + 
       e.name + "\t" + 
       e.job + "   \t" +
       e.mgr  + "\t" +
       e.hiredate + " " + 
       e.sal + " " + 
       e.deptno );
end
1
2
3
4
5
6
7
8
9
10
11
12

根据field过滤

when
  e : Emp(sal > 1500)
then    
    System.out.println(e.id + " " + e.name + "\t" + e.job  
    + "   \t" +  e.mgr  + "\t" + e.hiredate + " " + e.sal
     + " " + e.deptno );
end
1
2
3
4
5
6
7

Operators 操作符

操作符有很多种类:

  • Arithmetic operators (+, -, *, /, %) 算数操作符
  • Relational operators (>, >=, ==, !=) 关系操作符
  • Logical operators 逻辑操作符
  • conjunction (and, &&, ",") 与
  • disjunction (or, ||) 或
  • negation (!, do not confuse with not) 取反 (!, 不要和 not 混淆)
  • Drools operators (in, matches, etc...) | Drools 操作符 (in, matches, 等等...)
$e : Emp(sal > 1500, deptno == 10 || deptno == 20) 
$e : Emp(sal > 1500 && deptno == 10 || deptno == 20) 
1
2

Relational Operators 关系操作符 "=""

搜索 managers

rule "Sample"
when
   e : Emp(job == "MANAGER")
1
2
3
7566 PUTIN	MANAGER   	7839	1981 2975 20
7782 MERKEL	MANAGER   	7839	1981 2450 10
7698 BLAIR	MANAGER   	7839	1981 2850 30
1
2
3

1982雇佣的人

when
   e : Emp(hiredate == 1982)
1
2
7934 ELISON	CLERK   	7782	1982 1300 10
7788 CARNEGIE	ANALYST   	7566	1982 3000 20
1
2

选择除了clerks之外的所有人.

when
  e : Emp(job != 'CLERK')
1
2
7788 CARNEGIE	ANALYST   	7566	1982 3000 20
7902 TOOSK	ANALYST   	7566	1981 3000 20
7521 WALTON	SALESMAN   	7698	1981 1250 30
7844 GATES	SALESMAN   	7698	1981 1500 30
7499 BAROSSO	SALESMAN   	7698	1981 1600 30
7654 CHIRACK	SALESMAN   	7698	1981 1250 30
7566 PUTIN	MANAGER   	7839	1981 2975 20
7782 MERKEL	MANAGER   	7839	1981 2450 10
7698 BLAIR	MANAGER   	7839	1981 2850 30
7839 BUSH	PRESIDENT   	0	1981 5000 10
1
2
3
4
5
6
7
8
9
10

选择收入在1000和2000之间的人 (inclusive)

when
  e : Emp(sal >= 1000 , sal <= 2000)
1
2
7934 ELISON	CLERK   	7782	1982 1300 10
7876 FORD	CLERK   	7788	1983 1100 20
7521 WALTON	SALESMAN   	7698	1981 1250 30
7844 GATES	SALESMAN   	7698	1981 1500 30
7499 BAROSSO	SALESMAN   	7698	1981 1600 30
7654 CHIRACK	SALESMAN   	7698	1981 1250 30
1
2
3
4
5
6

下面所有语句功能一样

e : Emp(sal >= 1000 , sal <= 2000)
e : Emp(sal >= 1000 && sal  <= 2000)
e : Emp(sal >= 1000 && <= 2000)
1
2
3

"in" operator 操作符

in 操作符检查值是否存在于某个集合内 选择在No.10 或者No.20部门工作的人

when
  e : Emp(deptno in (10,20))
1
2
7934 ELISON	CLERK   	7782	1982 1300 10
7876 FORD	CLERK   	7788	1983 1100 20
7788 CARNEGIE	ANALYST   	7566	1982 3000 20
7369 THATCHER	CLERK   	7902	1980 800 20
7902 TOOSK	ANALYST   	7566	1981 3000 20
7566 PUTIN	MANAGER   	7839	1981 2975 20
7782 MERKEL	MANAGER   	7839	1981 2450 10
7839 BUSH	PRESIDENT   	0	1981 5000 10

```bash
上面的语句也可以写成
```java
 e : Emp(deptno == 10 || deptno == 20)
 e : (Emp(deptno == 10) or Emp(deptno == 20))
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Drools引擎对上两行的评估方式完全不同 关键字or 会将规则分割成两个规则 详情请看 RETE TREE 的举例说明!

选择 managers 或者 clerks.

when
  e : Emp(job in ('CLERK','MANAGER'))
1
2
7934 ELISON	CLERK   	7782	1982 1300 10
7876 FORD	CLERK   	7788	1983 1100 20
7369 THATCHER	CLERK   	7902	1980 800 20 
7900 BUFFETT	CLERK   	7698	1981 950 30
7566 PUTIN	MANAGER   	7839	1981 2975 20
7782 MERKEL	MANAGER   	7839	1981 2450 10
7698 BLAIR	MANAGER   	7839	1981 2850 30
1
2
3
4
5
6
7

matches 操作符

'maches' 操作符检查值是否与模式匹配 (java 正则表达式).

  • 匹配一个单一字符
  • 匹配任何字符, 包括空(没有)字符. More information: http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html

选择名字以 "B" 开头的人.

when
    e: Emp(name matches "B.*")

1
2
3
7900 BUFFETT	CLERK   	7698	1981 950 30
7499 BAROSSO	SALESMAN   	7698	1981 1600 30
7698 BLAIR	MANAGER   	7839	1981 2850 30
7839 BUSH	PRESIDENT   	0	1981 5000 10
1
2
3
4

选择名字的第二个字符是‘a’的人

when
    e: Emp(name matches ".A.*")
1
2
7788 CARNEGIE	ANALYST   	7566	1982 3000 20
7521 WALTON	SALESMAN   	7698	1981 1250 30
7844 GATES	SALESMAN   	7698	1981 1500 30
7499 BAROSSO	SALESMAN   	7698	1981 1600 30
1
2
3
4

not matches 操作符

 when
    e: Emp(name not matches "B.*")
1
2

这样写语法是不正确的:

 when
    e: Emp(name ! matches "B.*")
    e: ! Emp(name matches "B.*")
1
2
3

组合条件 你可以使用逻辑操作符书写组合条件

  • "and", "&&", "," (conjunction) (与)
  • "or", "||" (disjunction) (或)
  • "not", "!" (negation) (反) Examples 搜索收入高于2500的managers
when
    e: Emp(job == "MANAGER" , sal > 2500) 
7566 PUTIN	MANAGER   	7839	1981 2975 20
7698 BLAIR	MANAGER   	7839	1981 2850 30
1
2
3
4

下面的语句运行结果一致

when
    e: Emp(job == "MANAGER" && sal > 2500) 
1
2

注意 "," 和 "&&" 优先级不同

Operators priority 操作符优先级

(nested) property access    .	
List/Map access            [ ]	
constraint binding   :	
multiplicative       * / %	 
additive             + -	 
shift                << >> >>>	 
relational           < > <= >= instanceof	 
equality             == !=	
bit-wise non-short circuiting AND               &	 
bit-wise non-short circuiting exclusive OR	^	 
bit-wise non-short circuiting inclusive OR	|	 
logical AND	&&	 
logical OR	||	 
ternary	? :	 
Comma separated AND	,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

从多个Fact Types中选择数据

笛卡儿积 (直积)

rule "Sample"
when
   d :Dept()
   e :Emp()
then    
  System.out.println(e.name + "\t" + d.dname)
end
1
2
3
4
5
6
7
ELISON	OPERATIONS
ELISON	SALES
ELISON	RESEARCH
ELISON	ACCOUNTING
FORD	OPERATIONS
FORD	SALES
FORD	RESEARCH
FORD	ACCOUNTING
...
BUSH	OPERATIONS
BUSH	SALES
BUSH	RESEARCH
BUSH	ACCOUNTING
1
2
3
4
5
6
7
8
9
10
11
12
13

about this cross product ,refer:https://docs.jboss.org/drools/release/7.14.0.Final/drools-docs/html_single/#_cross_products

只选择那些在两个fact types中都匹配deptno的数据

rule "Sample"
when
  d :Dept()
  e :Emp(d.deptno == deptno)
then    
  System.out.println(e.name + "\t" + d.dname)
end
1
2
3
4
5
6
7
ELISON	ACCOUNTING
FORD	RESEARCH
CARNEGIE	RESEARCH
THATCHER	RESEARCH
TOOSK	RESEARCH
WALTON	SALES
BUFFETT	SALES
GATES	SALES
BAROSSO	SALES
CHIRACK	SALES
PUTIN	RESEARCH
MERKEL	ACCOUNTING
BLAIR	SALES
BUSH	ACCOUNTING
1
2
3
4
5
6
7
8
9
10
11
12
13
14

寻找员工姓名和工资等级

rule "Sample"
when
   s :Salgrade()
   e :Emp(sal >= s.losal && <= s.hisal)
then    
  System.out.println(e.name + "\t" + s.grade)
end
1
2
3
4
5
6
7
ELISON	2
FORD	1
CARNEGIE	4
THATCHER	1
TOOSK	4
WALTON	2
BUFFETT	1
GATES	3
BAROSSO	3
CHIRACK	2
PUTIN	4
MERKEL	4
BLAIR	4
BUSH	5
1
2
3
4
5
6
7
8
9
10
11
12
13
14

更加复杂的例子

rule "Sample"
when
   s :Salgrade()
   d :Dept()
   e :Emp(sal >= s.losal && <= s.hisal, d.deptno == deptno)
then    
  System.out.println(e.name + "\t" + s.grade + "\t" + d.dname )
end

1
2
3
4
5
6
7
8
9
ELISON	2	ACCOUNTING
FORD	1	RESEARCH
CARNEGIE	4	RESEARCH
THATCHER	1	RESEARCH
TOOSK	4	RESEARCH
WALTON	2	SALES
BUFFETT	1	SALES
GATES	3	SALES
BAROSSO	3	SALES
CHIRACK	2	SALES
PUTIN	4	RESEARCH
MERKEL	4	ACCOUNTING
BLAIR	4	SALES
BUSH	5	ACCOUNTING
1
2
3
4
5
6
7
8
9
10
11
12
13
14

搜索特别事实

寻找有雇员的部门

when
   d :Dept()
   exists (Emp(deptno == d.deptno))
then    
  System.out.println( d.dname )
1
2
3
4
5
ACCOUNTING
RESEARCH
SALES
1
2
3

寻找没有雇员的部门

when
   d :Dept()
   not (Emp(deptno == d.deptno))
then    
  System.out.println( d.dname )
1
2
3
4
5
OPERATIONS
1

寻找同一类型的facts

一份谁是谁上级的报告

rule "Sample"
when
   e :Emp()
   m :Emp(m.id == e.mgr)
then    
  System.out.println( e.name + " reports to " + m.name )
end
1
2
3
4
5
6
7
ELISON reports to MERKEL
FORD reports to CARNEGIE
CARNEGIE reports to PUTIN
THATCHER reports to TOOSK
TOOSK reports to PUTIN
WALTON reports to BLAIR
BUFFETT reports to BLAIR
GATES reports to BLAIR
BAROSSO reports to BLAIR
CHIRACK reports to BLAIR
PUTIN reports to BUSH
MERKEL reports to BUSH
BLAIR reports to BUSH
1
2
3
4
5
6
7
8
9
10
11
12
13

累计函数

Drools 有一些 累计(accumulate)函数:

  • average
  • min
  • max
  • count
  • sum

寻找整个公司的平均工资

when
  accumulate (e :Emp(), avg : average(e.sal)) 
then    
System.out.println(avg)
1
2
3
4
 2073
1

还可以写成:

when
   avg: Number() from accumulate (Emp(s: sal),average(s))
then    
   System.out.println(avg)
1
2
3
4
accumulate (e: Emp(), avg: average(e.sal))
  e:Emp(sal >  
    (Double)avg
  )
then
  System.out.println(e.name + "\t" + e.sal + " average is "  + avg)
end
1
2
3
4
5
6
7

Multi-function Accumulates

你可以一次使用多个累计函数:

when
  accumulate (e :Emp(), 
  	$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"
  )
1
2
3
4
5
6
7
8
9
10
11
12
Average salary: 2073.214285714286
Min salary: 800.0
Max salary: 5000.0
1
2
3

Groups 组

一个组包含了属性值相同的facts。 在统计学里也叫做factor levels.

| CARNEGIE | ANALYST   | 3000.00 |
| TOOSK    | ANALYST   | 3000.00 |
| ELISON   | CLERK     | 1300.00 |
| FORD     | CLERK     | 1100.00 |
| THATCHER | CLERK     | 800.00  |
| BUFFETT  | CLERK     | 950.00  |
| PUTIN    | MANAGER   | 2975.00 |
| MERKEL   | MANAGER   | 2450.00 |
| BLAIR    | MANAGER   | 2850.00 |
| BUSH     | PRESIDENT | 5000.00 |
| GATES    | SALESMAN  | 1500.00 |
| BAROSSO  | SALESMAN  | 1600.00 |
| WALTON   | SALESMAN  | 1250.00 |
| CHIRACK  | SALESMAN  | 1250.00 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14

这里有五个job组:ANALYST, CLERK, MANAGER, PRESIDENT and SALESMAN.

rule "Sample"
when
  Emp(j: job) 
  accumulate (e :Emp(job == j),    	$avg : average(e.sal)  	) 
then    
  System.out.println(   "Average salary in position " + j + "is: " + $avg ) 
end
1
2
3
4
5
6
7
Average salary in position CLERKis: 1037.5
Average salary in position CLERKis: 1037.5
Average salary in position ANALYSTis: 3000.0
Average salary in position CLERKis: 1037.5
Average salary in position ANALYSTis: 3000.0
Average salary in position SALESMANis: 1400.0
Average salary in position CLERKis: 1037.5
Average salary in position SALESMANis: 1400.0
Average salary in position SALESMANis: 1400.0
Average salary in position SALESMANis: 1400.0
Average salary in position MANAGERis: 2758.3333333333335
Average salary in position MANAGERis: 2758.3333333333335
Average salary in position MANAGERis: 2758.3333333333335
Average salary in position PRESIDENTis: 5000.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Declaring and inserting new facts 声明和插入新的facts

上面的解决方法的问题是它重复了 (循环) 14 次 (雇员的数量).

要解决这个问题,我们可以标记“已经处理过的组”。我们可以通过“插入一个新的fact SalByJob"实现这个,然后我们检查是否已经计算出了平均值

not SalByJob(j == job)
1
declare SalByJob
   job : String
   avgSal : Double
end

rule "Sample"
when
   Emp(j: job) and
   not SalByJob(j == job)
   accumulate (e :Emp(job == j), 	$avg : average(e.sal)   	) 
then    
   System.out.println(   "Average salary in position " + j + "is: " + $avg + "\n" )
   insert(new SalByJob(j,$avg))
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
declare SalByJob
   job : String
end

rule "Sample"
when
   Emp(j: job) and
   not SalByJob(j == job)
   accumulate (e :Emp(job == j), 	$avg : average(e.sal)   	) 
then    
   System.out.println(   "Average salary in position " + j + "is: " + $avg + "\n" )
   insert(new SalByJob(j))
end

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Average salary in position CLERKis: 1037.5
Average salary in position ANALYSTis: 3000.0
Average salary in position SALESMANis: 1400.0
Average salary in position MANAGERis: 2758.3333333333335
Average salary in position PRESIDENTis: 5000.0
1
2
3
4
5

过滤累计函数的结果

寻找平均工资高于2000的岗位

rule "Find avarage in position"
when
    Emp(j: job)
    accumulate(Emp(s: sal,job == j), $avgSal: average(s))    
    eval($avgSal > 2000)   
    //   Number(doubleValue > 2000) from $avgSal
then
    System.out.println(j + " " + $avgSal)
end
1
2
3
4
5
6
7
8
9
PRESIDENT 5000.0
MANAGER 2758.3333333333335
MANAGER 2758.3333333333335
MANAGER 2758.3333333333335
ANALYST 3000.0
ANALYST 3000.0
1
2
3
4
5
6
declare Position
   job : String
   avergeSalary : Double
end 

rule "Find avarage in position"
when
    Emp(j: job)
    accumulate(Emp(s: sal,job == j), $avgSal: average(s))
    not Position(job == j)    
then
 	insert(new Position(j,$avgSal))
end

rule "Get position where average salary > 2000"
when 
	$p:Position(avergeSalary > 2000)
then
   System.out.println($p.job + " " + $p.avergeSalary)
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

选择工资高于公司平均工资的雇员

when
 Number(avg : longValue) from accumulate (Emp(s: sal),average(s))
 e: Emp(sal > avg)  
then    
 System.out.println(e.name + " earns " + e.sal + " the average is " + avg)  
1
2
3
4
5

如果我们想寻找所有和Blair有一样职位的人

when
  blr:  Emp(name == "BLAIR")
  e: Emp(job == blr.job)  
then    
  System.out.println(e.name + " works as " + e.job)
end
1
2
3
4
5
6

我们想找20号部门里工资最高的人

when 
  Number($max : intValue) from accumulate (Emp(s: sal,deptno == 20 ), max(s))
  e : Emp(deptno == 20,sal == $max) 
then    
  System.out.println(e.name + " " + e.deptno +" " + e.sal )
1
2
3
4
5

我们想找每个部门工资最高的人

rule "Sample"
when
  Dept(dn :deptno)
  Number($max : longValue) from accumulate (Emp(s: sal,deptno == dn ), max(s))
  e : Emp(deptno == dn,sal == $max)
then    
  System.out.println(e.name + " " + e.deptno +" " + e.sal )
end
1
2
3
4
5
6
7
8

Collect Functions

寻找雇员多于3人的部门

rule "Sample"
when 
 $d : Dept()
 $emps : ArrayList (size > 3)
       from collect (Emp(deptno == $d.deptno))
then    
  System.out.println($d.dname )
end
1
2
3
4
5
6
7
8

自定义 Accumulate 函数

rule "Sample custom sum function"
when
d : Dept()
$total : Number( doubleValue > 100 )
  from accumulate( Emp( deptno == d.deptno, $value : sal ),
  init( double total = 0; ),
  action( total += $value; ),
  reverse( total -= $value; ),
  result( total ) )
then
  System.out.println(d.dname + " department has sum of salaries " + $total);
end
1
2
3
4
5
6
7
8
9
10
11
12