02、Drools 规则引擎 - 入门(上)

第一个规则项目

这篇指导将带你走过创建一个简单Drools应用项目的过程。

需要的工具

JDK11+环境配置

版本3.8.6+的maven

可选,一个代码编辑器,可以是IDEA,VSCode或者Eclipse

用maven原型创建一个项目

用下面的命令创建一个项目

mvnarchetype:generate -DarchetypeGroupId=org.kie -DarchetypeArtifactId=kie-drools-exec-model-ruleunit-archetype -DarchetypeVersion=8.40.0.Final

在命令执行期间,输入项目的属性值

Define value for property 'groupId': org.example
Define value for property 'artifactId': my-project
Define value for property 'version' 1.0-SNAPSHOT: :
Define value for property 'package' org.example: :
...
 Y: : Y
...
[INFO] BUILD SUCCESS

现在,你的第一个规则项目建好了,让我们进到项目里面去查看一下。

首先,是pom文件

<dependency>
   <groupId>org.drools</groupId>
   <artifactId>drools-ruleunits-engine</artifactId>
</dependency>

对于单元规则用例来说,这是一个必须的依赖。

你可以继续使用传统的drools7风格的规则而不是单元规则。

这个用例里面,使用kie-drools-exec-model-archetype。

原型包含一个DRL文件,如下面的例子所示:

package org.example;

unit MeasurementUnit;

rule "will execute per each Measurement having ID color"
when
        /measurements[ id == "color", $colorVal : val ]
then
        controlSet.add($colorVal);
end

query FindColor
    $m: /measurements[ id == "color" ]
end

这个规则检测传入的Measurement数据,并且当其实颜色信息时,将其值存储在一个全局变量controlSet中 。when的部分实现了模式匹配,then的部分实现了当条件成立时的行为。

下一步,找到src/main/java/org/example/MeasurementUnit.java 该类详细说明了规则里面的单元MeasurementUnit。这个被叫做规则单元,用于对数据源,全局变量和DRL规则进行分组。

public class MeasurementUnit implements RuleUnitData {

    private final DataStore<Measurement> measurements;
    private final Set<String> controlSet = new HashSet<>();

    ...

规则文件rules.drl中的/measurements是绑定到MeasurementUnit中的mensurements属性的字段。所以你知道输入的数据类型是Measurement。这个类也被定义为全局变量controlSet。

然后,src/main/java/org/example/Measurement.java 是规则里面的一个java bean的类。这样的对象被称作Fact。

最后,src/test/java/org/example/Measurement.java是执行规则的测试用例。你可以学习在自己的应用中使用简单的API。

MeasurementUnit measurementUnit = new MeasurementUnit();

RuleUnitInstance<MeasurementUnit> instance = RuleUnitProvider.get().createRuleUnitInstance(measurementUnit);

创建一个Measurement实例,然后用RuleUnitProvider创建一个带有Measurement实例的RuleUnitInstance。

measurementUnit.getMeasurements().add(new Measurement("color", "red"));
measurementUnit.getMeasurements().add(new Measurement("color", "green"));
measurementUnit.getMeasurements().add(new Measurement("color", "blue"));

在measurementUnit.measurements添加Measurement facts。这意味着facts被插入到了Drools规则引擎。

List<Measurement> queryResult = instance.executeQuery("FindColor").stream().map(tuple -> (Measurement) tuple.get("$m")).collect(toList());

执行一个叫做FindColor的查询。当你执行一个查询,将自动启动与插入的facts匹配的规则。如果你指向启动规则,不需要查询,你可以直接调用Instance.fire()。

instance.close();

在最后,调用close方法释放RuleUnitInstance所持有的资源。

让我们用mvm clean test命令去运行一下测试程序。

[INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] Running org.example.RuleTest 2022-06-13 12:49:56,499 [main] INFO Creating RuleUnit 2022-06-13 12:49:56,696 [main] INFO Insert data 2022-06-13 12:49:56,700 [main] INFO Run query. Rules are also fired [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.411 s - in org.example.RuleTest

现在你可以添加自己的规则和facts到项目里面去了。

规则项目需要在通过mvn编译阶段生成代码。如果你直接在IDE里面运行RuleTest.java,你可能需要先运行一下mvn compile命令。

Drools中的角色服务入门

作为一个业务规则的开发者,你可以使用Drools设计各种各样的决策服务。这篇文章基于 从Kogito Examples GitHub repository(https://github.com/kiegroup/kogito-examples/tree/stable/kogito-quarkus-examples/dmn-quarkus-example)获得的Traffic_Violation样例工程描述了如何去创建并测试一个交通违章的例子。这个样例项目使用决策模型去定义司机在交通违章中的处罚。你可以根据本文档的步骤去建立一个项目和其包含的文件等,或者打开查看已经创建好的Traffic_Violation的示例项目。或者,你可以直接跳到项目评估部分,方法是从上面的连接中本地查看现成的Traffic_Violation示例项目,然后跳到 Evaluating the traffic violations DMN model with Drools(使用Drools评估交通违法DMN模型)(地址:https://docs.drools.org/8.40.0.Final/drools-docs/drools/getting-started/index.html#gs-evaluating-dmn_getting-started-decision-services)部分。

为了得到更多Drools中DMN模块和实现的信息,可以参考DMN Engine in Drools section(https://docs.drools.org/8.40.0.Final/drools-docs/drools/getting-started/index.html#dmn-con_dmn-models).

先决条件

  • 有一个明确的部署平台。例如使用drools所谓java的依赖,或者使用在云原生平台上使用Kogito。
  • 满足部署平台的先决条件。
  • 在遵循被教程的同时,考虑部署平台的部署过程。

从头开始创建交通违法项目

在IDE中创建一个名为traffic-violation的项目。该项目包含很多素材,例如数据对象,DMN素材,和测试方案。你创建的样例工程和已经存在的Traffic_Violation样例工程,是相似的**。**

根据你使用的IDE和下面的介绍,创建一个基于mavne的KJAR项目。

决策模型

决策模型是由OMG为了描述和建模而建立的一套标准。DMN定义了一套XML的模型,该模式可以让DMN模型在符合DMN模式的平台之间甚至跨越组织去分享,以便让业务分析师和业务规则开发人员在设计与实现DMN决策服务时进行合作。DMN标准和为了设计与建立业务模型过程的BPMN标准相似的标准,并且能够一起使用。

想要获取更多关于DMN背景和应用的信息,请看 Drools DMN landing page

(https://www.drools.org/learn/dmn.html).

创建交通违法的DMN决策需求图

决策需求图是你的DMN模型的视觉表示。使用KIE DMN便捷器去为交通违法项目设计决策需求图,并且决策需求图组件的决策逻辑。

 

图示1.交通违法示例的DRD

先决条件

你已经用Drools建立了一个交通违法项目。

过程

1、 在交通违法项目的首页,点击添加Asset;
2、 在AddAsset页面,点击DMN创建新的DMN窗口会被打开a.在创建新DMN窗口中,在DMN的name属性里面输入TrafficViolation.b.从Package列表里面,选择com.myspace.traffic_violation.c.点击OKDMN设计器里面的DMN素材就会被打开;
3、 在DMN设计板上,拖两个DMN输入数据点到画布上![ ][nbsp2]图示2.DMN输入数据点;
4、 在右上角点击编辑![ ][nbsp3]icon;
5、 双击输入点并且对其中一个重命名为Driver,另一个重命名为Violation;
6、 拖一个DMNDecision决策点到画布上;
7、 双击决策节点并且重命名为Fine;
8、 点击Violation输入节点,选择CreateDMNInformationRequirement图标,并且点击Fine决策节点去连接这两个节点![ ][nbsp4]图示3.CreateDMNInformationRequirement图标;
9、 拖一个DMNDecision决策节点到画布上;
10、 双击决策节点,重命名为Shouldthedriverbesuspended?;
11、 点击Driver输入节点,选择CreateDMNInformationRequirement图标连接Shouldthedriverbesuspended?决策节点;
12、 点击Fine决策节点,选择
CreateDMNInformationRequirement
图标,选择**Shouldthedriverbesuspended?**决策节点;
13、 点击保存;

注意:当你定期地保存DRD时,DMN设计者会对DMN模型进行验证,并且在模型完全定义之前,可能会产生错误的信息。在你完成DMN定义之后,如果还有错误,需要对指定的问题进行故障排除。

创建交通违章DMN自定义数据类型

DMN数据类型决定了在DMN装箱表达式中的表、列或字段中用于定义决策逻辑的数据的结构。你可以使用默认的数据类型(像String,Number或者Boolean),也可以使用自定义的数据类型,去指定你想实现装箱表达式值的属性和约束。使用KIE DMN编辑器的数据类型Tab为交通违章项目,定义自定义数据类型。

 

图示4.自定义数据类型tab

创建下面的表列表tDriver,tViolation和tFine自定义数据类型.

Name Type
tDriver Structure
Name string
Age number
State string
City string
Points number
Name Type
tViolation Structure
Code string
Date date
Type string
Speed Limit number
Actual Speed number
Name Type
tFine Structure
Amount number
Points

number

先决条件:

你用KIE DMN编辑器创建了交通违章DMN决策需求表

 

过程

1、 创建自定义数据tDriver,在DataTypestab页里点击AddacustomDataType,在name属性栏里输入tDriver,在Type列表里面选择Structure;

2、 单击NewDataType右侧的复选框来保存你的更改;

3、 通过点击tDriver旁边的加号,添加下列属性到tDriver数据结构中点击每一个新数据类型右侧的复合按钮保存更改;

Name(string)

Age(number)

State(string)

City(string)

Points(number)

4、 创建自定义数据tViolation,点击NewDataType,在Name属性中输入tViolation,在Type列表里面选择Structure;

 

图示6. 自定义数据类型tViolation

6、 通过点击tViolation旁边的加号,添加下列属性到tViolation数据结构中点击每一个新数据类型右侧的复合按钮保存更改;

Code(string)

Date(date)

Type(string)

Speed Limit(number)

Actual Speed(number)

7、 在嵌套数据类型Type里添加下列约束,点击编辑图标,点击添加约束,在Selectconstrainttype下拉菜单里选择Enumeration

Speed

Parking

Driving under the influence

8、 点击OK,然后点击Type数据类型右侧的复选框保存你的修改;

9、 创建自定义数据tFine,点击NewDataType,在Name属性中输入tFine,在Type列表里面选择Structure,点击保存;

 

图示7. 自定义数据类型tFine

10、 通过点击tFine旁边的加号,添加下列属性到tFine数据结构中点击每一个新数据类型右侧的复合按钮保存更改;

Amount(number)

Points(number)

11、 点击Save;

为DRD的输入和决策节点分配自定义数据类型

在创建DMN自定义数据类型之后,将这些自定义数据分配给交通违章DRD里面的DMN输入节点和DMN决策节点。

先决条件:

在KIE DMN编辑器里面已经创建了交通违章DMN自定义数据类型。

过程:

1、 单击DMN设计者的Model菜单的tab页,单击DMN设计者的右上角的属性图标,导出DRD的属性;
2、 在DRD中,选择Driver输入节点并且在Properties面板的数据类型下拉菜单里面选择tDriver;
3、 选择Violation输入节点并且在Properties面板的数据类型下拉菜单里面选择tViolation;
4、 选择Fine输入节点并且在Properties面板的数据类型下拉菜单里面选择tFine;
5、 选择**Shouldthedriverbesuspended?**决策节点并且设置如下属性;

1、 数据类型:string;
2、 问题:Shouldthedriverbesuspendedduetopointsonhisdriverlicense?;
3、 允许的回答:Yes,No;
6、 单击保存;

至此,你已经将自定义数据类型分配给了DRD的输入和决策节点。

定义交通违章DMN的决策逻辑

计算罚款和决定是否没收驾照,你可以用DMN决策表和上下文的装箱表达式去定义交通文章的DMN决策逻辑。

 

图示8罚款表达式

 

图示9司机是否被没收驾照表达式

先决条件

已经用KIE DMN编辑器将DMN的自定义数据类型分配给了交通违章DRD中的合适的决策和输入节点。

过程

1、 计算罚款,在DMN设计者画布中,选择Fine决策节点,单击边界图标打开DMN装箱表达式的设计器;

 

图示10 决策节点的编辑图标

2、 单击Selectexpression->DecisionTable

 

图示11 选择Decisiong Table的逻辑类型

3、 对于Violaation的Date,Violation的Code和Violation的Speedlimit列,右击并选择删除;

4、 单击Violation的ActualSpeed列并且在表达式属性中输入表达式Violation.ActualSpeed-Violation.SpeedLimit;

5、 在决策表的第一行中输入下列值;

Violation.Type:"speed"

Violation.Actual Speed - Violation.Speed Limit:[10..30)

Amount:500

Points:3

右击第一行并选择Insert below添加另外一行。

6、 在第二行输入下列值;

Violation.Type:"speed"

Violation.Actual Speed - Violation.Speed Limit:>=30

Amount:1000

Points:7

右击第二行并选择Insert below添加另外一行。

7、 在第三行输入下列值;

Violation.Type:"parking"

Violation.Actual Speed - Violation.Speed Limit:-

Amount:100

Points:1

右击第三行并选择Insert below添加另外一行。

8、 在第四行输入下列值;

Violation.Type:"driving under the influence"

Violation.Actual Speed - Violation.Speed Limit:-

Amount:1000

Points:5

9、 单击Save;

10、 定义没收驾照规则,返回DMN设计器画布,选择**Shouldthedriverbesuspended?**决策节点,单击编辑图标打开DMN装箱表达式设计器;

11、 单击Selectexpression->Context.;

12、 单击ContextEntry-1,输入TotalPoints作为name,从数据类型的下拉菜单里选择number;

13、 单击TotalPoints旁边的单元格,从上下文菜单选择Literalexperssion,输入Driver.Points+Fine.Points作为表达式;

14、 单击Driver.Points+Fine.Points的下一格,在上下文菜单选择LiteralExperssion,输入ifTotalPoints>=20then"Yes"else"No";

15、 点击保存;

至此,你已经定义了如何罚款和决策何时没收司机驾照的决策上下文。你可以导航到交通违章项目页面,点击Build按钮构建例子项目,并解决记录在警告面板中的错误。