Drools 7.66 官方文档翻译

参考自:
Drools 文档 — 官方文档
Drools 7.66.0 — 官方文档
.
.
.
说明:目录采用格式:官方文档编号 + 我定义的标题

1.3.1 安装和使用

2022-03-02 15:46

drools jar dependency

2.3 DMN

DMN:Decision Model and Notation(决策模型标记)
BPMN:Business Process Model and Notation(业务流程模型标记)

交替规则 DMN
》》》jar 部署 kie-server上,远程访问

7.3.0 改为新版测试(Drools workbench)

可Rest API 访问(账号,密码)

3.1.1 KIE

KIE 是 Drools 和 jBPM 的共享核心。
它为构建、部署和利用资源提供了统一的方法和编程模型。

KIE:Knowledge Is Everything(知识就是一切)
jBPM:Java Business Process Management(Java 业务流程管理)
在这里插入图片描述

3.1.2 KIE生命周期

使用KIE系统的不同方面,或生命周期,无论是Drools还是jBPM,通常可以分为以下几个方面:

  • Author
    使用 UI 隐喻创作知识,例如:DRL、BPMN2、决策表、类模型。
  • Build
    将编写的知识构建为可部署的单元。
    对于KIE来说,这个单位是一个JAR。

  • Test
    在将KIE知识部署到应用程序之前进行测试。

  • Deploy
    将单元部署到应用程序可以利用(消耗)它们的位置。(drl打包到 jar里面,我们也可以加载到 drl 文件)
    KIE 使用 Maven 风格的存储库。

  • Utilize(使用)
    加载 JAR 以提供应用程序可以与之交互的 KIE 会话 (KieSession)。
    KIE 通过 KIE 容器 (KieContainer) 在运行时公开 JAR。
    运行时与之交互的 KieSessions 是从 KieContainer 创建的。

  • Run
    系统交互与KieSession,通过API。

  • Work
    用户交互与KieSession,通过命令行或UI。

  • Manage
    管理任何KieSession或KieContainer。

总结图:
在这里插入图片描述

3.1.3 集群支持

7.4后支持集群(运行时)

3.1.4 资产(不同场景)

只有 DRL 灵活,可集成 IDE、语法。
(Drools Rule Language)

3.1.5 储存和构建

1、项目版本控制选项 (Git)

1
2
3
内置 git(workbench)

外部git

2、项目管理选项 (Maven)

1
2
3
内置 maven(workbench)

外部maven(需配置)

3、项目构建选项

1
2
3
4
5
6
7
内置kjar(workbench)

maven外部(kjar:需要配置 kmodule.xml文件)

嵌入 Java(KieModuleModel 编程式创建 kmodule.xml,加载 KieFileSystem)

CI/CD时,打包成 kjar

3.1.6 部署

2022-03-02 16:24

1、部署 kie-server(kjar)

2、嵌入Java(JVM)
(KIE API 配置 KieScanner,定期更新 KieContainer)

3.1.7 测试

1、kie-server(REST)

2、嵌入Java(JVM)

3、workbench(决策)
》》》需要创建资产 assets(DRL文件,实体类,场景测试…)

3.1.8 部署架构

1、kie-server + wildfly(最适用于 DMN)

2、IDE + kie-server(wildfly):DRL、电子决策表、DMN

3、IDE + Java(我们)

图示:
在这里插入图片描述

3.2.1 最小化部署

KIE 使用默认值来最小化配置量。空的 kmodule.xml 是最简单的配置。必须始终有一个 kmodule.xml 文件,即使是空的,因为它用于发现 JAR 及其内容。

Maven 可以“mvn install”将 KieModule 部署到本地机器,本地机器上的所有其他应用程序都使用它。或者它可以“mvn deploy”将 KieModule 推送到远程 Maven 存储库。构建应用程序将拉入 KieModule 并在此过程中填充本地 Maven 存储库。

在这里插入图片描述

我画的:
在这里插入图片描述

1
2
3
4
5
6
7
8
9
10
11

resources
package/*.drl(知识)
META-INF/kmodule.xml(必须存在,即使里面为空:例如下面)
<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule"/>

pom.xml
kjar(打包方式)
drools-compiler(依赖)
kie-maven-plugin(插件)

两种部署:
1、maven依赖jar(单版本)
kie扫描类路径 kmodule.xml(所有依赖的jar)

2、动态添加(并行版本)

3.2.2 org.kie.api.builder

在这里插入图片描述

3.2.2.1 创建和构建 Kie 项目

不同于其他 maven 项目
特别之处:resources/META-INF/kmodule.xml

1
2
<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule"/>

默认值:有默认 KieBase(空 kmodule.xml)

1
2
3
4
5
6
7
8
9
10
11
org.kie.api.runtime.KieContainer
=>(创建 Kie 资产) 缓存 KieSession 创建

org.kie.api.KieServices
=> 所有 kie 运行、构建接口(创建 Classpath KieContainer)

org.kie.api.KieBase
=> 知识定义库(Rules、Processes、funtions、type Models)。
=> 不包含数据。

org.kie.api.event.kiebase.KieBaseEventManager

3.2.2.2 kmodule.xml 文件

2022-03-02 18:27

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
KieBase
=> 不存储数据,只定义知识
=> 创建 KieSession(创建会话非常轻量)
=> 创建 KieBase 可能很重
=> 尽可能缓存:重复创建 KieSession(缓存机制:KieContainer)

KieSession
=> 插入数据
=> 启动流程
=> 储存和执行运行时数据

kmodule.xml
=> 可定义多个 KieBase,每个KieBase可定义不同的KieSession
=> KieBase1
=> KieSession1
=> KieSession2
=> KieBase2
=> KieSession1
=> KieSession2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2022-03-02 18:43

KBase 属性
name 默认空 (需要指定,并且唯一)
package 全部 (逗号分割) 扫描资产
include 无 (逗号分割) 包含哪个KieBase
default false 是否 KieModule默认
平等行为 唯一 工作内存(唯一、equals)
事件处理模式 cloud cloud(件=> fact),stream(事件推理)
声明式议程 禁用

KieSession
name 空 (唯一,从 KieContainer获取)
type 有状态 (有状态:可迭代; 无状态:一次性内存)
default false (此模块默认值,KieContainer无需传名称获取。每个类型KieSession最多一个默认)
时钟类型 即使的reltime pseudo伪装的(事件时间戳:系统时钟; 应用程序控制伪时钟:单元测试时间规则)
信仰体系 简单的 jtms,可废止

KieServices.Factory.get();
=> KieContainer(classpath kmodule.xml)
=> KieBase
=> KieSession(有状态)
=> StatelessSession(无状态)

=> newReleaseId("com.taopanfeng", "drools-test", "1.0")
=> ReleaseId

=> newKieContainer(ReleaseId)
=> KieContainer 多版本(动态)

2022-03-02 19:11
前面讲的是基于 kmodule.xml classpath 创建 KieContainer。
我们项目(计分卡)【需要 KieContainer 创建 KieBase】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Configuration
@Slf4j
public class DroolsConfig {

//指定规则文件存放的目录
private static final String RULES_PATH = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + "rules/**/*.drl";

@Bean
@ConditionalOnMissingBean
public KieBase kieBase() throws IOException {
// [0] KieServices
KieServices kieServices = KieServices.Factory.get();

// [1] KieFileSystem
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
Resource[] files = resourcePatternResolver.getResources(RULES_PATH);
for (Resource file : files) {
kieFileSystem.write(ResourceFactory.newUrlResource(file.getURL()));
}

// [2] KieContainer
KieRepository kieRepository = kieServices.getRepository();
kieRepository.addKieModule(kieRepository::getDefaultReleaseId);
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
kieBuilder.buildAll();
KieContainer kieContainer = kieServices.newKieContainer(kieRepository.getDefaultReleaseId());

// [3] KieBase
return kieContainer.getKieBase();
}

}

3.2.2.3 maven构建

1
2
3
kjar

plugin: kie-maven-plugin

想用 @kie.api.Position,Java类中。(需要加 kie-api 依赖)
》》》尽量 kjar 轻量,不依赖其他。

没有maven插件(jar)
》》》all 放入 resources jar 中。

运行时,加载jar,构建资源。
(编译出错时,KieContainer 创建出来是 null)。
》》》编译放到运行中做(不建议这样,建议 maven 插件)。

3.2.2.4 编程式

1
2
3
4
5
6
7
KieBase

KieSession

KieFileSystem(虚拟文件系统)
=> 由 KieServices 创建
=> write(Resource) 写入资深(DRL文件)

编程式构建 kmodule.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 创建 xxxModel (编程式 XML 配置)
KieServices.newKieModuleModel();
=> newKieBaseModel(name);
=> newKieSessionModel(name);


// 写入资源到文件系统
KieServices.newKieFileSystem();
=> writeKModuleXML(kServices.toXML)
=> write("src/main/resources/rule/test.drl", String content 或 Resource)
=> write(org.kie.api.io.Resource)

// 获取 KieResources 对象
org.kie.api.Service
=> org.kie.api.io.KieResources
===> kServices.getSources().方法(等同于下面)
===> ResourceFactory.方法

// a.txt => DRL
write("src/main/resource/a.txt", KieResources.newInputStream, setResourcesType(ResourceType.DRL))


KieServices kieServices = KieServices.Factory.get();
KieFileSystem kfs = ...
kieServices.newKieBuilder( kfs ).buildAll();
KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());

检查编译结果是最佳实践。
报告 3 种不同严重性的KieBuilder编译结果:ERROR、WARNING 和 INFO。
ERROR 表示项目编译失败,在这种情况下,没有生成KieModule,也没有向KieRepository添加任何东西。
WARNING和INFO结果可以被忽略,但可用于检查。

1
2
KieBuilder kieBuilder = kieServices.newKieBuilder( kfs ).buildAll();
assertEquals( 0, kieBuilder.getResults().getMessages( Message.Level.ERROR ).size() );

2022-03-02 20.59
再说一遍

1
2
3
4
5
6
7
8
9

KieContainer
=> 创建 KieBase
=> 包含 KieModule(定义 KieBase)

KieBase
=> 所有知识定义:rules、processes、functions、type models
=> 创建 KieSession
======> 插入数据,启动流程实例。

2022-03-02 21.16
OSGi(开放服务网关协议,Open Service Gateway Initiative)

有时,例如在 OSGi 环境中,KieBase需要解析不在默认类加载器中的类型。
在这种情况下,有必要KieBaseConfiguration使用附加的类加载器创建一个,并在从它KieContainer创建一个新的类加载器时将其传递给KieBase。

1
2
3
4
// 使用自定义 ClassLoader 创建新的 KieBase
KieServices kieServices = KieServices.Factory.get();
KieBaseConfiguration kbaseConf = kieServices.newKieBaseConfiguration( null, MyType.class.getClassLoader() );
KieBase kbase = kieContainer.newKieBase( kbaseConf );

3.2.3.2 KieSessions 和 KieBase 修改

KieSessions 后面更详细地讨论。

KieBase创建并返回KieSession对象,它可以选择保留对这些对象的引用。
(KieBase修改,KieSession可感知,将把修改应用于会话)

当KieBase修改发生时,这些修改将应用于会话中的数据。该引用是弱引用,也是可选的,由布尔标志控制。

Drools WorkBench 测试

2022.03.03 06.10

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
wb:
hutool
drl import hutool类


本地 app 动态读取:
本地 hutool 依赖
否则 newKieContainer = null(编译出错)



wb:
build,install
app:
url(IS 输入流) => 拦截(本地jar)
=> drl import app 类
=> 本地存在 √
=> 本地不存在 ×


想办法让 kie-wb `不编译就可以`,忽略打包错误。

△ 暂时放弃吧,09.52了。

3.2.3.3 KieScanner

2022.03.03 10.08

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
KieScanner(扫描)
=> 动态更新(定时执行)
=> 手动更新(手动立即执行)

=> maven 指定 GAV
=> 文件夹指定 GAV 目录


会自动更新(本质更新了 KieContainer)
=> KieBase
=> KieSession


动态更新
SNAPSHOT
LATEST
RELEASE
不可运行时更新
固定版本

3.2.3.4 maven范围依赖

1
2
3
4
5
6
7
8
9
[1.0.1] 等同于 1.0.1

[1.0.0, 2.0.0)

[1.0.0,)

LATEST

RELEASE

3.2.3.5 Settings.xml 和远程存储库设置

setting.xml 三个位置

远程 maven 库

1
2
3
KieContainer
=> 包含 KieModule(KieModule 定义了 KieBase)
=> 创建 KieBase(KieBase 创建 KieSession)

3.2.4.3 KieRuntime

set Global
注册 channel

Global

1
2
3
4
5
6
7
设置:kieSession.setGlobal

不等于 fact

更新不会重新触发规则

全局静态(适用 RHS)

3.2.4.4 Event、Listener

支持多种 Event(xxxEvent)
BeforeMatchFiredEvent
AfterMatchFiredEvent

添加删除监听
DefaultAgendaEventListener
DebugRuleRuntimeEventListener

3.2.4.5 KieRuntimeLogger

1
2
3
4
5
console

thread

file

3.2.4.6 Commands、CommandExecutor

1
2
3
4
5
6
7
CommandExecutor => 无状态(包含 finally dispose,一次性的)
=> ExecutionResults 获取结果集

CommandFactory 批处理 list
=> setInsert
=> setGlobal
=> setGlobal

3.2.4.7 无状态

1
2
3
4
5
6
7
8
封装 KieSession,不扩展

关注决策场景

不支持 fireAllRules() 方法
=> 使用 execute 方法

避免手动 dispose(一次性)

execute流程(一次性)

1
2
3
4
5
6
7
创建 KieSession

添加数据(执行命令)

调用 fireAllRules

调用 dispose(finally)
1
2
3
Globals
=> 本身 Map > delegate(优先级)
=> 自己没有,取 delegate

3.2.4.9 持久化 和 事务

JPA:Java Persistence Api
JTA:Java Transaction Api

3.2.5 部署架构

在这里插入图片描述

在这里插入图片描述

3.2.6 构建、部署

2022-03-03 14:03

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
3.2.6.1
默认会话 KieSession

3.2.6.2
具名会话

3.2.6.3
嵌套KieBase
=> include
=> 依赖Maven

3.2.6.4
多个KieBase(package "*" 当前及子包)

3.2.6.5
来自 KieRepository 的 KieContainer
// 创建 KieContainer
kService.newKieContainer(kService, newReleaseId(GAV))
无任何 kmodule,maven 依赖 kie-ci



# 3.2.6.6~8
手动 Resource(KieBase、KieSession) 导入 KieModule(编程式)

# 3.2.6.9
默认 KieModule
=> kfs.write(...drl)
=> buildAll();
=> 默认 ReleaseId

# 3.2.6.10
KieModuleModel
=> KieBaseModel
=> KieSessionModel
=> include
kfs.write(xml)

3.2.7 可执行模型(嵌入式)

2022-03-03 14.33

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Drools 中 Rule 默认 kie-maven-plugin 构建

构建时,基于 Java 表示 Set<Rule>

相比于之前打包,可执行模型更快创建(KieContainer、KieBase)
》》》特别是大量DRL文件,或更多资产(assets)时。

强依赖(pom.xml)
=> 插件:kie-maven-plugin
=> 依赖:drools-model-compiler




编译:
=> 下载 kjar,安装在 KieContainer(解析、编译DRL文件:量大会很慢)
=> 可执行模型(DRL文件 => Java类)
》》》更快重新创建KieContainer、KieBase

运行:
=> JIT(Just In Time 即使编译)。
=> 例如:mvel => 字节码
=> 注意: 查询最多 10个参数,Rule中的最多 24个 $变量。

3.2.7.1 修改禁用

mvn clear install -DgenerateModel=△

  • YES_WITHDRL:(默认)生成与原始项目中的 DRL 文件对应的可执行模型,并将 DRL 文件添加到生成的 KJAR 以用于文档目的(无论如何,KIE 库都是从可执行模型构建的)。
  • YES:生成与原项目中的DRL文件对应的可执行模型,并从生成的KJAR中排除DRL文件。
  • NO:不生成可执行模型。

编程式:

1
2
3
4
5
buildAll(); NO

buildAll(DrlProject.class); NO

buildAll(ExecutableModelProject.class); 生成DRL对应的可执行模型

3.2.7.2 启动可执行模型

2022-03-03 15.34

drools 7.39版本后,默认 kie-maven-plugin 构建。

不使用可执行模型
1、不使用 kie-maven-plugin 插件
2、不依赖 drools-model-compiler

如果依赖 drools-model-compiler,可执行模型编译成 Drools内部数据结构。
方便 drools 引擎执行。

1
2
3
4
5
6
7
8
9
10
KieScanner(更新 KieContainer)
=> 依赖 kie-ci.jar
=> KieServices.newKieScanner(kContainer);
=> kScanner.scanNow(); 手动
=> kScanner.start(long ms) 扫描间隔
》》》注:不会扫描固定版本,需后缀 SNAPSHOT、RELEASE、LATEST


配置 setting.xml => updatePolicy: always
检查新版本,增量构建(KieBase、KieContainer 新的版本)

4 Drools规则引擎

2022-03-03 17:07

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Drools规则引擎:
储存
处理
评估数据(计算)

为了执行:
Rule(业务)
决策表

基本功能:
传入数据,或事实(fact)
与条件匹配(决定任务是否执行)

组件:
Rules:业务Rule 或 DMN决策:至少触发Rule(LHS)、Rule影响动作(RHS)
Facts:输入或更改的数据(匹配规则 => 执行)
Production memory:Rules存放在Drools引擎中的储存单元。
Working memory:Facts存放在Drools引擎中的储存单元。
Agenda:注册和激活(如果适用)准备执行Rules的储存单元。




Drools引擎:
=> 激活并注册Rule(在Agenda中)
=> 优先级,冲突的Rule(排序后执行)

在这里插入图片描述

4.1 KieSession

2022-03-03 17:28

1
2
3
4
5
6
7
8
9
10
11
12
13
14
KieSession 创建
=> KieBase创建(推荐)
=> KieContainer创建(kmodule.xml 定义 KieSession)

KieSession
=> 存储、执行 => 运行时数据

KieBase
=> 是一个仓库,定义了KieModule(kmodule.xml)
=> 无任何运行时数据

KieSession
=> 无状态:运行时数据丢弃(每次execute 都会finally dispose)。
=> 有状态:不手动dispose(); 就会继续存在。
  • 无状态

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25

    无状态
    => 无数据保存
    => 不使用推理对事实迭代更改

    无状态:场景
    => 校验:某个人是否可以申请贷款
    => 计算:计算贷款
    => 路由和过滤:东西分类,或事件发送

    => 例如:18岁以下不能考驾照($可选,为了区分变量 和 属性 Field)

    execute(再说一次)
    => 创建KieSession
    => 添加数据,执行命令
    => fireAllRules();
    => dispose(); finally块中执行


    无状态
    => 3中可迭代执行
    => 三种全局变量 Globals
    => command;
    => out作为results;
    => getGlobals();(注意并发)
  • 有状态

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    有状态
    => 推断对fact迭代更改
    => 调用后也会保存(数据 facts)
    => 记得dispose(); 避免内存泄漏

    场景
    => 监控:股票市场,自动化购买
    => 诊断:运行故障诊断或医疗诊断流程
    => 物流:包裹跟踪和交付准备
    => 确保合规:验证市场交易合法性

    => 例如:火灾、洒水器、警报
    => 结果保留,后续调用
    => insert => fireAllRules...
    => delete => fireAllRules...
  • KieSession Pool
    2022-03-03 18:40

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
会话池:解决避免瓶颈
》》》KieSession 百万,可能大量清理。


1、创建
KieContainer.newKieSessionPool(10);
》》》kSessionPool 初始化,可继续增加。

2、使用
pool.newKieSession 有状态
pool.stateless 无状态
》》》execute 池中拿,而不创。

3、销毁
=> kContainer.dispose(); 销毁pool
=> pool.shutdown();

4.2 Drools引擎基本功能

1
2
3
4
5
6
7
8
9
10
基本功能
=> 数据与业务相匹配
=> 决定是否执行规则,以及如何执行规则。
=> 根据现有知识推断,根据推断结果操作。

☆☆☆☆☆
在许多情况下,规则系统中的新数据是其他规则执行的结果,而这些新数据会影响其他规则执行。

Truth(真理):识别,处理矛盾。
=> 例如:执行2条规则导致矛盾,Drools引擎会根据之前计算的结果选择操作(action)

2022-03-03 19:22

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
insert()
术语:插入,一般指此。
插入后,一般有 retracted fact(收回事实)

insertLogical()
插入事实后,Rule为false,自动 retracted fact。
没有条件支持,才会自动收回fact。
Drools引擎认为这是:合理的 justified
fact要重写下面两个方法
equals => 只会存在一个 equals
hashcode

重复equals插入逻辑,count++
规则false,count--
count为0,则 retracted fact(收回事实)。

4.2.1 政府身份证案例

2022-03-03 19:58

1
2
3
4
5
6
7
8
Rule的 坏写法
=> 整体的
=> 有漏洞的

Rule的 好写法
=> 知识职责解耦
=> 封装知识
=> 为这些封装提供语义抽象

4.2.2 fact 相等模式

1
2
3
4
5
6
7
8
9
10
11
12
identity
默认,IdentityHashMap

equality
HashMap



改变模式(三种方式):
1、系统变量
2、编程式
3、kmodule.xml

4.3 Drools引擎执行控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
新 Rule -> 进入 Working memory,可能匹配并执行。


1个 Working memory 操作,可能多个 Rule 符合执行。
若有 Rule 完全匹配时,Drools 引擎创建激活实例。
引用Rule,匹配Fact。
激活实例 -> 添加到 Agenda
Agenda:1、解决冲突 2、控制执行顺序

执行fireAllRules(); 后,Drools引擎循环过程:2个阶段。

阶段1:Agenda evaluation(议程评估)
找到可执行的Rule,找不到,exit。
找到可执行的Rule,注册激活实例到 Agenda,进行下一个阶段。

阶段2:Working memory(工作内存行动)
执行阶段1中注册的Rule。
所有操作完后,或 Java中再次执行 fireAllRules() 后,返回阶段1再次评估。

Agenda中,一条Rule执行会导致另一条Rule删除。
为了避免,可以定义在Drools引擎中执行规则的方式和时间(how and when)。
=> salience、agenda-group、activation-group

2022-03-03 20.44
在这里插入图片描述

4.3.1 salience

2022-03-03 20.52

1
2
3
4
Rule的salience属性:
=> int(默认0)
=> 可负可正
=> int越大,越先执行。

4.3.2 agenda-group

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
agenda-group
相同属性绑定一起(一组Rule)
有焦点focus的先执行(优先级高)
setFocus() 设置焦点
设置 auto-focus属性,下次Rule激活实例,焦点自动分配agenda-group。

细节:
setFocus()
Drools引擎将agenda-group添加到 specified rule stack top(栈顶)。
因为是栈顶,所有多个 setFocus() 执行时,后setFocus 先执行(栈)。

默认"MAIN",不是 specified agenda-group,先执行(stack),除非有 focus agenda-group。
只执行 "MAIN",从上到下。
有 setFocus 时,先执行 setFocus,再执行 "MAIN"。

优先级递减:
=> auto-focus + setFocus (后setFocus先执行:栈)
=> auto-focus
=> setFocus(后setFocus先执行:栈)
=> 无 setFocus

4.3.3 activation-group

2022-03-04 07.22

相同属性 activation-group 的 Rule 被称为一个激活组

一个激活组只执行1条Rule。
满足Rule条件后,其他Rule会从 agenda 中删除。

4.3.4 执行模式和线程安全

Passive mode 被动模式:(默认)fireAllRules();
Active mode 主动模式:fireUnitHalt();

1
2
3
4
5
6
7
多线程同时使用:
线程1 线程2

先被动,后主动。
会等待被动执行完成,再执行主动。
先主动,后被动。
被动会被抛弃不进行执行,主动一直在运行中。

4.3.5 Fact传播模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Lazy 懒加载(默认)
传播特性可能与插入不同。
在批处理集合中传播(而不是实时传播)。

Immediate 立即
立即传播,与用户或程序插入顺序相同。

Eager 急切
在Rule执行之前,在批处理集合中,Fact是Lazy。
Drools引擎将 Eager 传播行为用于具有 no-loop 或 lock-on-active 属性的规则。


可使用 @Propagation 修改。
(不懂作用) 2022-03-04 08.02

4.3.6 Agenda Filter

true:执行Rule
false:不执行

例如:执行以 “Test” 结尾的 Rule。

1
ksession.fireAllRules( new RuleNameEndsWithAgendaFilter( "Test" ) );

4.3.7 Rule Units

规则单元是一组数据源、全局变量和DRL规则,它们共同作用于特定的目的。
您可以使用规则单元将规则集划分为更小的单元,将不同的数据源绑定到这些单元,然后执行单个单元。
规则单元是规则分组DRL属性(例如用于执行控制的规则议程组或激活组)的一种增强的替代方法。
当您希望协调规则执行,以便一个规则单元的完整执行触发另一个规则单元的开始时,规则单元是很有帮助的
(使用 agenda-group 也可以实现动态激活 RHS 中 setFocus)

4.4.1 Phreak 算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
简介:
有 Rete 算法发展而来。
包括增强型 Reta 算法 ReteOO。
比 Rete、ReteOO更有扩展性,大型系统速度也更快。


Rete VS Phreak
Rete:
eager 急切(immediat rule evaluation 即时规则评估)。评估=LHS
面向数据(data)。

Phreak:
lazy 懒加载(delayed rule evaluation 延迟规则评估)。评估=LHS
面向目标(goal)。

Phreak 优点、介绍、原理
(省略)

4.4.2 Rule基本配置

1
2
3
4
5
6
7
8
9
10
11
12
13
1、异常处理器
默认 DefaultConsequenceExceptionHandler

2、多线程评估(LHS)
默认 false
queries、salience、agenda-group 默认自动切换单线程
无法控制 DRL 顺序,可能出错(保证顺序应使用 salience)

3、顺序性
默认 false
更新不会触发 Rule。
忽略:insert、update、modify
=> 因为不会触发更新,所以适用于无状态会话。

4.5 复杂事件处理 CEP

2022-03-04 09.14

CEP(complex event processing 复杂事件处理)

声明fact、事件、滑动窗口。
元数据标签、cloud/stream,event运算符,query查询。

4.7 监听器

监听器原则:尽可能单纯,无交互,无状态(会阻塞 Drools)。

agenda:执行一次前中后
runtime:增删改
在这里插入图片描述

4.8 性能优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1、无状态应用启动 时序性模式(参考4.4.2)

2、监听器尽量简单化,dispose前,先 detach 监听。
摧毁工作内存前,先摧毁监听器。

3、配置 LambdaIntrospector 缓存大小:太小降低性能
默认 32

4、lambda外部化(优化内存)

5、配置节点阈值
默认 9
节点索引超过 9 用索引,例如:
Person(age > 10)
Person(age > 20)
Person(age > 30)
...

6、启用连接节点范围索引
fact 多的情况下比较适用。例如:256 * 16 个fact。
可以提高 LHS 评估性能。

5 Rule语法规则

DRL(Drools Rule Language 流口水规则语言)

LHS(Left Hand Side 左手边)
RHS(Right Hand Side 右手边)

1
2
3
4
5
6
7
8
9
.drl 文件定义业务规则(rule)

主要为资产(assets)

drl文件包含一个或多个rule
LHS:when(conditions)
RHS:then(actions)

Drools Workbench 提供 Java、drl、xml 语法高亮

5.1 DRL Rules 语法

2022-03-04 10.30

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package // 放在顶部

import // 默认导入自己包中的资产(Object)

function // 可选

query // 可选

declare // 可选

global // 可选

rule "rule name" // 名称唯一
// 属性
when
// 条件
then
// 动作
end

rule "rule2 name"

...

5.1.1 package

1
2
3
4
5
6
7
1、包名要唯一

2、和 java package 一样(;可省略)

3、package可定义属性
rule中可也可以定义属性,就近原则。
rule 属性 > package 属性

5.1.2 import

1
同 Java(;可省略)

5.1.3 function

为了定义语义抽象(参数不同的情况下定义)。

或 import 静态方法,在 then 中用。

5.1.4 query

工作内存中查询 Fact
kSession.getQueryResults(“query name”);
=> List 可迭代
(了解)

5.1.5 declare

2022-03-04 11.10

1
2
3
4
5
6
7
8
新 Fact:简化版 entity Object

元数据(Fact):定义元数据(已有Fact、新Fact)

声明Fact:
同Java(会编译成 Java entity Object,可定义,可使用)
枚举声明
可继承(extends)

5.1.6 Global 全局变量

1
2
3
4
5
6
7
8
提供数据、服务
集成RHS。
例如:发短信,发邮件。
多个DRL文件中使用,都要 global 声明全局变量。

不要用在LHS,除非Global变量不可变。(你保证不会修改它)
全局变量不会插入 Drools引擎工作内存,
所以 Drools引擎不能跟踪 global 变量值。

5.1.7 Rule属性(重点)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
salience
int(默认0)
可正可负,越大先执行。

enabled
布尔
是否启用 Rule

date-effective
△:字符串日期,例如:"2022-03-13"
now > △(执行)

date-expires
now < △(执行)

no-loop
布尔
重新触发,不能激活。
未被触发过,可执行。

agenda-group
获取焦点执行(setFocus),然后执行默认(不设置 => "MAIN")

auto-focus
布尔
重新激活,该议程组自动获取焦点(setFocus)

activation-group
从上到下
同一个组只能激活最先匹配的那一个。

duration
多少 long ms 后,不能被激活。

2022-03-04 12.02

timer(cron:* 0/15 * * * ?)
15分钟执行一次

calendar "* * 0-7,8-23 ? * *"
Quartz calendar定义调度

lock-on-active
ruleflow group 再次被激活
agenda group 再次接收焦点(Focus)

对于上面这两种情况,下次规则无法被激活
直到结束
ruleflow group 不激活
agenda group 失去焦点

这是 no-loop 增强版
匹配 Rule 会被丢弃(不激活)
无论来源是什么(不仅仅是 Rule自己)
其他 Rule的增删改,自己是感知不到的。

★★★★★ 许多 Rule 修改一个 Fact,不希望任何 Rule 重新匹配,再次触发。

ruleflow-group
(废弃)
改用 agenda-group 表示一组 Rule

dialect
"JAVA"默认 或 "MVEL"
一般用在 package 范围。
可能特殊 Rule 用在属性(Rule)

——————-

分隔符
上面是一开始用笔写在本子上的,再用键盘打印的。
下面的是直接,用电脑做的笔记。

5.1.8 WHEN(LHS)

重写
在这里插入图片描述

5.1.8.1 模式和约束

Patterns and constraints
DRL 规则条件中的模式是 Drools 引擎要匹配的段。一个模式可以潜在地匹配插入到 Drools 引擎工作内存中的每个事实。模式还可以包含约束以进一步定义要匹配的事实。
在这里插入图片描述
在这里插入图片描述

  • getter 方法
    下面二者是相同的效果。
    默认 age 或调用其 getAge() 方法,因为它遵循标准的 JavaBeans 规范。

    1
    2
    3
    4
    5
    Person( age == 50 )

    // This is the same as the following getter format:

    Person( getAge() == 50 )
  • fallback 方法
    如果 getter 方法不存在,或执行 另外 Fallback 方法。

    1
    2
    3
    4
    5
    Person( age == 50 )

    // If `Person.getAge()` does not exist, the compiler uses the following syntax:

    Person( age() == 50 )
  • 属性嵌套

    1
    2
    3
    4
    5
    Person( address.houseNumber == 50 )

    // This is the same as the following format:

    Person( getAddress().getHouseNumber() == 50 )

    但不推荐那么做。
    如果更新工作内存中 Address 的话,也要把 Person 给更新。
    (只更新 Address 的话,Drools引擎只能感知到工作内存中 Address 更新,是感知不到 Person 更新的。)

  • 不要在调用前改变Fact
    Fact 状态不应该在调用之前被改变。除非每次改变 Fact 都更新工作内存。

    1
    2
    3
    4
    Person( incrementAndGetAge() == 10 ) // Do not do this.


    Person( System.currentTimeMillis() % 1000 == 0 ) // Do not do this.
  • 等等 比较

    1
    2
    3
    4
    5
    6
    7
    == 等同于


    // java.util.Objects.equals
    public static boolean equals(Object a, Object b) {
    return (a == b) || (a != null && a.equals(b));
    }
  • 强制类型转换
    数值计算,“10” 或强制转为 int 类型 10。
    1
    Person( age == "10" ) // "10" is coerced to 10
  • 逗号等同于 and

    1
    2
    3
    4
    5
    // Person 年龄至少50岁,体重至少80公斤:
    Person( age > 50, weight > 80 )

    // Person 年龄50岁以上,体重80公斤以上,身高2米以上:
    Person( age > 50, weight > 80, height > 2 )
  • 优先级
    && 与 and 表达的意思是一样的,但是优先级不同。
    && 与 || 的优先级要大于逗号 , 的。
    但是,逗号,具有更好的 drools 引擎性能 和 可读性。

注意:不要在复合约束条件中使用逗号,来表示and,应该使用 &&

1
2
3
4
5
// 不要使用以下格式:
Person( ( age > 50, weight > 80 ) || height > 2 )

// 请使用以下格式:
Person( ( age > 50 && weight > 80 ) || height > 2 )

5.1.8.2 绑定变量

推荐使用 $variable 来命名(不强制)。

1
2
3
4
5
6
rule "simple rule"
when
$p : Person()
then
System.out.println( "Person " + $p );
end
  • 绑定变量到属性

    1
    2
    3
    // //两名同龄的人:
    Person( $firstAge : age ) // 绑定
    Person( age == $firstAge ) // 约束表达式
  • 混合绑定
    虽然支持,但不推荐那么用。会影响 Drools引擎的复杂评估。

    1
    2
    3
    4
    5
    // 不要使用以下格式:
    Person( $a : age * 2 < 100 )

    // 请使用以下格式:
    Person( age * 2 < 100, $a : age )
  • 两倍绑定,应使用括号

    1
    Person( $a : (age * 2) )

5.1.8.3 嵌套和内联

嵌套情况下,可以使用 .(<constraints> )
例如:

1
2
3
4
Person( name == "mark", address.city == "london", address.country == "uk" )

// 可以改为下面这种
Person( name == "mark", address.( city == "london", country == "uk") )
  • 井号 内联类型转换

    1
    2
    3
    4
    5
    6
    7
    8
    // 子类型名称内联转换:
    Person( name == "mark", address#LongAddress.country == "uk" )

    // 全限定类名的内联转换:
    Person( name == "mark", address#org.domain.LongAddress.country == "uk" )

    // 多个内联转换:
    Person( name == "mark", address#LongAddress.country#DetailedCountry.population > 10000000 )
  • instanceof 类型判断

    1
    2
    // 如果无法进行内联转换(例如,如果instanceof返回false),则考虑评估false。
    Person( name == "mark", address instanceof LongAddress, address.country == "uk" )

5.1.8.4 Date类型

默认情况下,Drools 引擎支持日期格式dd-mmm-yyyy。(例如:"27-Oct-2009"
也可以设置系统变量来自定义设置。drools.dateformat="dd-mmm-yyyy hh:mm"

drools.defaultlanguage您还可以通过使用和系统属性更改语言区域设置来自定义日期格式drools.defaultcountry
(例如,泰国的区域设置设置为drools.defaultlanguage=thdrools.defaultcountry=TH)。

1
Person( bornBefore < "27-Oct-2009" )

5.1.8.5 自动装箱和原始类型

Drools 尝试使用原始类型保存,若是 Object 类型,需要进行装箱。
在评估的时候,也会强制转为可能的类型。因此,原始类型可以作为 Object 来进行比较。

5.1.8.6 约束运算符

  • 分组访问
    .()

    1
    2
    3
    4
    5
    6
    // 未分组的属性访问器:
    Person( name == "mark", address.city == "london", address.country == "uk" )

    // 分组属性访问器:
    // 句点前缀点 . 将嵌套对象约束与方法调用区分开来。
    Person( name == "mark", address.( city == "london", country == "uk") )
  • 内联类型转换
    #

    1
    2
    3
    4
    5
    6
    7
    8
    // 子类型名称内联转换:
    Person( name == "mark", address#LongAddress.country == "uk" )

    // 全限定类名的内联转换:
    Person( name == "mark", address#org.domain.LongAddress.country == "uk" )

    // 多个内联转换:
    Person( name == "mark", address#LongAddress.country#DetailedCountry.population > 10000000 )
  • 非空判断
    .!
    1
    2
    3
    4
    5
    Person( $streetName : address!.street )

    // 这在内部重写如下:

    Person( address != null, $streetName : address.street )
  • List索引,Map键
    []

    1
    2
    3
    4
    5
    // 等同于 `childList(0).getAge() == 18`:
    Person(childList[0].age == 18)

    // 等同于 `credentialMap.get("jdoe").isValid()`:
    Person(credentialMap["jdoe"].valid)
  • 可比较
    对具有自然顺序的属性使用这些运算符。这些属性仅适用于可比较的属性。
    < <= > >=

    1
    2
    3
    Person( birthDate < $otherBirthDate ) // Date字段,< 运算符表示before

    Person( firstName < $otherFirstName ) // String字段,运算符表示按字母顺序排列 before
  • 不等于
    == !=

    1
    2
    3
    4
    5
    6
    7
    Person( firstName == "John" )

    // 这类似于以下格式:

    java.util.Objects.equals(person.getFirstName(), "John")

    "John".equals(person.getFirstName())
1
2
3
4
5
Person( firstName != "John" )

// 这类似于以下格式:

!java.util.Objects.equals(person.getFirstName(), "John")
1
2
3
4
5
6
7
8
== 等同于



// java.util.Objects#equals
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
  • 条件组合
    && ||

    1
    2
    3
    4
    5
    6
    7
    8
    // 简单缩写组合关系条件使用单一 `&&`:
    Person(age > 30 && < 40)

    // 使用分组的复杂缩写组合关系:
    Person(age ((> 30 && < 40) || (> 20 && < 25)))

    // 将缩写组合关系与约束连接词混合:
    Person(age > 30 && < 40 || location == "london")
  • 正则表达式
    matches not matches
    这些运算符仅适用于String属性。

如果您matches对一个null值使用,则结果评估始终为false。
如果您not matches对一个null值使用,则结果评估始终为true。
与在 Java 中一样,您编写为文字的正则表达式String必须使用双反斜杠\\进行转义。

1
2
3
4
5
// 匹配
Person( country matches "(USA)?\\S*UK" )

// 不匹配
Person( country not matches "(USA)?\\S*UK" )
  • 是否包含
    Array或Collection是否包含指定值。
    也可以用于String类型:String.contains()和!String.contains()约束检查。
    为了向后兼容,excludes运算符是受支持的同义词not contains

contains not contains
Collection

1
2
3
4
5
6
7
8
9
10
// Collection with a specified field:
FamilyTree( countries contains "UK" )

FamilyTree( countries not contains "UK" )


// Collection with a variable:
FamilyTree( countries contains $var )

FamilyTree( countries not contains $var )

String

1
2
3
4
5
6
7
8
9
10
// Sting literal with a specified field:
Person( fullName contains "Jr" )

Person( fullName not contains "Jr" )


// String literal with a variable:
Person( fullName contains $var )

Person( fullName not contains $var )
  • 是否存在…里面
    可以理解为 SQL 中的 in not in
    memberOf not memberOf
    1
    2
    3
    FamilyTree( person memberOf $europeanDescendants )

    FamilyTree( person not memberOf $europeanDescendants )
  • 发音相同
    该运算符使用 Soundex 算法。
    soundslike

    1
    2
    // Match firstName "Jon" or "John":
    Person( firstName soundslike "John" )
  • 字符串开头,结尾,长度
    str[startsWith | endsWith | length]

    1
    2
    3
    4
    5
    6
    7
    8
    // Verify what the String starts with:
    Message( routingValue str[startsWith] "R1" )

    // Verify what the String ends with:
    Message( routingValue str[endsWith] "R2" )

    // Verify the length of the String:
    Message( routingValue str[length] 17 )
  • 在…里面
    等同于 SQL 中的 in not in
    in notin

    1
    2
    3
    4
    5
    Person( $color : favoriteColor )
    Color( type in ( "red", "blue", $color ) )

    Person( $color : favoriteColor )
    Color( type notin ( "red", "blue", $color ) )

5.1.8.7 运算符优先级

在这里插入图片描述

5.1.8.8 规则条件关键字

  • and
    使用它来将条件组件分组为逻辑合取。支持中缀和前缀and。您可以使用括号明确地对模式进行分组()。
    默认情况下,所有列出的模式都与and未指定连词时结合使用。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 中缀 `and`:
    Color( colorType : type ) and Person( favoriteColor == colorType )

    // 中缀 `and` 分组:
    (Color( colorType : type ) and (Person( favoriteColor == colorType ) or Person( favoriteColor == colorType ))

    // 前缀 `and`:
    (and Color( colorType : type ) Person( favoriteColor == colorType ))

    // 默认隐式 `and`:
    Color( colorType : type )
    Person( favoriteColor == colorType )

声明绑定不要使用 and,可以使用 or。
例如下面的错误案例:

1
2
// 编译错误:
$person : (Person( name == "Romeo" ) and Person( name == "Juliet"))
  • or
    使用它来将条件组件分组为逻辑析取。支持中缀和前缀or。您可以使用括号明确地对模式进行分组()。
    您也可以将模式绑定与 一起使用or,但每个模式必须单独绑定。
    1
    2
    3
    4
    5
    6
    7
    8
    // 中缀 `or`:
    Color( colorType : type ) or Person( favoriteColor == colorType )

    // 中缀 `or` 分组:
    (Color( colorType : type ) or (Person( favoriteColor == colorType ) and Person( favoriteColor == colorType ))

    // 前缀 `or`:
    (or Color( colorType : type ) Person( favoriteColor == colorType ))

带有 pattern 绑定的示例:
下面的 $pensioner 只能绑定其中一个。

1
2
3
4
$pensioner : (Person( sex == "f", age > 60 ) or Person( sex == "m", age > 65 ))

(or $pensioner : Person( sex == "f", age > 60 )
$pensioner : Person( sex == "m", age > 65 ))
  • exists
    使用它来指定必须存在的事实和约束。
    如果您将此元素与多个模式一起使用,请用括号将模式括起来()。

注意:此选项仅在第一次匹配时触发,而不是后续匹配。

1
2
3
4
5
6
exists Person( firstName == "John")

exists (Person( firstName == "John", age == 42 ))

exists (Person( firstName == "John" ) and
Person( lastName == "Doe" ))
  • not
    使用它来指定不能存在的事实和约束。
    如果您将此元素与多个模式一起使用,请用括号将模式括起来()。

    1
    2
    3
    4
    5
    6
    not Person( firstName == "John")

    not (Person( firstName == "John", age == 42 ))

    not (Person( firstName == "John" ) and
    Person( lastName == "Doe" ))
  • forall
    使用它来验证与第一个模式匹配的所有事实是否与所有剩余模式匹配。
    当forall构造满足时,规则评估为true。
    这个元素是一个作用域分隔符,所以它可以使用任何以前绑定的变量,但它内部的任何变量都不能在它之外使用。

    1
    2
    3
    4
    5
    6
    7
    8
    rule "All full-time employees have red ID badges"
    when
    forall( $emp : Employee( type == "fulltime" )
    Employee( this == $emp, badgeColor = "red" ) )
    then
    // True, all full-time employees have red ID badges.
    // true,所有的全职员工都有红色的身份证
    end
1
2
3
4
5
6
7
8
9
10
rule "All employees have health and dental care programs"
when
forall( $emp : Employee()
HealthCare( employee == $emp )
DentalCare( employee == $emp )
)
then
// True, all employees have health and dental care.
// true,所有员工都有 health证 和 dental证
end
1
2
3
4
5
6
7
8
9
10
rule "Not all employees have health and dental care"
when
not ( forall( $emp : Employee()
HealthCare( employee == $emp )
DentalCare( employee == $emp ) )
)
then
// True, not all employees have health and dental care.
// true,不是所有员工都有 health证 和 dental证
end
  • from
    使用它来指定模式的数据源。
    这使 Drools 引擎能够对不在工作内存中的数据进行推理。
    数据源可以是绑定变量的子字段,也可以是方法调用的结果。

用于定义对象源的表达式是任何遵循常规 MVEL 语法的表达式。因此,该from元素使您能够轻松使用对象属性导航、执行方法调用以及访问映射和集合元素。
在这里插入图片描述

from $变量

1
2
3
4
5
6
7
rule "Validate zipcode"
when
Person( $personAddress : address )
Address( zipcode == "23920W" ) from $personAddress
then
// Zip code is okay.
end

from $变量.属性

1
2
3
4
5
6
7
rule "Validate zipcode"
when
$p : Person()
$a : Address( zipcode == "23920W" ) from $p.address
then
// Zip code is okay.
end

from 迭代所有对象 $变量.集合属性

1
2
3
4
5
6
7
rule "Apply 10% discount to all items over US$ 100 in an order"
when
$order : Order()
$item : OrderItem( value > 100 ) from $order.items
then
// Apply discount to `$item`.
end

大集合放入变量
一个一个放入,不如直接把集合放入 KIE 的会话中去。

1
2
3
when
$order : Order()
OrderItem( value > 100, order == $order )

带有 lock-on-active 属性的 from
带有 lock-on-active 属性的 from 可能导致规则不被执行。可以使用以下方式解决:
1、当你插入所有Fact到工作内存,或 你使用嵌套引用在你的约束表达式的时候。尽量避免 from 元素的使用。
2、使用 modify() 块的时候,要放在 rule 条件的最后一句。
3、使用 ruleflow group 的时候,使用其中一个来管理另外一个的时候。要避免使用 lock-on-active 属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
rule "Assign people in North Carolina (NC) to sales region 1"
ruleflow-group "test"
lock-on-active true
when
$p : Person()
$a : Address( state == "NC" ) from $p.address
then
modify ($p) {} // 将该员工分配到销售区域1。
end

rule "Apply a discount to people in the city of Raleigh"
ruleflow-group "test"
lock-on-active true
when
$p : Person()
$a : Address( city == "Raleigh" ) from $p.address
then
modify ($p) {} // 对这个人给予折扣。
end

from括号的配合
含from子句的pattern后面不能跟以括号开头的另一个pattern。
此限制的原因是 DRL 解析器将from表达式读取为”from $l (String() or Number())”,它无法将此表达式与函数调用区分开来。
最简单的解决方法是将from子句括在括号中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 错误用法
rule R
when
$l : List()
String() from $l
(String() or Number())
then
// Actions
end

// 正确使用
rule R
when
$l : List()
(String() from $l)
(String() or Number())
then
// Actions
end
  • entry-point
    入口点,通常与 from 一起使用。
    要在 java 中声明。
    略。。。感觉没啥用。

  • collect
    收集。
    可以使用任何 java.util.Collection 实现类。
    例如:List、LinkedList和HashSet,或您自己的类。

(外可内用,内不可外用。)
collect外绑定变量可以在collect内用,collect内绑定变量不可以在collect外用。

1
2
3
4
5
6
7
8
9
10
11
// 收集为 List
import java.util.List

rule "Raise priority when system has more than three pending alarms"
when
$system : System()
$alarms : List( size >= 3 )
from collect( Alarm( system == $system, status == 'pending' ) )
then
// Raise priority because `$system` has three or more `$alarms` pending.
end
1
2
3
4
5
6
7
8
9
10
11
12
13
// 配合 from 使用
import java.util.LinkedList;

rule "Send a message to all parents"
when
$town : Town( name == 'Paris' )
$mothers : LinkedList()
from collect( Person( children > 0 )
from $town.getPeople()
)
then
// Send a message to all parents.
end
  • accumulate
    积累。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    格式:
    accumulate( <source pattern>; <functions> [;<constraints>] )



    Drools 引擎支持以下预定义accumulate函数。
    这些函数接受任何表达式作为输入。
    average
    min
    max
    count
    sum
    collectList
    collectSet
    略。
  • eval
    条件元素eval本质上是一个包罗万象的元素,它允许执行任何语义代码(返回原始布尔值)。
    这段代码可以引用规则包中规则条件和函数中绑定的变量。
    过度使用会eval降低规则的声明性,并可能导致 Drools 引擎性能不佳。
    虽然eval可以在模式中的任何地方使用,但它通常作为规则条件中的最后一个条件元素添加。
    在这里插入图片描述

eval的实例不能被索引,因此效率不如字段约束。
然而,这使得它们非常适合用于函数返回值随时间变化的情况,这在 字段约束 中是不允许的。

1
2
3
p1 : Parameter()
p2 : Parameter()
eval( p1.getList().containsKey( p2.getItem() ) )
1
2
3
4
p1 : Parameter()
p2 : Parameter()
// 在 LHS 里调用 isValid 函数
eval( isValid( p1, p2 ) )

5.1.8.9 OOPath 语法

OOPath 是 XPath 的面向对象的语法扩展,旨在浏览 DRL 规则条件约束中的对象图。
OOPath 使用来自 XPath 的紧凑表示法在处理集合和过滤约束时导航相关元素,特别适用于对象图。

5.1.9 THEN(RHS)

LHS => Rule Conditions
RHS => Rule Actions

RHS 的主要目的是在 Drools 引擎的工作内存中插入、删除或修改数据。
有效的RHS是小的、声明性的和可读的。

如果您需要在RHS中使用命令式或条件代码,最好是将规则划分为多个更小且更具声明性的规则。

1
2
3
4
5
6
7
8
rule "Underage"// 未成年的
when
application : LoanApplication()// 贷款申请
Applicant( age < 21 )// 年龄 < 21
then
application.setApproved( false );// 不同意
application.setExplanation( "Underage" );// 设置说明:未成年
end

5.1.9.1 RHS 增删改方法

DRL 支持您可以在 DRL 规则操作中使用的以下规则操作方法。
您可以使用这些方法来修改 Drools 引擎的工作内存,而无需先引用工作内存实例。

DRL支持以下规则操作方法,您可以在DRL规则操作中使用它们。
您可以使用这些方法来修改Drools引擎的工作内存,而无需先引用工作内存实例。
这些方法充当Drools分发版中RuleContext类提供的方法的快捷方式。

  • set
    直接修改工作内存Fact对象
    1
    2
    // 使用它来设置字段的值。
    set<field> ( <value> )

例如:

1
2
3
// 设置贷款申请批准值的示例规则操作
$application.setApproved ( false );// 不同意
$application.setExplanation( "has been bankrupt" );// 已经破产了
  • modify(推荐modify替代 update)
    使用它来指定要为事实修改的字段并将更改通知 Drools 引擎。
    此方法提供了一种结构化的事实更新方法。它将update操作与 setter 调用相结合以更改对象字段。
    1
    2
    3
    4
    5
    modify ( <fact-expression> ) {
    <expression>,
    <expression>,
    ...
    }

例如:

1
2
3
4
5
// 修改贷款申请金额和批准的示例规则操作
modify( LoanApplication ) {
setAmount( 100 ),// 金额 100
setApproved ( true )// 同意
}
  • update(推荐modify替代 update)
    使用它来指定要更新的字段和整个相关事实,并将更改通知 Drools 引擎。
    调用 update 之前,要调用set去修改这个事实。
    为避免此添加步骤,请改用该modify方法(不进行流程的操控)。

  • insert

使用它可以将一个新事实插入到Drools引擎的工作内存中,并根据需要定义结果字段和值。

1
insert( new <object> );

例如:插入一个学生

1
insert( new Student() );
  • insertLogical
    使用它将一个新的Fact逻辑地插入到Drools引擎中。
    Drools引擎负责对事实的插入和撤回进行逻辑判断。
    在常规或规定的插入之后,必须显式地收回事实(retract)。
    在逻辑插入之后,当插入事实的规则中的条件不再为真时,插入的事实将自动收回(retract)。
  • delete(推荐delete替代 retract)
    使用此属性从Drools引擎中删除对象。

(retract)
DRL也支持关键字retract并执行相同的操作,但是为了与关键字insert保持一致,DRL代码通常更倾向于delete。

1
delete( <object> );

例如:

1
delete( $student);

5.1.9.2 RHS 其他方法

  • drools.getRule().getName()
    返回当前触发规则的名称。

  • drools.getMatch()
    返回Match激活当前触发规则的那个。
    它包含对日志记录和调试有用的信息,
    => 例如drools.getMatch().getObjects()返回对象列表,使规则能够以正确的元组顺序触发。

从drools变量中,您还可以获得对KieRuntime提供有用方法的引用以与正在运行的会话进行交互

  • drools.getKieRuntime().halt()
    如果用户或应用程序先前调用了 ,则终止规则执行fireUntilHalt()。当用户或应用程序调用fireUntilHalt()方法时,Drools 引擎以active模式启动并评估规则,直到用户或应用程序显式调用halt()方法。否则,默认情况下,Drools 引擎在passive模式下运行并仅在用户或应用程序显式调用fireAllRules()方法时评估规则。

  • drools.getKieRuntime().getAgenda()
    返回对 KIE 会话的引用Agenda,进而提供对规则激活组、规则议程组和规则流组的访问。
    例如:设置焦点 drools.getKieRuntime().getAgenda().getAgendaGroup( “CleanUp” ).setFocus();

还有

1
2
3
4
5
drools.getKieRuntime().setGlobal(), ~.getGlobal(), ~.getGlobals(): 设置或检索全局变量。

drools.getKieRuntime().getEnvironment():返回运行时Environment,类似于您的操作系统环境。

drools.getKieRuntime().getQueryResults(<string> query):运行查询并返回结果。

5.1.9.3 do then if-else

略。
因为 drools 支持的是可读性,较小精悍的。
这种只作为扩展。

真想用行不行,肯定行,但不推荐。
在这里插入图片描述