gloabl关键字用在规则文件中定义全局变量。
它可以让应用程序的对象在规则文件中被访问。
可以用来为规则提供数据服务。
语法结构: global 对象类型 对象名称
注意1: 基本类型的包装类
注意2: 引用类型(排除基本类型包装类)和集合等,在一个规则中改变了值,其他规则会感知到。
示例:
global-rues.drl
package rules;
// 引入实体
import com.example.droolstest02.entity.TestNoneEntity;
global java.lang.Integer count
global java.util.List data
// 编写规则
rule "global_0"
no-loop true
when
$test:TestNoneEntity(str == "global")
then
System.out.println("count="+count);
System.out.println("data="+data);
count = count+1;
data.add("增加");
end
// 编写规则
rule "global_1"
no-loop true
when
$test:TestNoneEntity(str == "global")
then
System.out.println("修改后输出,count="+count);
System.out.println("修改后输出,data="+data);
end
package com.example.droolstest02;
import com.example.droolstest02.entity.EnableEntity;
import com.example.droolstest02.entity.TestNoneEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.drools.core.base.RuleNameEqualsAgendaFilter;
import org.drools.core.base.RuleNameStartsWithAgendaFilter;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Slf4j
@SpringBootTest
class DroolsTest04ApplicationTests {
@Autowired
KieBase kieBase;
// 测试
@Test
public void droolsTest(){
System.out.println("开始执行时间:"+ LocalDateTime.now().toEpochSecond(ZoneOffset.UTC));
KieSession kieSession = kieBase.newKieSession();
TestNoneEntity test = TestNoneEntity.builder().str("global").build();
// 全局变量
int count = 100;
List<String> data = new ArrayList<>();
data.add("001");
data.add("002");
kieSession.setGlobal("count", count);
kieSession.setGlobal("data", data);
// 1-规则引擎处理逻辑
kieSession.insert(test);
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("global"));
kieSession.dispose();
log.info("最后输出,count:{}", count);
log.info("最后输出,data:{}", data);
}
}
输出结果:
query查询提供了一种查询 working memory 中符合约束条件的Fact对象的简单方法。
它仅包含规则文件当中的LHS部分,不用指定when和then 。
为啥不用指定呢,因为我们只用他的返回结果。
不仅代码可以直接调用query,drl也可以调用query。
注意1:query名字在同一个KIE BASE包中必须要唯一。所以我们全局唯一即可。
注意2:参数传递方式很特别,参数后边需要跟一个“;”。
query-rues.drl
package rules;
// 引入实体
import com.example.droolstest02.entity.TestQueryEntity;
global java.lang.Integer count
global java.util.List data
query "query_1"
$test:TestQueryEntity(name == "张三")
end
query "query_2"(String qName, Integer qAge)
$test:TestQueryEntity(name == qName && age == qAge)
end
rule "query_rule_0"
when
$test:TestQueryEntity(name == "诸葛十三")
or query_1()
// 注意这里的“;”
or query_2("李四", 18;)
then
System.out.println("使用自定义query查询结果");
end
package com.example.droolstest02;
import com.example.droolstest02.entity.TestNoneEntity;
import com.example.droolstest02.entity.TestQueryEntity;
import lombok.extern.slf4j.Slf4j;
import org.drools.core.base.RuleNameStartsWithAgendaFilter;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.QueryResults;
import org.kie.api.runtime.rule.QueryResultsRow;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@SpringBootTest
class DroolsTestQueryApplicationTests {
@Autowired
KieBase kieBase;
// 测试
@Test
public void droolsTest(){
System.out.println("开始执行--------------");
KieSession kieSession = kieBase.newKieSession();
TestQueryEntity test01 = TestQueryEntity.builder().name("张三").age(10).build();
TestQueryEntity test02 = TestQueryEntity.builder().name("李四").age(18).build();
// 1-规则引擎处理逻辑
kieSession.insert(test01);
kieSession.insert(test02);
QueryResults queryReesult1 = kieSession.getQueryResults("query_1");
QueryResults queryReesult2 = kieSession.getQueryResults("query_2", "张三", 10);
for (QueryResultsRow queryResultsRow : queryReesult1) {
TestQueryEntity test = (TestQueryEntity)queryResultsRow.get("$test");
System.out.println("query_1结果:"+test);
}
for (QueryResultsRow queryResultsRow : queryReesult2) {
TestQueryEntity test = (TestQueryEntity)queryResultsRow.get("$test");
System.out.println("query_2结果:"+test);
}
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("query"));
kieSession.dispose();
}
}
输出结果:
这里的function与我们Java里的方法是一样的。
可以在规则体中定义函数,然后再其他地方调用。
作用其实也是把一些公共的业务逻辑整合到一个地方。
函数定义语法:
funtion 返回值类型 函数名(可选参数) {
// 逻辑代码
}
我们定义一个穿衣服方法,来给诸葛十三穿衣服。
function-rues.drl
package rules;
// 引入实体
import com.example.droolstest02.entity.TestNoneEntity;
function String cyf(String name){
return String.format("给%s穿衣服", name);
}
rule "function_001"
when
TestNoneEntity(str == "穿衣服")
then
String res = cyf("诸葛十三");
System.out.println("输出:"+res);
end
DroolsTestFunctionApplicationTests.java
package com.example.droolstest02;
import com.example.droolstest02.entity.TestNoneEntity;
import com.example.droolstest02.entity.TestQueryEntity;
import lombok.extern.slf4j.Slf4j;
import org.drools.core.base.RuleNameStartsWithAgendaFilter;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.QueryResults;
import org.kie.api.runtime.rule.QueryResultsRow;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@Slf4j
@SpringBootTest
class DroolsTestFunctionApplicationTests {
@Autowired
KieBase kieBase;
// 测试
@Test
public void droolsTest(){
System.out.println("开始执行--------------");
KieSession kieSession = kieBase.newKieSession();
TestNoneEntity test01 = TestNoneEntity.builder().str("穿衣服").build();
// 1-规则引擎处理逻辑
kieSession.insert(test01);
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("function"));
kieSession.dispose();
}
}
输出:
身为单身的你,一定要增强左右手。
当然,我们这里讲的不是增强你左右手的方法,而是讲drools的左手边(LHS)增强。
左手边我们已经很了解了,就是用于模式匹配的条件。下边讲一个新用法。(不是我喜新厌旧,是因为它太香了)
写过sql的我们都知道in和not in的用法,其实这里差不多。我就直接上代码了。
package rules;
// 引入实体
import com.example.droolstest02.entity.TestNoneEntity;
rule "lhsplus_in"
when
$test:TestNoneEntity(str in ("狗蛋","建国","黑土"))
then
System.out.println("in输出:"+$test.getStr());
end
rule "lhsplus_notin"
when
$test:TestNoneEntity(str not in ("狗蛋","建国","黑土"))
then
System.out.println("not输出:"+$test.getStr());
end
package com.example.droolstest02;
import com.example.droolstest02.entity.TestNoneEntity;
import lombok.extern.slf4j.Slf4j;
import org.drools.core.base.RuleNameStartsWithAgendaFilter;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@Slf4j
@SpringBootTest
class DroolsTestNoneApplicationTests {
@Autowired
KieBase kieBase;
// 测试
@Test
public void droolsTest(){
System.out.println("开始执行--------------");
KieSession kieSession = kieBase.newKieSession();
TestNoneEntity test01 = TestNoneEntity.builder().str("狗蛋").build();
TestNoneEntity test02 = TestNoneEntity.builder().str("二狗").build();
// 1-规则引擎处理逻辑
kieSession.insert(test01);
kieSession.insert(test02);
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("lhsplus"));
kieSession.dispose();
}
}
输出:
eval用于规则体的LHS部分,并且返回一个Boolean类型的值。语法结构:eval(表达式)
package rules;
// 引入实体
import com.example.droolstest02.entity.TestNoneEntity;
rule "lhsplus_eval"
when
$test:TestNoneEntity(str == "eval") and eval(100 > 20)
then
System.out.println("eval输出");
end
not 相当于我们平时用的 ! 例如 !“小仙女”.equals(name)
取反的意思。
注意: not与exists一样,只会执行一次,比如有多个对象符合规则,not规则只执行一次。
package rules;
// 引入实体
import com.example.droolstest02.entity.TestNoneEntity;
rule "lhsplus_not"
when
not TestNoneEntity(str == "not")
then
System.out.println("not规则触发");
end
package com.example.droolstest02;
import com.example.droolstest02.entity.TestNoneEntity;
import lombok.extern.slf4j.Slf4j;
import org.drools.core.base.RuleNameStartsWithAgendaFilter;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@Slf4j
@SpringBootTest
class DroolsTestNoneApplicationTests {
@Autowired
KieBase kieBase;
// 测试
@Test
public void droolsTest(){
System.out.println("开始执行--------------");
KieSession kieSession = kieBase.newKieSession();
TestNoneEntity test01 = TestNoneEntity.builder().str("aaa").build();
TestNoneEntity test02 = TestNoneEntity.builder().str("bbbb").build();
// 1-规则引擎处理逻辑
kieSession.insert(test01);
kieSession.insert(test02);
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("lhsplus"));
kieSession.dispose();
}
}
输出结果:
exists与not相反,不存在。
当然,如果存在多个符合条件的Fact对象,这个规则也只会触发一次。
打个比方,如果有好几个人犯错,那么只惩罚一个,杀鸡儆猴。
那我们可以使用exists
示例:
package rules;
// 引入实体
import com.example.droolstest02.entity.TestNoneEntity;
rule "lhsplus_exists01"
when
TestNoneEntity(str == "坏人")
then
System.out.println("普通匹配");
end
rule "lhsplus_exists02"
when
exists TestNoneEntity(str == "坏人")
then
System.out.println("exists匹配");
end
package com.example.droolstest02;
import com.example.droolstest02.entity.TestNoneEntity;
import lombok.extern.slf4j.Slf4j;
import org.drools.core.base.RuleNameStartsWithAgendaFilter;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@Slf4j
@SpringBootTest
class DroolsTestNoneApplicationTests {
@Autowired
KieBase kieBase;
// 测试
@Test
public void droolsTest(){
System.out.println("开始执行--------------");
KieSession kieSession = kieBase.newKieSession();
TestNoneEntity test01 = TestNoneEntity.builder().str("坏人").build();
TestNoneEntity test02 = TestNoneEntity.builder().str("好人").build();
TestNoneEntity test03 = TestNoneEntity.builder().str("坏人").build();
// 1-规则引擎处理逻辑
kieSession.insert(test01);
kieSession.insert(test02);
kieSession.insert(test03);
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("lhsplus_exists"));
kieSession.dispose();
}
}
输出:
哪儿都有继承,人类有继承,java有继承,左手还有继承。继承真好。
drools的继承也可以说是扩展 ,我理解,继承是把when条件合在一起(并且的关系)
比如大于50 并且小于400,我们可以这样写。
package rules;
// 引入实体
import com.example.droolstest02.entity.TestNoneEntity;
rule "lhsplus_extend_base"
when
$test01:TestNoneEntity(i > 50)
then
end
rule "lhsplus_extend_01" extends "lhsplus_extend_base"
when
$test02:TestNoneEntity(i < 400)
then
System.out.println("符合条件:$test01="+$test01.getI()+",$test02="+$test02.getI());
end
package com.example.droolstest02;
import com.example.droolstest02.entity.TestNoneEntity;
import lombok.extern.slf4j.Slf4j;
import org.drools.core.base.RuleNameStartsWithAgendaFilter;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@Slf4j
@SpringBootTest
class DroolsTestNoneApplicationTests {
@Autowired
KieBase kieBase;
// 测试
@Test
public void droolsTest(){
KieSession kieSession = kieBase.newKieSession();
TestNoneEntity test02 = TestNoneEntity.builder().i(60).build();
// 1-规则引擎处理逻辑
kieSession.insert(test02);
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("lhsplus_extend"));
kieSession.dispose();
}
}
输出结果:
测试过程中,发现了个神奇的事儿,就是我传入的fact都会交叉判断,也就是搞一个什么笛卡尔结果。
所以不建议大家使用这个extend,太麻烦。
可能有人没了解啥意思,是这样 我传入一个:30、60、600
大家看一下输出结果:
形成了几个组合:
60、30
60、60
600、30
600、60
package com.example.droolstest02;
import com.example.droolstest02.entity.TestNoneEntity;
import lombok.extern.slf4j.Slf4j;
import org.drools.core.base.RuleNameStartsWithAgendaFilter;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@Slf4j
@SpringBootTest
class DroolsTestNoneApplicationTests {
@Autowired
KieBase kieBase;
// 测试
@Test
public void droolsTest(){
KieSession kieSession = kieBase.newKieSession();
TestNoneEntity test01 = TestNoneEntity.builder().i(30).build();
TestNoneEntity test02 = TestNoneEntity.builder().i(60).build();
TestNoneEntity test03 = TestNoneEntity.builder().i(600).build();
// 1-规则引擎处理逻辑
kieSession.insert(test01);
kieSession.insert(test02);
kieSession.insert(test3);
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("lhsplus_extend"));
kieSession.dispose();
}
}
输出结果:
身为单身汉,左右手必须都要增强,万一哪天有机会英雄救美,没劲儿可不行。
在规则文件RHS部分的主要工作是插入、删除、或者修改工作内存中的Fact数据,来达到控制规则疫情的执行目的。当然我们大部分时候会调用我们自己的service方法,毕竟还时java代码写着舒服。
insert方法的作用是向工作内存中插入数据,并让相关规则重新匹配。
直接上代码:随着年龄的增长,我们输出不一样的结论。
当然了,我们一定要记得,之前讲过的一个lock-on-active 是可以限制这种规则触发的,所以我们测试的时候不设置这个属性。
package rules;
// 引入实体
import com.example.droolstest02.entity.TestNoneEntity;
rule "rhsplus_insert01"
when
$test01:TestNoneEntity(i == 18)
then
System.out.println("18啦,可以谈恋爱啦!");
System.out.println("过了3年,21了");
TestNoneEntity test = TestNoneEntity.builder().i(21).build();
insert(test);
end
rule "rhsplus_insert02"
when
$test01:TestNoneEntity(i == 21)
then
System.out.println("21啦,赶紧找对象!");
System.out.println("过了9年,30了");
TestNoneEntity test = TestNoneEntity.builder().i(30).build();
insert(test);
end
rule "rhsplus_insert03"
when
$test01:TestNoneEntity(i == 30)
then
System.out.println("30啦,还没对象!");
end
package com.example.droolstest02;
import com.example.droolstest02.entity.TestNoneEntity;
import lombok.extern.slf4j.Slf4j;
import org.drools.core.base.RuleNameStartsWithAgendaFilter;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@Slf4j
@SpringBootTest
class DroolsTestNoneApplicationTests {
@Autowired
KieBase kieBase;
// 测试
@Test
public void droolsTest(){
KieSession kieSession = kieBase.newKieSession();
TestNoneEntity test01 = TestNoneEntity.builder().i(18).build();
// 1-规则引擎处理逻辑
kieSession.insert(test01);
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("rhsplus_insert"));
kieSession.dispose();
}
}
输出:
更新方法的作用,顾名思义,更新内存中的数据,并让相关的规则重新匹配。
当然了,lock-on-active 也是可以限制重新匹配的,所以我们测试的时候不设置这个属性。
业务中一定要防止死循环。一定。
package rules;
// 引入实体
import com.example.droolstest02.entity.TestNoneEntity;
rule "rhsplus_update01"
when
$test01:TestNoneEntity(i == 18)
then
System.out.println("18啦,可以谈恋爱啦!");
System.out.println("过了3年,21了");
$test01.setI(21);
update($test01);
end
rule "rhsplus_update02"
when
$test01:TestNoneEntity(i == 21)
then
System.out.println("21啦,赶紧找对象!");
System.out.println("过了9年,30了");
$test01.setI(30);
update($test01);
end
rule "rhsplus_update03"
when
$test01:TestNoneEntity(i == 30)
then
System.out.println("30啦,还没对象!");
end
package com.example.droolstest02;
import com.example.droolstest02.entity.TestNoneEntity;
import lombok.extern.slf4j.Slf4j;
import org.drools.core.base.RuleNameStartsWithAgendaFilter;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@Slf4j
@SpringBootTest
class DroolsTestNoneApplicationTests {
@Autowired
KieBase kieBase;
// 测试
@Test
public void droolsTest(){
KieSession kieSession = kieBase.newKieSession();
TestNoneEntity test01 = TestNoneEntity.builder().i(18).build();
// 1-规则引擎处理逻辑
kieSession.insert(test01);
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("rhsplus_update"));
kieSession.dispose();
}
}
输出:
modify与update意思差不多,只是写法不一样。
package rules;
// 引入实体
import com.example.droolstest02.entity.TestNoneEntity;
rule "rhsplus_modify01"
when
$test01:TestNoneEntity(i == 18)
then
System.out.println("18啦,可以谈恋爱啦!");
System.out.println("过了3年,21了");
modify($test01){
setI(21)
}
end
rule "rhsplus_modify02"
when
$test01:TestNoneEntity(i == 21)
then
System.out.println("21啦,赶紧找对象!");
System.out.println("过了9年,30了");
modify($test01){
setI(30)
}
end
rule "rhsplus_modify03"
when
$test01:TestNoneEntity(i == 30)
then
System.out.println("30啦,还没对象!");
end
删除工作内存的数据,并让相关规则重新匹配。
delete和retract是等效的,但是retract慢慢被废弃了,现在提倡使用delete
如果我们没有delete,应该是两个规则都会匹配到,但是我们在第一个规则中删除了内存中对象,所以第二个规则就不会被匹配到。
package rules;
// 引入实体
import com.example.droolstest02.entity.TestNoneEntity;
rule "rhsplus_delete01"
when
$test01:TestNoneEntity(i > 10)
then
System.out.println("大于10!");
// retract($test01);
delete($test01);
end
rule "rhsplus_delete02"
when
$test01:TestNoneEntity(i > 15)
then
System.out.println("大于15!");
end
package com.example.droolstest02;
import com.example.droolstest02.entity.TestNoneEntity;
import lombok.extern.slf4j.Slf4j;
import org.drools.core.base.RuleNameStartsWithAgendaFilter;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@Slf4j
@SpringBootTest
class DroolsTestNoneApplicationTests {
@Autowired
KieBase kieBase;
// 测试
@Test
public void droolsTest(){
KieSession kieSession = kieBase.newKieSession();
TestNoneEntity test01 = TestNoneEntity.builder().i(18).build();
// 1-规则引擎处理逻辑
kieSession.insert(test01);
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("rhsplus_delete"));
kieSession.dispose();
}
}
输出:
halt的作用是立即终止后面所有规则的执行。
下边的规则“rhsplus_halt02”是不会执行的。
package rules;
// 引入实体
import com.example.droolstest02.entity.TestNoneEntity;
rule "rhsplus_halt01"
when
$test01:TestNoneEntity(i > 10)
then
System.out.println("大于10!");
drools.halt();
end
rule "rhsplus_halt02"
when
$test01:TestNoneEntity(i > 15)
then
System.out.println("大于15!");
end
getWorkingMemory:返回工作内存对象,不晓得什么业务会使用到。
getRule:返回规则对象
等等…