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
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
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)
2
Relational Operators 关系操作符 "=""
搜索 managers
rule "Sample"
when
e : Emp(job == "MANAGER")
2
3
7566 PUTIN MANAGER 7839 1981 2975 20
7782 MERKEL MANAGER 7839 1981 2450 10
7698 BLAIR MANAGER 7839 1981 2850 30
2
3
1982雇佣的人
when
e : Emp(hiredate == 1982)
2
7934 ELISON CLERK 7782 1982 1300 10
7788 CARNEGIE ANALYST 7566 1982 3000 20
2
选择除了clerks之外的所有人.
when
e : Emp(job != 'CLERK')
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
2
3
4
5
6
7
8
9
10
选择收入在1000和2000之间的人 (inclusive)
when
e : Emp(sal >= 1000 , sal <= 2000)
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
2
3
4
5
6
下面所有语句功能一样
e : Emp(sal >= 1000 , sal <= 2000)
e : Emp(sal >= 1000 && sal <= 2000)
e : Emp(sal >= 1000 && <= 2000)
2
3
"in" operator 操作符
in 操作符检查值是否存在于某个集合内 选择在No.10 或者No.20部门工作的人
when
e : Emp(deptno in (10,20))
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))
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'))
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
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.*")
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
2
3
4
选择名字的第二个字符是‘a’的人
when
e: Emp(name matches ".A.*")
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
2
3
4
not matches 操作符
when
e: Emp(name not matches "B.*")
2
这样写语法是不正确的:
when
e: Emp(name ! matches "B.*")
e: ! Emp(name matches "B.*")
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
2
3
4
下面的语句运行结果一致
when
e: Emp(job == "MANAGER" && sal > 2500)
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 ,
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
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
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
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
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
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
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
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
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 )
2
3
4
5
ACCOUNTING
RESEARCH
SALES
2
3
寻找没有雇员的部门
when
d :Dept()
not (Emp(deptno == d.deptno))
then
System.out.println( d.dname )
2
3
4
5
OPERATIONS
寻找同一类型的facts
一份谁是谁上级的报告
rule "Sample"
when
e :Emp()
m :Emp(m.id == e.mgr)
then
System.out.println( e.name + " reports to " + m.name )
end
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
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)
2
3
4
2073
还可以写成:
when
avg: Number() from accumulate (Emp(s: sal),average(s))
then
System.out.println(avg)
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
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"
)
2
3
4
5
6
7
8
9
10
11
12
Average salary: 2073.214285714286
Min salary: 800.0
Max salary: 5000.0
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 |
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
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
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)
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
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
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
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
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
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
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)
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
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 )
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
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
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
2
3
4
5
6
7
8
9
10
11
12