在 Red Hat Process Automation Manager 中开发决策服务

Red Hat Process Automation Manager 7.9

摘要

本文档论述了如何使用决策模型和表示法(DMN)模型、Jols 规则语言(DRL)文件、指导决策表和其他决策授权资产来使用 Red Hat Process Automation Manager 开发决策服务。

�言

作为商业决策的开发人员,您可以使用 Red Hat Process Automation Manager 使用决策模型和表示法(DMN)模型、Jols 规则(DRL)规则、指导决策表和其他规则授权资产来开发决策服务。

使开�包�更多

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。我们从这四个术语开始:master、slave、黑名单和白名单。由于此项工作十分艰巨,这些更改将在即将推出的几个发行版本中逐步实施。详情请查看 CTO Chris Wright 信息

部分 I. 使用 DMN 模型设计决策服务

作为商业部门或业务规则开发人员,您可以使用决策模型和表示法(DMN)来以图形方式建模一个决策服务。DMN 决策模型的决定要求由决策要求图(DRG)决定,其在一个或多个决策要求图(DRD)中描述。DRD 可以代表 DMN 模型的部分或全部 DRG。DRDs 从开始到完成后跟踪决策,每个决策节点都使用 DMN 框表达式中定义的逻辑(如路由表)。

Red Hat Process Automation Manager 为 DMN 1.2 模型提供设计和运行时支持,具有符合级别 3 的 DMN 1.1 和 1.3 模型的运行时支持。您可以直接在 Business Central 中设计 DMN 模型,或将现有 DMN 模型导入到 Red Hat Process Automation Manager 项目中,以部署和执行。Business Central 的 DMN 设计程序目前不支持 DMN 1.1 和 1.3 模型。

有关 DMN 的更多信息,请参阅对象管理组(OMG) 决策模型和表示法规格

有关带有示例 DMN 决策服务的逐步教程,请参阅开始使用决策服务

第 1 章 Red Hat Process Automation Manager 中的决策授权资产

Red Hat Process Automation Manager 支持多个资产,可用于为您的决策服务定义决策。每个决定授权资产都有不同的优点,您可能需要根据您的目标和需求使用多个资产的组合。

下表重点介绍 Red Hat Process Automation Manager 项目支持的主要决策授权资产,以帮助您决定或确认在决策服务中定义决策的最佳方法。

表 1.1. Red Hat Process Automation Manager 支持的决策授予资产

assethighlight编写工具Documentation

决策模型和表示法(DMN)模型

  • 是根据对象管理组(OMG)定义的表示法标准决定模型。
  • 使用代表部分或所有决策要求图(DRG)的图形决策要求图(DRG)来跟踪业务决策流程
  • 使用允许在 DMN 兼容平台之间共享 DMN 模型的 XML 模式
  • 支持 Friendly Enough Expression Language (FEEL),以在 DMN 决策表和其他 DMN 框表达式中定义决策逻辑
  • 可以与 Business Process Model 和 Notation (DSLN)进程模型有效集成
  • 是创建全面、演示和稳定的决策流程的最佳选择

Business Central 或其他与 DMN 兼容的编辑器

使用 DMN 模型设计决策服务

主要决策表

  • 是您在 Business Central 的基于 UI 的表设计程序中创建的规则表
  • 是电子表格决策表的向导替代方法
  • 为可接受的输入提供字段和选项
  • 支持用于创建规则模板的模板键和值
  • 支持点击策略、实时验证以及其他资产不支持的其他额外功能
  • 最好以受控的 tabular 格式创建规则,以最小化编译错误

Business Central

使用指导决策表设计决策服务

电子表格决策表

  • 是 XLS 或 XLSX 电子表格决策表,您可以上传到 Business Central
  • 支持用于创建规则模板的模板键和值
  • 最好在 Business Central 外部管理的路由表中创建规则
  • 对于在上传时正确编译的规则具有严格的语法要求

电子表格编辑器

使用电子表格决策表设计决策服务

指导规则

  • 是您在 Business Central 中基于 UI 的规则设计程序中创建的单个规则
  • 为可接受的输入提供字段和选项
  • 最好以受控格式创建单个规则,以最小化编译错误

Business Central

使用指导规则设计决策服务

指导规则模板

  • 是您在 Business Central 中的基于 UI 的模板设计程序中创建的可重复使用的规则结构
  • 为可接受的输入提供字段和选项
  • 支持用于创建规则模板的模板键和值(与资产相关的目的不同)
  • 最好创建具有相同规则结构但具有不同定义的字段值的规则

Business Central

使用指导规则模板设计决策服务

DRL 规则

  • 是直接在 .drl 文本文件中定义的单个规则
  • 提供定义规则和其他规则行为的最灵活
  • 可以在某些独立环境中创建,并与 Red Hat Process Automation Manager 集成
  • 最好创建需要高级 DRL 选项的规则
  • 具有正确编译的规则具有严格的语法要求

Business Central 或集成开发环境(IDE)

使用 DRL 规则设计决策服务

预测模型标记语言(PMML)模型

  • 是预测的 data-analytic 模型,它基于由 Data Mining Group (DMG)定义的表示法标准
  • 使用一个 XML 模式,允许在 PMML 兼容平台之间共享 PMML 模型
  • 支持 Regression、Scorecard、Tree、Ming 和其他模型类型
  • 可以包含独立 Red Hat Process Automation Manager 项目,也可以导入到 Business Central 中的项目中
  • 最好在 Red Hat Process Automation Manager 中将预测数据整合到决策服务中

pmML 或 XML 编辑器

使用 PMML 模型设计决策服务

第 2 章 决策模型和表示法(DMN)

决策模型和表示法(DMN)是由对象管理组(OMG)建立的标准,用于描述和建模操作决策。DMN 定义了一个 XML 模式,它允许在 DMN 兼容平台和机构间共享 DMN 模型,以便开发人员能够互动并实施 DMN 决策服务。DMN 标准与流程类似,并可与用于设计和建模的 Business Process Model 和 Notation (DSLN)标准一起使用。

有关 DMN 的背景和应用程序的更多信息,请参阅 OMG Decision Model 和 Notation 规格

2.1. DMN 一致性级别

DMN 规范定义了软件实施中的三个增量等级。在一个级别上声明合规的产品也必须符合任何前面的级别。例如,有一致性级别 3 的实施还必须包含支持的组件,符合级别 1 和 2。有关每个符合等级的正式定义,请参阅 OMG Decision Model 和 Notation 规格

以下列表总结了三个 DMN 一致性级别:

一致性级别 1
DMN 一致性级别 1 实施支持决策要求图(DRD)、决策逻辑和决策表,但决策模型不可执行。任何语言都可用于定义表达式,包括自然的、非结构化语言。
等级级别 2
DMN 一致性级别 2 实施包括符合级别 1 的要求,并支持简化的 Friendly Enough Expression Language (S-FEEL)表达式和完全可执行的决策模型。
等级级别 3
DMN 一致性级别 3 实施包括符合级别 1 和 2 的要求,并支持 Friendly Enough Expression Language (FEEL)表达式、完整的框表达式和完全可执行的决策模型。

Red Hat Process Automation Manager 为 DMN 1.2 模型提供设计和运行时支持,具有符合级别 3 的 DMN 1.1 和 1.3 模型的运行时支持。您可以直接在 Business Central 中设计 DMN 模型,或将现有 DMN 模型导入到 Red Hat Process Automation Manager 项目中,以部署和执行。Business Central 的 DMN 设计程序目前不支持 DMN 1.1 和 1.3 模型。

2.2. DMN 决策要求图(DRD)组件

决策要求图(DRD)是 DMN 模型的可视化表示。DRD 可以代表 DMN 模型的部分或所有决策要求图(DRG)。DRD 使用决策节点、业务知识模型、业务知识源、输入数据和决策服务来跟踪决策。

下表总结了 DRD 中的组件:

表 2.1. DRD 组件

组件æ��è¿°表示法

元素

决策

一个或多个输入元素的节点根据定义的决策逻辑决定输出。

DMN 决策节点

业务知识模型

包含一个或多个决策元素的可重复使用的功能。具有相同逻辑但依赖于不同的子输入数据或子部门的决策使用业务知识模型来确定要遵循哪些流程。

DMN bkm node

知识源

监管决策或业务知识模型的外部机构、文档、提交或策略。知识源是指实际因素的参考,而不是可执行的业务逻辑。

DMN 知识源节点

输入数据

在决策节点或业务知识模型中使用的信息。输入数据通常包括与业务相关的业务级概念或对象,如 Lending 策略中使用的 loan applicant 数据。

DMN 输入数据节点

决策服务

包含一组可重复使用的决策,作为调用的服务发布。一个决策服务可以从外部应用程序或 Dan 商业流程调用。

DMN 决策服务节点

要求连接器

信息要求

从输入数据节点或决策节点连接到需要信息的另一个决策节点。

DMN 信息连接器

知识要求

从业务知识模型连接到决策节点,或连接到调用决策逻辑的另一种业务知识模式。

DMN 知识连接器

授权要求

从输入数据节点或决策节点连接到依赖知识源,或从知识源到决策节点、业务知识模型或其他知识源。

DMN 授权连接器

工件

文本注解

与输入数据节点、决策节点、业务知识模型或知识源相关联。

DMN 注解节点

关联

从输入数据节点、决策节点、业务知识模型或知识源连接到文本注解。

DMN 关联连接器

下表总结了 DRD 元素之间允许的连接器:

表 2.2. DRD 连接器规则

连接到è¿�æ�¥ç±»å�‹ç¤ºä¾‹

决策

决策

信息要求

对决定的 DMN 决策

业务知识模型

决策

知识要求

DMN bkm 决策

业务知识模型

DMN bkm to bkm

决策服务

决策

知识要求

DMN 决策服务以决定

业务知识模型

DMN 决定服务到 bkm

输入数据

决策

信息要求

对决定的 DMN 输入

知识源

授权要求

对知识源的 DMN 输入

知识源

决策

授权要求

准备决定的 DM 知识源

业务知识模型

DMN 知识源为 bkm

知识源

知识来源了解知识源

决策

文本注解

关联

DMN 决定注解

业务知识模型

DMN bkm 用于注解

知识源

DMN 知识源以注解

输入数据

DMN 输入注解

以下示例 DRD 在实践中演示了其中一些 DMN 组件:

图 2.1. 示例 DRD: Loan prequalification

DMN 示例 drd

以下示例 DRD 演示了作为可重复使用的决定服务一部分的 DMN 组件:

图 2.2. DRD 示例:将处理作为决策服务进行调用

DMN 示例 drd3

在 DMN 决策服务节点中,底部段中的决策节点融合了来自决策服务的输入数据,以便在决策服务节点的顶部决定。然后,根据决策服务带来的顶级决策,将根据 DMN 模型的任何后续决策或企业知识要求来实施。您可以在其他 DMN 模型中重复使用 DMN 决策服务,以使用不同的输入数据和不同的传出连接应用相同的决策逻辑。

2.3. FEEL 中的规则表达式

友好的 Enough Expression Language (FEEL)是对象管理组(OMG) DMN 规范定义的表达式语言。FEEL 表达式在 DMN 模型中定义决策的逻辑。FEEL 旨在通过为决策模型结构分配语义来促进决策模型和执行。决策要求图(DRD) occupy 表单元中的 FEEL 表达式是决策节点和业务知识模型的方框表达式。

有关 DMN 中的 FEEL 的更多信息,请参阅 OMG Decision Model 和 Notation 规格

2.3.1. FEEL 中的数据类型

友好的 Enough Expression Language (FEEL)支持以下数据类型:

  • number
  • 字符串
  • 布尔值
  • 日期
  • Time
  • 日期和时间
  • 天数和持续时间
  • 年和月持续时间
  • Functions
  • context
  • 范围(或间隔)
  • list
注意

DMN 规格目前不提供将变量声明为 函数上下文、范围或 列表的 显式方法,但 Red Hat Process Automation Manager 扩展了 DMN 内置类型来支持这些类型的变量。

以下列表描述了每种数据类型:

number

FEEL 中的数字基于 IEEE 754-2008 Decimal 128 格式,其 34 位数字精度。在内部,数字在 Java 中以 MathContext DECIMAL128 的形式表示。 https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.htmlFEEL 只支持一个数字数据类型,因此同一类型用于表示整数和浮动点号。

FEEL 号使用点(.)作为十进制分隔符。FEEL 不支持 -INF+INFNaN。FEEL 使用 null 来代表无效数字。

Red Hat Process Automation Manager 扩展 DMN 规格并支持额外的数字表示法:

  • Scientific : 您可以使用带有后缀 e<exp>E<exp> 的 Scientific 表示法。例如,1.2e3 与编写表达式 1.239)101143 相同,但是一个字面而不是表达式。
  • 十六进制 :您可以使用前缀为 0x 的十六进制数字。例如,0xff 与十进制数字 255 相同。支持大写字母和小写字母。例如,0XFF0xff 相同。
  • 类型后缀: 您可以使用类型后缀 fFdDlL。这些后缀将被忽略。
字符串

FEEL 中的字符串是以双引号分隔的任何字符序列。

示例

"John Doe"

布尔值
FEEL 使用三值布尔值逻辑,因此布尔值逻辑表达式可能的值为 truefalsenull
日期

FEEL 不支持日期字面,但您可以使用内置 date () 函数来构建日期值。FEEL 中的日期字符串遵循 XML 架构第 2 部分中定义的格式:Datatypes 文档。格式为 "YYYY-MM-DD",其中 YYYY 是四位,MM 是带有两位数字的月份,DD 是一天的数量。

例如:

date( "2017-06-23" )

日期对象的时间等于 "00:00:00",即午夜。日期被视为本地,没有时区。

Time

FEEL 不支持时间字面,但您可以使用内置 time () 函数来构建时间值。FEEL 中的时间字符串遵循 XML 架构第 2 部分中定义的格式:Datatypes 文档。格式为 "hh:mm:ss[.uu][(+-) hh:mm]",其中 hh 是一天的小时(从 0023),mm 是小时中的分钟,sss 是分钟(以分钟为单位)。(可选)字符串可以在第二个时间段内定义毫秒数(uu),并从 UTC 时间包含一个正数(+)或负数(-)偏移量以定义其时区。您可以使用字母 z 表示 UTC 时间,而不必使用偏移值 -00:00。如果没有定义偏移量,则时间被视为 local。

示例:

time( "04:25:12" )
time( "14:10:00+02:00" )
time( "22:35:40.345-05:00" )
time( "15:00:30z" )

定义偏移或时区的时间值不能与未定义偏移或时区的本地时间进行比较。

日期和时间

FEEL 不支持日期和时间字面,但您可以使用内置 日期和时间 () 函数来构建日期和时间值。FEEL 中的日期和时间字符串遵循 XML 架构第 2 部分定义的格式:Datatypes 文档。格式为 "< date>T<time>",其中 <date & gt; 和 <time > 遵循预先发布的 XML 模式格式,由 T 共存。

示例:

date and time( "2017-10-22T23:59:00" )
date and time( "2017-06-13T14:10:00+02:00" )
date and time( "2017-02-05T22:35:40.345-05:00" )
date and time( "2017-06-13T15:00:30z" )

定义偏移或时区的日期和时间值不能与不定义偏移或时区的本地日期和时间值进行比较。

重要

如果您的 DMN 规范的实现不支持 XML 模式中的空格,请使用关键字 dateTime 作为 日期和时间

天数和持续时间

FEEL 不支持天数和持续时间字面,但您可以使用内置 duration () 函数来构建天数和持续时间值。FEEL 中的天数和持续时间字符串遵循 XML 架构第 2 部分中定义的格式:Datatypes 文档,但仅限于天数、小时、分钟和秒。不支持月和年。

示例:

duration( "P1DT23H12M30S" )
duration( "P23D" )
duration( "PT12H" )
duration( "PT35M" )
重要

如果您的 DMN 规范的实现不支持 XML 模式中的空格,请使用关键字 dayTimeDuration 作为 天数和持续时间的组合

年和月持续时间

FEEL 不支持年和月持续时间字面,但您可以使用内置 duration () 函数来构建天数和持续时间值。FEEL 中的年和月持续时间字符串遵循 XML 架构第 2 部分定义的格式:Datatypes 文档,但仅限于年和月。不支持天数、小时、分钟或秒。

示例:

duration( "P3Y5M" )
duration( "P2Y" )
duration( "P10M" )
duration( "P25M" )
重要

如果您的 DMN 规范的实现不支持 XML 模式中的空格,请使用关键字 yearMonthDuration 作为 年和月持续时间

Functions

FEEL 具有可用于创建功能的功能字面(或匿名功能)。DMN 规格目前不提供将变量声明为 函数的 显式方法,但 Red Hat Process Automation Manager 扩展了 DMN 内置类型来支持函数的变量。

例如:

function(a, b) a + b

在本例中,FEEL 表达式会创建一个添加参数 ab 且返回结果的功能。

context

FEEL 具有可用于创建上下文的上下文字面。FEEL 中的 上下文是 键和值对列表,类似于 Java 等语言的映射。DMN 规格目前不提供将变量声明为 上下文 的显式方法,但 Red Hat Process Automation Manager 扩展了 DMN 内置类型来支持上下文变量。

例如:

{ x : 5, y : 3 }

在本例中,表达式会创建一个带有两个条目 xy 的上下文,代表图表中的协调。

在 DMN 1.2 中,创建上下文的另一种方法是创建一个项目定义,它将键列表作为属性组成,然后将变量声明为具有该项目定义类型。

Red Hat Process Automation Manager DMN API 支持以两种方式表示的 DMN the Definition structural 类型:

  • 用户定义的 Java 类型:必须是有效的 IaaS 对象,定义属性,并为 DMN114 Definition 中的每个组件获取。如果需要,您也可以对代表组件名称的 getters 使用 @FEELProperty 注释,这会导致 Java 标识符无效。
  • java.util.Map 接口:映射需要定义适当的条目,其键与 DMN114 Definition 中的组件名称对应
范围(或间隔)

FEEL 具有 范围 字面,您可以使用它来创建范围或间隔。FEEL 中 的范围是 一个值,它定义了较低和上限,其中可以是打开或关闭。DMN 规格目前不提供将变量声明为 范围的 显式方法,但 Red Hat Process Automation Manager 扩展了 DMN 内置类型来支持范围的变量。

范围的语法采用以下格式定义:

range          := interval_start endpoint '..' endpoint interval_end
interval_start := open_start | closed_start
open_start     := '(' | ']'
closed_start   := '['
interval_end   := open_end | closed_end
open_end       := ')' | '['
closed_end     := ']'
endpoint       := expression

端点的表达式必须返回类似值,下限端点必须低于上限的端点。

例如,以下字面表达式定义了 110 之间的间隔,包括边界(两个端点关闭间隔):

[ 1 .. 10 ]

以下字面表达式定义了 1 小时到 12 小时之间的间隔,包括下限(关闭间隔),但排除上限边界(开放间隔):

[ duration("PT1H") .. duration("PT12H") )

您可以使用决策表中的范围来测试值范围,或者在简单的字面表达式中使用范围。例如,如果变量 x 的值介于 0100 之间,则以下字面表达式返回 true

x in [ 1 .. 100 ]
list

FEEL 具有 列出 可用于创建项目列表的字面点。FEEL 的列表 由用逗号分开的值列表表示,用方括号括起。DMN 规格目前不提供将变量声明为 列表的 显式方法,但 Red Hat Process Automation Manager 扩展了 DMN 内置类型来支持列表的变量。

例如:

[ 2, 3, 4, 5 ]

FEEL 中的所有列表都包含相同类型和不可变的元素。列表中的元素可以被索引访问,其中第一个元素为 1。负索引可以访问从列表末尾开始的元素,以便 -1 是最后一个元素。

例如,以下表达式返回列表 x 的第二个元素:

x[2]

以下表达式返回列表 x 的 second-to-last 元素:

x[-2]

列表中的元素也可以通过函数 来计算,该函数使用元素列表作为参数。

例如,以下表达式返回 4

count([ 2, 3, 4, 5 ])

2.3.2. FEEL 中的内置功能

为提升与其他平台和系统的互操作性,FEEL 包含了内置的函数库。内置的 FEEL 功能在 dros Decision Model and Notation (DMN)引擎中实施,以便您在 DMN 决策服务中使用功能。

以下小节描述了每个内置的 FEEL 功能,格式为 NAME( PARAMETERS )。有关 DMN 中的 FEEL 功能的更多信息,请参阅 OMG Decision Model 和 Notation 规格

2.3.2.1. 转换功能

以下功能支持在不同类型值之间进行转换。其中一些功能使用特定的字符串格式,如以下示例:

date( from ) - using date

从一个 日期 值转换。

表 2.3. å�‚æ•°

�数类�格�

from

字符串

日期字符串

示例

date( "2012-12-25" ) - date( "2012-12-24" ) = duration( "P1D" )

date (from)- 使用日期和时间

日期值转换到 日期 值,并将时间组件设置为 null。

表 2.4. å�‚æ•°

�数类�

from

日期和时间

示例

date(date and time( "2012-12-25T11:00:00Z" )) = date( "2012-12-25" )

date (year, month, day)

从指定的年、月份 和日期 值生成日期。

表 2.5. å�‚æ•°

�数类�

year

number

month

number

day

number

示例

date( 2012, 12, 25 ) = date( "2012-12-25" )

date and time( date, time )

从指定 日期 生成日期和时间,并忽略任何时间组件和指定时间。

表 2.6. å�‚æ•°

�数类�

date

日期和时间

time

time

示例

date and time ( "2012-12-24T23:59:00" ) = date and time(date( "2012-12-24" ), time( "23:59:00" ))

日期和时间(from)

从指定的字符串生成 日期和时间

表 2.7. å�‚æ•°

�数类�格�

from

字符串

日期日期字符串

示例

date and time( "2012-12-24T23:59:00" ) + duration( "PT1M" ) = date and time( "2012-12-25T00:00:00" )

time( from )

从指定的字符串生成 时间

表 2.8. å�‚æ•°

�数类�格�

from

字符串

时间字符串

示例

time( "23:59:00z" ) + duration( "PT2M" ) = time( "00:01:00@Etc/UTC" )

time( from )

从指定参数生成 时间,并忽略任何日期组件。

表 2.9. å�‚æ•°

�数类�

from

时间和日期

示例

time(date and time( "2012-12-25T11:00:00Z" )) = time( "11:00:00Z" )

time (hour, minute, second, offset?)

从指定小时、分钟和第二组件值生成时间。

表 2.10. å�‚æ•°

�数类�

hour

number

minute

number

second

number

offset (可选)

天数和持续时间 或 null

示例

time( "23:59:00z" ) = time(23, 59, 0, duration( "PT0H" ))

number (from, grouping separator, decimal separator)

使用指定的分隔符 转换为 数字

表 2.11. å�‚æ•°

�数类�

from

代表有效数字的字符串

分组分隔符

空格()、逗号()、句点(.)或 null

十进制分隔符

类型与 分组分隔符 相同,但值不能匹配

示例

number( "1 000,0", " ", "," ) = number( "1,000.0", ",", "." )

string( from )

提供指定参数的字符串表示。

表 2.12. å�‚æ•°

�数类�

from

非空值

例�

string( 1.1 ) = "1.1"
string( null ) = null

duration( from )

几天和持续时间值或 年和 月持续时间 值转换。

表 2.13. å�‚æ•°

�数类�格�

from

字符串

持续时间字符串

例�

date and time( "2012-12-24T23:59:00" ) - date and time( "2012-12-22T03:45:00" ) = duration( "P2DT20H14M" )
duration( "P2Y2M" ) = duration( "P26M" )

年和月的持续时间(从、到 )

计算两个指定参数之间的 年和月持续时间

表 2.14. å�‚æ•°

�数类�

from

日期和时间

to

日期和时间

示例

years and months duration( date( "2011-12-22" ), date( "2013-08-24" ) ) = duration( "P1Y8M" )

2.3.2.2. 布尔值功能

以下功能支持布尔值操作。

not( negand )

执行 negand 操作对象的逻辑负部分。

表 2.15. å�‚æ•°

�数类�

negand

布尔值

例�

not( true ) = false
not( null ) = null

2.3.2.3. 字符串函数

以下功能支持字符串操作。

注意

在 FEEL 中,Unicode 字符根据其代码点进行计算。

substring (string, start position, length?)

从指定长度的起始位置返回子字符串。第一个字符位于位置值 1

表 2.16. å�‚æ•°

�数类�

字符串

字符串

启动位置

number

长度 (可选)

number

例子

substring( "testing",3 ) = "sting"
substring( "testing",3,3 ) = "sti"
substring( "testing", -2, 1 ) = "n"
substring( "\U01F40Eab", 2 ) = "ab"

注意

在 FEEL 中,字符串字面为 "\U01F40Eab"Evolutionab 字符串(horse 符号后跟 ab)。

string length( string )

计算指定字符串的长度。

表 2.17. å�‚æ•°

�数类�

字符串

字符串

例�

string length( "tes" ) = 3
string length( "\U01F40Eab" ) = 3

upper case( string )

生成指定字符串的大写版本。

表 2.18. å�‚æ•°

�数类�

字符串

字符串

示例

upper case( "aBc4" ) = "ABC4"

lower case( string )

生成指定字符串的小写版本。

表 2.19. å�‚æ•°

�数类�

字符串

字符串

示例

lower case( "aBc4" ) = "abc4"

substring before( string, match )

计算匹配项前的子字符串。

表 2.20. å�‚æ•°

�数类�

字符串

字符串

match

字符串

例�

substring before( "testing", "ing" ) = "test"
substring before( "testing", "xyz" ) = ""

substring after( string, match )

在匹配项后计算子字符串。

表 2.21. å�‚æ•°

�数类�

字符串

字符串

match

字符串

例�

substring after( "testing", "test" ) = "ing"
substring after( "", "a" ) = ""

replace (input, pattern, replacement, flags?)

计算正则表达式替换。

表 2.22. å�‚æ•°

�数类�

输入

字符串

pattern

字符串

替换

字符串

标记 (可选)

字符串

注意

此功能使用 XQuery 1.0 和 XPath 2.0 功能和 Operator 中定义的正则表达式参数。

示例

replace( "abcd", "(ab)|(a)", "[1=$1][2=$2]" ) = "[1=ab][2=]cd"

contains (string, match)

如果字符串包含匹配项,则返回 true

表 2.23. å�‚æ•°

�数类�

字符串

字符串

match

字符串

示例

contains( "testing", "to" ) = false

starting with (string, match)

如果字符串以匹配项开头,则返回 true

表 2.24. å�‚æ•°

�数类�

字符串

字符串

match

字符串

示例

starts with( "testing", "te" ) = true

end with (string, match)

如果字符串以匹配项结尾,则返回 true

表 2.25. å�‚æ•°

�数类�

字符串

字符串

match

字符串

示例

ends with( "testing", "g" ) = true

match (input, pattern, flags?)

如果输入与正则表达式匹配,则返回 true

表 2.26. å�‚æ•°

�数类�

输入

字符串

pattern

字符串

标记 (可选)

字符串

注意

此功能使用 XQuery 1.0 和 XPath 2.0 功能和 Operator 中定义的正则表达式参数。

示例

matches( "teeesting", "^te*sting" ) = true

split( string, delimiter )

返回原始字符串的列表,并将它分成分隔符正则表达式模式。

表 2.27. å�‚æ•°

�数类�

字符串

字符串

delimiter

正则表达式模式的字符串

注意

此功能使用 XQuery 1.0 和 XPath 2.0 功能和 Operator 中定义的正则表达式参数。

例�

split( "John Doe", "\\s" ) = ["John", "Doe"]
split( "a;b;c;;", ";" ) = ["a","b","c","",""]

2.3.2.4. 列出功能

以下功能支持列表操作。

注意

在 FEEL 中,列表中的第一个元素的索引是 1。列表中最后一个元素的索引可以识别为 -1

list contains (list, element)

如果列表包含元素,则返回 true

表 2.28. å�‚æ•°

�数类�

list

list

元素

任何类型,包括 null

示例

list contains( [1,2,3], 2 ) = true

count( list )

计算列表中的元素。

表 2.29. å�‚æ•°

�数类�

list

list

例�

count( [1,2,3] ) = 3
count( [] ) = 0
count( [1,[2,3]] ) = 2

min( list )

返回列表中最小比较元素。

表 2.30. å�‚æ•°

�数类�

list

list

替代签名

min( e1, e2, ..., eN )

例�

min( [1,2,3] ) = 1
min( 1 ) = 1
min( [1] ) = 1

max( list )

返回列表中最大比较元素。

表 2.31. å�‚æ•°

�数类�

list

list

替代签名

max( e1, e2, ..., eN )

例�

max( 1,2,3 ) = 3
max( [] ) = null

sum( list )

返回列表中数字的总和。

表 2.32. å�‚æ•°

�数类�

list

数量 元素 列表

替代签名

sum( n1, n2, ..., nN )

例�

sum( [1,2,3] ) = 6
sum( 1,2,3 ) = 6
sum( 1 ) = 1
sum( [] ) = null

mean( list )

计算列表中元素的平均(不同含义)。

表 2.33. å�‚æ•°

�数类�

list

数量 元素 列表

替代签名

mean( n1, n2, ..., nN )

例�

mean( [1,2,3] ) = 2
mean( 1,2,3 ) = 2
mean( 1 ) = 1
mean( [] ) = null

all( list )

如果列表中的所有元素都为 true,则返回 true。

表 2.34. å�‚æ•°

�数类�

list

布尔值 元素 列表

替代签名

all( b1, b2, ..., bN )

例�

all( [false,null,true] ) = false
all( true ) = true
all( [true] ) = true
all( [] ) = true
all( 0 ) = null

any( list )

如果列表中的任何元素为 true,则返回 true。

表 2.35. å�‚æ•°

�数类�

list

布尔值 元素 列表

替代签名

any( b1, b2, ..., bN )

例�

any( [false,null,true] ) = true
any( false ) = false
any( [] ) = false
any( 0 ) = null

sublist (list, start position, length?)

从起始位置返回子列表,仅限于 length 元素。

表 2.36. å�‚æ•°

�数类�

list

list

启动位置

number

长度 (可选)

number

示例

sublist( [4,5,6], 1, 2 ) = [4,5]

append( list, item )

创建附加到项目或项目的列表。

表 2.37. å�‚æ•°

�数类�

list

list

任何类型的

示例

append( [1], 2, 3 ) = [1,2,3]

concatenate( list )

创建是串联列表结果的列表。

表 2.38. å�‚æ•°

�数类�

list

list

示例

concatenate( [1,2],[3] ) = [1,2,3]

insert before( list, position, newItem )

创建在指定位置插入了 newItem 的列表。

表 2.39. å�‚æ•°

�数类�

list

list

position

number

newItem

任何类型的

示例

insert before( [1,3],1,2 ) = [2,1,3]

remove( list, position )

创建一个包含指定位置中排除的元素的列表。

表 2.40. å�‚æ•°

�数类�

list

list

position

number

示例

remove( [1,2,3], 2 ) = [1,3]

reverse( list )

返回反向列表。

表 2.41. å�‚æ•°

�数类�

list

list

示例

reverse( [1,2,3] ) = [3,2,1]

index of( list, match )

返回与元素匹配的索引。

�数

  • 类型列表 列表
  • 任何类型的 匹配

表 2.42. å�‚æ•°

�数类�

list

list

match

任何类型的

示例

index of( [1,2,3,2],2 ) = [2,4]

union( list )

从多个列表中返回所有元素的列表,并排除重复项。

表 2.43. å�‚æ•°

�数类�

list

list

示例

union( [1,2],[2,3] ) = [1,2,3]

distinct values( list )

从单个列表中返回元素列表,并排除重复项。

表 2.44. å�‚æ•°

�数类�

list

list

示例

distinct values( [1,2,3,2,1] ) = [1,2,3]

flatten( list )

返回扁平化列表。

表 2.45. å�‚æ•°

�数类�

list

list

示例

flatten( [[1,2],[[3]], 4] ) = [1,2,3,4]

product( list )

返回列表中数字的产品。

表 2.46. å�‚æ•°

�数类�

list

数量 元素 列表

替代签名

product( n1, n2, ..., nN )

例�

product( [2, 3, 4] ) = 24
product( 2, 3, 4 ) = 24

median (list)

返回列表中数字的介质。如果元素数量是奇数,则结果是中间的元素。如果元素数量甚至如此,则结果是两个中间元素的平均值。

表 2.47. å�‚æ•°

�数类�

list

数量 元素 列表

替代签名

median( n1, n2, ..., nN )

例�

median( 8, 2, 5, 3, 4 ) = 4
median( [6, 1, 2, 3] ) = 2.5
median( [ ] ) = null

stddev( list )

返回列表中数字的标准差异。

表 2.48. å�‚æ•°

�数类�

list

数量 元素 列表

替代签名

stddev( n1, n2, ..., nN )

例�

stddev( 2, 4, 7, 5 ) = 2.081665999466132735282297706979931
stddev( [47] ) = null
stddev( 47 ) = null
stddev( [ ] ) = null

mode( list )

返回列表中数字的模式。如果返回多个元素,则数字会按照升序排序。

表 2.49. å�‚æ•°

�数类�

list

数量 元素 列表

替代签名

mode( n1, n2, ..., nN )

例�

mode( 6, 3, 9, 6, 6 ) = [6]
mode( [6, 1, 9, 6, 1] ) = [1, 6]
mode( [ ] ) = [ ]

2.3.2.5. 数字功能

以下功能支持数字操作。

decimal (n, scale)

返回带有指定扩展的数字。

表 2.50. å�‚æ•°

�数类�

n

number

scale

范围内的 数字 [rhacm6111..6176]

例子

decimal( 1/3, 2 ) = .33
decimal( 1.5, 0 ) = 2
decimal( 2.5, 0 ) = 2

floor( n )

返回小于或等于指定数量的最大整数。

表 2.51. å�‚æ•°

�数类�

n

number

例�

floor( 1.5 ) = 1
floor( -1.5 ) = -2

ceiling( n )

返回大于或等于指定数量的最小整数。

表 2.52. å�‚æ•°

�数类�

n

number

例�

ceiling( 1.5 ) = 2
ceiling( -1.5 ) = -1

abs( n )

返回绝对值。

表 2.53. å�‚æ•°

�数类�

n

数字天和持续时间年数和月持续时间

例�

abs( 10 ) = 10
abs( -10 ) = 10
abs( @"PT5H" ) = @"PT5H"
abs( @"-PT5H" ) = @"PT5H"

modulo( dividend, divisor )

返回被分开的划分的剩余部分。如果 dind 或 divisor 是负数,则结果与 divisor 相同。

注意

此功能也表示为 modulo (dividend, divisor)= splitnd - divisor (dividen d/divisor)

表 2.54. å�‚æ•°

�数类�

splitnd

number

divisor

number

例�

modulo( 12, 5 ) = 2
modulo( -12,5 )= 3
modulo( 12,-5 )= -3
modulo( -12,-5 )= -2
modulo( 10.1, 4.5 )= 1.1
modulo( -10.1, 4.5 )= 3.4
modulo( 10.1, -4.5 )= -3.4
modulo( -10.1, -4.5 )= -1.1

sqrt( number )

返回指定数字的方括号。

表 2.55. å�‚æ•°

�数类�

n

number

示例

sqrt( 16 ) = 4

log( number )

返回指定数字的日志。

表 2.56. å�‚æ•°

�数类�

n

number

示例

decimal( log( 10 ), 2 ) = 2.30

exp( number )

返回 Euler 的数值,相当于指定数字的指数。

表 2.57. 参数

�数类�

n

number

示例

decimal( exp( 5 ), 2 ) = 148.41

odd( number )

如果指定数量为奇数,则返回 true

表 2.58. å�‚æ•°

�数类�

n

number

例�

odd( 5 ) = true
odd( 2 ) = false

even( number )

如果指定的数字是,则返回 true

表 2.59. å�‚æ•°

�数类�

n

number

例�

even( 5 ) = false
even ( 2 ) = true

2.3.2.6. 日期和时间功能

以下功能支持日期和时间操作。

is( value1, value2 )

如果两个值在 FEEL 语义域中都相同,则返回 true

表 2.60. å�‚æ•°

�数类�

value1

任何类型的

value2

任何类型的

例�

is( date( "2012-12-25" ), time( "23:00:50" ) ) = false
is( date( "2012-12-25" ), date( "2012-12-25" ) ) = true
is( time( "23:00:50z" ), time( "23:00:50" ) ) = false

2.3.2.7. 范围功能

以下功能支持临时排序操作,以在单个 scalar 值和这些值的范围之间建立关系。这些功能与健康状态级别 Seven (HL7)国际 质量语言(CQL) 1.4 语法中 的组件类似。

before( )

当元素 A 位于元素 B 之前时,返回 true,当同时满足评估到 true 的相关要求时。

签�

  1. before( point1 point2 )
  2. before (point range)
  3. before (range point)
  4. before( range1,range2 )

评估为 true的要求

  1. point1 < point2
  2. point < range.start or (point = range.start not (range.start included))
  3. range.end < point 或(range.end = point 而不是(range.end included))
  4. range1.end < range2.start 或((not (range1.end included) or not (range2.start included)和 range1.end = range2.start)

例�

before( 1, 10 ) = true
before( 10, 1 ) = false
before( 1, [1..10] ) = false
before( 1, (1..10] ) = true
before( 1, [5..10] ) = true
before( [1..10], 10 ) = false
before( [1..10), 10 ) = true
before( [1..10], 15 ) = true
before( [1..10], [15..20] ) = true
before( [1..10], [10..20] ) = false
before( [1..10), [10..20] ) = true
before( [1..10], (10..20] ) = true

after( )

当元素 A 位于元素 B 之后,返回 true,当同时满足评估到 true 的相关要求时。

签�

  1. after( point1 point2 )
  2. after (point range)
  3. after( range, point )
  4. after( range1 range2 )

评估为 true的要求

  1. point1 > point2
  2. point > range.end 或(point = range.end not (range.end included))
  3. range.start > point 或(range.start = point not (range.start included))
  4. range1.start > range2.end 或((not (range1.start included) or not (range2.end included)和 range1.start = range2.end)

例�

after( 10, 5 ) = true
after( 5, 10 ) = false
after( 12, [1..10] ) = true
after( 10, [1..10) ) = true
after( 10, [1..10] ) = false
after( [11..20], 12 ) = false
after( [11..20], 10 ) = true
after( (11..20], 11 ) = true
after( [11..20], 11 ) = false
after( [11..20], [1..10] ) = true
after( [1..10], [11..20] ) = false
after( [11..20], [1..11) ) = true
after( (11..20], [1..11] ) = true

meets( )

当元素 A 满足元素 B 以及满足评估到 true 的相关要求时,返回 true

签�

  1. meets( range1, range2 )

评估为 true的要求

  1. range1.end included and range2.start included and range1.end = range2.start

例�

meets( [1..5], [5..10] ) = true
meets( [1..5), [5..10] ) = false
meets( [1..5], (5..10] ) = false
meets( [1..5], [6..10] ) = false

met by( )

当元素 B 满足元素 A 以及同时满足评估到 true 的相关要求时,返回 true

签�

  1. met by( range1, range2 )

评估为 true的要求

  1. range1.start included 和 range2.end included and range1.start = range2.end

例�

met by( [5..10], [1..5] ) = true
met by( [5..10], [1..5) ) = false
met by( (5..10], [1..5] ) = false
met by( [6..10], [1..5] ) = false

overlaps( )

当元素 A 重叠元素 B 以及满足评估到 true 的相关要求时,返回 true

签�

  1. overlaps( range1, range2 )

评估为 true的要求

  1. (range1.end > range2.start or (range1.end = range2.start and (range1.end included or range2.end included))和(range1.start < range2.end or (range1.start = range2.end and range1.start included and range2.end included))

例�

overlaps( [1..5], [3..8] ) = true
overlaps( [3..8], [1..5] ) = true
overlaps( [1..8], [3..5] ) = true
overlaps( [3..5], [1..8] ) = true
overlaps( [1..5], [6..8] ) = false
overlaps( [6..8], [1..5] ) = false
overlaps( [1..5], [5..8] ) = true
overlaps( [1..5], (5..8] ) = false
overlaps( [1..5), [5..8] ) = false
overlaps( [1..5), (5..8] ) = false
overlaps( [5..8], [1..5] ) = true
overlaps( (5..8], [1..5] ) = false
overlaps( [5..8], [1..5) ) = false
overlaps( (5..8], [1..5) ) = false

overlaps before( )

当元素 A 重叠前和满足评估到 true 的相关要求时,返回 true

签�

  1. overlaps before( range1 range2 )

评估为 true的要求

  1. (range1.start < range2.start or (range1.start = range2.start and range1.start included and range2.start included)和(range1.end > range2.start or (range1.end = range2.start and range2.start included))和(range1.end < range2.end = range2.end = range2.end,(not (range1.end included)或 range2.end included))

例�

overlaps before( [1..5], [3..8] ) = true
overlaps before( [1..5], [6..8] ) = false
overlaps before( [1..5], [5..8] ) = true
overlaps before( [1..5], (5..8] ) = false
overlaps before( [1..5), [5..8] ) = false
overlaps before( [1..5), (1..5] ) = true
overlaps before( [1..5], (1..5] ) = true
overlaps before( [1..5), [1..5] ) = false
overlaps before( [1..5], [1..5] ) = false

overlaps after( )

当元素 A 在元素 B 之后以及也满足评估到 true 的相关要求时,返回 true

签�

  1. overlaps after( range1 range2 )

评估为 true的要求

  1. (range2.start < range1.start or (range2.start = range1.start and range2.start included and not (range1.start included)) and (range2.end > range1.start or (range2.start and range2.end included))和 range1.start)和(range2.end < range1.end or (range2.end = range1.end and (not (range2.end included)或 range1.end included))

例�

overlaps after( [3..8], [1..5] )= true
overlaps after( [6..8], [1..5] )= false
overlaps after( [5..8], [1..5] )= true
overlaps after( (5..8], [1..5] )= false
overlaps after( [5..8], [1..5) )= false
overlaps after( (1..5], [1..5) )= true
overlaps after( (1..5], [1..5] )= true
overlaps after( [1..5], [1..5) )= false
overlaps after( [1..5], [1..5] )= false
overlaps after( (1..5), [1..5] )= false
overlaps after( (1..5], [1..6] )= false
overlaps after( (1..5], (1..5] )= false
overlaps after( (1..5], [2..5] )= false

finishes( )

当元素 A 完成元素 B 以及满足评估到 true 的相关要求时,返回 true

签�

  1. finishes (point, range)
  2. finishes( range1, range2 )

评估为 true的要求

  1. range.end included and range.end = point
  2. range1.end included = range2.end included 和 range1.end = range2.end 和(range1.start > range2.start or (range1.start = range2.start and (not (range1.start included)或 range2.start included))

例�

finishes( 10, [1..10] ) = true
finishes( 10, [1..10) ) = false
finishes( [5..10], [1..10] ) = true
finishes( [5..10), [1..10] ) = false
finishes( [5..10), [1..10) ) = true
finishes( [1..10], [1..10] ) = true
finishes( (1..10], [1..10] ) = true

finished by( )

当元素 A 通过元素 B 完成时,返回 true,当同时满足评估到 true 的相关要求时。

签�

  1. finished by (range, point)
  2. finished by( range1 range2 )

评估为 true的要求

  1. range.end included and range.end = point
  2. range1.end included = range2.end included 和 range1.end = range2.end and (range1.start < range2.start or (range1.start = range2.start and (range1.start included or not (range2.start included)))

例�

finished by( [1..10], 10 ) = true
finished by( [1..10), 10 ) = false
finished by( [1..10], [5..10] ) = true
finished by( [1..10], [5..10) ) = false
finished by( [1..10), [5..10) ) = true
finished by( [1..10], [1..10] ) = true
finished by( [1..10], (1..10] ) = true

includes( )

当元素 A 包含元素 B 以及满足评估到 true 的相关要求时,返回 true

签�

  1. includes (range, point)
  2. includes (range1, range2)

评估为 true的要求

  1. (range.start < point 和 range.end > point)或(range.start = point and range.start included)或(range.end = point.end included)
  2. (range1.start < range2.start or (range1.start = range2.start and (range1.start includes or not (range2.start included)))和(range1.end > range2.end or (range1.end = range2.end and (range1.end included or not (range2.end included))))

例�

includes( [1..10], 5 ) = true
includes( [1..10], 12 ) = false
includes( [1..10], 1 ) = true
includes( [1..10], 10 ) = true
includes( (1..10], 1 ) = false
includes( [1..10), 10 ) = false
includes( [1..10], [4..6] ) = true
includes( [1..10], [1..5] ) = true
includes( (1..10], (1..5] ) = true
includes( [1..10], (1..10) ) = true
includes( [1..10), [5..10) ) = true
includes( [1..10], [1..10) ) = true
includes( [1..10], (1..10] ) = true
includes( [1..10], [1..10] ) = true

during( )

当元素 A 在元素 B 期间,返回 true,当同时满足评估到 true 的相关要求时。

签�

  1. during( point, range )
  2. during( range1 range2 )

评估为 true的要求

  1. (range.start < point 和 range.end > point)或(range.start = point and range.start included)或(range.end = point.end included)
  2. (range2.start < range1.start or (range2.start = range1.start and (range2.start included or not (range1.start included)))和(range2.end > range1.end or (range2.end = range1.end and (range2.end included or not (range1.end included))))

例�

during( 5, [1..10] ) = true
during( 12, [1..10] ) = false
during( 1, [1..10] ) = true
during( 10, [1..10] ) = true
during( 1, (1..10] ) = false
during( 10, [1..10) ) = false
during( [4..6], [1..10] ) = true
during( [1..5], [1..10] ) = true
during( (1..5], (1..10] ) = true
during( (1..10), [1..10] ) = true
during( [5..10), [1..10) ) = true
during( [1..10), [1..10] ) = true
during( (1..10], [1..10] ) = true
during( [1..10], [1..10] ) = true

starts( )

当元素 A 启动元素 B 以及满足评估到 true 的相关要求时,返回 true

签�

  1. starts( point, range )
  2. starts( range1, range2 )

评估为 true的要求

  1. range.start = point and range.start included
  2. range1.start = range2.start and range1.start included = range2.start included and (range1.end < range2.end or (range1.end = range2.end and (not (range1.end included)或 range2.end included))

例�

starts( 1, [1..10] ) = true
starts( 1, (1..10] ) = false
starts( 2, [1..10] ) = false
starts( [1..5], [1..10] ) = true
starts( (1..5], (1..10] ) = true
starts( (1..5], [1..10] ) = false
starts( [1..5], (1..10] ) = false
starts( [1..10], [1..10] ) = true
starts( [1..10), [1..10] ) = true
starts( (1..10), (1..10) ) = true

started by( )

当元素 A 由元素 B 以及满足评估到 true 的相关要求时,返回 true

签�

  1. started by( range, point )
  2. started by( range1, range2 )

评估为 true的要求

  1. range.start = point and range.start included
  2. range1.start = range2.start and range1.start included = range2.start included and (range2.end < range1.end or (range2.end = range1.end and (not (range2.end included)或 range1.end included))

例�

started by( [1..10], 1 ) = true
started by( (1..10], 1 ) = false
started by( [1..10], 2 ) = false
started by( [1..10], [1..5] ) = true
started by( (1..10], (1..5] ) = true
started by( [1..10], (1..5] ) = false
started by( (1..10], [1..5] ) = false
started by( [1..10], [1..10] ) = true
started by( [1..10], [1..10) ) = true
started by( (1..10), (1..10) ) = true

coincides( )

当元素与元素 B 和满足评估到 true 的相关要求时,返回 true

签�

  1. coincides (point1, point2)
  2. coincides (range1, range2)

评估为 true的要求

  1. point1 = point2
  2. range1.start = range2.start and range1.start included = range2.start included 和 range1.end = range2.end included = range2.end included = range2.end included

例�

coincides( 5, 5 ) = true
coincides( 3, 4 ) = false
coincides( [1..5], [1..5] ) = true
coincides( (1..5), [1..5] ) = false
coincides( [1..5], [2..6] ) = false

2.3.2.8. 临时功能

以下功能支持常规临时操作。

第一天(日期 )

返回年当日的 Iceorian 号。

表 2.61. å�‚æ•°

�数类�

date

日期和时间

示例

day of year( date(2019, 9, 17) ) = 260

week (date)的日期

返回星期几天:" Monday"、" Tuesday""Wednesday""Thursday""Friday""Saturday""Sunday "。

表 2.62. å�‚æ•°

�数类�

date

日期和时间

示例

day of week( date(2019, 9, 17) ) = "Tuesday"

year of month (date)

返回年月的 Iceorian: "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November" , 或 "December "。

表 2.63. å�‚æ•°

�数类�

date

日期和时间

示例

month of year( date(2019, 9, 17) ) = "September"

year of month (date)

返回由 ISO 8601 定义年一周。

表 2.64. å�‚æ•°

�数类�

date

日期和时间

例�

week of year( date(2019, 9, 17) ) = 38
week of year( date(2003, 12, 29) ) = 1
week of year( date(2004, 1, 4) ) = 1
week of year( date(2005, 1, 1) ) = 53
week of year( date(2005, 1, 3) ) = 1
week of year( date(2005, 1, 9) ) = 1

2.3.2.9. 排序功能

以下功能支持排序操作。

sort( list, precedes )

返回同一元素的列表,但根据排序功能排序。

表 2.65. å�‚æ•°

�数类�

list

list

前者

function

示例

sort( list: [3,1,4,5,2], precedes: function(x,y) x < y ) = [1,2,3,4,5]

2.3.2.10. 上下文功能

以下功能支持上下文操作。

get value( m, key )

从指定条目键的上下文返回值。

表 2.66. å�‚æ•°

�数类�

m

context

key

字符串

例�

get value( {key1 : "value1"}, "key1" ) = "value1"
get value( {key1 : "value1"}, "unexistent-key" ) = null

get entries( m )

返回指定上下文的键值对列表。

表 2.67. å�‚æ•°

�数类�

m

context

示例

get entries( {key1 : "value1", key2 : "value2"} ) = [ { key : "key1", value : "value1" }, {key : "key2", value : "value2"} ]

2.3.3. FEEL 中的变量和函数名称

与很多传统表达式语言不同,FEEL (FEEL)支持空格和一些特殊字符作为变量和功能名称的一部分。FEEL 名称 必须以字母、? _ 元素开头。也允许使用 unicode 字母字符。变量名称不能以语言关键字开头,如 true每个 名称。变量名称中的剩余字符可以是任何起始字符,以及 数字、空格和特殊字符,如 +- -、/、+、'.

例如,以下名称是所有有效的 FEEL 名称:

  • 年龄
  • birth Date
  • flight 234 预检查过程

FEEL 中的变量和功能名称有几个限制:

模糊
使用空格、关键字和其他特殊字符作为名称的一部分可能会导致 FEEL 模糊。模糊在表达式的上下文中解决,从左到右匹配。解析器将变量名称解析为在范围内匹配的最大名称。如果需要,您可以使用 () 来忽略名称。
名称中的空格

DMN 规格限制 FEEL 名称中的空格的使用。根据 DMN 规格,名称可以包含多个空格,但不能包含两个连续空格。

为了使语言更易于使用并避免由于空格造成的常见错误,Red Hat Process Automation Manager 会删除对连续空格的使用的限制。Red Hat Process Automation Manager 支持带有任意数量的连续空格的变量名称,但将它们规范化为一个空间。例如,Red Hat Process Automation Manager 中可以接受 变量引用 带有一个空格和第一个名称,其中两个空格都可以接受。

Red Hat Process Automation Manager 还规范化使用其他空格,如网页、标签页和行破坏中常见的不可破坏的空格。从 Red Hat Process Automation Manager FEEL 引擎的角度来看,所有这些字符在处理前都规范化成一个空格。

关键字 中的关键字
中的 关键字是语言中不能用作变量名称一部分的唯一关键字。虽然规范允许在变量名称的中间使用关键字,但在变量名称中使用关键字与 grammar 定义冲突,每个 表达式结构和 一些 表达式结构。

2.4. 框表达式中的 DMN 决策逻辑

DMN 中的方框表达式是您用来在决策要求图(DRD)中定义决策节点和业务知识模型的底层逻辑。某些框表达式可以包含其他框表达式,但顶级表达式对应于单个 DRD 工件的决策逻辑。DRD 代表 DMN 决策模型的流,但框表达式定义单个节点的实际决策逻辑。DRD 和方框表达式一起形成完整的功能 DMN 决策模型。

以下是 DMN 框表达式的类型:

  • 决策表
  • 字面表达式
  • context
  • 关系
  • Functions
  • 调用
  • list
注意

Red Hat Process Automation Manager 在 Business Central 中提供框列表表达式,但支持 FEEL 列表 数据类型,您可以在框的字面表达式中使用。有关 Red Hat Process Automation Manager 中 列表 数据类型和其他 FEEL 数据类型的更多信息,请参阅 第 2.3.1 节 “FEEL 中的数据类型”

您用来在框表达式中使用的所有 Friendly Enough Expression Language (FEEL)表达式都必须符合 OMG Decision Model 和 Notation 规范中的 FEEL 语法要求。

2.4.1. DMN 决策表

DMN 中的决策表是以 tabular 格式的一个或多个新规则的可视化表示。您可以使用决策表为在决策模型中给定点应用这些规则的决策节点定义规则。每个规则都由表中的一行组成,并包含该特定行定义条件(输入)和结果(输出)的列。每行的定义足以使用条件值生成结果。输入和输出值可以是 FEEL 表达式或定义的数据类型值。

例如,以下决策基于定义的 Lan applicant 的信信分数评级来确定信信分数评级:

图 2.3. 信用卡分数评级的决策表

DMN 决策表示例

以下决策表根据 applicant loan eligibility 和 bureau 调用类型,决定 applicants 的 Lending 策略中的下一步:

图 2.4. Lending 策略的决策表

DMN 决策表 example2

以下决策表决定将 loan 作为协调决策模式的共识决定:

图 2.5. loan prequalification 的决策表

DMN 决策表 example3

决策表是建模规则和决策逻辑的常用方法,用于许多公司(如 DMN)以及实施框架(如 dols)。

重要

Red Hat Process Automation Manager 支持 DMN 决策表和 dros 原生决策表,但它们具有不同语法要求的不同类型资产,且不可互换。有关 Red Hat Process Automation Manager 中的 dros 原生决策表的更多信息,请参阅使用电子表格决策表设计决策服务

2.4.1.1. 在 DMN 决策表中按策略

按策略决定在决策表中的多个规则与提供的输入值匹配时如何达到结果。例如,如果一个规则在决策表中应用了一个销售活动,而另一个规则则适用于领导人员,那么当客户同时是面和站时,决策表命中策略必须指示是否应用一个部门,或者另一个(唯一 )或两个公司(Collect Sum)。您可以指定决策表左上角的点击策略(美国FC+)的单个字符。

DMN 支持以下决策表命中策略:

  • unique (U): 仅保留一个要匹配的规则。任何重叠都会引发错误。
  • any (A): 查找要匹配的多个规则,但它们都必须具有相同的输出。如果多个匹配规则没有相同的输出,则会引发错误。
  • 优先级(P): 使多个规则匹配,具有不同输出。选择输出值列表中的第一个输出。
  • first (F): 按规则顺序使用第一个匹配项。
  • 收集(C+、C>、C<、C114): 基于聚合功能从多个规则 Aggregates 输出。

    • collect (C): 在任意列表中 Aggregates 值。
    • 收集 Sum (C+): 输出所有收集的值的总和。值必须是数字。
    • collect Min (C&lt;):输出匹配项中的最小值。生成的值必须相似,如数字、日期或文本(字典顺序)。
    • collect Max (C&gt;):输出匹配项中的最大值。生成的值必须相似,如数字、日期或文本(字典顺序)。
    • 收集计数(C114): 输出匹配规则的数量。

2.4.2. 方框的字面表达式

DMN 中的方框字面表达式是一个字面 FEEL 表达式,作为表单元中的文本,通常具有标记列和分配的数据类型。您可以使用方框的字面表达式来定义简单或复杂的节点逻辑,或者直接在 FEEL 中定义决策中特定节点的决策数据。字面 FEEL 表达式必须符合 OMG Decision Model 和 Notation 规格中的 FEEL 语法要求。

例如,以下框的字面表达式在 Lending 决策中定义最低可接受的 PITI 计算(principal、Oidanting、加利和指导),其中 可接受的率 是 DMN 模型中定义的变量:

图 2.6. 最小 PITI 值的方框字面表达式

DMN 字面表达式 example2

以下框的字面表达式根据其分数(如年龄、位置和感兴趣的标准)将可能评估候选者(soul mates)按其分数划分在在线评估应用程序中的列表:

图 2.7. 用于匹配在线评估候选者的方框字面表达式

DMN 字面表达式 example3b

2.4.3. 框的上下文表达式

DMN 中的方框上下文表达式是一组带有结果值的变量名称和值。每个名称-值对都是上下文条目。您可以使用 context 表达式来表示决策逻辑中的数据定义,并为 DMN 决策模型中的所需决策元素设置值。框上下文表达式中的值可以是数据类型值或 FEEL 表达式,也可以包含任何类型的嵌套子表达式,如路由表、字面表达式或其他上下文表达式。

例如,以下框上下文表达式根据定义的数据类型(tPassengerTable,tFlightNumberList)定义在 flight-rebooking 决策模型中排序延迟传递器的因素:

图 2.8. 用于 flight passenger waiting list 的方框上下文表达式

DMN 上下文表达式示例

以下框上下文表达式定义了因素,决定 loan applicant 是否可以满足基于主体、感兴趣的、参与和过期(PITI)的最小电池付款(PITI),以带有子上下文表达式的前端比率计算表示:

图 2.9. 用于前端客户端 PITI 比率的方框上下文表达式

DMN 上下文表达式 example2

2.4.4. 框关系表达式

DMN 中的框关系表达式是一个传统数据表,其中包含给定实体的信息,被列为行。您可以使用框关系表来定义特定节点的决策中相关实体的决策数据。框关系表达式与设置变量名称和值的上下文表达式类似,但关系表达式不包含结果值,并根据每个列中定义的变量列出所有变量值。

例如,以下框关系表达式提供了员工在员工自己的决定方面的信息:

图 2.10. 带有员工信息的框关系表达式

DMN 关系表达式示例

2.4.5. 框函数表达式

DMN 中的框函数表达式是一个参数化表达式,其中包含字面 FEEL 表达式、外部 JAVA 或 PMML 函数的嵌套上下文表达式或任何类型的嵌套框表达式。默认情况下,所有业务知识模型都定义为开箱即用的功能表达式。您可以使用方框的功能表达式来调用决策逻辑上的功能,并定义所有业务知识模型。

例如,以下框函数表达式决定 flight-rebooking strategy 模型中的 airline flight 容量:

图 2.11. 用于 flight 容量的框功能表达式

DMN 功能表达式示例

以下框函数表达式包含一个基本的 Java 功能,作为在决策模型计算中确定绝对值的上下文表达式:

图 2.12. 用于绝对值的方框函数表达式

DMN 功能表达式 example2

以下框函数表达式决定在许可决策中作为业务知识模型的每月安装,其函数值定义为嵌套上下文表达式:

图 2.13. 在业务知识模型中安装计算的框函数表达式

DMN 功能表达式 example3

以下框的功能表达式使用 DMN 文件中包含的 PMML 模型来定义 Lending 决策中的最低可接受的 PITI 计算(principal、相关的、参与和过期):

图 2.14. 在业务知识模型中带有包含的 PMML 模型的方框函数表达式

DMN 功能表达式 example5

2.4.6. 框的调用表达式

DMN 中的方框调用表达式是一个框表达式,用于调用企业知识模型。框的调用表达式包含要调用的业务知识模型的名称和参数绑定列表。每个绑定都由一行上的两个框表达式表示:左侧的框包含一个参数名称,右侧的框包含其值分配给参数的绑定表达式,以评估调用的业务知识模型。您可以使用方框调用在决策模型中定义的业务知识模型调用特定的决策节点。

例如,以下的调用表达式调用 Reassign Next Passenger Business 知识模型,来作为 flight-rebooking 决策模型中的协调节点:

图 2.15. 框调用表达式来重新分配 flight passengers

DMN 调用示例

以下框的调用表达式调用 InstallmentCalculation Business 知识模型,以便在继续实现决策前为 loan 计算每月安装量:

图 2.16. 为所需的每月安装提供框调用表达式

DMN 调用 example2

2.4.7. 框列表表达式

DMN 中的框列表表达式代表 FEEL 项目列表。您可以使用方框列表来定义决策中特定节点的相关项目列表。您还可以将字面 FEEL 表达式用于列出单元格中的项目,以创建更复杂的列表。

例如,以下框列表表达式标识了 Lan 应用程序决策服务的批准的信用卡机构:

图 2.17. 批准信用卡机构的框列表表达式

DMN 列表表达式示例

以下框列表表达式还标识批准的信分数机构,但使用 FEEL 逻辑来定义基于 DMN 输入节点的过期状态(Inc.、LLC、SA、GA):

图 2.18. 使用 FEEL 逻辑进行批准的信分数状态的框列表表达式

DMN 列表表达式 example2
DMN 列表表达式 example2a

2.5. DMN 模型示例

以下是一个真实的 DMN 模型示例,它演示了如何根据输入数据、情况和公司指南使用决策来达到决策。在这种情况下,从 San Diego 到 New the 的 flight 会被取消,需要受影响的 airline 来查找其 inconvenienced passengers 的替代安排。

首先,热线会收集所需信息,以确定如何将前端应用到其目的地:

输入数据
  • flights 列表
  • passengers 列表
决策
  • 优先选择在新 flight 上获得席位的人员
  • 确定将提供哪些通过engers 的转换
业务知识模型
  • 决定传递优先级的公司流程
  • 任何有可用空间的动态
  • 用于确定如何重新分配不便传递人员的公司规则

然后,airline 使用 DMN 标准在以下决策要求图(DRD)中建模其决策过程,以确定最佳重新订阅解决方案:

图 2.19. flight rebooking 的 DRD

DMN passenger rebooking drd

与流图类似,DRD 使用形成来代表进程中的不同元素。OVAL 包含两个必要的输入数据,rectangles 在模型中包含决策点,并附带清晰的线(业务知识模型)包含可重复使用的逻辑,可重复调用。

DRD 从框表达式中提取每个元素的逻辑,该表达式使用 FEEL 表达式或数据类型值提供变量定义。

有些框表达式是基本的表达式,例如以下决定建立优先级的等待列表:

图 2.20. 优先级等待列表的方框上下文表达式示例

DMN 上下文表达式示例

某些框表达式会更加复杂,以及计算,例如用于重新分配下一个延迟传递器的以下业务知识模型:

图 2.21. 用于 passenger 重新分配的框功能表达式

DMN重新分配 passenger

以下是此决策模型的 DMN 源文件:

<dmn:definitions xmlns="https://www.drools.org/kie-dmn/Flight-rebooking" xmlns:dmn="http://www.omg.org/spec/DMN/20151101/dmn.xsd" xmlns:feel="http://www.omg.org/spec/FEEL/20140401" id="_0019_flight_rebooking" name="0019-flight-rebooking" namespace="https://www.drools.org/kie-dmn/Flight-rebooking">
  <dmn:itemDefinition id="_tFlight" name="tFlight">
    <dmn:itemComponent id="_tFlight_Flight" name="Flight Number">
      <dmn:typeRef>feel:string</dmn:typeRef>
    </dmn:itemComponent>
    <dmn:itemComponent id="_tFlight_From" name="From">
      <dmn:typeRef>feel:string</dmn:typeRef>
    </dmn:itemComponent>
    <dmn:itemComponent id="_tFlight_To" name="To">
      <dmn:typeRef>feel:string</dmn:typeRef>
    </dmn:itemComponent>
    <dmn:itemComponent id="_tFlight_Dep" name="Departure">
      <dmn:typeRef>feel:dateTime</dmn:typeRef>
    </dmn:itemComponent>
    <dmn:itemComponent id="_tFlight_Arr" name="Arrival">
      <dmn:typeRef>feel:dateTime</dmn:typeRef>
    </dmn:itemComponent>
    <dmn:itemComponent id="_tFlight_Capacity" name="Capacity">
      <dmn:typeRef>feel:number</dmn:typeRef>
    </dmn:itemComponent>
    <dmn:itemComponent id="_tFlight_Status" name="Status">
      <dmn:typeRef>feel:string</dmn:typeRef>
    </dmn:itemComponent>
  </dmn:itemDefinition>
  <dmn:itemDefinition id="_tFlightTable" isCollection="true" name="tFlightTable">
    <dmn:typeRef>tFlight</dmn:typeRef>
  </dmn:itemDefinition>
  <dmn:itemDefinition id="_tPassenger" name="tPassenger">
    <dmn:itemComponent id="_tPassenger_Name" name="Name">
      <dmn:typeRef>feel:string</dmn:typeRef>
    </dmn:itemComponent>
    <dmn:itemComponent id="_tPassenger_Status" name="Status">
      <dmn:typeRef>feel:string</dmn:typeRef>
    </dmn:itemComponent>
    <dmn:itemComponent id="_tPassenger_Miles" name="Miles">
      <dmn:typeRef>feel:number</dmn:typeRef>
    </dmn:itemComponent>
    <dmn:itemComponent id="_tPassenger_Flight" name="Flight Number">
      <dmn:typeRef>feel:string</dmn:typeRef>
    </dmn:itemComponent>
  </dmn:itemDefinition>
  <dmn:itemDefinition id="_tPassengerTable" isCollection="true" name="tPassengerTable">
    <dmn:typeRef>tPassenger</dmn:typeRef>
  </dmn:itemDefinition>
  <dmn:itemDefinition id="_tFlightNumberList" isCollection="true" name="tFlightNumberList">
    <dmn:typeRef>feel:string</dmn:typeRef>
  </dmn:itemDefinition>
  <dmn:inputData id="i_Flight_List" name="Flight List">
    <dmn:variable name="Flight List" typeRef="tFlightTable"/>
  </dmn:inputData>
  <dmn:inputData id="i_Passenger_List" name="Passenger List">
    <dmn:variable name="Passenger List" typeRef="tPassengerTable"/>
  </dmn:inputData>
  <dmn:decision name="Prioritized Waiting List" id="d_PrioritizedWaitingList">
    <dmn:variable name="Prioritized Waiting List" typeRef="tPassengerTable"/>
    <dmn:informationRequirement>
      <dmn:requiredInput href="#i_Passenger_List"/>
    </dmn:informationRequirement>
    <dmn:informationRequirement>
      <dmn:requiredInput href="#i_Flight_List"/>
    </dmn:informationRequirement>
    <dmn:knowledgeRequirement>
      <dmn:requiredKnowledge href="#b_PassengerPriority"/>
    </dmn:knowledgeRequirement>
    <dmn:context>
      <dmn:contextEntry>
        <dmn:variable name="Cancelled Flights" typeRef="tFlightNumberList"/>
        <dmn:literalExpression>
          <dmn:text>Flight List[ Status = "cancelled" ].Flight Number</dmn:text>
        </dmn:literalExpression>
      </dmn:contextEntry>
      <dmn:contextEntry>
        <dmn:variable name="Waiting List" typeRef="tPassengerTable"/>
        <dmn:literalExpression>
          <dmn:text>Passenger List[ list contains( Cancelled Flights, Flight Number ) ]</dmn:text>
        </dmn:literalExpression>
      </dmn:contextEntry>
      <dmn:contextEntry>
        <dmn:literalExpression>
          <dmn:text>sort( Waiting List, passenger priority )</dmn:text>
        </dmn:literalExpression>
      </dmn:contextEntry>
    </dmn:context>
  </dmn:decision>
  <dmn:decision name="Rebooked Passengers" id="d_RebookedPassengers">
    <dmn:variable name="Rebooked Passengers" typeRef="tPassengerTable"/>
    <dmn:informationRequirement>
      <dmn:requiredDecision href="#d_PrioritizedWaitingList"/>
    </dmn:informationRequirement>
    <dmn:informationRequirement>
      <dmn:requiredInput href="#i_Flight_List"/>
    </dmn:informationRequirement>
    <dmn:knowledgeRequirement>
      <dmn:requiredKnowledge href="#b_ReassignNextPassenger"/>
    </dmn:knowledgeRequirement>
    <dmn:invocation>
      <dmn:literalExpression>
        <dmn:text>reassign next passenger</dmn:text>
      </dmn:literalExpression>
      <dmn:binding>
        <dmn:parameter name="Waiting List"/>
        <dmn:literalExpression>
          <dmn:text>Prioritized Waiting List</dmn:text>
        </dmn:literalExpression>
      </dmn:binding>
      <dmn:binding>
        <dmn:parameter name="Reassigned Passengers List"/>
        <dmn:literalExpression>
          <dmn:text>[]</dmn:text>
        </dmn:literalExpression>
      </dmn:binding>
      <dmn:binding>
        <dmn:parameter name="Flights"/>
        <dmn:literalExpression>
          <dmn:text>Flight List</dmn:text>
        </dmn:literalExpression>
      </dmn:binding>
    </dmn:invocation>
  </dmn:decision>
  <dmn:businessKnowledgeModel id="b_PassengerPriority" name="passenger priority">
    <dmn:encapsulatedLogic>
      <dmn:formalParameter name="Passenger1" typeRef="tPassenger"/>
      <dmn:formalParameter name="Passenger2" typeRef="tPassenger"/>
      <dmn:decisionTable hitPolicy="UNIQUE">
        <dmn:input id="b_Passenger_Priority_dt_i_P1_Status" label="Passenger1.Status">
          <dmn:inputExpression typeRef="feel:string">
            <dmn:text>Passenger1.Status</dmn:text>
          </dmn:inputExpression>
          <dmn:inputValues>
            <dmn:text>"gold", "silver", "bronze"</dmn:text>
          </dmn:inputValues>
        </dmn:input>
        <dmn:input id="b_Passenger_Priority_dt_i_P2_Status" label="Passenger2.Status">
          <dmn:inputExpression typeRef="feel:string">
            <dmn:text>Passenger2.Status</dmn:text>
          </dmn:inputExpression>
          <dmn:inputValues>
            <dmn:text>"gold", "silver", "bronze"</dmn:text>
          </dmn:inputValues>
        </dmn:input>
        <dmn:input id="b_Passenger_Priority_dt_i_P1_Miles" label="Passenger1.Miles">
          <dmn:inputExpression typeRef="feel:string">
            <dmn:text>Passenger1.Miles</dmn:text>
          </dmn:inputExpression>
        </dmn:input>
        <dmn:output id="b_Status_Priority_dt_o" label="Passenger1 has priority">
          <dmn:outputValues>
            <dmn:text>true, false</dmn:text>
          </dmn:outputValues>
          <dmn:defaultOutputEntry>
            <dmn:text>false</dmn:text>
          </dmn:defaultOutputEntry>
        </dmn:output>
        <dmn:rule id="b_Passenger_Priority_dt_r1">
          <dmn:inputEntry id="b_Passenger_Priority_dt_r1_i1">
            <dmn:text>"gold"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r1_i2">
            <dmn:text>"gold"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r1_i3">
            <dmn:text>>= Passenger2.Miles</dmn:text>
          </dmn:inputEntry>
          <dmn:outputEntry id="b_Passenger_Priority_dt_r1_o1">
            <dmn:text>true</dmn:text>
          </dmn:outputEntry>
        </dmn:rule>
        <dmn:rule id="b_Passenger_Priority_dt_r2">
          <dmn:inputEntry id="b_Passenger_Priority_dt_r2_i1">
            <dmn:text>"gold"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r2_i2">
            <dmn:text>"silver","bronze"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r2_i3">
            <dmn:text>-</dmn:text>
          </dmn:inputEntry>
          <dmn:outputEntry id="b_Passenger_Priority_dt_r2_o1">
            <dmn:text>true</dmn:text>
          </dmn:outputEntry>
        </dmn:rule>
        <dmn:rule id="b_Passenger_Priority_dt_r3">
          <dmn:inputEntry id="b_Passenger_Priority_dt_r3_i1">
            <dmn:text>"silver"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r3_i2">
            <dmn:text>"silver"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r3_i3">
            <dmn:text>>= Passenger2.Miles</dmn:text>
          </dmn:inputEntry>
          <dmn:outputEntry id="b_Passenger_Priority_dt_r3_o1">
            <dmn:text>true</dmn:text>
          </dmn:outputEntry>
        </dmn:rule>
        <dmn:rule id="b_Passenger_Priority_dt_r4">
          <dmn:inputEntry id="b_Passenger_Priority_dt_r4_i1">
            <dmn:text>"silver"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r4_i2">
            <dmn:text>"bronze"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r4_i3">
            <dmn:text>-</dmn:text>
          </dmn:inputEntry>
          <dmn:outputEntry id="b_Passenger_Priority_dt_r4_o1">
            <dmn:text>true</dmn:text>
          </dmn:outputEntry>
        </dmn:rule>
        <dmn:rule id="b_Passenger_Priority_dt_r5">
          <dmn:inputEntry id="b_Passenger_Priority_dt_r5_i1">
            <dmn:text>"bronze"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r5_i2">
            <dmn:text>"bronze"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r5_i3">
            <dmn:text>>= Passenger2.Miles</dmn:text>
          </dmn:inputEntry>
          <dmn:outputEntry id="b_Passenger_Priority_dt_r5_o1">
            <dmn:text>true</dmn:text>
          </dmn:outputEntry>
        </dmn:rule>
      </dmn:decisionTable>
    </dmn:encapsulatedLogic>
    <dmn:variable name="passenger priority" typeRef="feel:boolean"/>
  </dmn:businessKnowledgeModel>
  <dmn:businessKnowledgeModel id="b_ReassignNextPassenger" name="reassign next passenger">
    <dmn:encapsulatedLogic>
      <dmn:formalParameter name="Waiting List" typeRef="tPassengerTable"/>
      <dmn:formalParameter name="Reassigned Passengers List" typeRef="tPassengerTable"/>
      <dmn:formalParameter name="Flights" typeRef="tFlightTable"/>
      <dmn:context>
        <dmn:contextEntry>
          <dmn:variable name="Next Passenger" typeRef="tPassenger"/>
          <dmn:literalExpression>
            <dmn:text>Waiting List[1]</dmn:text>
          </dmn:literalExpression>
        </dmn:contextEntry>
        <dmn:contextEntry>
          <dmn:variable name="Original Flight" typeRef="tFlight"/>
          <dmn:literalExpression>
            <dmn:text>Flights[ Flight Number = Next Passenger.Flight Number ][1]</dmn:text>
          </dmn:literalExpression>
        </dmn:contextEntry>
        <dmn:contextEntry>
          <dmn:variable name="Best Alternate Flight" typeRef="tFlight"/>
          <dmn:literalExpression>
            <dmn:text>Flights[ From = Original Flight.From and To = Original Flight.To and Departure > Original Flight.Departure and Status = "scheduled" and has capacity( item, Reassigned Passengers List ) ][1]</dmn:text>
          </dmn:literalExpression>
        </dmn:contextEntry>
        <dmn:contextEntry>
          <dmn:variable name="Reassigned Passenger" typeRef="tPassenger"/>
          <dmn:context>
            <dmn:contextEntry>
              <dmn:variable name="Name" typeRef="feel:string"/>
              <dmn:literalExpression>
                <dmn:text>Next Passenger.Name</dmn:text>
              </dmn:literalExpression>
            </dmn:contextEntry>
            <dmn:contextEntry>
              <dmn:variable name="Status" typeRef="feel:string"/>
              <dmn:literalExpression>
                <dmn:text>Next Passenger.Status</dmn:text>
              </dmn:literalExpression>
            </dmn:contextEntry>
            <dmn:contextEntry>
              <dmn:variable name="Miles" typeRef="feel:number"/>
              <dmn:literalExpression>
                <dmn:text>Next Passenger.Miles</dmn:text>
              </dmn:literalExpression>
            </dmn:contextEntry>
            <dmn:contextEntry>
              <dmn:variable name="Flight Number" typeRef="feel:string"/>
              <dmn:literalExpression>
                <dmn:text>Best Alternate Flight.Flight Number</dmn:text>
              </dmn:literalExpression>
            </dmn:contextEntry>
          </dmn:context>
        </dmn:contextEntry>
        <dmn:contextEntry>
          <dmn:variable name="Remaining Waiting List" typeRef="tPassengerTable"/>
          <dmn:literalExpression>
            <dmn:text>remove( Waiting List, 1 )</dmn:text>
          </dmn:literalExpression>
        </dmn:contextEntry>
        <dmn:contextEntry>
          <dmn:variable name="Updated Reassigned Passengers List" typeRef="tPassengerTable"/>
          <dmn:literalExpression>
            <dmn:text>append( Reassigned Passengers List, Reassigned Passenger )</dmn:text>
          </dmn:literalExpression>
        </dmn:contextEntry>
        <dmn:contextEntry>
          <dmn:literalExpression>
            <dmn:text>if count( Remaining Waiting List ) > 0 then reassign next passenger( Remaining Waiting List, Updated Reassigned Passengers List, Flights ) else Updated Reassigned Passengers List</dmn:text>
          </dmn:literalExpression>
        </dmn:contextEntry>
      </dmn:context>
    </dmn:encapsulatedLogic>
    <dmn:variable name="reassign next passenger" typeRef="tPassengerTable"/>
    <dmn:knowledgeRequirement>
      <dmn:requiredKnowledge href="#b_HasCapacity"/>
    </dmn:knowledgeRequirement>
  </dmn:businessKnowledgeModel>
  <dmn:businessKnowledgeModel id="b_HasCapacity" name="has capacity">
    <dmn:encapsulatedLogic>
      <dmn:formalParameter name="flight" typeRef="tFlight"/>
      <dmn:formalParameter name="rebooked list" typeRef="tPassengerTable"/>
      <dmn:literalExpression>
        <dmn:text>flight.Capacity > count( rebooked list[ Flight Number = flight.Flight Number ] )</dmn:text>
      </dmn:literalExpression>
    </dmn:encapsulatedLogic>
    <dmn:variable name="has capacity" typeRef="feel:boolean"/>
  </dmn:businessKnowledgeModel>
</dmn:definitions>

第 3 章 Red Hat Process Automation Manager 中的 DMN 支持

Red Hat Process Automation Manager 为 DMN 1.2 模型提供设计和运行时支持,具有符合级别 3 的 DMN 1.1 和 1.3 模型的运行时支持。您可以通过几种方法将 DMN 模型与 Red Hat Process Automation Manager 决策服务集成:

  • 使用 DMN 设计程序直接在 Business Central 中设计您的 DMN 模型。
  • 在 Business Central 中将 DMN 文件导入到项目中(Menu → Design → Projects → Import Asset)。Business Central 的 DMN 设计程序目前不支持 DMN 1.1 和 1.3 模型。
  • 在没有 Business Central 的情况下,将 DMN 文件打包为您的项目知识 JAR (KJAR)文件的一部分。

除了所有 DMN 一致性级别 3 要求外,Red Hat Process Automation Manager 还包括对 FEEL 和 DMN 模型组件的增强和修复,以优化使用 Red Hat Process Automation Manager 实施 DMN 决策服务的体验。从平台的角度来看,DMN 模型类似于 Red Hat Process Automation Manager 中的任何其他业务资产,如 DRL 文件或电子表格决策表,您可以包含在 Red Hat Process Automation Manager 项目中,并部署到 KIE 服务器,以启动您的 DMN 决策服务。

有关使用 Red Hat Process Automation Manager 项目打包和部署方法包含外部 DMN 文件的更多信息,请参阅 打包和部署 Red Hat Process Automation Manager 项目

3.1. Red Hat Process Automation Manager 中的可配置 DMN 属性

Red Hat Process Automation Manager 提供以下 DMN 属性,您可以在 KIE Server 或客户端应用程序上执行 DMN 模型时进行配置。当您在 KIE 服务器上部署项目时,您可以使用 Red Hat Process Automation Manager 项目中的 kmodule.xml 文件配置其中一些属性。

org.kie.dmn.strictConformance

启用后,此属性默认禁用除 DMN 标准外提供的任何扩展或配置集,如 DMN 1.2 的一些帮助程序功能,或者将 DMN 1.2 回移植到 DMN 1.1 的功能。您可以使用此属性配置决策引擎,使其只支持纯 DMN 功能,如运行 DMN 技术兼容性组件 (TCK)时。

默认值:false

-Dorg.kie.dmn.strictConformance=true
org.kie.dmn.runtime.typecheck

启用后,此属性启用实际值验证符合 DMN 模型中声明的类型,作为 DRD 元素的输入或输出。您可以使用此属性来验证提供给 DMN 模型的数据还是由 DMN 模型生成的数据是否符合模型中指定的内容。

默认值:false

-Dorg.kie.dmn.runtime.typecheck=true
org.kie.dmn.decisionservice.coercesingleton

默认情况下,此属性使定义单个输出决定的决策服务的结果是输出决定值的单个值。禁用后,此属性使定义单个输出决定的决策结果成为该决定的单个条目 的上下文。您可以根据项目要求,使用此属性来调整决策服务输出。

默认值为: true

-Dorg.kie.dmn.decisionservice.coercesingleton=false
org.kie.dmn.profiles.$PROFILE_NAME

当使用 Java 完全限定名称进行评估时,此属性在启动时将 DMN 配置集加载到决策引擎中。您可以使用此属性来实现预定义的 DMN 配置集,其支持的功能与 DMN 标准不同。例如,如果您使用 Signavio DMN modeller 创建 DMN 模型,请使用此属性将 Signavio DMN 配置集中的功能实施到 DMN 决策服务中。

-Dorg.kie.dmn.profiles.signavio=org.kie.dmn.signavio.KieDMNSignavioProfile
org.kie.dmn.runtime.listeners.$LISTENER_NAME

当使用 Java 完全限定名称进行评估时,此属性会在启动时加载并将 DMN Runtime Listener 注册到决策引擎中。您可以使用此属性注册 DMN 侦听器,以便在 DMN 模型评估过程中通知多个事件。

要在 KIE 服务器上部署项目时配置此属性,请修改项目的 kmodule.xml 文件中的此属性。当监听程序特定于您的项目,且配置必须仅在 KIE 服务器中应用到您部署的项目时,此方法很有用。

<kmodule xmlns="http://www.drools.org/xsd/kmodule">
  <configuration>
    <property key="org.kie.dmn.runtime.listeners.mylistener" value="org.acme.MyDMNListener"/>
  </configuration>
</kmodule>

要为 Red Hat Process Automation Manager 环境全局配置此属性,请使用命令终端或其他全局应用程序配置机制修改此属性。当决策引擎嵌入为 Java 应用程序的一部分时,这种方法非常有用。

-Dorg.kie.dmn.runtime.listeners.mylistener=org.acme.MyDMNListener
org.kie.dmn.compiler.execmodel

启用后,此属性可让在运行时将 DMN 决策表逻辑编译到可执行规则模型中。您可以使用此属性更有效地评估 DMN 决策逻辑。当可执行模型编译最初在项目编译期间执行时,此属性很有用。启用此属性可能会导致决策引擎第一次评估期间添加编译时间,但后续的编译效率更高。

默认值:false

-Dorg.kie.dmn.compiler.execmodel=true

第 4 章 在 Business Central 中创建和编辑 DMN 模型

您可以使用 Business Central 中的 DMN 设计程序来设计 DMN 决策要求图(DRD),并为完整的功能 DMN 决策模型定义决策逻辑。Red Hat Process Automation Manager 为 DMN 1.2 模型提供符合级别 3 的设计和运行时支持,包括 FEEL 和 DMN 模型组件的增强和修复,以优化使用 Red Hat Process Automation Manager 实施 DMN 决策服务的体验。Red Hat Process Automation Manager 还提供对 DMN 1.1 和 1.3 模型的运行时支持,符合级别 3。Business Central 的 DMN 设计程序目前不支持 DMN 1.1 和 1.3 模型。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. 在 Business Central 项目中创建或导入 DMN 文件。

    要创建 DMN 文件,请点击 Add AssetDMN,输入信息性 DMN 模型名称,选择适当的 Package,然后点 Ok

    要导入现有的 DMN 文件,请点 Import Asset,输入 DMN 模型名称,选择适当的 Package,选择要上传的 DMN 文件,然后单击 Ok

    新的 DMN 文件现在列在 Project ExplorerDMN 面板中,并显示 DMN 决策要求图(DRD) svas。

    注意

    如果您导入了不包含布局信息的 DMN 文件,则导入的决策要求图(DRD)会在 DMN 设计程序中自动格式化。在 DMN Designer 中点 Save 保存 DRD 布局。

    如果导入的 DRD 没有自动格式化,您可以在 DMN 设计器中选择 执行自动布局 图标来格式化 DRD。

  3. 点左侧工具中的其中一个 DMN 节点并拖动一个 DMN 节点,开始将组件添加到您的新的或导入的 DMN 决策要求图(DRD)中:

    图 4.1. 添加 DRD 组件

    DMN 拖动决策节点

    可用的 DRD 组件如下:

    • 决策 :将此节点用于 DMN 决策,其中一个或多个输入元素根据定义的决策逻辑决定输出。
    • 业务知识模型 :将此节点用于带有一个或多个决策元素的可重复使用的功能。具有相同逻辑但依赖于不同的子输入数据或子部门的决策使用业务知识模型来确定要遵循哪些流程。
    • 知识源 :将此节点用于负责决定或业务知识模型的外部机构、文档、提交或策略。知识源是指实际因素的参考,而不是可执行的业务逻辑。
    • 输入数据 :使用此节点获取在决策节点或业务知识模型中使用的信息。输入数据通常包括与业务相关的业务级概念或对象,如 Lending 策略中使用的 loan applicant 数据。
    • 文本注释 :使用此节点获得与输入数据节点、决策节点、业务知识模型或知识源关联的额外说明。
    • 决策服务 :使用此节点包含一组可重复使用的决策,作为调用的决策服务。决策服务可以在其他 DMN 模型中使用,并可以从外部应用程序或 站 商业进程调用。
  4. 在 DMN Designer canvas 中,双击新的 DRD 节点,以输入信息性节点名称。
  5. 如果节点是一个决定或业务知识模型,请选择要显示节点选项的节点,然后点击 Edit 图标打开 DMN 框表达式设计器,以定义节点的决策逻辑:

    图 4.2. 打开新的决策节点框表达式

    DMN 决策编辑

    图 4.3. 打开新的业务知识模型框表达式

    DMN bkm edit

    默认情况下,所有业务知识模型都定义为包含字面 FEEL 表达式、外部 JAVA 或 PMML 函数的嵌套上下文表达式或嵌套的方框表达式。

    对于决策节点,您可以点击未定义表来选择要使用的方框表达式类型,如框的字面表达式、框的上下文表达式、决策表或其他 DMN 框表达式。

    图 4.4. 为决策节点选择逻辑类型

    DMN 决策框表达式选项

    对于业务知识模型,您可以点击左上角的功能单元来选择功能类型,或者右键点击功能值单元,选择 Clear,然后选择另一个类型的方框表达式。

    图 4.5. 为业务知识模型选择功能或其他逻辑类型

    DMN bkm 定义
  6. 在所选用于决策节点(任何表达式类型)或业务知识模型(功能表达式)的方框表达式设计程序中,单击适用的表单元,以定义表名称、变量数据类型、变量名称和值、函数参数和绑定或 FEEL 表达式,以包含在决策逻辑中。

    您可以右键点击单元,以了解适用的额外操作,如插入或删除表行和列或清除表内容。

    以下是决定节点的一个示例决策表,它根据定义的 Lan applicant 的信用卡分数评级来决定信信分数评级:

    图 4.6. 信用卡分数评级的决策节点决策表

    DMN 决策表 example1a

    以下是一个用于业务知识模型的方框函数表达式示例,它根据主体、感兴趣的、销售和技术(PITI)作为字面表达式计算电缆付款:

    图 4.7. PITI 计算的企业知识模型功能

    DMN 功能表达式 example4
  7. 为所选节点定义决策逻辑后,点 Back to "<MODEL_NAME>" 返回到 DRD 视图。
  8. 对于所选的 DRD 节点,请使用可用的连接选项在 DRD 中创建并连接到下一个节点,或者单击新节点并从左栏中将新节点拖到 DRD canvas 中。

    节点类型决定支持哪个连接选项。例如,输入数据节点 可以使用适用的连接类型连接到决策节点、知识源或文本注解,而 知识库源 节点可以连接到任何 DRD 元素。决策 节点只能连接到另一个决定或文本注解。

    以下连接类型可用,具体取决于节点类型:

    • 信息要求 :使用此连接从输入数据节点或决策节点与需要信息的另一个决定节点。
    • 知识要求 :使用此连接从业务知识模型到决策节点或调用决策逻辑的另一种业务知识模式。
    • 授权要求 :使用此连接从输入数据节点或决策节点到依赖知识源,或从知识源到决策节点、业务知识模型或其他知识来源。
    • 关联 :使用此连接,从输入数据节点、决策节点、业务知识模型或知识源到文本注释。

    图 4.8. 将信分数输入连接到信分数评级决定

    DMN 输入连接示例
    DMN 输入连接 example2
  9. 继续添加和定义您决策模型的剩余 DRD 组件。在 DMN 设计程序中定期点击 Save 来保存您的更改。

    注意

    当您定期保存 DRD 时,DMN 设计程序会对 DMN 模型执行静态验证,并可能生成错误消息,直到完全定义模型为止。完全定义了 DMN 模型后,如果保留任何错误,请相应地排除指定的问题。

  10. 添加并定义 DRD 的所有组件后,单击 Save 保存并验证已完成的 DRD。

    要调整 DRD 布局,您可以在 DMN 设计器右上角选择 Execution automatic layout 图标。

    以下是 loan prequalification 决策模型的 DRD 示例:

    图 4.9. 为 loan prequalification 已完成的 DRD

    DMN 示例 drd

    以下是使用可重复使用的决策服务处理决策模型的手机调用的 DRD 示例:

    图 4.10. 完成 DRD,用于通过决策服务进行手机调用处理

    DMN 示例 drd3

    在 DMN 决策服务节点中,底部段中的决策节点融合了来自决策服务的输入数据,以便在决策服务节点的顶部决定。然后,根据决策服务带来的顶级决策,将根据 DMN 模型的任何后续决策或企业知识要求来实施。您可以在其他 DMN 模型中重复使用 DMN 决策服务,以使用不同的输入数据和不同的传出连接应用相同的决策逻辑。

4.1. 在 Business Central 中框表达式中定义 DMN 决策逻辑

DMN 中的方框表达式是您用来在决策要求图(DRD)中定义决策节点和业务知识模型的底层逻辑。某些框表达式可以包含其他框表达式,但顶级表达式对应于单个 DRD 工件的决策逻辑。DRD 代表 DMN 决策模型的流,但框表达式定义单个节点的实际决策逻辑。DRD 和方框表达式一起形成完整的功能 DMN 决策模型。

您可以使用 Business Central 中的 DMN 设计程序,使用内置框表达式为您的 DRD 组件定义决策逻辑。

先决�件

  • 在 Business Central 中创建或导入 DMN 文件。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,点项目名称,然后选择您要修改的 DMN 文件。
  2. 在 DMN Designer canvas 中,选择要定义的决策节点或业务知识模型节点,然后点击 Edit 图标以打开 DMN 框表达式设计器:

    图 4.11. 打开新的决策节点框表达式

    DMN 决策编辑

    图 4.12. 打开新的业务知识模型框表达式

    DMN bkm edit

    默认情况下,所有业务知识模型都定义为包含字面 FEEL 表达式、外部 JAVA 或 PMML 函数的嵌套上下文表达式或嵌套的方框表达式。

    对于决策节点,您可以点击未定义表来选择要使用的方框表达式类型,如框的字面表达式、框的上下文表达式、决策表或其他 DMN 框表达式。

    图 4.13. 为决策节点选择逻辑类型

    DMN 决策框表达式选项

    对于业务知识模型节点,您可以点击左上角的功能单元来选择功能类型,或者右键点击功能值单元,选择 Clear,然后选择另一个类型的方框表达式。

    图 4.14. 为业务知识模型选择功能或其他逻辑类型

    DMN bkm 定义
  3. 在本例中,使用决策节点并选择 Decision Table 作为框的表达式类型。

    DMN 中的决策表是一个或多个规则的可视化表示,格式为 tabular。每个规则都由表中的一行组成,并包含该特定行定义条件(输入)和结果(输出)的列。

  4. 单击 input 列标头,以定义输入条件的名称和数据类型。例如,使用数字 数据类型命名输入列 Credit Score.FICO。此列指定数字信分值或 loan applicants 范围。
  5. 单击输出列标头,以定义输出值的名称和数据类型。例如,将输出列 Credit Score Rating 和 next of the Data Type 选项命名为 Data Types 页面,您可以在其中创建一个分数评级为约束的自定义数据类型。

    图 4.15. 为列标头值管理数据类型

    DMN 管理数据类型
  6. Data Types 页面中,点 New Data Type 来添加新数据类型,或者点击 Import Data Object 从您要用作 DMN 数据类型的项目导入现有数据对象。

    如果您从项目导入数据对象作为 DMN 数据类型,然后更新该对象,则必须重新导入数据对象作为 DMN 数据类型,以便在 DMN 模型中应用更改。

    在本例中,点 New Data Type 并创建一个 Credit_Score_Rating 数据类型 作为字符串

    图 4.16. 添加新数据类型

    DMN 自定义数据类型添加
  7. Add Constraints,从下拉菜单中选择 Enumeration,并添加以下限制:

    • "Excellent"
    • "Good"
    • "fair"
    • "Poor"
    • "Bad"

    图 4.17. 在新数据类型中添加限制

    DMN 自定义数据类型约束

    要更改数据类型约束的顺序,您可以点约束行左侧的结尾,并根据需要拖动行:

    图 4.18. 拖动约束以更改约束顺序

    DMN 自定义数据类型约束拖动

    有关指定数据类型的约束类型和语法要求的详情,请参考 决策模型和表示法规格

  8. OK 保存约束,然后点数据类型右侧的检查标记保存数据类型。
  9. 返回到 Credit Score Rating 决策表,单击 Credit Score Rating 列标头,然后将数据类型设置为这个新的自定义数据类型。
  10. 使用 Credit Score.FICO 输入列来定义信分数值或值范围,并使用 Credit Score Rating 列指定您在 Credit_Score_Rating 数据类型中定义的相应评级之一。

    右键点击任何值单元,以插入或删除行(规则)或列(clauses)。

    图 4.19. 信用卡分数评级的决策节点决策表

    DMN 决策表 example1a
  11. 定义所有规则后,单击决策表的左上角的角,以定义规则 Hit PolicyBuiltin 聚合器 (仅适用于 COLLECT hit 策略)。

    hit 策略决定在决策表中的多个规则与提供的输入值匹配时如何达到结果。内置聚合器决定在使用 COLLECT 命中策略时如何聚合规则值。

    图 4.20. 定义决策表命中策略

    DMN 按策略

    以下示例是一个更复杂的决策表,它决定了与同一 loan prequalification 决策模型中协调决策节点的 loan 许可:

    图 4.21. loan prequalification 的决策表

    DMN 决策表 example3

对于分区表以外的框表达式类型,您可以遵循类似导航的表达式表的指南,并为决策逻辑定义变量和参数,但根据框表达式类型的要求。某些框表达式(如框的字面表达式)可以是单列表,而其他框表达式(如函数、上下文和调用表达式)则可使用其他类型的嵌套表达式的多列表。

例如,以下框上下文表达式定义了参数,该参数来确定 loan applicant 是否可以满足基于主体、感兴趣的、参与和过期(PITI),使用子上下文表达式以前端比率计算表示:

图 4.22. 用于前端客户端 PITI 比率的方框上下文表达式

DMN 上下文表达式 example2

以下框函数表达式决定在许可决策中作为业务知识模型的每月安装,其函数值定义为嵌套上下文表达式:

图 4.23. 在业务知识模型中安装计算的框函数表达式

DMN 功能表达式 example3

有关每个框表达式类型的更多信息和示例,请参阅 第 2.4 节 “框表达式中的 DMN 决策逻辑”

4.2. 在 Business Central 中为 DMN 框表达式创建自定义数据类型

在 Business Central 中的 DMN 框表达式中,数据类型决定了您在框表达式中的关联表、列或字段中使用的数据的结构。您可以使用默认 DMN 数据类型(如字符串、数字、布尔值)或者创建自定义数据类型来指定要为空闲表达式值实施的其他字段和约束。

为框表达式创建的自定义数据类型可以是简单或结构化:

  • 简单 的数据类型只有一个名称和类型分配。示例: 期限(数字)
  • 结构化 数据类型包含多个与父数据类型关联的字段。示例:包含字段名称 (字符串)、Age ( 数字)、电子邮件(字符串) 的单个类型 Person

先决�件

  • 在 Business Central 中创建或导入 DMN 文件。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,点项目名称,然后选择您要修改的 DMN 文件。
  2. 在 DMN Designer canvas 中,选择要为其定义数据类型的决策节点或业务知识模型,然后单击 Edit 图标来打开 DMN 框表达式设计程序。
  3. 如果框表达式适用于尚未定义的决策节点,请单击未定义表来选择您要使用的框表达式类型,如框的字面表达式、框的上下文表达式、决策表或其他 DMN 框表达式。

    图 4.24. 为决策节点选择逻辑类型

    DMN 决策框表达式选项
  4. 点击表标头、列标头或参数字段的单元(取决于您要为其定义数据类型),然后单击 Manage 以进入可用于创建自定义数据类型的数据类型。

    图 4.25. 为列标头值管理数据类型

    DMN 管理数据类型

    您还可以通过选择 DMN 设计器右上角的 Properties 图标来为指定决策节点或业务知识模型节点设置自定义数据类型:

    图 4.26. 在决策要求图(DRD)属性中管理数据类型

    DMN 管理数据类型1a

    您在框表达式中为指定单元定义的数据类型决定了您在该关联表、列或框表达式中使用的数据的结构。

    在本例中,对于 DMN 决策表的输出列 Credit Score Rating 定义了一组基于适用信信的信信分数评级的自定义信分数评级。

  5. Data Types 页面中,点 New Data Type 来添加新数据类型,或者点击 Import Data Object 从您要用作 DMN 数据类型的项目导入现有数据对象。

    如果您从项目导入数据对象作为 DMN 数据类型,然后更新该对象,则必须重新导入数据对象作为 DMN 数据类型,以便在 DMN 模型中应用更改。

    在本例中,点 New Data Type 并创建一个 Credit_Score_Rating 数据类型 作为字符串

    图 4.27. 添加新数据类型

    DMN 自定义数据类型添加

    如果数据类型需要项目列表,请启用 List 设置。

  6. Add Constraints,从下拉菜单中选择 Enumeration,并添加以下限制:

    • "Excellent"
    • "Good"
    • "fair"
    • "Poor"
    • "Bad"

    图 4.28. 在新数据类型中添加限制

    DMN 自定义数据类型约束

    要更改数据类型约束的顺序,您可以点约束行左侧的结尾,并根据需要拖动行:

    图 4.29. 拖动约束以更改约束顺序

    DMN 自定义数据类型约束拖动

    有关指定数据类型的约束类型和语法要求的详情,请参考 决策模型和表示法规格

  7. OK 保存约束,然后点数据类型右侧的检查标记保存数据类型。
  8. 返回到 Credit Score Rating 决策表,点 Credit Score Rating 列标头,将数据类型设置为这个新的自定义数据类型,并使用您指定的 rating 约束定义该列的规则值。

    图 4.30. 信用卡分数评级的决策表

    DMN 决策表 example1a

    在这个情境的 DMN 决策模型中,Loan Pre qualification 决定将决策流化成以下 Loan Prequalification 决定,还需要自定义数据类型:

    图 4.31. loan prequalification 的决策表

    DMN 管理数据类型为空
  9. 继续本例,返回到 数据类型 窗口,单击 New Data Type,然后创建一个 Loan_Qualification 数据类型作为无限制的 结构

    保存新的结构化数据类型时,会显示第一个子字段,以便您可以开始在此父数据类型中定义嵌套数据字段。您可以在结构化表达式中使用这些子字段与父结构化数据类型关联,如分区表中的嵌套列标头或上下文或功能表达式中的嵌套表参数。

    对于额外的子字段,请选择 Loan_Qualification 数据类型旁边的添加图标:

    图 4.32. 使用嵌套字段添加新的结构化数据类型

    DMN 管理数据类型
  10. 在本例中,在结构化 Loan_Qualification 数据类型下,添加一个带有 "Qualified""Not Qualified" 枚举约束的 Qualification 字段,以及一个没有限制的 Reason 字段。另外,添加一个简单的 Back_End_Ratio 和 a the the_End_Ratio 数据类型,两者均具有 "Sufficient""Insufficient" 枚举限制。

    点您创建的每种数据类型右侧的检查标记来保存您的更改。

    图 4.33. 使用约束添加嵌套数据类型

    DMN 管理数据类型 structured2

    要更改数据类型的顺序或嵌套的数据类型,您可以点数据类型行的左侧,并根据需要拖动行:

    图 4.34. 拖动数据类型以更改数据类型顺序或嵌套

    DMN 管理数据类型 structured2 拖动
  11. 返回到路由表,对于每列,点列标头单元,将数据类型设置为新的对应的自定义数据类型,并使用您指定的约束为列定义规则值(如果适用)。

    图 4.35. loan prequalification 的决策表

    DMN 决策表 example3

对于除路由表以外的框表达式类型,您可以按照类似方式浏览表达式表的指南,并根据需要定义自定义数据类型。

例如,以下框函数表达式使用自定义 tCandidatetProfile 结构化数据类型来关联在线隐藏兼容性的数据:

图 4.36. 在线隐藏兼容性的方框函数表达式

DMN 管理数据类型 structured3

图 4.37. 在线隐藏兼容性的自定义数据类型定义

DMN 管理数据类型 structured3a

图 4.38. 带有自定义数据类型的参数定义,以便在线隐藏兼容性

DMN 管理数据类型 structured3b

4.3. Business Central 中的 DMN 文件中包含模型

在 Business Central 中的 DMN 设计程序中,您可以使用 Included Models 选项卡将项目中的其他 DMN 模型和预预测模型标记语言(PMML)模型包含在指定的 DMN 文件中。当您在另一个 DMN 文件中包含 DMN 模型时,您可以在相同的决策要求图(DRD)中使用这两个模型中的所有节点和逻辑。当您在 DMN 文件中包含 PMML 模型时,您可以调用 PMML 模型作为 DMN 决策节点或业务知识模型节点的方框函数表达式。

您不能将来自 Business Central 中的其他项目的 DMN 或 PMML 模型包含在 Business Central 中。

4.3.1. 在 Business Central 中的 DMN 文件中包括其他 DMN 模型

在 Business Central 中,您可以在指定的 DMN 文件中包含项目中的其他 DMN 模型。当您在另一个 DMN 文件中包含 DMN 模型时,您可以在相同的决策要求图(DRD)中使用这两个模型中的所有节点和逻辑,但您无法从包含的模型编辑节点。要从包含的模型编辑节点,您必须直接为包含的模型更新源文件。如果您为所含的 DMN 模型更新源文件,请打开包含 DMN 模型的 DMN 文件(或重新打开)以验证更改。

您不能在 Business Central 中包含其他项目的 DMN 模型。

先决�件

  • DMN 模型在 Business Central 中的同一个项目中创建或导入(作为 .dmn 文件),与您要包含模型的 DMN 文件相同。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,点项目名称,然后选择您要修改的 DMN 文件。
  2. 在 DMN Designer 中,点 Included Models 选项卡。
  3. Include Model,从 Models 列表中的项目中选择一个 DMN 模型,为包含的模型输入一个唯一名称,然后点 Include

    图 4.39. 包括 DMN 模型

    DMN 包括模型

    DMN 模型添加到这个 DMN 文件中,包含模型中的所有 DRD 节点都列在 Decision Navigator 视图中的 Decision Components 下:

    图 4.40. 带有所含 DMN 模型中的决策组件的 DMN 文件

    DMN 包括模型列表

    包含模型中的所有数据类型也列在 DMN 文件 的数据类型 选项卡中的只读模式:

    图 4.41. 带有包含 DMN 模型的数据类型的 DMN 文件

    DMN 包括模型数据类型
  4. 在 DMN 设计器的 Model 选项卡中,点包含的 DRD 组件拖到 canvas 中,开始在 DRD 中实施它们:

    图 4.42. 从包含的 DMN 模型中添加 DRD 组件

    DMN 包括模型 drd

    要从包含的模型编辑 DRD 节点或数据类型,您必须直接为包含模型更新源文件。如果您为所含的 DMN 模型更新源文件,请打开包含 DMN 模型的 DMN 文件(或重新打开)以验证更改。

    要编辑包含的模型名称或从 DMN 文件中删除包含的模型,请使用 DMN Designer 中的 Included Models 选项卡。

    重要

    当您删除包含的模型时,任何节点都从 DRD 中使用的模型中删除。

4.3.2. 在 Business Central 中的 DMN 文件中包括 PMML 模型

在 Business Central 中,您可以在指定的 DMN 文件中包括项目中的 Predictive Model Markup Language (PMML)模型。当您在 DMN 文件中包含 PMML 模型时,您可以调用 PMML 模型作为 DMN 决策节点或业务知识模型节点的方框函数表达式。如果您为包含的 PMML 模型更新源文件,您必须删除并重新包括 DMN 文件中的 PMML 模型以应用源更改。

您不能在 Business Central 中包含来自其他项目的 PMML 模型。

先决�件

  • PMML 模型在 Business Central 中导入(作为 .pmml 文件)与您要包含模型的 DMN 文件相同。

�程

  1. 在 DMN 项目中,在 pom.xml 文件中添加以下依赖项来启用 PMML 评估:

    <!-- Required for the PMML compiler -->
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>kie-pmml</artifactId>
      <version>${rhpam.version}</version>
      <scope>provided</scope>
    </dependency>
    
    <!-- Alternative dependencies for JPMML Evaluator, override `kie-pmml` dependency -->
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-dmn-jpmml</artifactId>
      <version>${rhpam.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.jpmml</groupId>
      <artifactId>pmml-evaluator</artifactId>
      <version>1.5.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.jpmml</groupId>
      <artifactId>pmml-evaluator-extension</artifactId>
      <version>1.5.1</version>
      <scope>provided</scope>
    </dependency>

    要访问 Business Central 中的项目 pom.xml 文件,您可以在屏幕左侧的 Project Explorer 菜单中选择任何现有资产,然后点击 Customize View gear 图标并选择 Repository Viewpom.xml

    如果要将完整的 PMML 规范实现与 PMML (JPMML)的 Java Evaluator API 搭配使用,请在 DMN 项目中使用替代的 JPMML 依赖项集合。如果同时存在 JPMML 依赖项和标准 kie-pmml 依赖项,则禁用 kie-pmml 依赖项。有关 JPMML 许可证条款的详情,请参考 Openscoring.io

    注意

    考虑将 Red Hat Business Automation Manager (BOM)依赖项添加到项目 pom.xml 文件,而不是为单个依赖项指定 Red Hat Process Automation Manager < version >。Red Hat Business Automation BOM 适用于 Red Hat Decision Manager 和 Red Hat Process Automation Manager。当您添加 BOM 文件时,项目中包含了来自提供的 Maven 存储库传输性依赖关系的正确版本。

    BOM 依赖项示例:

    <dependency>
      <groupId>com.redhat.ba</groupId>
      <artifactId>ba-platform-bom</artifactId>
      <version>7.9.1.redhat-00003</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>

    有关 Red Hat Business Automation BOM 的更多信息,请参阅 RHPAM 产品和 maven 库版本之间的映射是什么?

  2. 如果您在 DMN 项目中添加了 JPMML 依赖项以使用 JPMML Evaluator,请下载以下 JAR 文件并将其添加到 Red Hat Process Automation Manager 发行版中的 ~/kie-server.war/WEB-INF/lib~/business-central.war/WEB-INF/lib 目录中:

    这些工件需要在 KIE 服务器和 Business Central 中启用 JPMML 评估。

    重要

    红帽支持与 PMML (JPMML)的 Java Evaluator API 集成,用于 Red Hat Process Automation Manager 中的 PMML 执行。但是,红帽不支持 JPMML 库。如果您在 Red Hat Process Automation Manager 发行版中包含 JPMML 库,请参阅 JPMML 的 Openscoring.io 许可证条款。

  3. 在 Business Central 中,进入 MenuDesignProjects,点项目名称,然后选择您要修改的 DMN 文件。
  4. 在 DMN Designer 中,点 Included Models 选项卡。
  5. Include Model,从 Models 列表中的项目中选择一个 PMML 模型,为包含的模型输入一个唯一名称,然后点 Include

    图 4.43. 包括 PMML 模型

    DMN 包括模型 pmml

    PMML 模型添加到这个 DMN 文件中:

    图 4.44. 带有包含 PMML 模型的 DMN 文件

    DMN 包括模型列表 pmml
  6. 在 DMN 设计器的 Model 选项卡中,选择或创建您要调用 PMML 模型的决策节点或业务知识模型节点,然后点击 Edit 图标以打开 DMN 框表达式设计器:

    图 4.45. 打开新的决策节点框表达式

    DMN 决策编辑

    图 4.46. 打开新的业务知识模型框表达式

    DMN bkm edit
  7. 将表达式类型设置为 Function (对于业务知识模型节点的默认值),单击左上角的功能单元,然后选择 PMML
  8. 在表中的 文档和模型 行中,双击未定义的单元来指定 文档 中包含的 PMML 文档和相关的 PMML 模型:

    图 4.47. 在 DMN 业务知识模型中添加 PMML 模型

    DMN 包括模型表达式 pmml

    图 4.48. DMN 业务知识模型中的 PMML 定义示例

    DMN 功能表达式 example5

    如果您为包含的 PMML 模型更新源文件,您必须删除并重新包括 DMN 文件中的 PMML 模型以应用源更改。

    要编辑包含的模型名称或从 DMN 文件中删除包含的模型,请使用 DMN Designer 中的 Included Models 选项卡。

4.4. 使用 Business Central 中的多个图表创建 DMN 模型

对于复杂的 DMN 模型,您可以使用 Business Central 中的 DMN 设计程序设计多个 DMN 决策要求图(DRD),它们代表 DMN 决策模型的整体决策要求图(DRG)的一部分。在简单情况下,您可以使用单个 DRD 代表决策模型的所有总体 DRG,但在复杂的情形中,单个 DRD 可能会变得较大且难以遵循。因此,为了更好地组织具有许多决策要求的 DMN 决策模型,您可以将模型分成较小的嵌套 DRD,该模型由整个 DRG 的较大中央 DRD 表示组成。

先决�件

�程

  1. 在 Business Central 中,导航到您的 DMN 项目,并在项目中创建或导入 DMN 文件。
  2. 打开新的或导入的 DMN 文件,在 DMN 设计程序中查看 DRD,并使用左侧工具栏中的 DMN 节点开始设计或修改 DRD。
  3. 对于您要在单独的嵌套 DRD 中定义的任何 DMN 节点,请选择该节点,点 DRD Actions 图标,然后从可用选项中选择。

    图 4.49. 子目录 DRD 的 DRD 操作图标

    DMN drd 操作

    �用的选项如下:

    • 创建 :使用这个选项来创建嵌套的 DRD,您可以在其中单独定义所选节点的 DMN 组件和图表。
    • 添加到 :如果您已创建了嵌套的 DRD,请使用此选项将所选节点添加到现有 DRD 中。
    • 删除 :如果您选择的节点已在嵌套的 DRD 中,则使用此选项从该嵌套的 DRD 中删除该节点。

    在 DMN 决策模型中创建嵌套的 DRD 后,新的 DRD 会在单独的 DRD canvas 中打开,并在 Decision Navigator left 菜单中列出可用的 DRD 和组件。您可以使用 Decision Navigator 菜单重命名或删除嵌套的 DRD。

    图 4.50. 在 Decision Navigator 菜单中重命名新的嵌套 DRD

    DMN drd 操作重命名
  4. 在针对新嵌套 DRD 的独立 canvas 中,设计这部分 DMN 模型中所有必需的组件的流和逻辑,如通常一样。
  5. 继续为您的决策模型添加和定义任何其他嵌套的 DRD,并保存已完成的 DMN 文件。

    例如,以下用于 loan prequalification 决策模型的 DRD 包含模型的所有 DMN 组件,而无需任何嵌套的 DRD。这个示例依赖于单个 DRD,用于所有组件和逻辑,从而产生大量复杂的图表。

    图 4.51. 用于 loan prequalification 的单个 DRD

    DMN 示例 drd

    另外,请按照此流程中的步骤,您可以将这个示例 DRD 分成多个嵌套的 DRD,以更好地组织决策要求,如下例所示:

    图 4.52. 多个嵌套的 DRD 用于 loan prequalification

    DMN drd multiple

    图 4.53. 前端比率 DRD 概述

    DMN drd 多个前端

    图 4.54. DRD 用于前端比率

    DMN drd 多前端详情

    图 4.55. 信分数评级 DRD 概述

    DMN drd multiple credit score

    图 4.56. DRD 用于信信分数评级

    DMN drd multiple credit score details

    图 4.57. 后端比率 DRD 概述

    DMN drd 多个后端

    图 4.58. DRD 用于后端比率

    DMN drd 多后端详情

4.5. Business Central 中的 DMN 模型文档

在 Business Central 中的 DMN 设计程序中,您可以使用 Documentation 选项卡生成 DMN 模型的报告,供您打印或下载为 HTML 文件以供离线使用。DMN 模型报告包含 DMN 模型中的所有决策要求图(DRD)、数据类型和框表达式。您可以使用此报告共享 DMN 模型详情,或作为内部报告工作流的一部分。

图 4.59. DMN 模型报告示例

DMN 文档

4.6. Business Central 中的 DMN 设计器导航和属性

Business Central 中的 DMN 设计程序提供以下额外功能,可帮助您浏览决策要求图(DRD)的组件和属性。

DMN 文件和图形视图

在 DMN 设计器的右上角,选择 Project Explorer 视图以在所有 DMN 和其他文件间进行导航,或者选择 Decision Navigator 视图来导航所选 DRD 的决策组件、图形和框表达式:

图 4.60. Project Explorer 视图

DMN Designer 项目视图

图 4.61. 决策导航器视图

DMN Designer nav view
DMN Designer nav view2
注意

DMN 文件(包含模型选项卡)中包含的任何 DMN 模型中的 DRD 组件也会列在 DMN 文件的 Decision Components 面板中。

在 DMN 设计器右上角,选择 Explore 图 图标来查看所选 DRD 的提升预览,并在所选 DRD 节点间导航:

图 4.62. 探索图表视图

DMN Designer preview
DRD 属性和设计

在 DMN 设计器右上角,选择 Properties 图标来修改所选 DRD、DRD 节点或框表达式单元的识别信息、数据类型和外观:

图 4.63. DRD 节点属性

DMN Designer 属性

要查看整个 DRD 的属性,请点 DRD canvas 背景而不是特定节点。

DRD 搜索

在 DMN 设计器右上角,使用搜索栏搜索 DRD 中显示的文本。搜索功能在与多个节点相关的复杂 DRD 中特别有用:

图 4.64. DRD 搜索

DMN Designer 搜索

第 5 章 DMN 模型执行

您可以使用 Business Central 在 Red Hat Process Automation Manager 项目中创建或导入 DMN 文件,或者将 DMN 文件打包为您的项目知识 JAR (KJAR)文件的一部分,而无需 Business Central。在 Red Hat Process Automation Manager 项目中实现了 DMN 文件后,您可以通过将其部署到 KIE Server for Remote Access 或直接操作 KIE 容器来执行 DMN 决策服务。还提供了创建和部署 DMN 知识软件包的其他选项,大多数都类似所有知识资产,如 DRL 文件或进程定义。

有关使用项目打包和部署方法包含外部 DMN 资产的详情,请参考 打包和部署 Red Hat Process Automation Manager 项目

5.1. 直接嵌入 Java 应用程序中的 DMN 调用

当知识资产直接嵌入到调用程序中或物理拉取时,KIE 容器是本地的,或使用 KJAR 的 Maven 依赖项进行物理拉取。通常,如果代码版本和 DMN 定义版本之间有紧密关系,则通常直接将知识资产嵌入到项目中。在有意更新并重新部署应用程序后,对决定所做的任何更改都会生效。这种方法的一个优点是,正确的操作不依赖于任何外部依赖项到运行时,这可能是锁定环境的限制。

使用 Maven 依赖项可以进一步的灵活性,因为决策的特定版本可以动态更改(例如,使用系统属性),它可以定期扫描更新和自动更新。这引入了对服务的部署时间的外部依赖项,但在本地执行决策,从而减少在运行时对外部服务的依赖。

先决条件

  • 您已将 DMN 项目构建为 KJAR 工件,并将其部署到 Maven 存储库中,或者已包含您的 DMN 资产作为项目 classpath 的一部分。理想情况下,您已将 DMN 项目构建为可执行模型,以便更有效地执行:

    mvn clean install -DgenerateDMNModel=yes

    有关项目打包和部署以及可执行模型的更多信息,请参阅打包和部署 Red Hat Process Automation Manager 项目

�程

  1. 在客户端应用程序中,将以下依赖项添加到 Java 项目的相关类路径中:

    <!-- Required for the DMN runtime API -->
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-dmn-core</artifactId>
      <version>${rhpam.version}</version>
    </dependency>
    
    <!-- Required if not using classpath KIE container -->
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-ci</artifactId>
      <version>${rhpam.version}</version>
    </dependency>

    & lt;version > 是项目中当前使用的 Red Hat Process Automation Manager 的 Maven 工件版本(如 7.44.0.Final-redhat-00006)。

    注意

    考虑将 Red Hat Business Automation Manager (BOM)依赖项添加到项目 pom.xml 文件,而不是为单个依赖项指定 Red Hat Process Automation Manager < version >。Red Hat Business Automation BOM 适用于 Red Hat Decision Manager 和 Red Hat Process Automation Manager。当您添加 BOM 文件时,项目中包含了来自提供的 Maven 存储库传输性依赖关系的正确版本。

    BOM 依赖项示例:

    <dependency>
      <groupId>com.redhat.ba</groupId>
      <artifactId>ba-platform-bom</artifactId>
      <version>7.9.1.redhat-00003</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>

    有关 Red Hat Business Automation BOM 的更多信息,请参阅 RHPAM 产品和 maven 库版本之间的映射是什么?

  2. classpathReleaseId 创建 KIE 容器:

    KieServices kieServices = KieServices.Factory.get();
    
    ReleaseId releaseId = kieServices.newReleaseId( "org.acme", "my-kjar", "1.0.0" );
    KieContainer kieContainer = kieServices.newKieContainer( releaseId );

    其它选项:

    KieServices kieServices = KieServices.Factory.get();
    
    KieContainer kieContainer = kieServices.getKieClasspathContainer();
  3. 使用 model 命名空间和 modelName 从 KIE 容器获取 DMNRuntime,以及对要评估的 DMN 模型的引用:

    DMNRuntime dmnRuntime = KieRuntimeFactory.of(kieContainer.getKieBase()).get(DMNRuntime.class);
    
    String namespace = "http://www.redhat.com/_c7328033-c355-43cd-b616-0aceef80e52a";
    String modelName = "dmn-movieticket-ageclassification";
    
    DMNModel dmnModel = dmnRuntime.getModel(namespace, modelName);
  4. 为所需模型执行决策服务:

    DMNContext dmnContext = dmnRuntime.newContext();  1
    
    for (Integer age : Arrays.asList(1,12,13,64,65,66)) {
        dmnContext.set("Age", age);  2
        DMNResult dmnResult =
            dmnRuntime.evaluateAll(dmnModel, dmnContext);  3
    
        for (DMNDecisionResult dr : dmnResult.getDecisionResults()) {  4
            log.info("Age: " + age + ", " +
                     "Decision: '" + dr.getDecisionName() + "', " +
                     "Result: " + dr.getResult());
      }
    }
    1
    实例化一个新的 DMN 上下文,作为模型评估的输入。请注意,本例多次通过 Age Classification 决策进行循环。
    2
    为输入 DMN 上下文分配输入变量。
    3
    评估 DMN 模型中定义的所有 DMN 决策。
    4
    每个评估都可能导致一个或多个结果,创建循环。

    这个示例打印以下输出:

    Age 1 Decision 'AgeClassification' : Child
    Age 12 Decision 'AgeClassification' : Child
    Age 13 Decision 'AgeClassification' : Adult
    Age 64 Decision 'AgeClassification' : Adult
    Age 65 Decision 'AgeClassification' : Senior
    Age 66 Decision 'AgeClassification' : Senior

    如果 DMN 模型之前没有编译为高效执行的可执行模型,您可以在执行 DMN 模型时启用以下属性:

    -Dorg.kie.dmn.compiler.execmodel=true

5.2. 使用 KIE 服务器 Java 客户端 API 执行 DMN 服务

KIE Server Java 客户端 API 提供了轻量级的方法,通过 KIE 服务器的 REST 或 JMS 接口调用远程 DMN 服务。这个方法减少了与 KIE 基础交互所需的运行时依赖项数量。通过让它们能够按适当的速度单独迭代,从决策定义分离调用代码会增加灵活性。

有关 KIE Server Java 客户端 API 的更多信息,请参阅使用 KIE API 与 Red Hat Process Automation Manager 交互

先决�件

  • KIE 服务器已安装并配置,包括具有 kie-server 角色的用户的已知用户名和凭证。有关安装选项,请参阅 规划 Red Hat Process Automation Manager 安装
  • 您已将 DMN 项目构建为 KJAR 工件,并将其部署到 KIE 服务器中。理想情况下,您已将 DMN 项目构建为可执行模型,以便更有效地执行:

    mvn clean install -DgenerateDMNModel=yes

    有关项目打包和部署以及可执行模型的更多信息,请参阅打包和部署 Red Hat Process Automation Manager 项目

  • 您有包含 DMN 模型的 KIE 容器的 ID。如果有多个模型,还必须知道相关模型的模型命名空间和模型名称。

�程

  1. 在客户端应用程序中,将以下依赖项添加到 Java 项目的相关类路径中:

    <!-- Required for the KIE Server Java client API -->
    <dependency>
      <groupId>org.kie.server</groupId>
      <artifactId>kie-server-client</artifactId>
      <version>${rhpam.version}</version>
    </dependency>

    & lt;version > 是项目中当前使用的 Red Hat Process Automation Manager 的 Maven 工件版本(如 7.44.0.Final-redhat-00006)。

    注意

    考虑将 Red Hat Business Automation Manager (BOM)依赖项添加到项目 pom.xml 文件,而不是为单个依赖项指定 Red Hat Process Automation Manager < version >。Red Hat Business Automation BOM 适用于 Red Hat Decision Manager 和 Red Hat Process Automation Manager。当您添加 BOM 文件时,项目中包含了来自提供的 Maven 存储库传输性依赖关系的正确版本。

    BOM 依赖项示例:

    <dependency>
      <groupId>com.redhat.ba</groupId>
      <artifactId>ba-platform-bom</artifactId>
      <version>7.9.1.redhat-00003</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>

    有关 Red Hat Business Automation BOM 的更多信息,请参阅 RHPAM 产品和 maven 库版本之间的映射是什么?

  2. 使用适当的连接信息实例化 KieServicesClient 实例。

    例如:

    KieServicesConfiguration conf =
        KieServicesFactory.newRestConfiguration(URL, USER, PASSWORD); 1
    
    conf.setMarshallingFormat(MarshallingFormat.JSON);  2
    
    KieServicesClient kieServicesClient = KieServicesFactory.newKieServicesClient(conf);
    1
    连接信息:
    • 示例 URL :http://localhost:8080/kie-server/services/rest/server
    • 凭证应该引用具有 kie-server 角色的用户。
    2
    Marshalling 格式是 org.kie.server.api.marshalling.MarshallingFormat 的实例。它控制消息是否为 JSON 还是 XML。Marshalling 格式的选项包括 JSON、JAXB 或 XSTREAM。
  3. 通过在 KIE 服务器 Java 客户端实例上调用方法 getServicesClient (),从 KIE 服务器 Java 客户端获取 DMNServicesClient Client:

    DMNServicesClient dmnClient = kieServicesClient.getServicesClient(DMNServicesClient.class );

    dmnClient 现在可在 KIE 服务器上执行决策服务。

  4. 为所需模型执行决策服务。

    例如:

    for (Integer age : Arrays.asList(1,12,13,64,65,66)) {
        DMNContext dmnContext = dmnClient.newContext(); 1
        dmnContext.set("Age", age);  2
        ServiceResponse<DMNResult> serverResp =   3
            dmnClient.evaluateAll($kieContainerId,
                                  $modelNamespace,
                                  $modelName,
                                  dmnContext);
    
        DMNResult dmnResult = serverResp.getResult();  4
        for (DMNDecisionResult dr : dmnResult.getDecisionResults()) {
            log.info("Age: " + age + ", " +
                     "Decision: '" + dr.getDecisionName() + "', " +
                     "Result: " + dr.getResult());
        }
    }
    1
    实例化一个新的 DMN 上下文,作为模型评估的输入。请注意,本例多次通过 Age Classification 决策进行循环。
    2
    为输入 DMN 上下文分配输入变量。
    3
    评估 DMN 模型中定义的所有 DMN 决策:
    • $kieContainerId 是部署包含 DMN 模型的 KJAR 的容器 ID
    • $modelNamespace 是模型的命名空间。
    • $modelName 是模型的名称。
    4
    DMN Result 对象可从服务器响应中获得。

    此时,dmnResult 包含来自评估的 DMN 模型的所有决定结果。

    您还可以使用 DMNServicesClient 的替代方法在模型中执行特定的 DMN 决定。

    注意

    如果 KIE 容器只包含一个 DMN 模型,您可以省略 $modelNamespace$modelName,因为 KIE Server API 默认选择它。

5.3. 使用 KIE 服务器 REST API 执行 DMN 服务

直接与 KIE 服务器的 REST 端点交互,可在调用代码和决策逻辑定义之间提供最大的隔离。调用代码完全免费直接依赖项,您可以在完全不同的开发平台(如 Node.js.NET )中实施它。本节中的示例演示了 Nix 风格的 curl 命令,但提供相关信息以适应任何 REST 客户端。

当您使用 KIE 服务器的 REST 端点时,最佳实践是定义一个域对象 POJO Java 类,使用标准 KIE Server marshalling 注解进行注解。例如,以下代码使用正确注解的域对象 Person 类:

POJO Java 类示例

@javax.xml.bind.annotation.XmlAccessorType(javax.xml.bind.annotation.XmlAccessType.FIELD)
public class Person implements java.io.Serializable {

    static final long serialVersionUID = 1L;

    private java.lang.String id;
    private java.lang.String name;
    @javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(org.kie.internal.jaxb.LocalDateXmlAdapter.class)
    private java.time.LocalDate dojoining;

    public Person() {
    }

    public java.lang.String getId() {
        return this.id;
    }

    public void setId(java.lang.String id) {
        this.id = id;
    }

    public java.lang.String getName() {
        return this.name;
    }

    public void setName(java.lang.String name) {
        this.name = name;
    }

    public java.time.LocalDate getDojoining() {
        return this.dojoining;
    }

    public void setDojoining(java.time.LocalDate dojoining) {
        this.dojoining = dojoining;
    }

    public Person(java.lang.String id, java.lang.String name,
            java.time.LocalDate dojoining) {
        this.id = id;
        this.name = name;
        this.dojoining = dojoining;
    }

}

有关 KIE Server REST API 的更多信息,请参阅使用 KIE API 与 Red Hat Process Automation Manager 交互

先决�件

  • KIE 服务器已安装并配置,包括具有 kie-server 角色的用户的已知用户名和凭证。有关安装选项,请参阅 规划 Red Hat Process Automation Manager 安装
  • 您已将 DMN 项目构建为 KJAR 工件,并将其部署到 KIE 服务器中。理想情况下,您已将 DMN 项目构建为可执行模型,以便更有效地执行:

    mvn clean install -DgenerateDMNModel=yes

    有关项目打包和部署以及可执行模型的更多信息,请参阅打包和部署 Red Hat Process Automation Manager 项目

  • 您有包含 DMN 模型的 KIE 容器的 ID。如果有多个模型,还必须知道相关模型的模型命名空间和模型名称。

�程

  1. 确定用于访问 KIE 服务器 REST API 端点的基本 URL。这需要了解以下值(默认本地部署值作为示例):

    • 主机(localhost)
    • 端口(8080)
    • 根上下文(kie-server)
    • 基本 REST 路径(services/rest/)

    本地部署中的基本 URL 示例:

    http://localhost:8080/kie-server/services/rest/

  2. 确定用户身份验证要求。

    当在 KIE 服务器配置中直接定义用户时,会使用 HTTP 基本身份验证,并且需要用户名和密码。成功请求要求用户具有 kie-server 角色。

    以下示例演示了如何在 curl 请求中添加凭证:

    curl -u username:password <request>

    如果使用 Red Hat Single Sign-On 配置 KIE 服务器,请求必须包含 bearer 令牌:

    curl -H "Authorization: bearer $TOKEN" <request>
  3. 指定请求和响应的格式。REST API 端点可用于 JSON 和 XML 格式,并使用请求标头设置:

    JSON

    curl -H "accept: application/json" -H "content-type: application/json"

    XML

    curl -H "accept: application/xml" -H "content-type: application/xml"

  4. (可选)查询容器以获取部署的决策模型列表:

    [GET] server/containers/{containerId}/dmn

    curl 请求示例:

    curl -u krisv:krisv -H "accept: application/xml" -X GET "http://localhost:8080/kie-server/services/rest/server/containers/MovieDMNContainer/dmn"

    XML 输出示例:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <response type="SUCCESS" msg="OK models successfully retrieved from container 'MovieDMNContainer'">
        <dmn-model-info-list>
            <model>
                <model-namespace>http://www.redhat.com/_c7328033-c355-43cd-b616-0aceef80e52a</model-namespace>
                <model-name>dmn-movieticket-ageclassification</model-name>
                <model-id>_99</model-id>
                <decisions>
                    <dmn-decision-info>
                        <decision-id>_3</decision-id>
                        <decision-name>AgeClassification</decision-name>
                    </dmn-decision-info>
                </decisions>
            </model>
        </dmn-model-info-list>
    </response>

    JSON 输出示例:

    {
      "type" : "SUCCESS",
      "msg" : "OK models successfully retrieved from container 'MovieDMNContainer'",
      "result" : {
        "dmn-model-info-list" : {
          "models" : [ {
            "model-namespace" : "http://www.redhat.com/_c7328033-c355-43cd-b616-0aceef80e52a",
            "model-name" : "dmn-movieticket-ageclassification",
            "model-id" : "_99",
            "decisions" : [ {
              "decision-id" : "_3",
              "decision-name" : "AgeClassification"
            } ]
          } ]
        }
      }
    }
  5. 执行模型:

    [POST] server/containers/{containerId}/dmn

    curl 请求示例:

    curl -u krisv:krisv -H "accept: application/json" -H "content-type: application/json" -X POST "http://localhost:8080/kie-server/services/rest/server/containers/MovieDMNContainer/dmn" -d "{ \"model-namespace\" : \"http://www.redhat.com/_c7328033-c355-43cd-b616-0aceef80e52a\", \"model-name\" : \"dmn-movieticket-ageclassification\", \"decision-name\" : [ ], \"decision-id\" : [ ], \"dmn-context\" : {\"Age\" : 66}}"

    JSON 请求示例:

    {
      "model-namespace" : "http://www.redhat.com/_c7328033-c355-43cd-b616-0aceef80e52a",
      "model-name" : "dmn-movieticket-ageclassification",
      "decision-name" : [ ],
      "decision-id" : [ ],
      "dmn-context" : {"Age" : 66}
    }

    XML 请求示例(DSLB 格式):

    <?xml version="1.0" encoding="UTF-8"?>
    <dmn-evaluation-context>
        <model-namespace>http://www.redhat.com/_c7328033-c355-43cd-b616-0aceef80e52a</model-namespace>
        <model-name>dmn-movieticket-ageclassification</model-name>
        <dmn-context xsi:type="jaxbListWrapper" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <type>MAP</type>
            <element xsi:type="jaxbStringObjectPair" key="Age">
                <value xsi:type="xs:int" xmlns:xs="http://www.w3.org/2001/XMLSchema">66</value>
            </element>
        </dmn-context>
    </dmn-evaluation-context>
    注意

    无论请求格式是什么,请求需要以下元素:

    • 模型命名空间
    • å�‹å�·å��ç§°
    • 包含输入值的上下文对象

    JSON 响应示例:

    {
      "type" : "SUCCESS",
      "msg" : "OK from container 'MovieDMNContainer'",
      "result" : {
        "dmn-evaluation-result" : {
          "messages" : [ ],
          "model-namespace" : "http://www.redhat.com/_c7328033-c355-43cd-b616-0aceef80e52a",
          "model-name" : "dmn-movieticket-ageclassification",
          "decision-name" : [ ],
          "dmn-context" : {
            "Age" : 66,
            "AgeClassification" : "Senior"
          },
          "decision-results" : {
            "_3" : {
              "messages" : [ ],
              "decision-id" : "_3",
              "decision-name" : "AgeClassification",
              "result" : "Senior",
              "status" : "SUCCEEDED"
            }
          }
        }
      }
    }

    XML (DSLB 格式)响应示例:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <response type="SUCCESS" msg="OK from container 'MovieDMNContainer'">
          <dmn-evaluation-result>
                <model-namespace>http://www.redhat.com/_c7328033-c355-43cd-b616-0aceef80e52a</model-namespace>
                <model-name>dmn-movieticket-ageclassification</model-name>
                <dmn-context xsi:type="jaxbListWrapper" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                      <type>MAP</type>
                      <element xsi:type="jaxbStringObjectPair" key="Age">
                            <value xsi:type="xs:int" xmlns:xs="http://www.w3.org/2001/XMLSchema">66</value>
                      </element>
                      <element xsi:type="jaxbStringObjectPair" key="AgeClassification">
                            <value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">Senior</value>
                      </element>
                </dmn-context>
                <messages/>
                <decisionResults>
                      <entry>
                            <key>_3</key>
                            <value>
                                  <decision-id>_3</decision-id>
                                  <decision-name>AgeClassification</decision-name>
                                  <result xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Senior</result>
                                  <messages/>
                                  <status>SUCCEEDED</status>
                            </value>
                      </entry>
                </decisionResults>
          </dmn-evaluation-result>
    </response>

第 6 章 其他资源

部分 II. 使用 PMML 模型设计决策服务

作为自定义规则开发人员,您可以使用 Predictive Model Markup Language (PMML)来定义您可以在 Red Hat Process Automation Manager 中与决策服务集成的统计信息或数据小模型。Red Hat Process Automation Manager 包括针对 Regression、Scorecard、Tree 和 Mining 模型的 PMML 4.2.1 的消费者一致支持。Red Hat Process Automation Manager 不包括内置的 PMML 模型编辑器,但您可以使用 XML 或 PMML 特定的编写工具来创建 PMML 模型,然后将其与您的 Red Hat Process Automation Manager 项目集成。

有关 PMML 的更多信息,请参阅 DMG PMML 规格

注意

您还可以使用决策模型和表示法(DMN)模型设计您的决定服务,并将 PMML 模型作为 DMN 服务的一部分包含在内。有关 Red Hat Process Automation Manager 7.9 中的 DMN 支持的详情,请查看以下资源:

第 7 章 Red Hat Process Automation Manager 中的决策授权资产

Red Hat Process Automation Manager 支持多个资产,可用于为您的决策服务定义决策。每个决定授权资产都有不同的优点,您可能需要根据您的目标和需求使用多个资产的组合。

下表重点介绍 Red Hat Process Automation Manager 项目支持的主要决策授权资产,以帮助您决定或确认在决策服务中定义决策的最佳方法。

表 7.1. Red Hat Process Automation Manager 支持的决策授予资产

assethighlight编写工具Documentation

决策模型和表示法(DMN)模型

  • 是根据对象管理组(OMG)定义的表示法标准决定模型。
  • 使用代表部分或所有决策要求图(DRG)的图形决策要求图(DRG)来跟踪业务决策流程
  • 使用允许在 DMN 兼容平台之间共享 DMN 模型的 XML 模式
  • 支持 Friendly Enough Expression Language (FEEL),以在 DMN 决策表和其他 DMN 框表达式中定义决策逻辑
  • 可以与 Business Process Model 和 Notation (DSLN)进程模型有效集成
  • 是创建全面、演示和稳定的决策流程的最佳选择

Business Central 或其他与 DMN 兼容的编辑器

使用 DMN 模型设计决策服务

主要决策表

  • 是您在 Business Central 的基于 UI 的表设计程序中创建的规则表
  • 是电子表格决策表的向导替代方法
  • 为可接受的输入提供字段和选项
  • 支持用于创建规则模板的模板键和值
  • 支持点击策略、实时验证以及其他资产不支持的其他额外功能
  • 最好以受控的 tabular 格式创建规则,以最小化编译错误

Business Central

使用指导决策表设计决策服务

电子表格决策表

  • 是 XLS 或 XLSX 电子表格决策表,您可以上传到 Business Central
  • 支持用于创建规则模板的模板键和值
  • 最好在 Business Central 外部管理的路由表中创建规则
  • 对于在上传时正确编译的规则具有严格的语法要求

电子表格编辑器

使用电子表格决策表设计决策服务

指导规则

  • 是您在 Business Central 中基于 UI 的规则设计程序中创建的单个规则
  • 为可接受的输入提供字段和选项
  • 最好以受控格式创建单个规则,以最小化编译错误

Business Central

使用指导规则设计决策服务

指导规则模板

  • 是您在 Business Central 中的基于 UI 的模板设计程序中创建的可重复使用的规则结构
  • 为可接受的输入提供字段和选项
  • 支持用于创建规则模板的模板键和值(与资产相关的目的不同)
  • 最好创建具有相同规则结构但具有不同定义的字段值的规则

Business Central

使用指导规则模板设计决策服务

DRL 规则

  • 是直接在 .drl 文本文件中定义的单个规则
  • 提供定义规则和其他规则行为的最灵活
  • 可以在某些独立环境中创建,并与 Red Hat Process Automation Manager 集成
  • 最好创建需要高级 DRL 选项的规则
  • 具有正确编译的规则具有严格的语法要求

Business Central 或集成开发环境(IDE)

使用 DRL 规则设计决策服务

预测模型标记语言(PMML)模型

  • 是预测的 data-analytic 模型,它基于由 Data Mining Group (DMG)定义的表示法标准
  • 使用一个 XML 模式,允许在 PMML 兼容平台之间共享 PMML 模型
  • 支持 Regression、Scorecard、Tree、Ming 和其他模型类型
  • 可以包含独立 Red Hat Process Automation Manager 项目,也可以导入到 Business Central 中的项目中
  • 最好在 Red Hat Process Automation Manager 中将预测数据整合到决策服务中

pmML 或 XML 编辑器

使用 PMML 模型设计决策服务

第 8 章 预测模型标记语言(PMML)

预测模型标记语言(PMML)是由数据 Mining Group (DMG)建立的基于 XML 的标准,用于定义统计信息和数据最小模型。PMML 模型可以在 PMML 兼容平台和机构间共享,以便业务和开发人员在设计、分析和实施基于 PMML 的资产和服务中统一。

有关 PMML 的背景和应用程序的更多信息,请参阅 DMG PMML 规格

8.1. PMML 一致性级别

PMML 规范在软件实施中定义生成者和消费者一致性级别,以确保创建并可靠地创建并集成 PMML 模型。有关每个符合等级的正式定义,请查看 DMG PMML 一致性 页面。

以下列表总结了 PMML 一致性级别:

生成者一致性
如果工具或应用程序为至少一个类型的模型生成有效的 PMML 文档,则工具或应用程序将遵循生成者。满足 PMML producer 的要求可确保模型定义文档语法正确,并定义与模型规格中定义的语义标准一致的模型实例。
消费者一致性
如果应用程序至少接受一种类型的模型,则应用程序处于消费者要求,如果它接受有效的 PMML 文档。满足消费者遵守的要求可确保根据生成者遵守创建的 PMML 模型可以集成和使用。例如,如果应用程序是消费者符合 Regression 模型类型的消费者,则有效的 PMML 文档定义了由不同符合制作者生成的类型的模型在应用程序中可互换。

Red Hat Process Automation Manager 包括对以下 PMML 4.2.1 模型类型的消费者一致支持:

有关所有 PMML 模型类型的列表,包括 Red Hat Process Automation Manager 中不支持的项,请参阅 DMG PMML 规格

第 9 章 PMML 模型示例

PMML 定义了一个 XML 模式,它允许在不同 PMML 兼容平台之间使用 PMML 模型。PMML 规范可让多个软件平台处理同一文件进行编写、测试和生产执行,假设满足生成者和消费者要求。

以下是 PMML Regression、Scorecard、Tree 和 Mining 模型的示例。这些示例演示了您可以在 Red Hat Process Automation Manager 中与决策服务集成支持的模型类型。

有关更多 PMML 示例,请参阅 DMG PMML Sample Files 页面。

PMML Regression 模型示例

<PMML version="4.2" xsi:schemaLocation="http://www.dmg.org/PMML-4_2 http://www.dmg.org/v4-2-1/pmml-4-2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.dmg.org/PMML-4_2">
  <Header copyright="JBoss"/>
  <DataDictionary numberOfFields="5">
    <DataField dataType="double" name="fld1" optype="continuous"/>
    <DataField dataType="double" name="fld2" optype="continuous"/>
    <DataField dataType="string" name="fld3" optype="categorical">
      <Value value="x"/>
      <Value value="y"/>
    </DataField>
    <DataField dataType="double" name="fld4" optype="continuous"/>
    <DataField dataType="double" name="fld5" optype="continuous"/>
  </DataDictionary>
  <RegressionModel algorithmName="linearRegression" functionName="regression" modelName="LinReg" normalizationMethod="logit" targetFieldName="fld4">
    <MiningSchema>
      <MiningField name="fld1"/>
      <MiningField name="fld2"/>
      <MiningField name="fld3"/>
      <MiningField name="fld4" usageType="predicted"/>
      <MiningField name="fld5" usageType="target"/>
    </MiningSchema>
    <RegressionTable intercept="0.5">
      <NumericPredictor coefficient="5" exponent="2" name="fld1"/>
      <NumericPredictor coefficient="2" exponent="1" name="fld2"/>
      <CategoricalPredictor coefficient="-3" name="fld3" value="x"/>
      <CategoricalPredictor coefficient="3" name="fld3" value="y"/>
      <PredictorTerm coefficient="0.4">
        <FieldRef field="fld1"/>
        <FieldRef field="fld2"/>
      </PredictorTerm>
    </RegressionTable>
  </RegressionModel>
</PMML>

PMML Scorecard 模型示例

<PMML version="4.2" xsi:schemaLocation="http://www.dmg.org/PMML-4_2 http://www.dmg.org/v4-2-1/pmml-4-2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.dmg.org/PMML-4_2">
  <Header copyright="JBoss"/>
  <DataDictionary numberOfFields="4">
    <DataField name="param1" optype="continuous" dataType="double"/>
    <DataField name="param2" optype="continuous" dataType="double"/>
    <DataField name="overallScore" optype="continuous" dataType="double" />
    <DataField name="finalscore" optype="continuous" dataType="double" />
  </DataDictionary>
  <Scorecard modelName="ScorecardCompoundPredicate" useReasonCodes="true" isScorable="true" functionName="regression"    baselineScore="15" initialScore="0.8" reasonCodeAlgorithm="pointsAbove">
    <MiningSchema>
      <MiningField name="param1" usageType="active" invalidValueTreatment="asMissing">
      </MiningField>
      <MiningField name="param2" usageType="active" invalidValueTreatment="asMissing">
      </MiningField>
      <MiningField name="overallScore" usageType="target"/>
      <MiningField name="finalscore" usageType="predicted"/>
    </MiningSchema>
    <Characteristics>
      <Characteristic name="ch1" baselineScore="50" reasonCode="reasonCh1">
        <Attribute partialScore="20">
          <SimplePredicate field="param1" operator="lessThan" value="20"/>
        </Attribute>
        <Attribute partialScore="100">
          <CompoundPredicate booleanOperator="and">
            <SimplePredicate field="param1" operator="greaterOrEqual" value="20"/>
            <SimplePredicate field="param2" operator="lessOrEqual" value="25"/>
          </CompoundPredicate>
        </Attribute>
        <Attribute partialScore="200">
          <CompoundPredicate booleanOperator="and">
            <SimplePredicate field="param1" operator="greaterOrEqual" value="20"/>
            <SimplePredicate field="param2" operator="greaterThan" value="25"/>
          </CompoundPredicate>
        </Attribute>
      </Characteristic>
      <Characteristic name="ch2" reasonCode="reasonCh2">
        <Attribute partialScore="10">
          <CompoundPredicate booleanOperator="or">
            <SimplePredicate field="param2" operator="lessOrEqual" value="-5"/>
            <SimplePredicate field="param2" operator="greaterOrEqual" value="50"/>
          </CompoundPredicate>
        </Attribute>
        <Attribute partialScore="20">
          <CompoundPredicate booleanOperator="and">
            <SimplePredicate field="param2" operator="greaterThan" value="-5"/>
            <SimplePredicate field="param2" operator="lessThan" value="50"/>
          </CompoundPredicate>
        </Attribute>
      </Characteristic>
    </Characteristics>
  </Scorecard>
</PMML>

PMML Tree 模型示例

<PMML version="4.2" xsi:schemaLocation="http://www.dmg.org/PMML-4_2 http://www.dmg.org/v4-2-1/pmml-4-2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.dmg.org/PMML-4_2">
  <Header copyright="JBOSS"/>
  <DataDictionary numberOfFields="5">
    <DataField dataType="double" name="fld1" optype="continuous"/>
    <DataField dataType="double" name="fld2" optype="continuous"/>
    <DataField dataType="string" name="fld3" optype="categorical">
      <Value value="true"/>
      <Value value="false"/>
    </DataField>
    <DataField dataType="string" name="fld4" optype="categorical">
      <Value value="optA"/>
      <Value value="optB"/>
      <Value value="optC"/>
    </DataField>
    <DataField dataType="string" name="fld5" optype="categorical">
      <Value value="tgtX"/>
      <Value value="tgtY"/>
      <Value value="tgtZ"/>
    </DataField>
  </DataDictionary>
  <TreeModel functionName="classification" modelName="TreeTest">
    <MiningSchema>
      <MiningField name="fld1"/>
      <MiningField name="fld2"/>
      <MiningField name="fld3"/>
      <MiningField name="fld4"/>
      <MiningField name="fld5" usageType="predicted"/>
    </MiningSchema>
    <Node score="tgtX">
      <True/>
      <Node score="tgtX">
        <SimplePredicate field="fld4" operator="equal" value="optA"/>
        <Node score="tgtX">
          <CompoundPredicate booleanOperator="surrogate">
            <SimplePredicate field="fld1" operator="lessThan" value="30.0"/>
            <SimplePredicate field="fld2" operator="greaterThan" value="20.0"/>
          </CompoundPredicate>
          <Node score="tgtX">
            <SimplePredicate field="fld2" operator="lessThan" value="40.0"/>
          </Node>
          <Node score="tgtZ">
            <SimplePredicate field="fld2" operator="greaterOrEqual" value="10.0"/>
          </Node>
        </Node>
        <Node score="tgtZ">
          <CompoundPredicate booleanOperator="or">
            <SimplePredicate field="fld1" operator="greaterOrEqual" value="60.0"/>
            <SimplePredicate field="fld1" operator="lessOrEqual" value="70.0"/>
          </CompoundPredicate>
          <Node score="tgtZ">
            <SimpleSetPredicate booleanOperator="isNotIn" field="fld4">
              <Array type="string">optA optB</Array>
            </SimpleSetPredicate>
          </Node>
        </Node>
      </Node>
      <Node score="tgtY">
        <CompoundPredicate booleanOperator="or">
          <SimplePredicate field="fld4" operator="equal" value="optA"/>
          <SimplePredicate field="fld4" operator="equal" value="optC"/>
        </CompoundPredicate>
        <Node score="tgtY">
          <CompoundPredicate booleanOperator="and">
            <SimplePredicate field="fld1" operator="greaterThan" value="10.0"/>
            <SimplePredicate field="fld1" operator="lessThan" value="50.0"/>
            <SimplePredicate field="fld4" operator="equal" value="optA"/>
            <SimplePredicate field="fld2" operator="lessThan" value="100.0"/>
            <SimplePredicate field="fld3" operator="equal" value="false"/>
          </CompoundPredicate>
        </Node>
        <Node score="tgtZ">
          <CompoundPredicate booleanOperator="and">
            <SimplePredicate field="fld4" operator="equal" value="optC"/>
            <SimplePredicate field="fld2" operator="lessThan" value="30.0"/>
          </CompoundPredicate>
        </Node>
      </Node>
    </Node>
  </TreeModel>
</PMML>

PMML Mining 模型示例(modelChain)

<PMML version="4.2" xsi:schemaLocation="http://www.dmg.org/PMML-4_2 http://www.dmg.org/v4-2-1/pmml-4-2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://www.dmg.org/PMML-4_2">
  <Header>
    <Application name="Drools-PMML" version="7.0.0-SNAPSHOT" />
  </Header>
  <DataDictionary numberOfFields="7">
    <DataField name="age" optype="continuous" dataType="double" />
    <DataField name="occupation" optype="categorical" dataType="string">
      <Value value="SKYDIVER" />
      <Value value="ASTRONAUT" />
      <Value value="PROGRAMMER" />
      <Value value="TEACHER" />
      <Value value="INSTRUCTOR" />
    </DataField>
    <DataField name="residenceState" optype="categorical" dataType="string">
      <Value value="AP" />
      <Value value="KN" />
      <Value value="TN" />
    </DataField>
    <DataField name="validLicense" optype="categorical" dataType="boolean" />
    <DataField name="overallScore" optype="continuous" dataType="double" />
    <DataField name="grade" optype="categorical" dataType="string">
      <Value value="A" />
      <Value value="B" />
      <Value value="C" />
      <Value value="D" />
      <Value value="F" />
    </DataField>
    <DataField name="qualificationLevel" optype="categorical" dataType="string">
      <Value value="Unqualified" />
      <Value value="Barely" />
      <Value value="Well" />
      <Value value="Over" />
    </DataField>
  </DataDictionary>
  <MiningModel modelName="SampleModelChainMine" functionName="classification">
    <MiningSchema>
      <MiningField name="age" />
      <MiningField name="occupation" />
      <MiningField name="residenceState" />
      <MiningField name="validLicense" />
      <MiningField name="overallScore" />
      <MiningField name="qualificationLevel" usageType="target"/>
    </MiningSchema>
    <Segmentation multipleModelMethod="modelChain">
      <Segment id="1">
        <True />
        <Scorecard modelName="Sample Score 1" useReasonCodes="true" isScorable="true" functionName="regression"               baselineScore="0.0" initialScore="0.345">
          <MiningSchema>
            <MiningField name="age" usageType="active" invalidValueTreatment="asMissing" />
            <MiningField name="occupation" usageType="active" invalidValueTreatment="asMissing" />
            <MiningField name="residenceState" usageType="active" invalidValueTreatment="asMissing" />
            <MiningField name="validLicense" usageType="active" invalidValueTreatment="asMissing" />
            <MiningField name="overallScore" usageType="predicted" />
          </MiningSchema>
          <Output>
            <OutputField name="calculatedScore" displayName="Final Score" dataType="double" feature="predictedValue"                     targetField="overallScore" />
          </Output>
          <Characteristics>
            <Characteristic name="AgeScore" baselineScore="0.0" reasonCode="ABZ">
              <Extension name="cellRef" value="$B$8" />
              <Attribute partialScore="10.0">
                <Extension name="cellRef" value="$C$10" />
                <SimplePredicate field="age" operator="lessOrEqual" value="5" />
              </Attribute>
              <Attribute partialScore="30.0" reasonCode="CX1">
                <Extension name="cellRef" value="$C$11" />
                <CompoundPredicate booleanOperator="and">
                  <SimplePredicate field="age" operator="greaterOrEqual" value="5" />
                  <SimplePredicate field="age" operator="lessThan" value="12" />
                </CompoundPredicate>
              </Attribute>
              <Attribute partialScore="40.0" reasonCode="CX2">
                <Extension name="cellRef" value="$C$12" />
                <CompoundPredicate booleanOperator="and">
                  <SimplePredicate field="age" operator="greaterOrEqual" value="13" />
                  <SimplePredicate field="age" operator="lessThan" value="44" />
                </CompoundPredicate>
              </Attribute>
              <Attribute partialScore="25.0">
                <Extension name="cellRef" value="$C$13" />
                <SimplePredicate field="age" operator="greaterOrEqual" value="45" />
              </Attribute>
            </Characteristic>
            <Characteristic name="OccupationScore" baselineScore="0.0">
              <Extension name="cellRef" value="$B$16" />
              <Attribute partialScore="-10.0" reasonCode="CX2">
                <Extension name="description" value="skydiving is a risky occupation" />
                <Extension name="cellRef" value="$C$18" />
                <SimpleSetPredicate field="occupation" booleanOperator="isIn">
                  <Array n="2" type="string">SKYDIVER ASTRONAUT</Array>
                </SimpleSetPredicate>
              </Attribute>
              <Attribute partialScore="10.0">
                <Extension name="cellRef" value="$C$19" />
                <SimpleSetPredicate field="occupation" booleanOperator="isIn">
                  <Array n="2" type="string">TEACHER INSTRUCTOR</Array>
                </SimpleSetPredicate>
              </Attribute>
              <Attribute partialScore="5.0">
                <Extension name="cellRef" value="$C$20" />
                <SimplePredicate field="occupation" operator="equal" value="PROGRAMMER" />
              </Attribute>
            </Characteristic>
            <Characteristic name="ResidenceStateScore" baselineScore="0.0" reasonCode="RES">
              <Extension name="cellRef" value="$B$22" />
              <Attribute partialScore="-10.0">
                <Extension name="cellRef" value="$C$24" />
                <SimplePredicate field="residenceState" operator="equal" value="AP" />
              </Attribute>
              <Attribute partialScore="10.0">
                <Extension name="cellRef" value="$C$25" />
                <SimplePredicate field="residenceState" operator="equal" value="KN" />
              </Attribute>
              <Attribute partialScore="5.0">
                <Extension name="cellRef" value="$C$26" />
                <SimplePredicate field="residenceState" operator="equal" value="TN" />
              </Attribute>
            </Characteristic>
            <Characteristic name="ValidLicenseScore" baselineScore="0.0">
              <Extension name="cellRef" value="$B$28" />
              <Attribute partialScore="1.0" reasonCode="LX00">
                <Extension name="cellRef" value="$C$30" />
                <SimplePredicate field="validLicense" operator="equal" value="true" />
              </Attribute>
              <Attribute partialScore="-1.0" reasonCode="LX00">
                <Extension name="cellRef" value="$C$31" />
                <SimplePredicate field="validLicense" operator="equal" value="false" />
              </Attribute>
            </Characteristic>
          </Characteristics>
        </Scorecard>
      </Segment>
      <Segment id="2">
        <True />
        <TreeModel modelName="SampleTree" functionName="classification" missingValueStrategy="lastPrediction" noTrueChildStrategy="returnLastPrediction">
          <MiningSchema>
            <MiningField name="age" usageType="active" />
            <MiningField name="validLicense" usageType="active" />
            <MiningField name="calculatedScore" usageType="active" />
            <MiningField name="qualificationLevel" usageType="predicted" />
          </MiningSchema>
          <Output>
            <OutputField name="qualification" displayName="Qualification Level" dataType="string" feature="predictedValue"                     targetField="qualificationLevel" />
          </Output>
          <Node score="Well" id="1">
            <True/>
            <Node score="Barely" id="2">
              <CompoundPredicate booleanOperator="and">
                <SimplePredicate field="age" operator="greaterOrEqual" value="16" />
                <SimplePredicate field="validLicense" operator="equal" value="true" />
              </CompoundPredicate>
              <Node score="Barely" id="3">
                <SimplePredicate field="calculatedScore" operator="lessOrEqual" value="50.0" />
              </Node>
              <Node score="Well" id="4">
                <CompoundPredicate booleanOperator="and">
                  <SimplePredicate field="calculatedScore" operator="greaterThan" value="50.0" />
                  <SimplePredicate field="calculatedScore" operator="lessOrEqual" value="60.0" />
                </CompoundPredicate>
              </Node>
              <Node score="Over" id="5">
                <SimplePredicate field="calculatedScore" operator="greaterThan" value="60.0" />
              </Node>
            </Node>
            <Node score="Unqualified" id="6">
              <CompoundPredicate booleanOperator="surrogate">
                <SimplePredicate field="age" operator="lessThan" value="16" />
                <SimplePredicate field="calculatedScore" operator="lessOrEqual" value="40.0" />
                <True />
              </CompoundPredicate>
            </Node>
          </Node>
        </TreeModel>
      </Segment>
    </Segmentation>
  </MiningModel>
</PMML>

第 10 章 Red Hat Process Automation Manager 中的 PMML 支持

Red Hat Process Automation Manager 包括对以下 PMML 4.2.1 模型类型的消费者一致支持:

有关所有 PMML 模型类型的列表,包括 Red Hat Process Automation Manager 中不支持的项,请参阅 DMG PMML 规格

Red Hat Process Automation Manager 不包含内置的 PMML 模型编辑器,但您可以使用 XML 或 PMML 特定编写工具创建 PMML 模型,然后在 Red Hat Process Automation Manager 中的决策服务中集成 PMML 模型。您可以在 Business Central (Menu → Projects → Import Asset)中将 PMML 文件导入到项目中,或者将 PMML 文件打包为没有 Business Central 的项目知识 JAR (KJAR)文件的一部分。

当您向 Red Hat Process Automation Manager 中的项目添加 PMML 文件时,会生成多个资产。每种 PMML 模型都生成不同的资产集合,但所有 PMML 模型类型都会至少生成以下组资产:

  • 包含与 PMML 模型关联的所有规则的 DRL 文件
  • 至少两个 Java 类:

    • 用作模型类型的默认对象类型的数据类
    • 用于管理数据源和规则执行的 RuleUnit

如果 PMML 文件具有 MiningModel 作为根模型,则会生成每个文件的多个实例。

有关使用项目打包和部署方法包括 PMML 文件的更多信息,请参阅打包和部署 Red Hat Process Automation Manager 项目

10.1. Red Hat Process Automation Manager 中的 PMML 命名约定

以下是生成的 PMML 软件包、类和规则的命名约定:

  • 如果在 PMML 模型文件中未提供软件包名称,则默认软件包名称 org.kie.pmml.pmml_4_2 会作为前缀放在生成的规则的模型名称中,格式为 "org.kie.pmml_4_2"+modelName
  • 生成的 RuleUnit Java 类的软件包名称与生成的规则的软件包名称相同。
  • 生成的 RuleUnit Java 类的名称是带有 RuleUnit 的模型名称,格式为 modelName+"RuleUnit "。
  • 每个 PMML 模型至少有一个数据类被生成。这些类的软件包名称是 org.kie.pmml.pmml_4_2.model
  • 生成的数据类型的名称由模型类型决定,前缀为模型名称:

    • 回归模型:一个名为 modelName+"RegressionData"的数据类
    • Scorecard model: one data class named modelName+"ScoreCardData"
    • 树形模型:两个数据类,第一个命名 modelName+"TreeNode",第二个名为 modelName+"TreeToken"
    • 最小模型:一个名为 modelName+"MiningModelData"的数据类
注意

最小模型还会生成每个片段中的所有规则和类。

10.2. Red Hat Process Automation Manager 中的 PMML 扩展

PMML 规格支持 扩展 PMML 模型内容的扩展元素。您可以在 PMML 模型定义的每个级别上使用扩展,作为模型主元素中的第一个和最后一个子对象,以获得最大的灵活性。有关 PMML 扩展的更多信息,请参阅 DMG PMML 扩展机制

要优化 PMML 集成,Red Hat Process Automation Manager 支持以下额外的 PMML 扩展:

  • modelPackage: 为生成的规则和 Java 类指定软件包名称。在 PMML 模型文件的 Header 部分中包括此扩展。
  • adapter :指定用来包含规则的输入和输出数据的结构类型(Bean特征)。在 PMML 模型文件的 MiningSchemaOutput 部分(或两者)中插入此扩展。
  • ExternalClass :与 适配器 扩展一起使用,用来定义 MiningFieldOutputField。此扩展包含一个类,其属性名称与 MiningFieldOutputField 元素的名称匹配。

第 11 章 PMML 模型执行

您可以使用 Business Central (Menu → Projects → Projects → Import Asset)将 PMML 文件导入到 Red Hat Process Automation Manager 项目中,或将 PMML 文件打包为没有 Business Central 的项目知识 JAR (KJAR)文件的一部分。在 Red Hat Process Automation Manager 项目中实现了 PMML 文件后,您可以通过在 Java 应用程序中直接嵌入 PMML 调用或向配置的 KIE 服务器发送 ApplyPmmlModelCommand 命令来执行基于 PMML 的决策服务。

有关使用项目打包和部署方法包括 PMML 资产的更多信息,请参阅 打包和部署 Red Hat Process Automation Manager 项目

注意

您还可以在 Business Central 中包含 PMML 模型作为 Decision Model 和 Notation (DMN)服务的一部分。当您在 DMN 文件中包含 PMML 模型时,您可以调用 PMML 模型作为 DMN 决策节点或业务知识模型节点的方框函数表达式。有关在 DMN 服务中包含 PMML 模型的更多信息,请参阅使用 DMN 模型设计决策服务

11.1. 直接嵌入 Java 应用程序中的 PMML 调用

当知识资产直接嵌入到调用程序中或物理拉取时,KIE 容器是本地的,或使用 KJAR 的 Maven 依赖项进行物理拉取。通常,如果代码版本和 PMML 定义版本之间有紧密关系,您通常直接将知识资产嵌入到项目中。在有意更新并重新部署应用程序后,对决定所做的任何更改都会生效。这种方法的一个优点是,正确的操作不依赖于任何外部依赖项到运行时,这可能是锁定环境的限制。

使用 Maven 依赖项可以进一步的灵活性,因为决策的特定版本可以动态更改(例如,使用系统属性),它可以定期扫描更新和自动更新。这引入了对服务的部署时间的外部依赖项,但在本地执行决策,从而减少在运行时对外部服务的依赖。

先决�件

�程

  1. 在客户端应用程序中,将以下依赖项添加到 Java 项目的相关类路径中:

    <!-- Required for the PMML compiler -->
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>kie-pmml</artifactId>
      <version>${rhpam.version}</version>
    </dependency>
    
    <!-- Required for the KIE public API -->
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-api</artifactId>
      <version>${rhpam.version}</version>
    </dependencies>
    
    <!-- Required if not using classpath KIE container -->
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-ci</artifactId>
      <version>${rhpam.version}</version>
    </dependency>

    & lt;version > 是项目中当前使用的 Red Hat Process Automation Manager 的 Maven 工件版本(如 7.44.0.Final-redhat-00006)。

    注意

    考虑将 Red Hat Business Automation Manager (BOM)依赖项添加到项目 pom.xml 文件,而不是为单个依赖项指定 Red Hat Process Automation Manager < version >。Red Hat Business Automation BOM 适用于 Red Hat Decision Manager 和 Red Hat Process Automation Manager。当您添加 BOM 文件时,项目中包含了来自提供的 Maven 存储库传输性依赖关系的正确版本。

    BOM 依赖项示例:

    <dependency>
      <groupId>com.redhat.ba</groupId>
      <artifactId>ba-platform-bom</artifactId>
      <version>7.9.1.redhat-00003</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>

    有关 Red Hat Business Automation BOM 的更多信息,请参阅 RHPAM 产品和 maven 库版本之间的映射是什么?

  2. classpathReleaseId 创建 KIE 容器:

    KieServices kieServices = KieServices.Factory.get();
    
    ReleaseId releaseId = kieServices.newReleaseId( "org.acme", "my-kjar", "1.0.0" );
    KieContainer kieContainer = kieServices.newKieContainer( releaseId );

    其它选项:

    KieServices kieServices = KieServices.Factory.get();
    
    KieContainer kieContainer = kieServices.getKieClasspathContainer();
  3. 创建 PMMLRequestData 类实例,它将 PMML 模型应用到一组数据:

    public class PMMLRequestData {
        private String correlationId; 1
        private String modelName; 2
        private String source; 3
        private List<ParameterInfo<?>> requestParams; 4
        ...
    }
    1
    标识与特定请求或结果关联的数据
    2
    应该应用到请求数据的模型名称
    3
    由内部生成的 PMMLRequestData 对象用来识别所生成的请求的片段
    4
    发送输入数据点的默认机制
  4. 创建 PMML4Result 类的实例,其中包含将基于 PMML 的规则应用到输入数据的输出信息:

    public class PMML4Result {
        private String correlationId;
        private String segmentationId; 1
        private String segmentId; 2
        private int segmentIndex; 3
        private String resultCode; 4
        private Map<String, Object> resultVariables; 5
        ...
    }
    1
    当模型类型是 MiningModel 时使用。segmentationId 用于区分多个分段。
    2
    segmentationId 一起使用,以识别生成结果的片段。
    3
    用于维护片段的顺序。
    4
    用于确定模型是否已成功应用,其中 OK 表示成功。
    5
    包含结果变量的名称及其关联的值。

    除了正常的 getter 方法外,pmML4Result 类还支持以下方法直接检索结果变量的值:

    public <T> Optional<T> getResultValue(String objName, String objField, Class<T> clazz, Object...params)
    
    public Object getResultValue(String objName, String objField, Object...params)
  5. 创建 ParameterInfo 类的实例,用作作为 PMMLRequestData 类一部分的基本数据类型对象的打包程序:

    public class ParameterInfo<T> { 1
        private String correlationId;
        private String name; 2
        private String capitalizedName;
        private Class<T> type; 3
        private T value; 4
        ...
    }
    1
    处理许多不同类型的参数类
    2
    期望作为模型输入的变量名称
    3
    变量的实际类型的类
    4
    变量的实际值
  6. 根据您创建的所需的 PMML 类实例执行 PMML 模型:

    public void executeModel(KieBase kbase,
                             Map<String,Object> variables,
                             String modelName,
                             String correlationId,
                             String modelPkgName) {
        RuleUnitExecutor executor = RuleUnitExecutor.create().bind(kbase);
        PMMLRequestData request = new PMMLRequestData(correlationId, modelName);
        PMML4Result resultHolder = new PMML4Result(correlationId);
        variables.entrySet().forEach( es -> {
            request.addRequestParam(es.getKey(), es.getValue());
        });
    
        DataSource<PMMLRequestData> requestData = executor.newDataSource("request");
        DataSource<PMML4Result> resultData = executor.newDataSource("results");
        DataSource<PMMLData> internalData = executor.newDataSource("pmmlData");
    
        requestData.insert(request);
        resultData.insert(resultHolder);
    
        List<String> possiblePackageNames = calculatePossiblePackageNames(modelName,
                                                                        modelPkgName);
        Class<? extends RuleUnit> ruleUnitClass = getStartingRuleUnit("RuleUnitIndicator",
                                                                    (InternalKnowledgeBase)kbase,
                                                                    possiblePackageNames);
    
        if (ruleUnitClass != null) {
            executor.run(ruleUnitClass);
            if ( "OK".equals(resultHolder.getResultCode()) ) {
              // extract result variables here
            }
        }
    }
    
    protected Class<? extends RuleUnit> getStartingRuleUnit(String startingRule, InternalKnowledgeBase ikb, List<String> possiblePackages) {
        RuleUnitRegistry unitRegistry = ikb.getRuleUnitRegistry();
        Map<String,InternalKnowledgePackage> pkgs = ikb.getPackagesMap();
        RuleImpl ruleImpl = null;
        for (String pkgName: possiblePackages) {
          if (pkgs.containsKey(pkgName)) {
              InternalKnowledgePackage pkg = pkgs.get(pkgName);
              ruleImpl = pkg.getRule(startingRule);
              if (ruleImpl != null) {
                  RuleUnitDescr descr = unitRegistry.getRuleUnitFor(ruleImpl).orElse(null);
                  if (descr != null) {
                      return descr.getRuleUnitClass();
                  }
              }
          }
        }
        return null;
    }
    
    protected List<String> calculatePossiblePackageNames(String modelId, String...knownPackageNames) {
        List<String> packageNames = new ArrayList<>();
        String javaModelId = modelId.replaceAll("\\s","");
        if (knownPackageNames != null && knownPackageNames.length > 0) {
            for (String knownPkgName: knownPackageNames) {
                packageNames.add(knownPkgName + "." + javaModelId);
            }
        }
        String basePkgName = PMML4UnitImpl.DEFAULT_ROOT_PACKAGE+"."+javaModelId;
        packageNames.add(basePkgName);
        return packageNames;
    }

    规则由 RuleUnitExecutor 类执行。RuleUnitExecutor 类创建 KIE 会话,并将所需的 DataSource 对象添加到这些会话中,然后根据作为参数传递给 run () 方法的 RuleUnit 执行规则。calculatePossiblePackageNamesgetStartingRuleUnit 方法决定传递给 run () 方法的 RuleUnit 类的完全限定名称。

为便于您的 PMML 模型执行,您还可以使用 Red Hat Process Automation Manager 支持的 PMML4ExecutionHelper 类。有关 PMML 帮助程序类的详情,请参考 第 11.1.1 节 “pmML 执行帮助程序类”

11.1.1. pmML 执行帮助程序类

Red Hat Process Automation Manager 提供了一个 PMML4ExecutionHelper 类,它可帮助创建 PMML 模型执行所需的 PMMLRequestData 类,这有助于使用 RuleUnitExecutor 类执行规则。

以下是没有和 PMML4ExecutionHelper 类的 PMML 模型执行示例,作为比较:

不使用 PMML4ExecutionHelper的 PMML 模型执行示例

public void executeModel(KieBase kbase,
                         Map<String,Object> variables,
                         String modelName,
                         String correlationId,
                         String modelPkgName) {
    RuleUnitExecutor executor = RuleUnitExecutor.create().bind(kbase);
    PMMLRequestData request = new PMMLRequestData(correlationId, modelName);
    PMML4Result resultHolder = new PMML4Result(correlationId);
    variables.entrySet().forEach( es -> {
        request.addRequestParam(es.getKey(), es.getValue());
    });

    DataSource<PMMLRequestData> requestData = executor.newDataSource("request");
    DataSource<PMML4Result> resultData = executor.newDataSource("results");
    DataSource<PMMLData> internalData = executor.newDataSource("pmmlData");

    requestData.insert(request);
    resultData.insert(resultHolder);

    List<String> possiblePackageNames = calculatePossiblePackageNames(modelName,
                                                                    modelPkgName);
    Class<? extends RuleUnit> ruleUnitClass = getStartingRuleUnit("RuleUnitIndicator",
                                                                (InternalKnowledgeBase)kbase,
                                                                possiblePackageNames);

    if (ruleUnitClass != null) {
        executor.run(ruleUnitClass);
        if ( "OK".equals(resultHolder.getResultCode()) ) {
          // extract result variables here
        }
    }
}

protected Class<? extends RuleUnit> getStartingRuleUnit(String startingRule, InternalKnowledgeBase ikb, List<String> possiblePackages) {
    RuleUnitRegistry unitRegistry = ikb.getRuleUnitRegistry();
    Map<String,InternalKnowledgePackage> pkgs = ikb.getPackagesMap();
    RuleImpl ruleImpl = null;
    for (String pkgName: possiblePackages) {
      if (pkgs.containsKey(pkgName)) {
          InternalKnowledgePackage pkg = pkgs.get(pkgName);
          ruleImpl = pkg.getRule(startingRule);
          if (ruleImpl != null) {
              RuleUnitDescr descr = unitRegistry.getRuleUnitFor(ruleImpl).orElse(null);
              if (descr != null) {
                  return descr.getRuleUnitClass();
              }
          }
      }
    }
    return null;
}

protected List<String> calculatePossiblePackageNames(String modelId, String...knownPackageNames) {
    List<String> packageNames = new ArrayList<>();
    String javaModelId = modelId.replaceAll("\\s","");
    if (knownPackageNames != null && knownPackageNames.length > 0) {
        for (String knownPkgName: knownPackageNames) {
            packageNames.add(knownPkgName + "." + javaModelId);
        }
    }
    String basePkgName = PMML4UnitImpl.DEFAULT_ROOT_PACKAGE+"."+javaModelId;
    packageNames.add(basePkgName);
    return packageNames;
}

使用 PMML4ExecutionHelper执行 PMML 模型示例

public void executeModel(KieBase kbase,
                         Map<String,Object> variables,
                         String modelName,
                         String modelPkgName,
                         String correlationId) {
   PMML4ExecutionHelper helper = PMML4ExecutionHelperFactory.getExecutionHelper(modelName, kbase);
   helper.addPossiblePackageName(modelPkgName);

   PMMLRequestData request = new PMMLRequestData(correlationId, modelName);
   variables.entrySet().forEach(entry -> {
     request.addRequestParam(entry.getKey(), entry.getValue);
   });

   PMML4Result resultHolder = helper.submitRequest(request);
   if ("OK".equals(resultHolder.getResultCode)) {
     // extract result variables here
   }
}

当您使用 PMML4ExecutionHelper 时,您不需要指定可能的软件包名称或 RuleUnit 类,如您在典型的 PMML 模型执行中一样。

要构建 PMML4ExecutionHelper 类,您可以使用 PMML4ExecutionHelperFactory 类来确定如何检索 PMML4ExecutionHelper 的实例。

以下是用于构建 PMML4ExecutionHelper 类的可用的 PMML4ExecutionHelperFactory 类方法:

pmML4ExecutionHelperFactory 方法 KIE 基础中的 PMML 资产

当 PMML 资产已编译并从现有 KIE 基础中使用时,使用这些方法:

public static PMML4ExecutionHelper getExecutionHelper(String modelName, KieBase kbase)

public static PMML4ExecutionHelper getExecutionHelper(String modelName, KieBase kbase, boolean includeMiningDataSources)
PMML4ExecutionHelperFactory 方法在项目 classpath 上 PMML 资产

当 PMML 资产位于项目 classpath 时使用这些方法。classPath 参数是 PMML 文件的项目类路径位置:

public static PMML4ExecutionHelper getExecutionHelper(String modelName,  String classPath, KieBaseConfiguration kieBaseConf)

public static PMML4ExecutionHelper getExecutionHelper(String modelName,String classPath, KieBaseConfiguration kieBaseConf, boolean includeMiningDataSources)
PMML4ExecutionHelperFactory 方法在字节数组中 PMML 资产

当 PMML 资产采用字节阵列的形式时使用这些方法:

public static PMML4ExecutionHelper getExecutionHelper(String modelName, byte[] content, KieBaseConfiguration kieBaseConf)

public static PMML4ExecutionHelper getExecutionHelper(String modelName, byte[] content, KieBaseConfiguration kieBaseConf, boolean includeMiningDataSources)
PMML4ExecutionHelperFactory 方法在资源中 PMML 资产

当 PMML 资产采用 org.kie.api.io.Resource 对象的形式时使用这些方法:

public static PMML4ExecutionHelper getExecutionHelper(String modelName, Resource resource, KieBaseConfiguration kieBaseConf)

public static PMML4ExecutionHelper getExecutionHelper(String modelName, Resource resource, KieBaseConfiguration kieBaseConf, boolean includeMiningDataSources)
注意

classpath、bytes 数组和资源 PMML4ExecutionHelperFactory 方法为生成的规则和 Java 类创建一个 KIE 容器。容器用作 RuleUnitExecutor 使用的 KIE 基础的来源。容器不是持久性的。已在 KIE 基础中的 PMML 资产的 PMML4ExecutionHelperFactory 方法不会以这种方式创建 KIE 容器。

11.2. 使用 KIE 服务器执行 PMML 模型

您可以通过将 ApplyPmmlModelCommand 命令发送到配置的 KIE Server 来执行部署到 KIE 服务器的 PMML 模型。当您使用此命令时,PMMLRequestData 对象将发送到 KIE 服务器,并将一个 PMML4Result 结果对象作为回复接收。您可以通过来自配置的 Java 类或直接从 REST 客户端通过 KIE Server REST API 向 KIE 服务器发送 PMML 请求。

先决�件

�程

  1. 在客户端应用程序中,将以下依赖项添加到 Java 项目的相关类路径中:

    <!-- Required for the PMML compiler -->
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>kie-pmml</artifactId>
      <version>${rhpam.version}</version>
    </dependency>
    
    <!-- Required for the KIE public API -->
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-api</artifactId>
      <version>${rhpam.version}</version>
    </dependencies>
    
    <!-- Required for the KIE Server Java client API -->
    <dependency>
      <groupId>org.kie.server</groupId>
      <artifactId>kie-server-client</artifactId>
      <version>${rhpam.version}</version>
    </dependency>
    
    <!-- Required if not using classpath KIE container -->
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-ci</artifactId>
      <version>${rhpam.version}</version>
    </dependency>

    & lt;version > 是项目中当前使用的 Red Hat Process Automation Manager 的 Maven 工件版本(如 7.44.0.Final-redhat-00006)。

    注意

    考虑将 Red Hat Business Automation Manager (BOM)依赖项添加到项目 pom.xml 文件,而不是为单个依赖项指定 Red Hat Process Automation Manager < version >。Red Hat Business Automation BOM 适用于 Red Hat Decision Manager 和 Red Hat Process Automation Manager。当您添加 BOM 文件时,项目中包含了来自提供的 Maven 存储库传输性依赖关系的正确版本。

    BOM 依赖项示例:

    <dependency>
      <groupId>com.redhat.ba</groupId>
      <artifactId>ba-platform-bom</artifactId>
      <version>7.9.1.redhat-00003</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>

    有关 Red Hat Business Automation BOM 的更多信息,请参阅 RHPAM 产品和 maven 库版本之间的映射是什么?

  2. classpathReleaseId 创建 KIE 容器:

    KieServices kieServices = KieServices.Factory.get();
    
    ReleaseId releaseId = kieServices.newReleaseId( "org.acme", "my-kjar", "1.0.0" );
    KieContainer kieContainer = kieServices.newKieContainer( releaseId );

    其它选项:

    KieServices kieServices = KieServices.Factory.get();
    
    KieContainer kieContainer = kieServices.getKieClasspathContainer();
  3. 创建将请求发送到 KIE 服务器的类并接收响应:

    public class ApplyScorecardModel {
      private static final ReleaseId releaseId =
              new ReleaseId("org.acme","my-kjar","1.0.0");
      private static final String containerId = "SampleModelContainer";
      private static KieCommands commandFactory;
      private static ClassLoader kjarClassLoader; 1
      private RuleServicesClient serviceClient; 2
    
      // Attributes specific to your class instance
      private String rankedFirstCode;
      private Double score;
    
      // Initialization of non-final static attributes
      static {
        commandFactory = KieServices.Factory.get().getCommands();
    
        // Specifications for kjarClassLoader, if used
        KieMavenRepository kmp = KieMavenRepository.getMavenRepository();
        File artifactFile = kmp.resolveArtifact(releaseId).getFile();
        if (artifactFile != null) {
          URL urls[] = new URL[1];
          try {
            urls[0] = artifactFile.toURI().toURL();
            classLoader = new KieURLClassLoader(urls,PMML4Result.class.getClassLoader());
          } catch (MalformedURLException e) {
            logger.error("Error getting classLoader for "+containerId);
            logger.error(e.getMessage());
          }
        } else {
          logger.warn("Did not find the artifact file for "+releaseId.toString());
        }
      }
    
      public ApplyScorecardModel(KieServicesConfiguration kieConfig) {
        KieServicesClient clientFactory = KieServicesFactory.newKieServicesClient(kieConfig);
        serviceClient = clientFactory.getServicesClient(RuleServicesClient.class);
      }
      ...
      // Getters and setters
      ...
    
      // Method for executing the PMML model on KIE Server
      public void applyModel(String occupation, int age) {
        PMMLRequestData input = new PMMLRequestData("1234","SampleModelName"); 3
        input.addRequestParam(new ParameterInfo("1234","occupation",String.class,occupation));
        input.addRequestParam(new ParameterInfo("1234","age",Integer.class,age));
    
        CommandFactoryServiceImpl cf = (CommandFactoryServiceImpl)commandFactory;
        ApplyPmmlModelCommand command = (ApplyPmmlModelCommand) cf.newApplyPmmlModel(request); 4
    
        ServiceResponse<ExecutionResults> results =
            ruleClient.executeCommandsWithResults(CONTAINER_ID, command); 5
    
        if (results != null) {  6
          PMML4Result resultHolder = (PMML4Result)results.getResult().getValue("results");
          if (resultHolder != null && "OK".equals(resultHolder.getResultCode())) {
            this.score = resultHolder.getResultValue("ScoreCard","score",Double.class).get();
            Map<String,Object> rankingMap =
                 (Map<String,Object>)resultHolder.getResultValue("ScoreCard","ranking");
            if (rankingMap != null && !rankingMap.isEmpty()) {
              this.rankedFirstCode = rankingMap.keySet().iterator().next();
            }
          }
        }
      }
    }
    1
    如果您没有在客户端项目依赖项中包含 KJAR,则定义类加载程序
    2
    标识配置设置中定义的服务客户端,包括 KIE 服务器 REST API 访问凭证
    3
    初始化 PMMLRequestData 对象
    4
    创建 ApplyPmmlModelCommand实例
    5
    使用服务客户端发送命令
    6
    检索已执行的 PMML 模型的结果
  4. 执行类实例,将 PMML 调用请求发送到 KIE 服务器。

    或者,您可以使用 JMS 和 REST 接口将 ApplyPmmlModelCommand 命令发送到 KIE 服务器。对于 REST 请求,您可以使用 ApplyPmmlModelCommand 命令作为对 JSON、JAXB 或 XStream 请求格式的 http://SERVER:PORT/kie-server/services/rest/server/containers/instances/{containerId}POST 请求。

    POST 端点示例

    http://localhost:8080/kie-server/services/rest/server/containers/instances/SampleModelContainer

    JSON 请求正文示例

    {
      "commands": [ {
          "apply-pmml-model-command": {
            "outIdentifier": null,
            "packageName": null,
            "hasMining": false,
            "requestData": {
              "correlationId": "123",
              "modelName": "SimpleScorecard",
              "source": null,
              "requestParams": [
                {
                  "correlationId": "123",
                  "name": "param1",
                  "type": "java.lang.Double",
                  "value": "10.0"
                },
                {
                  "correlationId": "123",
                  "name": "param2",
                  "type": "java.lang.Double",
                  "value": "15.0"
                }
              ]
            }
          }
        }
      ]
    }

    带有端点和正文的 curl 请求示例

    curl -X POST "http://localhost:8080/kie-server/services/rest/server/containers/instances/SampleModelContainer" -H "accept: application/json" -H "content-type: application/json" -d "{ \"commands\": [ { \"apply-pmml-model-command\": { \"outIdentifier\": null, \"packageName\": null, \"hasMining\": false, \"requestData\": { \"correlationId\": \"123\", \"modelName\": \"SimpleScorecard\", \"source\": null, \"requestParams\": [ { \"correlationId\": \"123\", \"name\": \"param1\", \"type\": \"java.lang.Double\", \"value\": \"10.0\" }, { \"correlationId\": \"123\", \"name\": \"param2\", \"type\": \"java.lang.Double\", \"value\": \"15.0\" } ] } } } ]}"

    JSON 响应示例

    {
      "results" : [ {
        "value" : {"org.kie.api.pmml.DoubleFieldOutput":{
      "value" : 40.8,
      "correlationId" : "123",
      "segmentationId" : null,
      "segmentId" : null,
      "name" : "OverallScore",
      "displayValue" : "OverallScore",
      "weight" : 1.0
    }},
        "key" : "OverallScore"
      }, {
        "value" : {"org.kie.api.pmml.PMML4Result":{
      "resultVariables" : {
        "OverallScore" : {
          "value" : 40.8,
          "correlationId" : "123",
          "segmentationId" : null,
          "segmentId" : null,
          "name" : "OverallScore",
          "displayValue" : "OverallScore",
          "weight" : 1.0
        },
        "ScoreCard" : {
          "modelName" : "SimpleScorecard",
          "score" : 40.8,
          "holder" : {
            "modelName" : "SimpleScorecard",
            "correlationId" : "123",
            "voverallScore" : null,
            "moverallScore" : true,
            "vparam1" : 10.0,
            "mparam1" : false,
            "vparam2" : 15.0,
            "mparam2" : false
          },
          "enableRC" : true,
          "pointsBelow" : true,
          "ranking" : {
            "reasonCh1" : 5.0,
            "reasonCh2" : -6.0
          }
        }
      },
      "correlationId" : "123",
      "segmentationId" : null,
      "segmentId" : null,
      "segmentIndex" : 0,
      "resultCode" : "OK",
      "resultObjectName" : null
    }},
        "key" : "results"
      } ],
      "facts" : [ ]
    }

第 12 章 å…¶ä»–资æº�

部分 III. 使用 DRL 规则设计决策服务

作为自定义规则开发人员,您可以使用 Business Central 中的 DRL (Drools Rule Language)设计程序来定义新规则。DRL 规则以自由格式 .drl 文本文件直接定义,而不是像 Business Central 中的其他类型的规则资产一样以指导或表格格式定义。这些 DRL 文件组成项目的决策服务的核心。

注意

您还可以使用决策模型和表示法(DMN)模型而不是基于规则的或基于表的资产来设计您的决策服务。有关 Red Hat Process Automation Manager 7.9 中的 DMN 支持的详情,请查看以下资源:

先决�件

  • DRL 规则的空间和项目已在 Business Central 中创建。每个资产都与分配给空间的项目关联。详情请参阅 开始使用决策服务。

第 13 章 Red Hat Process Automation Manager 中的决策授权资产

Red Hat Process Automation Manager 支持多个资产,可用于为您的决策服务定义决策。每个决定授权资产都有不同的优点,您可能需要根据您的目标和需求使用多个资产的组合。

下表重点介绍 Red Hat Process Automation Manager 项目支持的主要决策授权资产,以帮助您决定或确认在决策服务中定义决策的最佳方法。

表 13.1. Red Hat Process Automation Manager 支持的决策授予资产

assethighlight编写工具Documentation

决策模型和表示法(DMN)模型

  • 是根据对象管理组(OMG)定义的表示法标准决定模型。
  • 使用代表部分或所有决策要求图(DRG)的图形决策要求图(DRG)来跟踪业务决策流程
  • 使用允许在 DMN 兼容平台之间共享 DMN 模型的 XML 模式
  • 支持 Friendly Enough Expression Language (FEEL),以在 DMN 决策表和其他 DMN 框表达式中定义决策逻辑
  • 可以与 Business Process Model 和 Notation (DSLN)进程模型有效集成
  • 是创建全面、演示和稳定的决策流程的最佳选择

Business Central 或其他与 DMN 兼容的编辑器

使用 DMN 模型设计决策服务

主要决策表

  • 是您在 Business Central 的基于 UI 的表设计程序中创建的规则表
  • 是电子表格决策表的向导替代方法
  • 为可接受的输入提供字段和选项
  • 支持用于创建规则模板的模板键和值
  • 支持点击策略、实时验证以及其他资产不支持的其他额外功能
  • 最好以受控的 tabular 格式创建规则,以最小化编译错误

Business Central

使用指导决策表设计决策服务

电子表格决策表

  • 是 XLS 或 XLSX 电子表格决策表,您可以上传到 Business Central
  • 支持用于创建规则模板的模板键和值
  • 最好在 Business Central 外部管理的路由表中创建规则
  • 对于在上传时正确编译的规则具有严格的语法要求

电子表格编辑器

使用电子表格决策表设计决策服务

指导规则

  • 是您在 Business Central 中基于 UI 的规则设计程序中创建的单个规则
  • 为可接受的输入提供字段和选项
  • 最好以受控格式创建单个规则,以最小化编译错误

Business Central

使用指导规则设计决策服务

指导规则模板

  • 是您在 Business Central 中的基于 UI 的模板设计程序中创建的可重复使用的规则结构
  • 为可接受的输入提供字段和选项
  • 支持用于创建规则模板的模板键和值(与资产相关的目的不同)
  • 最好创建具有相同规则结构但具有不同定义的字段值的规则

Business Central

使用指导规则模板设计决策服务

DRL 规则

  • 是直接在 .drl 文本文件中定义的单个规则
  • 提供定义规则和其他规则行为的最灵活
  • 可以在某些独立环境中创建,并与 Red Hat Process Automation Manager 集成
  • 最好创建需要高级 DRL 选项的规则
  • 具有正确编译的规则具有严格的语法要求

Business Central 或集成开发环境(IDE)

使用 DRL 规则设计决策服务

预测模型标记语言(PMML)模型

  • 是预测的 data-analytic 模型,它基于由 Data Mining Group (DMG)定义的表示法标准
  • 使用一个 XML 模式,允许在 PMML 兼容平台之间共享 PMML 模型
  • 支持 Regression、Scorecard、Tree、Ming 和其他模型类型
  • 可以包含独立 Red Hat Process Automation Manager 项目,也可以导入到 Business Central 中的项目中
  • 最好在 Red Hat Process Automation Manager 中将预测数据整合到决策服务中

pmML 或 XML 编辑器

使用 PMML 模型设计决策服务

第 14 章 DRL (Drools Rule Language)规则

DRL (Drools Rule Language)规则是在 .drl 文本文件中直接定义的警报规则。这些 DRL 文件是最终呈现 Business Central 中所有其他规则资产的源。您可以在 Business Central 界面中创建和管理 DRL 文件,或使用 Red Hat CodeReady Studio 或其他集成开发环境(IDE)在外部创建它们。DRL 文件可以包含一个或多个规则,这些规则至少定义规则条件(when)和操作(then)。Business Central 中的 DRL 设计程序提供了 Java、DRL 和 XML 的语法突出显示。

DRL 文件由以下组件组成:

DRL 文件中的组件

package

import

function  // Optional

query  // Optional

declare   // Optional

global   // Optional

rule "rule name"
    // Attributes
    when
        // Conditions
    then
        // Actions
end

rule "rule2 name"

...

以下示例 DRL 规则决定 loan 应用程序决策服务的年龄限制:

loan 应用程序年龄限制的规则示例

rule "Underage"
  salience 15
  agenda-group "applicationGroup"
  when
    $application : LoanApplication()
    Applicant( age < 21 )
  then
    $application.setApproved( false );
    $application.setExplanation( "Underage" );
end

DRL 文件可以包含单个或多个规则、查询和功能,并可定义资源声明,如导入、全局和属性,这些属性由您的规则和查询分配和使用。DRL 软件包必须在 DRL 文件的顶部列出,规则通常最后列出。所有其他 DRL 组件都可以遵循任何顺序。

每个规则都必须在 rule 软件包中具有唯一名称。如果您在软件包中的任何 DRL 文件中使用相同的规则名称多次,则规则无法编译。始终使用双引号括起规则名称(规则"规则名称"),以防止可能编译错误,特别是在规则名称中使用空格时。

与 DRL 规则相关的所有数据对象都必须与 Business Central 中的 DRL 文件位于同一个项目中。默认情况下导入同一软件包中的资产。其他软件包中的现有资产可以使用 DRL 规则导入。

14.1. DRL 中的软件包

软件包是 Red Hat Process Automation Manager 中相关资产的文件夹,如数据对象、DRL 文件、决策表和其他资产类型。软件包也充当每个组规则的唯一命名空间。单个规则基础可以包含多个软件包。您通常将软件包的所有规则存储在与 package 声明相同的文件中,以便软件包自我包含。但是,您可以从要在规则中使用的其他软件包导入对象。

以下示例是 mortgage 应用程序决策服务中 DRL 文件的软件包名称和命名空间:

DRL 文件中的软件包定义示例

package org.mortgages;

14.2. DRL 中的导入声明

与 Java 中的导入语句类似,在 DRL 文件中导入标识您要在规则中使用的任何对象的完全限定路径和类型名称。您可以使用 packageName.objectName 格式指定软件包和数据对象,单独行中有多个导入。决策引擎自动从 Java 软件包导入类,其名称与 DRL 软件包和软件包 java.lang 相同。

以下示例是 mortgage 应用程序决策服务中的 loan 应用程序对象的导入声明:

DRL 文件中的 import 语句示例

import org.mortgages.LoanApplication;

14.3. DRL 中的功能

DRL 文件中的功能将语义代码放到规则源文件中,而不是放在 Java 类中。如果重复使用规则的操作(then)部分并且只有参数因每个规则而异,则函数特别有用。在 DRL 文件中的规则之上,您可以声明函数或从帮助程序类导入静态方法作为函数,然后在规则部分操作(then)部分中使用函数。

以下示例演示了在 DRL 文件中声明或导入的功能:

带有规则的功能声明示例(选项 1)

function String hello(String applicantName) {
    return "Hello " + applicantName + "!";
}

rule "Using a function"
  when
    // Empty
  then
    System.out.println( hello( "James" ) );
end

使用规则导入功能示例(选择 2)

import function my.package.applicant.hello;

rule "Using a function"
  when
    // Empty
  then
    System.out.println( hello( "James" ) );
end

14.4. DRL 中的查询

DRL 文件中的查询搜索决策引擎的工作内存,以了解与 DRL 文件中规则相关的事实。您可以在 DRL 文件中添加查询定义,然后在应用程序代码中获取匹配的结果。查询搜索一组定义的条件,无需在或之后 指定 规格。查询名称对于 KIE 基础而言是全局的,因此在项目中的所有规则查询之间必须是唯一的。要返回查询的结果,您可以使用 ksession.get QueryResults ("name") 构建 QueryResults 定义,其中 "name" 是查询名称。这会返回查询结果列表,它可让您检索与查询匹配的对象。您可以在 DRL 文件中的规则上定义查询和查询结果参数。

以下示例是 DRL 文件中的查询定义,用于带有附带的应用程序代码的 mortgage 应用程序决策服务中的下划线 applicants:

DRL 文件中的查询定义示例

query "people under the age of 21"
    $person : Person( age < 21 )
end

获取查询结果的应用程序代码示例

QueryResults results = ksession.getQueryResults( "people under the age of 21" );
System.out.println( "we have " + results.size() + " people under the age  of 21" );

您还可以使用 循环的标准迭代返回的 QueryResults。每个元素都是 QueryResultsRow,您可以使用它来访问元组中的每个列。

获取和迭代查询结果的应用程序代码示例

QueryResults results = ksession.getQueryResults( "people under the age of 21" );
System.out.println( "we have " + results.size() + " people under the age of 21" );

System.out.println( "These people are under the age of 21:" );

for ( QueryResultsRow row : results ) {
    Person person = ( Person ) row.get( "person" );
    System.out.println( person.getName() + "\n" );
}

14.5. DRL 中的类型声明和元数据

DRL 文件中的声明定义了 DRL 文件中规则使用的事实类型或元数据:

  • 新事实类型: Red Hat Process Automation Manager 的 java.lang 软件包中的默认事实类型是 Object,但您可以根据需要在 DRL 文件中声明其他类型。在 DRL 文件中声明事实类型可让您直接在决策引擎中定义新的事实模型,而无需像 Java 一样使用较低语言创建模型。您还可以在已经构建域模型时声明新类型,并且您希望通过在原因过程中主要使用的额外实体来补充此模型。
  • 事实类型的元数据: 您可以将 @key (value) 格式的元数据与新的或现有事实相关联。元数据可以是任何不是由事实属性表示的数据,并在该事实类型的所有实例中保持一致。元数据可通过决策引擎在运行时查询,并在原因过程中使用。

14.5.1. 在 DRL 中没有元数据的类型声明

新事实的声明不需要任何元数据,但必须包含属性或字段的列表。如果 type 声明不包括识别属性,则决策引擎会在 classpath 中搜索现有的事实类,并在缺少类时引发错误。

以下示例是一个新的事实类型 Person 的声明,在 DRL 文件中没有元数据:

带有规则的新事实类型的声明示例

declare Person
  name : String
  dateOfBirth : java.util.Date
  address : Address
end

rule "Using a declared type"
  when
    $p : Person( name == "James" )
  then   // Insert Mark, who is a customer of James.
    Person mark = new Person();
    mark.setName( "Mark" );
    insert( mark );
end

在本例中,新的事实类型 Person 具有三个属性,即dateOfBirth,以及 地址每个属性都有一个 type,可以是任何有效的 Java 类型,包括您创建的另一个类或您之前声明的事实类型。dateOfBirth 属性具有来自 Java API 的 type java.util.Dateaddress 属性具有之前定义的事实类型 Address

为了避免在每次声明类时写入类的完全限定名称,您可以将完整类名称定义为 import 子句的一部分:

带有导入中完全限定类名称的 type 声明示例

import java.util.Date

declare Person
    name : String
    dateOfBirth : Date
    address : Address
end

当您声明新的事实类型时,决策引擎会在编译时生成代表事实类型的 Java 类。生成的 Java 类是类型定义的一对一映射。

例如,以下 Java 类是从示例 Person type 声明生成的:

为 Person 事实类型声明生成 Java 类

public class Person implements Serializable {
    private String name;
    private java.util.Date dateOfBirth;
    private Address address;

    // Empty constructor
    public Person() {...}

    // Constructor with all fields
    public Person( String name, Date dateOfBirth, Address address ) {...}

    // If keys are defined, constructor with keys
    public Person( ...keys... ) {...}

    // Getters and setters
    // `equals` and `hashCode`
    // `toString`
}

然后,您可以使用规则中生成的类,如前面的规则示例所示,并带有 Person 类型声明:

使用声明的 Person 事实类型的规则示例

rule "Using a declared type"
  when
    $p : Person( name == "James" )
  then   // Insert Mark, who is a customer of James.
    Person mark = new Person();
    mark.setName( "Mark" );
    insert( mark );
end

14.5.2. DRL 中的枚举类型声明

DRL 支持以声明 enum < factType> 格式声明 枚举类型,后跟以分号结尾的值列表。然后,您可以在 DRL 文件中的规则中使用枚举列表。

例如,以下枚举类型声明定义了员工调度规则的每周天数:

使用调度策略的枚举类型声明示例

declare enum DaysOfWeek
   SUN("Sunday"),MON("Monday"),TUE("Tuesday"),WED("Wednesday"),THU("Thursday"),FRI("Friday"),SAT("Saturday");

   fullName : String
end

rule "Using a declared Enum"
when
   $emp : Employee( dayOff == DaysOfWeek.MONDAY )
then
   ...
end

14.5.3. DRL 中的扩展类型声明

DRL 支持以声明 <factType1& gt; 扩展 <factType2&gt; 格式的类型声明继承。要根据 DRL 中声明的子类型扩展 Java 声明的类型,您可以在声明声明中重复父类型,而无需任何字段。

例如,以下 type 声明从顶级 Person 类型中扩展 CRUD 类型,以及来自 Tailoring 子类型的 LongTermStudent 类型:

扩展类型声明示例

import org.people.Person

declare Person end

declare Student extends Person
    school : String
end

declare LongTermStudent extends Student
    years : int
    course : String
end

14.5.4. 使用 DRL 中的元数据类型声明

您可以将格式 @key (value) (值是可选的)与事实类型或事实属性关联。元数据可以是任何不是由事实属性表示的数据,并在该事实类型的所有实例中保持一致。元数据可通过决策引擎在运行时查询,并在原因过程中使用。您在事实类型的属性之前声明的任何元数据都会被分配给事实类型,而您在属性后声明的元数据会被分配给该特定属性。

在以下示例中,为 Person 事实类型声明两个元数据属性 @author@dateOfCreation,为 name 属性声明两个元数据项目 @key@maxLength@key metadata 属性没有所需的值,因此省略括号和值。

事实类型和属性的元数据声明示例

import java.util.Date

declare Person
    @author( Bob )
    @dateOfCreation( 01-Feb-2009 )

    name : String @key @maxLength( 30 )
    dateOfBirth : Date
    address : Address
end

对于现有类型的元数据属性声明,您可以将完全限定类名称识别为所有声明的 import 子句的一部分,或作为单个 声明 条款的一部分:

导入类型的元数据声明示例

import org.drools.examples.Person

declare Person
    @author( Bob )
    @dateOfCreation( 01-Feb-2009 )
end

声明类型的 metadata 声明示例

declare org.drools.examples.Person
    @author( Bob )
    @dateOfCreation( 01-Feb-2009 )
end

14.5.5. DRL 中事实类型和属性声明的元数据标签

虽然您可以在 DRL 声明中定义自定义元数据属性,但决策引擎也支持以下预定义元数据标签来声明事实类型或事实类型属性。

注意

本节中的示例指向 VoiceCall 类,假设示例应用程序域模型包括以下类详情:

示例域模型中的 VoiceCall 事实类

public class VoiceCall {
  private String  originNumber;
  private String  destinationNumber;
  private Date    callDateTime;
  private long    callDuration;  // in milliseconds

  // Constructors, getters, and setters
}

@role

此标签决定了给定事实类型是否作为常规事实处理,还是在复杂的事件处理期间在决策引擎中处理事件。

默认参数: fact

支持的参数: factevent

@role( fact | event )

示例: Declare VoiceCall 作为事件类型

declare VoiceCall
  @role( event )
end

@timestamp

此标签会自动分配给决策引擎中的每个事件。默认情况下,时间由会话时钟提供,并在它插入到决策引擎的工作内存中时分配给事件。您可以指定自定义时间戳属性,而不是会话时钟添加的默认时间戳。

Default 参数:决策引擎会话时钟添加的时间

支持的参数: Session clock time 或自定义时间戳属性

@timestamp( <attributeName> )

示例: Declare VoiceCall timestamp 属性

declare VoiceCall
  @role( event )
  @timestamp( callDateTime )
end

@duration

此标签决定了决策引擎中事件的持续时间。事件可以是基于间隔的事件或时间事件。基于间隔的事件具有持续时间,并在决策引擎的工作内存中保留,直到其持续时间被宽松为止。点事件没有持续时间,基本上是基于间隔的事件,持续时间为零。默认情况下,决策引擎中的每个事件都为零。您可以指定自定义 duration 属性而不是默认值。

默认参数:Null (零)

支持的参数:自定义持续时间属性

@duration( <attributeName> )

示例: Declare VoiceCall duration 属性

declare VoiceCall
  @role( event )
  @timestamp( callDateTime )
  @duration( callDuration )
end

@expires

此标签决定事件在决策引擎工作内存中过期前的时长。默认情况下,当事件无法再匹配并激活任何当前规则时,事件会过期。您可以定义事件应过期的时间。此标签定义还覆盖由临时约束计算的隐式过期偏移,以及 KIE 基础中的分片窗口。只有在决策引擎以流模式运行时,此标签才可用。

默认参数:Null (事件后过期时间不再匹配并激活规则)

支持的参数: 自定义 timeOffset 属性,格式为 [IANAd][ theh][ them][114s][[ms]]

@expires( <timeOffset> )

示例:VoiceCall 事件的 Declare 过期偏移

declare VoiceCall
  @role( event )
  @timestamp( callDateTime )
  @duration( callDuration )
  @expires( 1h35m )
end

@typesafe

此选项卡决定给定事实类型是否使用类型 security 编译。默认情况下,所有类型声明都会在启用了安全类型的情况下编译。您可以将此行为覆盖为 type-unsafe 评估,其中所有约束都作为 MVEL 约束动态执行。这在处理没有任何通用或混合类型集合的集合时很有用。

默认参数: true

支持的参数: true,false

@typesafe( <boolean> )

示例:用于 type-unsafe 评估的 Declare VoiceCall

declare VoiceCall
  @role( fact )
  @typesafe( false )
end

@serialVersionUID

此标签在事实声明中为可序列化类定义了识别 serialVersionUID 值。如果 serializable 类没有显式声明 serialVersionUID,则序列化运行时间会根据类的不同方面计算该类的默认 serialVersionUID 值,如 Java 对象序列化规格 中所述。但是,为了实现最佳反序列化结果,并更好地与序列化 KIE 会话兼容,请在相关类或 DRL 声明中根据需要设置 serialVersionUID

默认参数:Null

支持的参数:Custom serialVersionUID 整数

@serialVersionUID( <integer> )

示例:VoiceCall 类的 Declare serialVersionUID

declare VoiceCall
  @serialVersionUID( 42 )
end

@key

此标签可让事实 type 属性用作事实类型的密钥标识符。然后,生成的类可以实施 equals ()hashCode () 方法,以确定类型的两个实例是否相互相等。决策引擎也可以使用所有密钥属性作为参数生成构造器。

默认参数: None

支持的参数: None

<attributeDefinition> @key

示例: Declare Person 类型属性作为键

declare Person
    firstName : String @key
    lastName : String @key
    age : int
end

在本例中,决策引擎检查 firstNamelastName 属性,以确定 Person 的两个实例是否相互相等,但不会检查 age 属性。决策引擎还隐式生成三个构造器:一个没有参数,一个带有 @key 字段,另一个带有所有字段:

key 声明中的 constructors 示例

Person() // Empty constructor

Person( String firstName, String lastName )

Person( String firstName, String lastName, int age )

然后,您可以根据密钥构造器创建类型的实例,如下例所示:

使用密钥构造器的实例示例

Person person = new Person( "John", "Doe" );

@position

此标签决定声明的事实类型属性或位置参数中的位置,覆盖属性的默认声明顺序。您可以使用此标签来修改模式中的位置限制,同时在类型声明和位置参数中维护一致的格式。您只能将此标签用于 classpath 上的类中的字段。如果单个类中的一些字段使用此标签,并且有些字段没有,没有此标签的属性将最后按声明的顺序排列。支持类的继承性,但不支持方法的接口。

默认参数: None

支持的参数:任何整数

<attributeDefinition> @position ( <integer> )

示例: Declare 是一个事实类型并覆盖声明的顺序

declare Person
    firstName : String @position( 1 )
    lastName : String @position( 0 )
    age : int @position( 2 )
    occupation: String
end

在本例中,属性按以下顺序按位置参数排列:

  1. lastName
  2. firstName
  3. 年龄
  4. occupation

在位置参数中,您不需要指定字段名称,因为位置映射到已知命名字段。例如,参数 Person (lastName == "Doe")Person ("Doe";) 相同,其中 lastName 字段在 DRL 声明中具有最高位置注解。分号 ; 表示它之前的所有内容都是位置参数。您可以使用分号分隔它们,将位置和命名参数混合在模式上。尚未绑定的位置参数中的任何变量都绑定到映射到该位置的字段。

以下示例模式演示了构建位置和命名参数的不同方法。模式有两个限制和绑定,分号将位置部分与命名参数部分区分。仅使用字面参数支持变量和字面和表达式在位置参数中被支持,而不仅仅是变量。

带有位置和命名参数的模式示例

Person( "Doe", "John", $a; )

Person( "Doe", "John"; $a : age )

Person( "Doe"; firstName == "John", $a : age )

Person( lastName == "Doe"; firstName == "John", $a : age )

位置参数可以归类为 输入参数输出参数。输入参数包含之前声明的绑定,并使用取消配置来针对该绑定进行约束。输出参数生成声明,并将其绑定到位置参数表示的字段(如果绑定尚不存在)。

在扩展类型声明中,在定义 @position 注释时要小心,因为属性位置在子类型中继承。这种继承可能会导致混合属性顺序,在某些情况下可能会混淆。两个字段可以具有相同的 @position 值,不需要声明连续的值。如果重复某个位置,则使用继承性来解决冲突,其中父类型中的位置值具有优先权,然后使用第一个到最后一个声明的声明顺序。

例如,以下扩展类型声明会导致混合位置优先级:

带有混合位置注解的扩展事实类型示例

declare Person
    firstName : String @position( 1 )
    lastName : String @position( 0 )
    age : int @position( 2 )
    occupation: String
end

declare Student extends Person
    degree : String @position( 1 )
    school : String @position( 0 )
    graduationDate : Date
end

在本例中,属性按以下顺序按位置参数排列:

  1. lastname (在父类型中包括 0)
  2. eXecut (子类型中的 0 组成)
  3. firstname (在父类型中保存 1)
  4. 等级 (位于子类型中的 1)
  5. 年龄 (在父类型中保存 2)
  6. occupation (没有位置注解的第一个字段)
  7. graduationDate (没有位置注解的秒字段)

14.5.6. 事实类型的属性更改设置和监听程序

默认情况下,决策引擎不会在每次触发规则时重新评估事实类型的所有事实模式,而是只响应给定模式内受限制或绑定的修改属性。例如,如果规则调用 modify () 作为规则操作的一部分,但操作不会在 KIE 基础中生成新的数据,则决策引擎不会自动重新评估所有事实模式,因为没有修改任何数据。此属性重新活动行为可防止 KIE 基础中不需要的递归,并导致更有效的规则评估。这个行为还意味着,您不必使用 no-loop 规则属性来避免无限递归。

您可以使用以下 Knowledgebase BuilderConfiguration 选项修改或禁用此属性重新活动行为,然后根据需要使用 Java 类或 DRL 文件中的属性更改设置来微调属性:

  • ALWAYS: (默认)所有类型都是重新主动的属性,但您可以使用 @classReactive property-change 设置禁用特定类型的属性重新活动。
  • ALLOWED: 没有类型是属性重新主动,但您可以使用 @propertyReactive property-change 设置为特定类型启用属性重新活动。
  • DISABLED :无类型是属性重新主动。所有 property-change 侦听程序都会被忽略。

KnowledgeBuilderConfiguration 中的属性重新活动设置示例

KnowledgeBuilderConfiguration config = KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration();
config.setOption(PropertySpecificOption.ALLOWED);
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(config);

另外,您可以更新 Red Hat Process Automation Manager 发行版本的 standalone.xml 文件中的 drools.propertySpecific 系统属性:

系统属性中属性中的属性重新活动设置示例

<system-properties>
  ...
  <property name="drools.propertySpecific" value="ALLOWED"/>
  ...
</system-properties>

决策引擎支持以下 property-change 设置和监听程序作为事实类或声明的 DRL 事实类型:

@classReactive

如果在决策引擎中将属性重新活动设置为 ALWAYS (所有类型都是重新主动),则此标签将禁用特定 Java 类或声明的 DRL 事实类型的默认属性重新活动行为。如果您希望决策引擎在每次触发规则时重新评估指定事实类型的所有事实模式,而不是只响应给定模式内的修改属性,则可以使用此标签。

示例:在 DRL 类型声明中禁用默认属性重新活动

declare Person
  @classReactive
    firstName : String
    lastName : String
end

示例:在 Java 类中禁用默认属性重新活动

@classReactive
public static class Person {
    private String firstName;
    private String lastName;
}

@propertyReactive

如果在决策引擎中将属性 reactivity 设置为 ALLOWED (除非指定),则此标签将启用特定 Java 类或声明的 DRL 事实类型的属性重新活动。如果您希望决策引擎只响应指定事实类型的给定模式或绑定的修改属性,则可以使用此标签,而不是在每次触发规则时重新评估所有事实模式。

示例:启用 DRL 类型声明中的属性重新活动(当全局禁用重新活动时)

declare Person
  @propertyReactive
    firstName : String
    lastName : String
end

示例:在 Java 类中启用属性重新活动(当全局禁用重新活动时)

@propertyReactive
public static class Person {
    private String firstName;
    private String lastName;
}

@watch

此标签为您在 DRL 规则中的事实模式中指定的额外属性启用属性重新活动。只有在决策引擎中将属性 reactivity 设置为 ALWAYS,或者如果属性 reactivity 设为 ALLOWED 时,才会支持该标签,相关事实类型使用 @propertyReactive 标签。您可以在 DRL 规则中使用该标签,在事实属性重新活动逻辑中添加或排除特定属性。

默认参数: None

支持的参数:Property name, rhncfg (all), ! (not), ! the ! the no properties)

<factPattern> @watch ( <property> )

示例:在事实模式中启用或禁用属性重新活动

// Listens for changes in both `firstName` (inferred) and `lastName`:
Person(firstName == $expectedFirstName) @watch( lastName )

// Listens for changes in all properties of the `Person` fact:
Person(firstName == $expectedFirstName) @watch( * )

// Listens for changes in `lastName` and explicitly excludes changes in `firstName`:
Person(firstName == $expectedFirstName) @watch( lastName, !firstName )

// Listens for changes in all properties of the `Person` fact except `age`:
Person(firstName == $expectedFirstName) @watch( *, !age )

// Excludes changes in all properties of the `Person` fact (equivalent to using `@classReactivity` tag):
Person(firstName == $expectedFirstName) @watch( !* )

如果您在事实类型中使用 @watch 标签处理使用 @classReactive 标签(禁用属性重新活动),或者在决策引擎中将属性重新活动时,决策引擎会生成一个编译错误,相关事实类型不使用 @propertyReactive 标签。如果您在监听器注解中重复的属性(如 @watch (firstName, ! firstName) ),也会出现编译错误。

@propertyChangeSupport

对于实施对 TTY 规范中定义的属性更改的支持的事实,此标签可让决策引擎监控事实属性中的更改。https://download.oracle.com/otndocs/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/

示例:Aronlare 属性更改对 sVirt 对象的支持

declare Person
    @propertyChangeSupport
end

14.5.7. 访问应用程序代码中声明的 DRL 类型

DRL 中的声明类型通常在 DRL 文件中使用,而当规则和应用程序之间共享模型时,通常使用 Java 模型。因为声明的类型是在 KIE 基础编译时生成的,所以应用程序无法访问它们,直到应用程序运行时为止。在某些情况下,应用程序需要直接从声明的类型访问和处理事实,特别是在应用程序包装决策引擎时,并为规则管理提供更高级别的、特定于域的用户界面。

要直接从应用程序代码处理声明的类型,您可以在 Red Hat Process Automation Manager 中使用 org.drools.definition.type.FactType API。通过此 API,您可以在声明的事实类型中实例化、读取和写入字段。

以下示例代码直接从应用程序修改 Person 事实类型:

通过 FactType API 处理声明的事实类型的应用程序代码示例

import java.util.Date;

import org.kie.api.definition.type.FactType;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;

...

// Get a reference to a KIE base with the declared type:
KieBase kbase = ...

// Get the declared fact type:
FactType personType = kbase.getFactType("org.drools.examples", "Person");

// Create instances:
Object bob = personType.newInstance();

// Set attribute values:
personType.set(bob, "name", "Bob" );
personType.set(bob, "dateOfBirth", new Date());
personType.set(bob, "address", new Address("King's Road","London","404"));

// Insert the fact into a KIE session:
KieSession ksession = ...
ksession.insert(bob);
ksession.fireAllRules();

// Read attributes:
String name = (String) personType.get(bob, "name");
Date date = (Date) personType.get(bob, "dateOfBirth");

API 还包括其他有用的方法,如一次性设置所有属性、从 映射 集合中读取值,或者一次性读取所有属性到 映射 集合中。

虽然 API 行为与 Java 反映类似,但 API 不使用反映性,并依赖于使用生成的字节代码实现的更多执行访问器。

14.6. DRL 中的全局变量

DRL 文件中的全局变量通常为规则提供数据或服务,如规则结果中使用的应用程序服务,并从规则返回数据,如规则结果中添加的日志或值。您可以通过 KIE 会话配置或 REST 操作在决策引擎的工作内存中设置全局值,声明 DRL 文件中的规则上面的全局变量,然后在规则的操作(然后)部分中使用它。对于多个全局变量,请使用 DRL 文件中的单独的行。

以下示例演示了决策引擎的全局变量列表配置,以及 DRL 文件中对应的全局变量定义:

决策引擎的全局列表配置示例

List<String> list = new ArrayList<>();
KieSession kieSession = kiebase.newKieSession();
kieSession.setGlobal( "myGlobalList", list );

带有规则的全局变量定义示例

global java.util.List myGlobalList;

rule "Using a global"
  when
    // Empty
  then
    myGlobalList.add( "My global list" );
end

警告

除非全局变量具有恒定的不可变值,否则请不要使用全局变量来建立规则中的条件。全局变量不会插入到决策引擎的工作内存中,因此决策引擎无法跟踪变量的值更改。

不要使用全局变量在规则间共享数据。规则始终原因并响应工作内存状态,因此,如果要将数据从规则传递给规则,把数据作为事实处理到决策引擎的工作内存中。

全局变量的用例可能是电子邮件服务的实例。在调用决策引擎的集成代码中,您可以获取 emailService 对象,然后在决策引擎的工作内存中进行设置。在 DRL 文件中,您声明有全局类型 emailService,并将其命名为 "email",然后在规则结果下,您可以使用 email.sendSMS (number, message) 等操作。

如果您在多个软件包中使用相同标识符声明全局变量,则必须使用同一类型设置所有软件包,以便它们引用相同的全局值。

14.7. DRL 中的规则属性

规则属性是您可以添加到新规则中的额外规格,以修改规则行为。在 DRL 文件中,您通常以以下格式定义规则条件和操作之外的规则属性,它们带有多个属性:

rule "rule_name"
    // Attribute
    // Attribute
    when
        // Conditions
    then
        // Actions
end

下表列出了您可以分配给规则的属性的名称和支持值:

表 14.1. 规则属性

�性值

salience

定义规则优先级的整数。在激活队列中排序时,具有较高 salience 值的规则会被赋予更高的优先级。

示例: salience 10

enabled

布尔值。选择选项时,将启用该规则。如果没有选择该选项,则禁用该规则。

示例: enabled true

date-effective

包含日期和时间定义的字符串。只有在当前日期和时间在日期 有效属性后,才能激活 该规则。

示例: date-effective "4-Sep-2018"

date-expires

包含日期和时间定义的字符串。如果当前日期和时间在 date-expires 属性后面,则无法激活该规则。

示例: date-expires "4-Oct-2018"

no-loop

布尔值。选择选项时,如果规则重新触发之前满足的条件,则无法重新激活(循环)规则。如果没有选择条件,则在以下情况下可以循环该规则。

示例: no-loop true

agenda-group

标识您要为其分配该规则的席位组的字符串。通过电缆组,您可以对员工进行分区,以提供更多对规则组的执行控制。只有购买重点组中的规则才能激活。

示例:M ickice-group "GroupName"

activation-group

标识您要为其分配该规则的激活(或 XOR)组的字符串。在激活组中,只能激活一条规则。触发的第一个规则将取消激活组中所有规则的所有待处理激活。

示例: activation-group "GroupName"

duration

较长的整数值,如果仍然满足规则条件,定义规则可以激活的时间(毫秒)。

示例: 持续时间 10000

timer

标识 int (interval)或用于调度该规则的 cron 计时器定义的字符串。

示例: 计时器(cron:9455114 ? ?) (每 15 分钟)

日历

用于调度规则的 Quartz 日历定义。

示例: calendars " IANA047 0-7,18-23 ?账单" (不包括非工作小时)

auto-focus

布尔值,仅适用于购买组内的规则。选择选项后,下一次规则被激活时,会自动向分配该规则的电缆组提供重点。

示例: auto-focus true

lock-on-active

布尔值,仅适用于规则流组或电缆组内的规则。选择选项后,规则的 ruleflow 组变为 active 或该规则的 sales 组会收到重点,直到 ruleflow 组不再活跃,否则该规则将丢失。这是 no-loop 属性的更强大的版本,因为无论更新的来源(不仅仅是规则本身)都会丢弃匹配的规则激活。此属性适用于计算规则,您可以有多个修改事实的规则,您不希望任何规则重新匹配并再次触发。

示例: lock-on-active true

ruleflow-group

标识规则流组的字符串。在规则流中,规则只能在由关联规则流激活组时触发。

示例: ruleflow-group "GroupName"

dialect

JAVAMVEL 识别为规则中代码表达式的语言。默认情况下,该规则使用在软件包级别指定的 dialect。此处指定的任何 dialect 都会覆盖规则的软件包分开设置。

示例: dialect "JAVA"

注意

当您使用没有可执行模型的 Red Hat Process Automation Manager 时,dialect "JAVA" 规则结果只支持 Java 5 语法。有关可执行模型的更多信息,请参阅 打包和部署 Red Hat Process Automation Manager 项目

14.7.1. DRL 中的计时器和日历规则属性

计时器和日历是 DRL 规则属性,可让您将调度和时间限制应用到 DRL 规则。根据用例,这些属性需要额外的配置。

DRL 规则中的 timer 属性是一个字符串,用于标识 int (interval)或用于调度规则的 cron 计时器定义,并支持以下格式:

计时器属性格式

timer ( int: <initial delay> <repeat interval> )

timer ( cron: <cron expression> )

间隔计时器属性示例

// Run after a 30-second delay
timer ( int: 30s )

// Run every 5 minutes after a 30-second delay each time
timer ( int: 30s 5m )

cron timer 属性示例

// Run every 15 minutes
timer ( cron:* 0/15 * * * ? )

间隔计时器遵循 java.util.Timer 对象的语义,其初始延迟和可选的重复间隔。Cron timers 遵循标准 Unix cron 表达式。

以下示例 DRL 规则使用 cron 计时器每 15 分钟发送 SMS 文本消息:

带有 cron 计时器的 DRL 规则示例

rule "Send SMS message every 15 minutes"
  timer ( cron:* 0/15 * * * ? )
  when
    $a : Alarm( on == true )
  then
    channels[ "sms" ].insert( new Sms( $a.mobileNumber, "The alarm is still on." );
end

通常,当触发规则时,计时器控制的规则将变为活动状态,并根据计时器设置重复执行规则结果。当规则条件不再与传入的事实匹配时,执行会停止。但是,决策引擎处理带有计时器的规则的方式取决于决策引擎是否处于 主动模式 还是 被动模式

默认情况下,当用户或应用程序显式调用 fireAllRules () 时,决策引擎以 被动模式 运行,并根据定义的计时器设置评估规则。相反,如果用户或应用程序调用 fireUntilHalt (),决策引擎以 active 模式启动,并持续评估规则,直到用户或应用程序显式调用 halt ()

当决策引擎处于 active 模式时,即使控制返回从调用返回 fireUntilHalt (),并且决策引擎仍与对工作内存所做的任何更改保持主动时,也会执行规则结果。例如,删除触发计时器规则执行的事实会导致重复执行终止,并插入事实,以便某些规则匹配会导致执行该规则。但是,决策引擎不会持续 激活,但仅在执行规则后处于活动状态。因此,在下一次执行计时器控制的规则前,决策引擎不会响应异步事实插入。分离 KIE 会话会终止所有计时器活动。

当决策引擎处于被动模式时,只有在再次调用 fireAllRules () 时,才会评估时间规则的规则结果。但是,您可以使用 TimedRuleExecutionOption 选项配置 KIE 会话来更改被动模式的默认 timer-execution 行为,如下例所示:

KIE 会话配置,以便在被动模式下自动执行时间规则

KieSessionConfiguration ksconf = KieServices.Factory.get().newKieSessionConfiguration();
ksconf.setOption( TimedRuleExecutionOption.YES );
KSession ksession = kbase.newKieSession(ksconf, null);

您还可以在 TimedRuleExecutionOption 选项上设置 FILTERED 规格,它可让您定义一个回调来过滤这些规则,如下例所示:

KIE 会话配置,以过滤自动执行哪个时间规则

KieSessionConfiguration ksconf = KieServices.Factory.get().newKieSessionConfiguration();
conf.setOption( new TimedRuleExecutionOption.FILTERED(new TimedRuleExecutionFilter() {
    public boolean accept(Rule[] rules) {
        return rules[0].getName().equals("MyRule");
    }
}) );

对于间隔计时器,您还可以使用带有 expr 的表达式计时器,而不是 int 将延迟和间隔定义为表达式而不是固定值。

以下示例 DRL 文件声明了一个事实类型,其中包含一个延迟和周期,然后在后续规则中使用表达式计时器:

带有表达式计时器的规则示例

declare Bean
  delay   : String = "30s"
  period  : long = 60000
end

rule "Expression timer"
  timer ( expr: $d, $p )
  when
    Bean( $d : delay, $p : period )
  then
    // Actions
end

本例中的表达式(如 $d$p )可以使用规则的 pattern-matching 部分中定义的任何变量。变量可以是可解析到持续时间的任何字符串值,也可以是内部以 数值(以毫秒为单位)值的任何数字值。

间隔和表达式计时器都可以使用以下可选参数:

  • Startend代表 日期或一个 值的字符串该值也可以是转换为 日期 (( Number ) n).longValue ()格式的 Java 日期的数字
  • repeat-limit :一个整数,用于定义计时器允许的最大重复数。如果同时设置了 endrepeat-limit 参数,则计时器会在达到两者的第一个时停止。

带有可选 startend -limit 和 repeat-limit 参数的 timer 属性示例

timer (int: 30s 1h; start=3-JAN-2020, end=4-JAN-2020, repeat-limit=50)

在这个示例中,规则会每小时调度一次,每周延迟 30 秒后,从 2020 年 1 月 3 日开始,并在 2020 年 1 月 4 日结束,或者循环重复了 50 次。

如果系统暂停(例如,会话会被序列化,然后调度之后的反序列化),无论在暂停期间丢失了多少激活,规则都会被调度一次,以继续与计时器设置同步。

DRL 规则中 的日历 属性是一个 Quartz 日历定义,用于调度规则并支持以下格式:

日历属性格式

calendars "<definition or registered name>"

日历属性示例

// Exclude non-business hours
calendars "* * 0-7,18-23 ? * *"

// Weekdays only, as registered in the KIE session
calendars "weekday"

您可以基于 Quartz 日历 API 调整 Quartz 日历,然后在 KIE 会话中注册日历,如下例所示:

调整 Quartz Calendar

Calendar weekDayCal = QuartzHelper.quartzCalendarAdapter(org.quartz.Calendar quartzCal)

在 KIE 会话中注册日历

ksession.getCalendars().set( "weekday", weekDayCal );

您可以将日历与标准规则一起使用,以及使用计时器的规则。calendar 属性可包含一个或多个以 String 字面形式编写的日历名称。

以下示例规则使用日历和计时器来调度规则:

带有日历和计时器的规则示例

rule "Weekdays are high priority"
  calendars "weekday"
  timer ( int:0 1h )
  when
    Alarm()
  then
    send( "priority high - we have an alarm" );
end

rule "Weekends are low priority"
  calendars "weekend"
  timer ( int:0 4h )
  when
    Alarm()
  then
    send( "priority low - we have an alarm" );
end

14.8. DRL (WHEN)中的规则条件

DRL 规则的 when 部分(也称为规则的 Left Hand Side (LHS) )包含执行操作必须满足的条件。条件由一系列声明 模式和限制 组成,根据软件包中的可用数据对象,带有可选 绑定 和支持的规则条件元素(关键字)。例如,如果某个公司需要 loan applicants 的时间超过 21 年,那么 "Underage" 规则的 when 条件将是 Applicant (age < 21)

注意

DRL 使用 when 而不是 if ,因为是其他执行流的一部分,该流通常会在特定时间点上检查条件。相反, 表示条件评估不仅限于特定的评估序列或时间点,而是随时发生。每当满足条件时,都会执行操作。

如果 when 部分为空,则条件被视为 true,并且首先在决策引擎中执行 fireAllRules () 调用时,将执行 部分中的操作。如果要使用规则设置决策引擎状态,这非常有用。

以下示例规则使用空条件在每次执行规则时插入事实:

没有条件的规则示例

rule "Always insert applicant"
  when
    // Empty
  then   // Actions to be executed once
    insert( new Applicant() );
end

// The rule is internally rewritten in the following way:

rule "Always insert applicant"
  when
    eval( true )
  then
    insert( new Applicant() );
end

如果规则条件使用多个模式,且没有定义的关键字(如 ),则默认组合是 :

没有关键字组合的规则示例

rule "Underage"
  when
    application : LoanApplication()
    Applicant( age < 21 )
  then
    // Actions
end

// The rule is internally rewritten in the following way:

rule "Underage"
  when
    application : LoanApplication()
    and Applicant( age < 21 )
  then
    // Actions
end

14.8.1. 模式和约束

DRL 规则条件中的 模式是 决策引擎要匹配的分段。模式可能与插入到决策引擎工作内存的每个事实匹配。模式也可以包含 约束,以进一步定义要匹配的事实。

在最简单的形式中,没有限制,模式与给定类型的事实匹配。在以下示例中,type 是 Person,因此模式将与决策引擎工作内存中的所有 Person 对象匹配:

单个事实类型的模式示例

Person()

这个类型不需要是一些事实对象的实际类。模式可以引用超级类甚至接口,可能与许多不同类的事实匹配。例如,以下模式与决策引擎工作内存中的所有对象匹配:

所有对象的模式示例

Object() // Matches all objects in the working memory

组成约束的特征的括号,如个人年龄的以下约束:

带有约束的模式示例

Person( age == 50 )

约束 是返回 truefalse 的表达式。DRL 中的模式限制基本上是带有一些改进的 Java 表达式,如属性访问,以及一些区别,如 ==!=equals ()!equals () 语义(而不是常见的语义)。

任何 192.168.1.0/24 属性都可以直接从模式限制访问。bean 属性在内部使用没有参数且返回一些标准站 getter 来公开。例如,age 属性写为 DRL 中的 年龄,而不是 getter getAge ()

带有 sVirt 属性的 DRL 约束语法

Person( age == 50 )

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

Person( getAge() == 50 )

Red Hat Process Automation Manager 使用标准 JDK Introspector 类来实现此映射,因此它遵循标准站规格。为获得最佳决策引擎性能,请使用属性访问格式,如 年龄,而不是明确使用 getters,如 getAge ()

警告

不要使用属性访问器来更改对象的状态,这可能会影响规则,因为决策引擎会缓存调用之间匹配的结果,以便提高效率。

例如,不要使用以下方法使用属性访问器:

public int getAge() {
    age++; // Do not do this.
    return age;
}
public int getAge() {
    Date now = DateUtil.now(); // Do not do this.
    return DateUtil.differenceInYears(now, birthday);
}

遵循第二个示例,插入一个事实,它将当前日期嵌套在工作内存中,并根据需要更新 fireAllRules () 之间的事实。

但是,如果无法找到属性的 getter,编译器将使用属性名称作为回退方法名称,且没有参数:

如果没有找到对象,回退方法

Person( age == 50 )

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

Person( age() == 50 )

您还可以以模式嵌套访问属性,如下例所示。嵌套属性由决策引擎索引。

带有嵌套属性访问的模式示例

Person( address.houseNumber == 50 )

// This is the same as the following format:

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

警告

在有状态 KIE 会话中,请小心使用嵌套的访问器,因为决策引擎的工作内存不知道任何嵌套的值,且不会检测何时更改。考虑不可变的值,而其任何父引用都会插入到工作内存中,或者,如果要修改嵌套值,请将所有外部事实标记为更新。在上例中,当 houseNumber 属性有变化时,所有具有该地址的 Person 必须标记为更新。

您可以使用任何返回 布尔值 的 Java 表达式作为模式括号内的约束。Java 表达式可以与其他表达式增强混合,如属性访问:

带有使用属性访问和 Java 表达式的约束的模式示例

Person( age == 50 )

您可以使用括号更改评估优先级,如在任何逻辑或数学表达式中一样:

约束评估顺序示例

Person( age > 100 && ( age % 10 == 0 ) )

您还可以在约束中重复使用 Java 方法,如下例所示:

使用可重复使用的 Java 方法的限制示例

Person( Math.round( weight / ( height * height ) ) < 25.0 )

警告

不要使用限制来更改对象的状态,这可能会影响规则,因为决策引擎会缓存调用之间匹配的结果,以提高效率。在规则条件中对事实执行的任何方法都必须是只读的方法。此外,事实的状态不应在规则调用之间更改,除非这些事实在每次更改时在工作内存中被标记为更新。

例如,不要使用以下方法使用模式约束:

Person( incrementAndGetAge() == 10 ) // Do not do this.
Person( System.currentTimeMillis() % 1000 == 0 ) // Do not do this.

标准 Java 操作器优先级适用于 DRL 中的约束运算符,DRL 运算符遵循标准的 Java 语义,但 ==!= 运算符除外。

== 运算符使用 null-safe equals () 语义,而不是常见的语义。例如,模式 Person (firstName == "John")java.util.Objects.equals (person.getFirstName (), "John"), 和 "John" 不为空,其模式也类似于 "John".equals (person.getFirstName ())

!= 运算符使用 null-safe !equals () 语义,而不是常见的语义。例如,模式 Person (firstName != "John")!java.util.Objects.equals (person.getFirstName (), "John") 类似。

如果约束的字段和约束值是不同的类型,则决策引擎将使用类型 coercion 来解决冲突并减少编译错误。例如,如果 "ten" 作为数字评估器中的字符串提供,则会出现编译错误,而 "10" 则合并到数字 10 中。在 coercion 中,字段类型总是优先于值类型:

带有 coerced 值的约束示例

Person( age == "10" ) // "10" is coerced to 10

对于限制组,您可以使用逗号限制 使用隐式 和连接 语义:

具有多个约束的模式示例

// Person is at least 50 years old and weighs at least 80 kilograms:
Person( age > 50, weight > 80 )

// Person is at least 50 years old, weighs at least 80 kilograms, and is taller than 2 meters:
Person( age > 50, weight > 80, height > 2 )

注意

虽然 && 和,但运算符具有相同的语义,但它们可以通过不同的优先级来解决。 && 运算符在 || 操作器前,以及 &&|| 运算符都放在 , 运算符 前。在顶级约束中使用逗号运算符来优化决策引擎性能和人类可读性。

您不能将逗号运算符嵌入到复合约束表达式中,如括号中:

复合约束表达式中错误使用的逗号示例

// Do not use the following format:
Person( ( age > 50, weight > 80 ) || height > 2 )

// Use the following format instead:
Person( ( age > 50 && weight > 80 ) || height > 2 )

14.8.2. 在模式和限制中绑定变量

您可以将变量绑定到模式和约束,以引用规则其他部分中的匹配对象。通过您在数据模型中注解事实的方式,绑定变量可帮助您更有效地定义规则或更加一致。要在规则中的变量和字段之间更容易区分,请为变量使用标准格式 $variable,特别是在复杂的规则中。此惯例很有用,但在 DRL 中不需要。

例如,以下 DRL 规则将变量 $p 用于带有 Person 事实的模式:

带有绑定变量的模式

rule "simple rule"
  when
    $p : Person()
  then
    System.out.println( "Person " + $p );
end

同样,您还可以将变量绑定到模式约束中的属性,如下例所示:

// Two persons of the same age:
Person( $firstAge : age ) // Binding
Person( age == $firstAge ) // Constraint expression
注意

确保为更清晰、更有效的规则定义分隔约束绑定和约束表达式。虽然支持混合绑定和表达式,但它们可能会复杂模式并影响评估效率。

// Do not use the following format:
Person( $age : age * 2 < 100 )

// Use the following format instead:
Person( age * 2 < 100, $age : age )

决策引擎不支持绑定到同一声明,但支持多个属性的 取消 参数。虽然位置参数始终使用 unification 处理,但命名参数存在联合符号 :=

以下示例模式在两个 Person 事实之间统一 age 属性:

带有未配置的模式示例

Person( $age := age )
Person( $age := age )

取消声明第一次发生的绑定,并限制为绑定字段的同一值,以进行序列发生。

14.8.3. 嵌套约束和内联多播

在某些情况下,您可能需要访问嵌套对象的多个属性,如下例所示:

访问多个属性的模式示例

Person( name == "mark", address.city == "london", address.country == "uk" )

您可以将这些属性访问器分组到使用语法 . (<constraints>) 嵌套的对象,以便更易读的规则,如下例所示:

带有分组限制的模式示例

Person( name == "mark", address.( city == "london", country == "uk") )

注意

period 前缀 . 将嵌套对象约束与方法调用区分开。

当您以模式处理嵌套对象时,您可以使用语法 < type>114<subtype > 广播到子类型,并使父类型中的 getters 可供子类型使用。您可以使用对象名称或完全限定类名称,您可以转换为一个或多个子类型,如下例所示:

将内联转换为子类型的模式示例

// Inline casting with subtype name:
Person( name == "mark", address#LongAddress.country == "uk" )

// Inline casting with fully qualified class name:
Person( name == "mark", address#org.domain.LongAddress.country == "uk" )

// Multiple inline casts:
Person( name == "mark", address#LongAddress.country#DetailedCountry.population > 10000000 )

这些示例模式 cast AddressLongAddress,以及上一次示例中的 Detailsed Country,在每个示例中,父 getters 可供子类型使用。

您可以使用 instanceof 运算符来推断在后续使用带有模式的指定类型的结果,如下例所示:

Person( name == "mark", address instanceof LongAddress, address.country == "uk" )

如果无法进行内联多播(例如,如果 instanceof 返回 false),则评估被视为 false

14.8.4. 约束中的日期字面

默认情况下,决策引擎支持日期格式 dd-mmm-yyyy。您可以通过提供系统属性 drools.dateformat="dd-mmm-yyyy hh:mm" 的其它格式掩码来自定义日期格式,包括时间格式掩码。您还可以使用 drools.defaultlanguagedrools.defaultcountry 系统属性更改语言区域设置来自定义日期格式(例如,Thailand 的区域设置被设置为 drools.defaultlanguage=thdrools.defaultcountry=TH)。

带有日期字面限制的模式示例

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

14.8.5. DRL 模式约束支持的 Operator

DRL 在模式约束中支持 Operator 的标准 Java 语义,但有一些例外和一些额外的运算符在 DRL 中是唯一的。以下列表总结了 DRL 约束中不同于标准 Java 语义或 DRL 约束中唯一的 Operator。

.(), #

使用 . () 运算符将属性 accessors 分组到嵌套对象,并使用 guestfish 运算符,将子类型转换为嵌套对象中的子类型。遍历子类型使来自父类型的 getters 可供子类型使用。您可以使用对象名称或完全限定类名称,您可以转换为一个或多个子类型。

带有嵌套对象的模式示例

// Ungrouped property accessors:
Person( name == "mark", address.city == "london", address.country == "uk" )

// Grouped property accessors:
Person( name == "mark", address.( city == "london", country == "uk") )

注意

period 前缀 . 将嵌套对象约束与方法调用区分开。

将内联转换为子类型的模式示例

// Inline casting with subtype name:
Person( name == "mark", address#LongAddress.country == "uk" )

// Inline casting with fully qualified class name:
Person( name == "mark", address#org.domain.LongAddress.country == "uk" )

// Multiple inline casts:
Person( name == "mark", address#LongAddress.country#DetailedCountry.population > 10000000 )

!.

使用此操作器以 null-safe 的方式解引用属性。! 左侧的值。 运算符不能为空(解析为 != null),才能为模式匹配提供正结果。

带有 null-safe 解引用的限制示例

Person( $streetName : address!.street )

// This is internally rewritten in the following way:

Person( address != null, $streetName : address.street )

[]

使用此操作器根据 index 或键的 Map 值访问 List 值。

带有 ListMap 访问权限的约束示例

// The following format is the same as `childList(0).getAge() == 18`:
Person(childList[0].age == 18)

// The following format is the same as `credentialMap.get("jdoe").isValid()`:
Person(credentialMap["jdoe"].valid)

<, <=, >, >=

在具有自然排序的属性中使用这些运算符。例如,对于 Date 字段,&lt ; 运算符在 之前 表示,对于 String 字段,运算符在 之前按字母顺序 表示。这些属性仅适用于相似的属性。

operator 之前 的限制示例

Person( birthDate < $otherBirthDate )

Person( firstName < $otherFirstName )

==, !=

在约束中将这些运算符用作 equals ()!equals () 方法,而不是常见的 相同 语义。

带有 null-safe 相等的约束示例

Person( firstName == "John" )

// This is similar to the following formats:

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

带有 null-safe 不匹配的限制示例

Person( firstName != "John" )

// This is similar to the following format:

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

&&, ||

使用这些运算符创建缩写组合关系条件,该条件对字段添加多个限制。您可以使用括号 () 对限制进行分组,以创建递归语法模式。

带有缩写组合关系的限制示例

// Simple abbreviated combined relation condition using a single `&&`:
Person(age > 30 && < 40)

// Complex abbreviated combined relation using groupings:
Person(age ((> 30 && < 40) || (> 20 && < 25)))

// Mixing abbreviated combined relation with constraint connectives:
Person(age > 30 && < 40 || location == "london")

匹配不匹配

使用这些运算符来指示字段匹配或不匹配指定的 Java 正则表达式。通常,正则表达式是一个字符串字面,但解析为有效正则表达式的变量也支持。这些操作器仅适用于 String 属性。如果您使用 null 值匹配的,则生成的评估始终为 false。如果您使用 null 值不匹配,则生成的评估始终为 true。与 Java 一样,您写为 字符串 字面的正则表达式必须使用双反斜杠 \\ 来转义。

要匹配或不匹配正则表达式的约束示例

Person( country matches "(USA)?\\S*UK" )

Person( country not matches "(USA)?\\S*UK" )

包含不包含

使用这些运算符来验证是 Array 还是集合包含或不包含指定的值的字段。这些运算符适用于 ArrayCollection 属性,但您也可以使用这些运算符代替 String.contains ()!String.contains () 约束检查。

包含且不包含 集合的限制示例

// 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 字面的限制示例

// 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 )

注意

为向后兼容,excludes 运算符是不受支持的 synonym,不包含

memberOf,not memberOf

使用这些运算符来验证字段是否为一个数组的成员,还是定义为变量的集合的成员。 ArrayCollection 必须是变量。

带有 memberOf 而不是 memberOf 的限制示例

FamilyTree( person memberOf $europeanDescendants )

FamilyTree( person not memberOf $europeanDescendants )

soundslike

使用此运算符验证词语是否具有几乎相同的声音,使用英语探测与给定值(与 match 运算符类似)。此 operator 使用 Soundex 算法。

带有 类似声音的约束示例

// Match firstName "Jon" or "John":
Person( firstName soundslike "John" )

str

使用此运算符验证 字符串 是否以或以指定的值开头或结尾的字段。您还可以使用此操作器验证 String 的长度。

带有 str的约束示例

// 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 )

在 中,not in

使用这些运算符指定多个可能的值来匹配约束(复合值限制)。只有 in 和不支持在 operator 中支持复合值限制 的功能。这些运算符的第二个操作对象必须是以逗号分隔的值列表,用括号括起。您可以将值作为变量、字面、返回值或合格的标识符提供。这些运算符内部使用操作符 ==!= 作为多个限制的列表。

带有 innotin的限制示例

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

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

14.8.6. DRL 模式约束中的 Operator 优先级

DRL 支持适用约束运算符的标准 Java 操作器优先级,但有一些例外和一些额外的运算符在 DRL 中是唯一的。下表在适用的情况下列出了 DRL operator 优先级,从最高到最低的优先级:

表 14.2. DRL 模式约束中的 Operator 优先级

Operator 类型Operator备注

嵌套或空安全属性访问

., .(), !.

不支持标准 Java 语义

列表映射 访问

[]

不支持标准 Java 语义

约束绑定

:

不支持标准 Java 语义

multiplicative

*, /%

 

additive

+, -

 

移动

>>, >>>, <<

 

关系

& lt; , &lt;= , & gt; , & gt;= , instanceof

 

相等

== !=

使用 equals ()!equals () 语义,而不是标准的 Java 相同的 语义

非短路 AND

&

 

非短路 exclusive OR

^

 

非短路包含 OR

|

 

logical AND

&&

 

logical OR

||

 

ternary

? :

 

以逗号分隔的 AND

,

不支持标准 Java 语义

14.8.7. DRL 中支持的规则条件元素(关键字)

DRL 支持以下规则条件元素(关键字),您可以与您在 DRL 规则条件中定义的模式一起使用:

和

使用它来将条件组件分组到逻辑组合中。在fix prefix 中被支持,并被支持。您可以使用括号 () 显式分组模式。默认情况下,所有列出的模式都会与 合并,如果没有指定。

带有 and的模式示例

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

//Infix `and` with grouping:
(Color( colorType : type ) and (Person( favoriteColor == colorType ) or Person( favoriteColor == colorType ))

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

// Default implicit `and`:
Color( colorType : type )
Person( favoriteColor == colorType )

注意

不要使用带有 and 关键字的前导 声明绑定 (例如,您可以使用 )。声明一次只能引用单个事实,如果您使用声明绑定和,那么当 满足时,它将同时匹配事实,并导致错误。

滥用 的示例

// Causes compile error:
$person : (Person( name == "Romeo" ) and Person( name == "Juliet"))

或者

使用此选项将条件组件分组到逻辑取消中。在fix 和 prefix 中不被支持。您可以使用括号 () 显式分组模式。您还可以使用模式 绑定或,但每个模式都必须单独绑定。

带有 or的模式示例

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

//Infix `or` with grouping:
(Color( colorType : type ) or (Person( favoriteColor == colorType ) and Person( favoriteColor == colorType ))

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

带有 模式绑定的模式示例

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 ))

or condition 元素的行为与 connective || 运算符不同,用于字段限制和限制。决策引擎不会直接解释 or 元素,而是使用逻辑转换来使用或作为多个子规则重写规则。此过程最终会生成具有单个 根节点的规则,以及每个 condition 元素的一个子规则。每个子规则都像任何常规规则一样激活并执行,子规则之间没有特殊行为或交互。

因此,当两个或者多个 disjunction 术语满足时,请考虑 or condition 元素生成两个或多个类似规则的快捷方式。

exists

使用它来指定必须存在的事实和约束。这个选项仅针对第一个匹配项触发,而不在以后的匹配项上触发。如果您将此元素与多种模式一起使用,请将模式与括号 () 括起来。

存在模式示例

exists Person( firstName == "John")

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

exists (Person( firstName == "John" ) and
        Person( lastName == "Doe" ))

not

使用它来指定不能存在的事实和约束。如果您将此元素与多种模式一起使用,请将模式与括号 () 括起来。

没有的模式示例

not Person( firstName == "John")

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

not (Person( firstName == "John" ) and
     Person( lastName == "Doe" ))

forall

使用此选项来验证与第一个模式匹配的所有事实是否与所有剩余的模式匹配。当满足 forall 结构时,该规则将评估为 true。此元素是一个范围分隔符,因此它可以使用任何之前绑定的变量,但其中没有变量绑定可在它之外使用。

带有 forall的规则示例

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.
end

在本例中,规则选择类型为 "fulltime" 的所有 Employee 对象。对于与此模式匹配的每个事实,该规则会评估遵循的模式(从属颜色),如果匹配,该规则将评估为 true

要说明决策引擎工作内存中给定类型的所有事实必须与一组限制匹配,您可以使用单一模式来方便使用。

带有 forall 和单一模式的规则示例

rule "All full-time employees have red ID badges"
  when
    forall( Employee( badgeColor = "red" ) )
  then
    // True, all full-time employees have red ID badges.
end

您可以将 forall 构造使用多个模式,或者嵌套它们与其他 condition 元素一起,例如在 not 元素构造中。

带有 forall 和多个模式的规则示例

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.
end

带有 forall 而不是t 的规则示例

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.
end

注意

all (p1 p2 p2 p3 …​) 的格式等同于 not (p1 而不是(和 p2 p3 …​)

from

使用它来为模式指定数据源。这可让决策引擎超过工作内存中的数据。数据源可以是绑定变量上的子字段,也可以是方法调用的结果。用于定义对象源的表达式是遵循常规 MVEL 语法的任何表达式。因此,ca 元素可让您轻松使用对象属性导航、执行方法调用和访问映射和集合元素。

使用 from 和 pattern 绑定的规则示例

rule "Validate zipcode"
  when
    Person( $personAddress : address )
    Address( zipcode == "23920W" ) from $personAddress
  then
    // Zip code is okay.
end

带有 from 和图形表示法的规则示例

rule "Validate zipcode"
  when
    $p : Person()
    $a : Address( zipcode == "23920W" ) from $p.address
  then
    // Zip code is okay.
end

迭代所有对象的规则示例

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 会话中,然后在条件中加入集合,如下例所示:

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

带有 fromlock-on-active 规则属性的规则示例

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) {} // Assign the person to sales region 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) {} // Apply discount to the person.
end

重要

使用带有 lock-on-active 规则属性的 from 可能会导致规则没有被执行。您可以使用以下方法之一解决这个问题:

  • 当您可以将所有事实插入到决策引擎的工作内存中时,避免使用 from 元素,或者在约束表达式中使用嵌套对象引用。
  • modify () 块中使用的变量设置为规则条件中最后一个句子。
  • 当您可以明确管理同一 ruleflow 组中的规则时,避免使用 lock-on-active 规则属性。

包含 from 子句的模式不能后跟以括号开头的另一个模式。这个限制的原因是 DRL 解析器从表达式读取 " from $l (String ()或 Number ())",且无法将这个表达式与函数调用区分开。最简单的解决方法是将 from 子句嵌套在括号中,如下例所示:

来自 使用不正确且正确使用的规则示例

// Do not use `from` in this way:
rule R
  when
    $l : List()
    String() from $l
    (String() or Number())
  then
    // Actions
end

// Use `from` in this way instead:
rule R
  when
    $l : List()
    (String() from $l)
    (String() or Number())
  then
    // Actions
end

entry-point

使用它来定义入口点或 事件流,对应于模式的数据源。这个元素通常与 from condition 元素一起使用。您可以为事件声明入口点,以便决策引擎仅使用该入口点中的数据来评估规则。您可以通过在 DRL 规则中或明确在 Java 应用程序中引用入口点来隐式声明入口点。

来自 entry-point的规则示例

rule "Authorize withdrawal"
  when
    WithdrawRequest( $ai : accountId, $am : amount ) from entry-point "ATM Stream"
    CheckingAccount( accountId == $ai, balance > $am )
  then
    // Authorize withdrawal.
end

带有 EntryPoint 对象的 Java 应用程序代码示例和插入的事实

import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.EntryPoint;

// Create your KIE base and KIE session as usual:
KieSession session = ...

// Create a reference to the entry point:
EntryPoint atmStream = session.getEntryPoint("ATM Stream");

// Start inserting your facts into the entry point:
atmStream.insert(aWithdrawRequest);

collect

使用它来定义规则可作为条件的一部分使用的对象集合。规则从指定源或决策引擎的工作内存获取集合。collect 元素的结果模式可以是实现 java.util.Collection 接口的任何聚合类,并提供默认的 no-arg 公共构造器。您可以使用 Java 集合,如 ListLinkedListHashSet,或者您自己的类。如果在条件中的 collect 元素之前绑定变量,您可以使用变量限制源和结果模式。但是,collect 元素内所做的任何绑定都不可用,可在它之外使用。

带有 collect的规则示例

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

在本例中,该规则评估每个给定系统决策引擎工作内存中的所有待处理警报,并将它们分组到列表中。如果为给定系统找到三个或更多警告,则执行该规则。

您还可以使用与元素嵌套的 collect 元素,如下例所示:

中收集 和嵌套 的规则示例

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

累积

使用它来迭代对象集合,对每个元素执行自定义操作,并返回一个或多个结果对象(如果约束评估为 true)。这个元素是 collect condition 元素的更灵活且强大的形式。您可以在 累积 条件中使用预定义的功能,或根据需要实施自定义功能。您还可以在规则条件中使用缩写缩写 cc 来 累积

使用以下格式在规则中定义 累积 条件:

累积格式的首选格式

accumulate( <source pattern>; <functions> [;<constraints>] )

注意

虽然决策引擎支持 累积 元素的替代格式来实现向后兼容,但对于规则和应用程序中获得最佳性能,这种格式是首选的。

决策引擎支持以下预定义的 累积 功能。这些功能接受任何表达式作为输入。

  • 平均
  • 分钟
  • max
  • æ•°é‡�
  • sum
  • collectList
  • collectSet

在以下示例规则中,minmaxaverage 是在计算每个传感器的所有读取值的最小、最大值和平均温度值的功能:

计算温度值的累积规则示例

rule "Raise alarm"
  when
    $s : Sensor()
    accumulate( Reading( sensor == $s, $temp : temperature );
                $min : min( $temp ),
                $max : max( $temp ),
                $avg : average( $temp );
                $min < 20, $avg > 70 )
  then
    // Raise the alarm.
end

以下示例规则使用测量 的平均 函数来按照顺序计算所有项目的平均原率:

计算平均 profit 的规则示例

rule "Average profit"
  when
    $order : Order()
    accumulate( OrderItem( order == $order, $cost : cost, $price : price );
                $avgProfit : average( 1 - $cost / $price ) )
  then
    // Average profit for `$order` is `$avgProfit`.
end

要在 累积 条件中使用自定义特定于域的功能,请创建一个 Java 类来实现 org.kie.api.runtime.rule.AccumulateFunction 接口。例如,以下 Java 类定义了 AverageData 函数的自定义实现:

带有 平均 功能的自定义实现的 Java 类示例

// An implementation of an accumulator capable of calculating average values

public class AverageAccumulateFunction implements org.kie.api.runtime.rule.AccumulateFunction<AverageAccumulateFunction.AverageData> {

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {

    }

    public void writeExternal(ObjectOutput out) throws IOException {

    }

    public static class AverageData implements Externalizable {
        public int    count = 0;
        public double total = 0;

        public AverageData() {}

        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            count   = in.readInt();
            total   = in.readDouble();
        }

        public void writeExternal(ObjectOutput out) throws IOException {
            out.writeInt(count);
            out.writeDouble(total);
        }

    }

    /* (non-Javadoc)
     * @see org.kie.api.runtime.rule.AccumulateFunction#createContext()
     */
    public AverageData createContext() {
        return new AverageData();
    }

    /* (non-Javadoc)
     * @see org.kie.api.runtime.rule.AccumulateFunction#init(java.io.Serializable)
     */
    public void init(AverageData context) {
        context.count = 0;
        context.total = 0;
    }

    /* (non-Javadoc)
     * @see org.kie.api.runtime.rule.AccumulateFunction#accumulate(java.io.Serializable, java.lang.Object)
     */
    public void accumulate(AverageData context,
                           Object value) {
        context.count++;
        context.total += ((Number) value).doubleValue();
    }

    /* (non-Javadoc)
     * @see org.kie.api.runtime.rule.AccumulateFunction#reverse(java.io.Serializable, java.lang.Object)
     */
    public void reverse(AverageData context, Object value) {
        context.count--;
        context.total -= ((Number) value).doubleValue();
    }

    /* (non-Javadoc)
     * @see org.kie.api.runtime.rule.AccumulateFunction#getResult(java.io.Serializable)
     */
    public Object getResult(AverageData context) {
        return new Double( context.count == 0 ? 0 : context.total / context.count );
    }

    /* (non-Javadoc)
     * @see org.kie.api.runtime.rule.AccumulateFunction#supportsReverse()
     */
    public boolean supportsReverse() {
        return true;
    }

    /* (non-Javadoc)
     * @see org.kie.api.runtime.rule.AccumulateFunction#getResultType()
     */
    public Class< ? > getResultType() {
        return Number.class;
    }

}

要在 DRL 规则中使用自定义功能,请使用 import 累积语句导入 函数:

导入自定义功能的格式

import accumulate <class_name> <function_name>

带有导入 平均 功能的规则示例

import accumulate AverageAccumulateFunction.AverageData average

rule "Average profit"
  when
    $order : Order()
    accumulate( OrderItem( order == $order, $cost : cost, $price : price );
                $avgProfit : average( 1 - $cost / $price ) )
  then
    // Average profit for `$order` is `$avgProfit`.
end

14.8.8. OOPath 语法以及 DRL 规则条件中的对象图形

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

当事实的字段是一个集合时,您可以使用 from condition 元素(关键字)与集合中的所有项目绑定和原因。如果您需要在规则条件约束中浏览对象图表,则对 from condition 元素的广泛使用会导致详细和重复的语法,如下例所示:

从中浏览对象图形的规则示例

rule "Find all grades for Big Data exam"
  when
    $student: Student( $plan: plan )
    $exam: Exam( course == "Big Data" ) from $plan.exams
    $grade: Grade() from $exam.grades
  then
    // Actions
end

在本例中,域模型包含一个带有正在研究的 Plan 的 Tailoring 对象。此计划 可以有零个或多个研究 实例,并会包括零个或多个 Grade 实例在这种情况下,只有图形的根对象需要处于决策引擎的工作内存中,才能使此规则设置正常工作。

作为使用声明中广泛使用的更多替代方案,您可以使用缩写 OOPath 语法,如下例所示:

使用 OOPath 语法浏览对象图形的规则示例

rule "Find all grades for Big Data exam"
  when
    Student( $grade: /plan/exams[course == "Big Data"]/grades )
  then
    // Actions
end

通常,OOPath 表达式的核心 grammar 以扩展 Backus-Naur 格式(EBNF)标记定义:

OOPath 表达式的 EBNF 表示法

OOPExpr = [ID ( ":" | ":=" )] ( "/" | "?/" ) OOPSegment { ( "/" | "?/" | "." ) OOPSegment } ;
OOPSegment = ID ["#" ID] ["[" ( Number | Constraints ) "]"]

实际上,OOPath 表达式具有以下功能和功能:

  • 以正斜杠 / 或问问题标记开始,如果它是一个非主动 OOPath 表达式(本节后面介绍),则以正斜杠 / 或正斜杠 ?/ 开头。
  • 可以使用句点 . 操作符解引用对象的单个属性。
  • 可以使用正斜杠 / 运算符解引用对象的多个属性。如果返回集合,表达式会迭代集合中的值。
  • 可以过滤掉不满足一个或多个限制的对象。约束在方括号之间写成 predicate 表达式,如下例所示:

    将约束作为 predicate 表达式

    Student( $grade: /plan/exams[ course == "Big Data" ]/grades )

  • 可将遍历的对象缩减到通用集合中声明的类的子类。后续限制也可以安全地访问该子类中声明的属性,如下例所示。不是此内联 cast 中指定的类实例的对象会自动过滤掉。

    带有下游对象的约束

    Student( $grade: /plan/exams#AdvancedExam[ course == "Big Data", level > 3 ]/grades )

  • 可以引用当前迭代图形前遍历的图形的对象。例如,以下 OOPath 表达式仅匹配通过测试的平均等级:

    带有后引用对象的约束

    Student( $grade: /plan/exams/grades[ result > ../averageResult ] )

  • 可以是另一个 OOPath 表达式,如下例所示:

    递归约束表达式

    Student( $exam: /plan/exams[ /grades[ result > 20 ] ] )

  • 可以通过其方括号 [] 间的索引访问对象,如下例所示。要遵循 Java 规范,OOPath 索引基于 0,而 XPath 索引则基于 1。

    按索引访问对象的限制

    Student( $grade: /plan/exams[0]/grades )

OOPath 表达式可以是 reactive 或 non-reactive。决策引擎不会响应涉及在评估 OOPath 表达式期间遍历的深度嵌套对象的更新。

要使这些对象重新主动更改,请修改对象来扩展类 org.drools.core.phreak.ReactiveObject。修改对象以扩展 ReactiveObject 类后,domain 对象调用继承的方法 notifyModification,以在更新其中一个字段时通知决策引擎,如下例所示:

通知决策引擎迁移到其他课程的对象方法示例

public void setCourse(String course) {
        this.course = course;
        notifyModification(this);
        }

使用以下对应的 OOPath 表达式,当评估移到其他课程时,会重新执行该规则,并重新计算与该规则匹配的等级列表:

"Big Data" 规则中的 OOPath 表达式示例

Student( $grade: /plan/exams[ course == "Big Data" ]/grades )

您还可以使用 ?/ 分隔符而不是 / 分隔符来只对 OOPath 表达式的一个子端口禁用重新活动,如下例所示:

部分非主动的 OOPath 表达式示例

Student( $grade: /plan/exams[ course == "Big Data" ]?/grades )

通过本例,决策引擎会对评估所做的更改做出反应,或者如果为计划添加新的等级,则不会对计划进行了评估。

如果 OOPath 部分不是主动的,则 OOPath 表达式的所有剩余部分也会变为非活跃状态。例如,以下 OOPath 表达式完全非活跃:

完全非主动的 OOPath 表达式示例

Student( $grade: ?/plan/exams[ course == "Big Data" ]/grades )

因此,您不能在同一 OOPath 表达式中使用 ?/ 分隔符一次。例如,以下表达式会导致编译错误:

带有重复非活动标记的 OOPath 表达式示例

Student( $grade: /plan?/exams[ course == "Big Data" ]?/grades )

启用 OOPath 表达式的另一种方法是为 Red Hat Process Automation Manager 中的 ListSet 接口使用专用实现。这些实现是 ReactiveListReactiveSet 类。一个 ReactiveCollection 类也可用。该实施还支持通过 IteratorListIterator 类执行可变操作。

以下示例类使用这些类来配置 OOPath 表达式重新活动:

配置 OOPath 表达式的 Java 类示例

public class School extends AbstractReactiveObject {
    private String name;
    private final List<Child> children = new ReactiveList<Child>(); 1

    public void setName(String name) {
        this.name = name;
        notifyModification(); 2
    }

    public void addChild(Child child) {
        children.add(child); 3
        // No need to call `notifyModification()` here
    }
  }

1
使用 ReactiveList 实例对标准 Java List 实例进行重新主动支持。
2
在重新主动支持中更改时,使用所需的 notifyModification () 方法。
3
children 字段是一个 ReactiveList 实例,因此不需要 notifyModification () 方法调用。通知会自动处理,与通过 child 字段执行的所有其他变异操作一样。

14.9. DRL 中的规则操作(THEN)

规则 随后 部分(也称为规则 的右方(RHS) )包含满足规则条件部分时要执行的操作。操作由一个或多个根据规则条件和软件包中可用数据对象执行结果 的方法 组成。例如,如果某个公司需要 Lan applicant 的时间超过 21 年,则规则状况 Applicant (age < 21)和 loan applicant 超过 21 年,那么 "Underage" 规则的操作将被设置为 setApproved (false),因为 applicant 结束了 loan。

规则操作的主要用途是在决策引擎工作内存中插入、删除或修改数据。有效的规则操作是小、声明性和可读。如果您需要在规则操作中使用必需或有条件的代码,请将规则分成多个较小的和更声明性的规则。

loan 应用程序年龄限制的规则示例

rule "Underage"
  when
    application : LoanApplication()
    Applicant( age < 21 )
  then
    application.setApproved( false );
    application.setExplanation( "Underage" );
end

14.9.1. DRL 中支持的规则操作方法

DRL 支持以下规则操作方法,您可以在 DRL 规则操作中使用。您可以使用这些方法修改决策引擎的工作内存,而无需首先引用可正常工作的内存实例。这些方法充当 Red Hat Process Automation Manager 发行版本中的 Knowledgebase Helper 类提供的方法快捷方式。

对于所有规则操作方法,请从红帽客户门户网站下载 Red Hat Process Automation Manager 7.9.1 Source Distribution ZIP 文件,再进入到 ~/rhpam-7.9.1-sources/src/drools-$VERSION/drools-core/src/main/java/org/drools/core/spi/KnowledgeHelper.javahttps://access.redhat.com/jbossnetwork/restricted/listSoftware.html

set

使用它来设置字段的值。

set<field> ( <value> )

设置 loan 应用程序批准值的规则操作示例

$application.setApproved ( false );
$application.setExplanation( "has been bankrupt" );

修改

使用它来指定为事实修改的字段,并通知决策引擎的变化。这个方法提供了事实更新的结构化方法。它将 更新操作 与 setter 调用相结合,以更改对象字段。

modify ( <fact-expression> ) {
    <expression>,
    <expression>,
    ...
}

修改 loan 应用程序数量和批准的规则操作示例

modify( LoanApplication ) {
        setAmount( 100 ),
        setApproved ( true )
}

update

使用它来指定要更新的字段和整个相关事实,并通知决策引擎的变化。更改事实后,您必须调用 更新,然后才能更改可能受到更新的值影响的另一个事实。要避免此添加的步骤,请使用 modify 方法。

update ( <object, <handle> )  // Informs the decision engine that an object has changed

update ( <object> )  // Causes `KieSession` to search for a fact handle of the object

更新 loan 应用程序数量和批准的规则操作示例

LoanApplication.setAmount( 100 );
update( LoanApplication );

注意

如果提供 property-change 监听程序,则不需要在对象更改时调用此方法。有关属性更改监听程序的更多信息,请参阅 Red Hat Process Automation Manager 中的 决策引擎

insert

使用此选项将新事实插入到决策引擎的工作内存中,并根据事实的要求定义生成的字段和值。

insert( new <object> );

插入新 loan applicant 对象的规则操作示例

insert( new Applicant() );

insertLogical

使用它来以逻辑方式 将新的 事实插入到决策引擎中。决策引擎负责对事实的插入和重包进行逻辑决策。常规或声明的插入后,必须明确回收事实。逻辑插入后,插入的事实会在插入事实的规则中的条件不再满足满足时自动响应。

insertLogical( new <object> );

逻辑插入一个新的 loan applicant 对象的规则操作示例

insertLogical( new Applicant() );

delete

使用它来从决策引擎中删除对象。DRL 还支持关键字 retract 并执行相同的操作,但 删除 通常在 DRL 代码中首选,以便与关键字 插入 保持一致。

delete( <object> );

删除 loan applicant 对象的规则操作示例

delete( Applicant );

14.9.2. droolskcontext 变量的其他规则操作方法

除了标准规则操作方法外,决策引擎还支持方法和预定义的 droolskcontext 变量,您可以在规则操作中使用。

您可以使用 drools 变量从 Red Hat Process Automation Manager 发行版中的 Knowledgebase Helper 类调用方法,这也是标准规则操作方法所基于的类。对于所有 drools 规则操作选项,请从红帽客户门户网站下载 Red Hat Process Automation Manager 7.9.1 Source Distribution ZIP 文件,并进入 ~/rhpam-7.9.1-sources/src/drools-$VERSION/drools-core/src/main/java/org/drools/core/spi/KnowledgeHelper.javahttps://access.redhat.com/jbossnetwork/restricted/listSoftware.html

以下示例是可与 drools 变量一起使用的常用方法:

  • drools.halt (): 如果用户或应用程序之前名为 fireUntilHalt (),则终止规则执行。当用户或应用程序调用 fireUntilHalt () 时,决策引擎以 active 模式启动,并持续评估规则,直到用户或应用程序显式调用 halt ()。否则,决策引擎默认以 被动模式 运行,仅当用户或应用程序显式调用 fireAllRules () 时评估规则。
  • drools.getWorkingMemory () :返回 WorkingMemory 对象。
  • drools.setFocus ("<agenda_group>") :设置规则所属的指定机组。
  • drools.getRule ().getName () :返回规则的名称。
  • drools.getActivation () :返回与当前执行规则匹配的 Tuple,然后提供对应的 激活。这些调用可用于记录和调试目的。

您可以将 kcontext 变量与 getKieRuntime () 方法一起使用,从 KieContext 类调用其他方法,并扩展 Red Hat Process Automation Manager 发行版中的 RuleContext 类。完整的知识 Runtime API 通过 kcontext 变量公开,并提供广泛的规则操作方法。对于所有 kcontext 规则操作选项,请从红帽客户门户网站下载 Red Hat Process Automation Manager 7.9.1 Source Distribution ZIP 文件,并进入 ~/rhpam-7.9.1-sources/src/kie-api-parent-$VERSION/kie-api/src/main/java/org/kie/api/runtime/rule/RuleContext.javahttps://access.redhat.com/jbossnetwork/restricted/listSoftware.html

以下示例是可与 kcontext.getKieRuntime () 变量组合一起使用的常用方法:

  • kcontext.getKieRuntime ().halt (): 如果用户或应用程序之前名为 fireUntilHalt (),则终止规则执行。这个方法等同于 drools.halt () 方法。当用户或应用程序调用 fireUntilHalt () 时,决策引擎以 active 模式启动,并持续评估规则,直到用户或应用程序显式调用 halt ()。否则,决策引擎默认以 被动模式 运行,仅当用户或应用程序显式调用 fireAllRules () 时评估规则。
  • kcontext.getKieRuntime ().getAgenda () :返回对 KIE 会话 Agenda 的引用,并提供对规则激活组、规则关联组和 ruleflow 组的访问。

    访问销售组"CleanUp"的调用示例并设置重点

    kcontext.getKieRuntime().getAgenda().getAgendaGroup( "CleanUp" ).setFocus();

    这个示例等同于 drools.setFocus ("CleanUp")

  • kcontext.getKieRuntime ().getQueryResults (<string> query) : 运行查询并返回结果。这个方法等同于 drools.getKieRuntime ().getQueryResults ()
  • kcontext.getKieRuntime ().getKieBase (): 返回 KieBase 对象。KIE 基础是您规则系统中的所有知识来源,以及当前 KIE 会话的来源。
  • kcontext.getKieRuntime ().setGlobal (), ~.getGlobal (), ~.getGlobals () :设置或检索全局变量。
  • kcontext.getKieRuntime ().get Environment (): 返回运行时环境,类似于您的操作系统环境。

14.9.3. 带有条件和命名结果的高级规则操作

通常,有效的规则操作是小、声明性和可读。然而,在某些情况下,对每个规则有一个结果的限制可能会有一定难度,并导致详细和重复的规则语法,如下例所示:

带有详细和重复语法的规则示例

rule "Give 10% discount to customers older than 60"
  when
    $customer : Customer( age > 60 )
  then
    modify($customer) { setDiscount( 0.1 ) };
end

rule "Give free parking to customers older than 60"
  when
    $customer : Customer( age > 60 )
    $car : Car( owner == $customer )
  then
    modify($car) { setFreeParking( true ) };
end

重复的部分解决方案是使第二个规则扩展第一个规则,如下例所示:

带有扩展条件的部分增强的示例规则

rule "Give 10% discount to customers older than 60"
  when
    $customer : Customer( age > 60 )
  then
    modify($customer) { setDiscount( 0.1 ) };
end

rule "Give free parking to customers older than 60"
    extends "Give 10% discount to customers older than 60"
  when
    $car : Car( owner == $customer )
  then
    modify($car) { setFreeParking( true ) };
end

作为效率更高的替代方案,您可以使用修改条件将两个规则整合到一条规则中,并标记对应的规则操作,如下例所示:

带有条件和命名结果的合并示例规则

rule "Give 10% discount and free parking to customers older than 60"
  when
    $customer : Customer( age > 60 )
    do[giveDiscount]
    $car : Car( owner == $customer )
  then
    modify($car) { setFreeParking( true ) };
  then[giveDiscount]
    modify($customer) { setDiscount( 0.1 ) };
end

这个示例规则使用两个操作:常见的默认操作,另一个名为 grant Discount 的操作。当 KIE 基础中发现存在 60 年以上的客户时,无论客户是否有问题,都以条件激活 giveDiscount 操作。

您可以使用额外条件配置命名结果的激活,如以下示例中的 if 语句。if 语句中的条件总是在紧接它前的模式上评估。

带有额外条件的合并示例规则

rule "Give free parking to customers older than 60 and 10% discount to golden ones among them"
  when
    $customer : Customer( age > 60 )
    if ( type == "Golden" ) do[giveDiscount]
    $car : Car( owner == $customer )
  then
    modify($car) { setFreeParking( true ) };
  then[giveDiscount]
    modify($customer) { setDiscount( 0.1 ) };
end

如果构建构建,您还可以使用 嵌套 来评估不同的规则条件,如下例所示:

带有更复杂的条件的合并示例规则

rule "Give free parking and 10% discount to over 60 Golden customer and 5% to Silver ones"
  when
    $customer : Customer( age > 60 )
    if ( type == "Golden" ) do[giveDiscount10]
    else if ( type == "Silver" ) break[giveDiscount5]
    $car : Car( owner == $customer )
  then
    modify($car) { setFreeParking( true ) };
  then[giveDiscount10]
    modify($customer) { setDiscount( 0.1 ) };
  then[giveDiscount5]
    modify($customer) { setDiscount( 0.05 ) };
end

这个示例规则为黄金客户提供了 10% 的参与和免费服务,但只提供一个 5%,而不会免费给 Silver 客户使用。规则激活名为 give Discount5 的结果,并带有关键字 break 而不是 do。关键字在决策引擎人员中调度结果,使规则条件的剩余部分能够继续评估,同时 会破坏 任何进一步的条件评估。如果命名结果与带有 do 但没有激活的任何条件不匹配,则该规则将无法编译,因为规则条件部分永远不会被达到。

14.10. DRL 文件中的注释

DRL 支持带有双引号 // 前缀的单行注释,以及带有正斜杠和星号的多行注释。您可以使用 DRL 注释来注解 DRL 文件中的规则或任何相关组件。处理 DRL 文件时,决策引擎会忽略 DRL 注释。

带有注释的规则示例

rule "Underage"
  // This is a single-line comment.
  when
    $application : LoanApplication()  // This is an in-line comment.
    Applicant( age < 21 )
  then
    /* This is a multi-line comment
    in the rule actions. */
    $application.setApproved( false );
    $application.setExplanation( "Underage" );
end

重要

DRL 注释 不支持 hash 符号。

14.11. DRL 故障排除的错误消息

Red Hat Process Automation Manager 为 DRL 错误提供标准化的信息,以帮助您对 DRL 文件中的问题进行故障排除和解决问题。错误消息使用以下格式:

图 14.1. DRL 文件问题的错误消息格式

错误消息
  • 1st Block: Error code
  • 发生错误的 DRL 源中的 2nd Block: Line 和 column
  • 第 3 个块: 问题的描述
  • 4th Block: 发生错误的 DRL 源(规则、函数、查询)中的组件
  • 5th Block: 在发生错误的 DRL 源中的模式(如果适用)

Red Hat Process Automation Manager 支持以下标准化错误消息:

101: 无可行替代方案

表示解析器达到决策点,但不能识别替代方案。

带有不正确的拼写错误的规则示例

1: rule "simple rule"
2:   when
3:     exists Person()
4:     exits Student()  // Must be `exists`
5:   then
6: end

错误消�

[ERR 101] Line 4:4 no viable alternative at input 'exits' in rule "simple rule"

没有规则名称的规则示例

1: package org.drools.examples;
2: rule    // Must be `rule "rule name"` (or `rule rule_name` if no spacing)
3:   when
4:     Object()
5:   then
6:     System.out.println("A RHS");
7: end

错误消�

[ERR 101] Line 3:2 no viable alternative at input 'when'

在本例中,解析器在预期预期 名称时 会遇到关键字,因此当 作为不正确的预期令牌时,它会标记。

带有不正确语法的规则示例

1: rule "simple rule"
2:   when
3:     Student( name == "Andy )  // Must be `"Andy"`
4:   then
5: end

错误消息

[ERR 101] Line 0:-1 no viable alternative at input '<eof>' in rule "simple rule" in pattern Student

注意

行和列值为 0:-1 表示解析器达到源文件的末尾(<eof&gt;),但遇到不完整的结构,通常是因为缺少引号 "…​"、apostrophes '…​' 或括号 (…​)

102: 不匹配的输入

表示解析器预期在当前输入位置中缺少的特定符号。

带有不完整 rule 语句的规则示例

1: rule simple_rule
2:   when
3:     $p : Person(
        // Must be a complete rule statement

错误消息

[ERR 102] Line 0:-1 mismatched input '<eof>' expecting ')' in rule "simple rule" in pattern Person

注意

行和列值为 0:-1 表示解析器达到源文件的末尾(<eof&gt;),但遇到不完整的结构,通常是因为缺少引号 "…​"、apostrophes '…​' 或括号 (…​)

带有不正确语法的规则示例

1: package org.drools.examples;
2:
3: rule "Wrong syntax"
4:   when
5:     not( Car( ( type == "tesla", price == 10000 ) || ( type == "kia", price == 1000 ) ) from $carList )
       // Must use `&&` operators instead of commas `,`
6:   then
7:     System.out.println("OK");
8: end

错误信�

[ERR 102] Line 5:36 mismatched input ',' expecting ')' in rule "Wrong syntax" in pattern Car
[ERR 101] Line 5:57 no viable alternative at input 'type' in rule "Wrong syntax"
[ERR 102] Line 5:106 mismatched input ')' expecting 'then' in rule "Wrong syntax"

在本例中,syntactic 问题会导致多个与彼此相关的错误消息。使用 & amp;& 运算符替换逗号的单一解决方案会解决所有错误。 如果您遇到多个错误,请一次解决,以防出现以前的错误。

103: failed predicate

表示验证语义 predicate 被评估为 false。这些语义 predicates 通常用于识别 DRL 文件中的组件关键字,如 声明规则存在 等。

带有无效关键字的规则示例

 1: package nesting;
 2:
 3: import org.drools.compiler.Person
 4: import org.drools.compiler.Address
 5:
 6: Some text  // Must be a valid DRL keyword
 7:
 8: rule "test something"
 9:   when
10:     $p: Person( name=="Michael" )
11:   then
12:     $p.name = "other";
13:     System.out.println(p.name);
14: end

错误消�

[ERR 103] Line 6:0 rule 'rule_key' failed predicate: {(validateIdentifierKey(DroolsSoftKeywords.RULE))}? in rule

有些文本行 无效,因为它没有以或不是 DRL 关键字结构的一部分,因此解析器无法验证 DRL 文件的其余部分。

注意

此错误类似于 102:不匹配的输入,但通常涉及 DRL 关键字。

104:不允许使用分号

表示规则条件中的 eval () 子句使用分号(但不得使用)。

带有 eval () 和尾部分号的规则示例

1: rule "simple rule"
2:   when
3:     eval( abc(); )  // Must not use semicolon `;`
4:   then
5: end

错误消�

[ERR 104] Line 3:4 trailing semi-colon not allowed in rule "simple rule"

105: 不与任何项匹配

表示解析器在语法中达到了一个子规则,它必须至少匹配一次,但子规则与任何规则不匹配。解析器已输入了一个分支,无需超时。

空条件中带有无效文本的规则示例

1: rule "empty condition"
2:   when
3:     None  // Must remove `None` if condition is empty
4:   then
5:      insert( new Person() );
6: end

错误消�

[ERR 105] Line 2:2 required (...)+ loop did not match anything at input 'WHEN' in rule "empty condition"

在本例中,条件应为空,但使用了 None。通过删除 None 来解决此错误,这不是有效的 DRL 关键字、数据类型或模式结构。

注意

如果您遇到无法解决的其他 DRL 错误消息,请联系您的红帽大客户经理。

14.12. DRL 规则集中的规则单元

规则单元是数据源、全局变量和 DRL 规则组,适用于特定目的。您可以使用规则单元将规则集分区为较小的单元,将不同的数据源绑定到这些单元,然后执行单个单元。规则单元是规则组 DRL 属性的增强替代方案,如规则电缆组或执行控制的激活组。

当您要协调规则执行时,规则单元很有用,以便一个规则单元的完整执行会触发另一个规则单元的开始等。例如,假设您有一组用于数据增强的规则、处理该数据的一组规则,以及从处理的数据中提取输出的另一组规则。如果将这些规则集添加到三个不同的规则单元中,您可以协调这些规则单元,以便完成第一单元的执行会触发第二个单元的开始,第二个单元的完整执行会触发第三个单元的开始。

要定义规则单元,实施 RuleUnit 接口,如下例所示:

规则单元类示例

package org.mypackage.myunit;

public static class AdultUnit implements RuleUnit {
    private int adultAge;
    private DataSource<Person> persons;

    public AdultUnit( ) { }

    public AdultUnit( DataSource<Person> persons, int age ) {
        this.persons = persons;
        this.age = age;
    }

    // A data source of `Persons` in this rule unit:
    public DataSource<Person> getPersons() {
        return persons;
    }

    // A global variable in this rule unit:
    public int getAdultAge() {
        return adultAge;
    }

    // Life-cycle methods:
    @Override
    public void onStart() {
        System.out.println("AdultUnit started.");
    }

    @Override
    public void onEnd() {
        System.out.println("AdultUnit ended.");
    }
}

在本例中,人员 是类型为 Person 的事实来源。规则单元数据源是由给定规则单元处理的数据来源,代表决策引擎用于评估规则单元的入口点。adultAge 全局变量可从属于此规则单元的所有规则访问。最后两种方法是规则单元生命周期的一部分,由决策引擎调用。

决策引擎支持以下可选生命周期方法用于规则单元:

表 14.3. 规则单元生命周期方法

方法调用的时间

onStart()

规则单元执行开始

onEnd()

规则单元执行结束

onSuspend()

规则单元执行暂停(仅用于 runUntilHalt ()

onResume()

规则单元执行会被恢复(仅用于 runUntilHalt ()

onYield (RuleUnit other)

规则单元中规则的结果会触发执行不同的规则单元

您可以在规则单元中添加一个或多个规则。默认情况下,DRL 文件中的所有规则都与遵循 DRL 文件名命名约定的规则单元自动关联。如果 DRL 文件位于同一软件包中,且名称与实现 RuleUnit 接口的类相同,则 DRL 文件中的所有规则都会隐式属于该规则单元。例如,org.mypackage.myunit 软件包中的 AdultUnit.drl 文件中的所有规则都自动是规则单元 org.mypackage.myunit.AdultUnit 的一部分。

要覆盖此命名惯例并明确声明 DRL 文件中的规则单元,请使用 DRL 文件中的 unit 关键字。单元 声明必须立即遵循 package 声明,并包含 DRL 文件中规则所属的类名称。

DRL 文件中的规则单元声明示例

package org.mypackage.myunit
unit AdultUnit

rule Adult
  when
    $p : Person(age >= adultAge) from persons
  then
    System.out.println($p.getName() + " is adult and greater than " + adultAge);
end

警告

不要混合同一 KIE 基础中的规则单元和没有规则单元。将两个规则组合在 KIE 基础中会导致编译错误。

您还可以使用 OOPath 表示法以更方便的方式重写相同的模式,如下例所示:

使用 OOPath 表示法的 DRL 文件中的规则单元声明示例

package org.mypackage.myunit
unit AdultUnit

rule Adult
  when
    $p : /persons[age >= adultAge]
  then
    System.out.println($p.getName() + " is adult and greater than " + adultAge);
end

注意

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

在本例中,规则条件中的任何匹配事实都从规则单元类的 DataSource 定义中定义的个人数据源检索。规则条件和操作使用 adultAge 变量的方式与在 DRL 文件级别上定义全局变量的方式相同。

要执行 KIE 基础中定义的一个或多个规则单元,请创建一个新的 RuleUnitExecutor 类,从相关数据源创建规则单元,并运行规则单元执行器:

规则单元执行示例

// Create a `RuleUnitExecutor` class and bind it to the KIE base:
KieBase kbase = kieContainer.getKieBase();
RuleUnitExecutor executor = RuleUnitExecutor.create().bind( kbase );

// Create the `AdultUnit` rule unit using the `persons` data source and run the executor:
RuleUnit adultUnit = new AdultUnit(persons, 18);
executor.run( adultUnit );

规则由 RuleUnitExecutor 类执行。RuleUnitExecutor 类创建 KIE 会话,并将所需的 DataSource 对象添加到这些会话中,然后根据作为参数传递给 run () 方法的 RuleUnit 执行规则。

当相关的 Person 事实插入到个人数据源中时,执行代码会生成以下输出:

规则单元执行输出示例

org.mypackage.myunit.AdultUnit started.
Jane is adult and greater than 18
John is adult and greater than 18
org.mypackage.myunit.AdultUnit ended.

您可以将规则单元变量注册到 executor 中,而是明确创建规则单元实例,并传递给 executor 运行的规则单元类,然后 executor 创建规则单元的实例。然后,您可以在运行规则单元前根据需要设置 DataSource 定义和其他变量。

带有注册变量的替代规则单元执行选项

executor.bindVariable( "persons", persons );
        .bindVariable( "adultAge", 18 );
executor.run( AdultUnit.class );

您传递给 RuleUnitExecutor.bindVariable () 方法的名称在运行时将变量绑定到规则单元类的字段,其名称具有相同名称。在上例中,RuleUnitExecutor 将数据源插入到新规则单元中,其数据源绑定到 "persons" 名称,并将绑定到 String "adultAge" 的值插入到带有 AdultUnit 类中对应名称的字段中。

要覆盖此默认 variable-binding 行为,请使用 @UnitVar 注释为规则单元类的每个字段明确定义逻辑绑定名称。例如,以下类中的字段绑定使用其他名称重新定义:

使用 @UnitVar修改变量绑定名称的代码示例

package org.mypackage.myunit;

public static class AdultUnit implements RuleUnit {
    @UnitVar("minAge")
    private int adultAge = 18;

    @UnitVar("data")
    private DataSource<Person> persons;
}

然后,您可以使用这些替代名称将变量绑定到 executor,并运行规则单元:

使用修改后的变量名称执行规则单元示例

executor.bindVariable( "data", persons );
        .bindVariable( "minAge", 18 );
executor.run( AdultUnit.class );

您可以使用 run () 方法(等同于 KIE 会话上的 fireAllRules () )或使用 runUntilHalt () 方法(等同于 KIE 会话上的 fireUntilHalt () )在 被动模式下执行 规则单元。默认情况下,决策引擎以 被动模式 运行,仅当用户或应用程序明确调用 run () (或针对标准规则的 fireAllRules () )时评估规则单元。如果用户或应用程序调用 runUntilHalt () 用于规则单元(或 fireUntilHalt () 用于标准规则),则决策引擎以 活跃模式 启动并评估规则单元,直到用户或应用程序显式调用 halt ()

如果您使用 runUntilHalt () 方法,请在单独的执行线程上调用方法以避免阻塞主线程:

在单独的线程中使用 runUntilHalt () 执行规则单元示例

new Thread( () -> executor.runUntilHalt( adultUnit ) ).start();

14.12.1. 规则单元的数据源

规则单元数据源是由给定规则单元处理的数据来源,代表决策引擎用于评估规则单元的入口点。规则单元可以有零个或更多数据源,在规则单元中声明的每个 DataSource 定义可以对应于规则单元 executor 的不同入口点。多个规则单元可以共享一个数据源,但每个规则单元都必须使用插入同一对象的不同入口点。

您可以在规则单元类中使用固定数据集合创建 DataSource 定义,如下例所示:

数据源定义示例

DataSource<Person> persons = DataSource.create( new Person( "John", 42 ),
                                                new Person( "Jane", 44 ),
                                                new Person( "Sally", 4 ) );

因为数据源代表规则单元的入口点,您可以在规则单元中插入、更新或删除事实:

在规则单元中插入、修改和删除事实的代码示例

// Insert a fact:
Person john = new Person( "John", 42 );
FactHandle johnFh = persons.insert( john );

// Modify the fact and optionally specify modified properties (for property reactivity):
john.setAge( 43 );
persons.update( johnFh, john, "age" );

// Delete the fact:
persons.delete( johnFh );

14.12.2. 规则单元执行控制

当您要协调规则执行时,规则单元很有用,以便执行一个规则单元会触发另一个规则单元的开始等。

为便于规则单元执行控制,决策引擎支持以下规则单元方法,您可以在 DRL 规则操作中使用,以协调规则单元的执行:

  • drools.run () :触发指定规则单元类的执行。这个方法有意中断规则单元的执行,并激活其他指定的规则单元。
  • drools.guard (): Prevents (guards)指定的规则单元类执行,直到满足关联的规则条件。这个方法声明性地调度其他指定规则单元的执行。当决策引擎为保护规则中的条件至少生成一个匹配项时,保护的规则单元被视为活动状态。规则单元可以包含多个保护规则。

作为 drools.run () 方法的示例,考虑每个都属于指定的规则单元的以下 DRL 规则:NotAdult 规则使用 drools.run (AdultUnit.class) 方法触发 AdultUnit 规则单元的执行:

使用 drools.run ()控制执行的 DRL 规则示例

package org.mypackage.myunit
unit AdultUnit

rule Adult
  when
    Person(age >= 18, $name : name) from persons
  then
    System.out.println($name + " is adult");
end

package org.mypackage.myunit
unit NotAdultUnit

rule NotAdult
  when
    $p : Person(age < 18, $name : name) from persons
  then
    System.out.println($name + " is NOT adult");
    modify($p) { setAge(18); }
    drools.run( AdultUnit.class );
end

这个示例还使用从这些规则构建的 KIE 基础创建的 RuleUnitExecutor 类,以及绑定到它的 人员的 DataSource 定义:

规则执行器和数据源定义示例

RuleUnitExecutor executor = RuleUnitExecutor.create().bind( kbase );
DataSource<Person> persons = executor.newDataSource( "persons",
                                                     new Person( "John", 42 ),
                                                     new Person( "Jane", 44 ),
                                                     new Person( "Sally", 4 ) );

在本例中,示例直接从 RuleUnitExecutor 类创建 DataSource 定义,并将其绑定到单个语句中的 "persons" 变量。

当相关的 Person 事实插入到个人数据源中时,执行代码会生成以下输出:

规则单元执行输出示例

Sally is NOT adult
John is adult
Jane is adult
Sally is adult

NotAdult 规则在评估人员 "Sly" 时检测到匹配项,这些人员为 18 年。然后,该规则将自己的年龄修改为 18,并使用 drools.run (AdultUnit.class) 方法触发 AdultUnit 规则单元的执行。AdultUnit 规则单元包含一个规则,现在可以为 DataSource 定义中的所有 3 个人执行该规则。

作为 drools.guard () 方法的示例,请考虑以下 BoxOffice 类和 BoxOfficeUnit 规则单元类:

BoxOffice 类示例

public class BoxOffice {
    private boolean open;

    public BoxOffice( boolean open ) {
        this.open = open;
    }

    public boolean isOpen() {
        return open;
    }

    public void setOpen( boolean open ) {
        this.open = open;
    }
}

BoxOfficeUnit 规则单元类示例

public class BoxOfficeUnit implements RuleUnit {
    private DataSource<BoxOffice> boxOffices;

    public DataSource<BoxOffice> getBoxOffices() {
        return boxOffices;
    }
}

这个示例还使用以下 TicketIssuerUnit 规则单元类来保持活动的办公室框票据,只要至少有一个框办公室处于打开状态。这个规则单元 使用 人员和 票据 数据源定义

TicketIssuerUnit 规则单元类示例

public class TicketIssuerUnit implements RuleUnit {
    private DataSource<Person> persons;
    private DataSource<AdultTicket> tickets;

    private List<String> results;

    public TicketIssuerUnit() { }

    public TicketIssuerUnit( DataSource<Person> persons, DataSource<AdultTicket> tickets ) {
        this.persons = persons;
        this.tickets = tickets;
    }

    public DataSource<Person> getPersons() {
        return persons;
    }

    public DataSource<AdultTicket> getTickets() {
        return tickets;
    }

    public List<String> getResults() {
        return results;
    }
}

BoxOfficeUnit 规则单元包含一个 BoxOfficeIsOpen DRL 规则,它使用 drools.guard (TicketIssuerUnit.class) 方法来保护执行 TicketIssuerUnit 规则单元,如以下 DRL 规则示例所示:

使用 drools.guard ()控制执行的 DRL 规则示例

package org.mypackage.myunit;
unit TicketIssuerUnit;

rule IssueAdultTicket when
    $p: /persons[ age >= 18 ]
then
    tickets.insert(new AdultTicket($p));
end
rule RegisterAdultTicket when
    $t: /tickets
then
    results.add( $t.getPerson().getName() );
end

package org.mypackage.myunit;
unit BoxOfficeUnit;

rule BoxOfficeIsOpen
  when
    $box: /boxOffices[ open ]
  then
    drools.guard( TicketIssuerUnit.class );
end

在这个示例中,只要至少有一个框办公室 处于打开状态,则保护的 TicketIssuerUnit 规则单元处于活动状态并分发事件票据。如果没有更多框 处于打开状态,则防止执行 guarded TicketIssuerUnit 规则单元。

以下示例类演示了一个更加完整的办公室场景:

框办公室情境类示例

DataSource<Person> persons = executor.newDataSource( "persons" );
DataSource<BoxOffice> boxOffices = executor.newDataSource( "boxOffices" );
DataSource<AdultTicket> tickets = executor.newDataSource( "tickets" );

List<String> list = new ArrayList<>();
executor.bindVariable( "results", list );

// Two box offices are open:
BoxOffice office1 = new BoxOffice(true);
FactHandle officeFH1 = boxOffices.insert( office1 );
BoxOffice office2 = new BoxOffice(true);
FactHandle officeFH2 = boxOffices.insert( office2 );

persons.insert(new Person("John", 40));

// Execute `BoxOfficeIsOpen` rule, run `TicketIssuerUnit` rule unit, and execute `RegisterAdultTicket` rule:
executor.run(BoxOfficeUnit.class);

assertEquals( 1, list.size() );
assertEquals( "John", list.get(0) );
list.clear();

persons.insert(new Person("Matteo", 30));

// Execute `RegisterAdultTicket` rule:
executor.run(BoxOfficeUnit.class);

assertEquals( 1, list.size() );
assertEquals( "Matteo", list.get(0) );
list.clear();

// One box office is closed, the other is open:
office1.setOpen(false);
boxOffices.update(officeFH1, office1);
persons.insert(new Person("Mark", 35));
executor.run(BoxOfficeUnit.class);

assertEquals( 1, list.size() );
assertEquals( "Mark", list.get(0) );
list.clear();

// All box offices are closed:
office2.setOpen(false);
boxOffices.update(officeFH2, office2); // Guarding rule is no longer true.
persons.insert(new Person("Edson", 35));
executor.run(BoxOfficeUnit.class); // No execution

assertEquals( 0, list.size() );

14.12.3. 规则单元身份冲突

在带有保护的规则单元的规则单元执行场景中,规则可以保护多个规则单元,并同时保护规则单元,然后由多个规则激活。对于这些双向保护场景,规则单元必须具有明确定义的身份以避免身份冲突。

默认情况下,规则单元的身份是规则单元类名称,并被视为 RuleUnitExecutor 的单例类。这种识别行为在 RuleUnit 接口的 getUnitIdentity () 默认方法中进行编码:

RuleUnit 接口中的默认身份方法

default Identity getUnitIdentity() {
    return new Identity( getClass() );
}

在某些情况下,您可能需要覆盖此默认识别行为,以避免规则单元间的冲突。

例如,以下 RuleUnit 类包含一个接受任何类型的对象的 DataSource 定义:

unit 0 规则单元类示例

public class Unit0 implements RuleUnit {
    private DataSource<Object> input;

    public DataSource<Object> getInput() {
        return input;
    }
}

此规则单元包含以下 DRL 规则,该规则根据两个条件保护另一个规则单元(在 OOPath 表示法中):

规则单元中的 GuardAgeCheck DRL 规则示例

package org.mypackage.myunit
unit Unit0

rule GuardAgeCheck
  when
    $i: /input#Integer
    $s: /input#String
  then
    drools.guard( new AgeCheckUnit($i) );
    drools.guard( new AgeCheckUnit($s.length()) );
end

已保护的 AgeCheckUnit 规则单元验证一组人的年龄。AgeCheckUnit 包含要检查的人员的 DataSource 定义、它验证的 minAge 变量,以及收集结果的列表:

AgeCheckUnit 规则单元示例

public class AgeCheckUnit implements RuleUnit {
    private final int minAge;
    private DataSource<Person> persons;
    private List<String> results;

    public AgeCheckUnit( int minAge ) {
        this.minAge = minAge;
    }

    public DataSource<Person> getPersons() {
        return persons;
    }

    public int getMinAge() {
        return minAge;
    }

    public List<String> getResults() {
        return results;
    }
}

AgeCheckUnit 规则单元包含以下 DRL 规则,该规则执行数据源中的 人员 验证:

规则单元中的 CheckAge DRL 规则示例

package org.mypackage.myunit
unit AgeCheckUnit

rule CheckAge
  when
    $p : /persons{ age > minAge }
  then
    results.add($p.getName() + ">" + minAge);
end

这个示例创建了一个 RuleUnitExecutor 类,将类绑定到包含这两个规则单元的 KIE 基础,并为同一规则单元创建两个 DataSource 定义:

executor 和数据源定义示例

RuleUnitExecutor executor = RuleUnitExecutor.create().bind( kbase );

DataSource<Object> input = executor.newDataSource( "input" );
DataSource<Person> persons = executor.newDataSource( "persons",
                                                     new Person( "John", 42 ),
                                                     new Person( "Sally", 4 ) );

List<String> results = new ArrayList<>();
executor.bindVariable( "results", results );

现在,您可以将一些对象插入到输入数据源中,并执行 unit 0 规则单元:

使用插入的对象执行规则单元示例

ds.insert("test");
ds.insert(3);
ds.insert(4);
executor.run(Unit0.class);

执行的结果列表示例

[Sally>3, John>3]

在本例中,名为 AgeCheckUnit 的规则单元被视为单例类,然后仅执行一次,minAge 变量设为 3。插入到输入数据源中的字符串 "test" 和 Integer 4 也可以触发第二个执行,并将 minAge 变量设置为 4。但是,第二个执行不会发生,因为已评估具有相同身份的另一个规则单元。

要解决此规则单元身份冲突,请覆盖 AgeCheckUnit 类的 getUnitIdentity () 方法,以便在规则单元身份中包含 minAge 变量:

修改 AgeCheckUnit 规则单元,以覆盖 getUnitIdentity () 方法

public class AgeCheckUnit implements RuleUnit {

    ...

    @Override
    public Identity getUnitIdentity() {
        return new Identity(getClass(), minAge);
    }
}

使用这个覆盖,前面的规则单元执行示例会生成以下输出:

执行修改的规则单元的结果列表示例

[John>4, Sally>3, John>3]

现在,minAge 设置为 34 的规则单元被视为两个不同的规则单元,两者都被执行。

第 15 章 数据对象

数据对象是您创建的规则资产的构建块。数据对象是在项目的指定软件包中作为 Java 对象实现的自定义数据类型。例如,您可以创建一个带有数据字段 Name, Address, 和 DateOfBirthPerson 对象,以指定 loan 应用程序规则的个人详情。这些自定义数据类型决定了您的资产和您决定服务所基于的数据。

15.1. 创建数据对象

以下流程是创建数据对象的通用概述。它不特定于特定的业务资产。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetData Object
  3. 输入唯一 数据对象 名称并选择 您希望 数据对象可用于其他规则资产的软件包。同一软件包中不能存在具有相同名称的数据对象。在指定的 DRL 文件中,您可以从任何软件包导入数据对象。

    从其他软件包导入数据对象

    您可以直接将现有数据对象从另一个软件包导入到资产设计人员,如指导规则或指导决策表设计器。选择项目中的相关规则资产和资产设计器,转至 Data Objects → New 项 以选择要导入的对象。

  4. 要使数据对象持久,请选择 Persistable 复选框。Persistable 数据对象可以根据 JPA 规范存储在数据库中。默认 JPA 是 Hibernate。
  5. 点 确定。
  6. 在数据对象设计器中,单击 add 字段,将字段添加到带有属性 Id,Label, 和 Type 的对象。所需属性被标记为星号。

    • id : 输入字段的唯一 ID。
    • label : (可选)输入字段的标签
    • type : 输入字段的数据类型。
    • 列表: (可选)选择此复选框来启用该字段为指定类型保存多个项目。

      图 15.1. 在数据对象中添加数据字段

      在数据对象中添加数据字段
  7. Create 添加新字段,或者点 Create 并继续 添加新字段,并继续添加新字段。

    注意

    要编辑字段,请选择字段行,并使用屏幕右侧的 常规属性

第 16 章 在 Business Central 中创建 DRL 规则

您可以在 Business Central 中为项目创建和管理 DRL 规则。在每个 DRL 规则文件中,您可以根据您在软件包中创建或导入的数据对象来定义与规则相关的规则条件、操作和其他组件。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetDRL file
  3. 输入信息 化 DRL 文件名 并选择适当的 软件包。您指定的软件包必须是分配所需数据对象或将被分配的软件包。

    如果在项目中定义了任何域特定语言( DSL)资产,您也可以选择 Show claim DSL 句子。这些 DSL 资产将成为您在 DRL 设计程序中定义的条件和操作的可用对象。

  4. Ok 创建规则资产。

    新的 DRL 文件现在列在 Project ExplorerDRL 面板中,如果您选择了 Show claim DSL sentences 选项,则在 DSL R 面板中列出。您为其分配此 DRL 文件的软件包列在文件的顶部。

  5. 在 DRL 设计器左侧面板中的 事实类型 列表中,确认您的规则所需的所有数据对象和数据对象字段(计算每个)都列出。如果没有,您可以使用 DRL 文件中的 import 语句从其他软件包导入相关数据 对象,或者在软件包中创建 数据对象。
  6. 所有数据对象就位后,返回到 DRL 设计器的 Model 选项卡,并使用以下任一组件定义 DRL 文件:

    DRL 文件中的组件

    package
    
    import
    
    function  // Optional
    
    query  // Optional
    
    declare   // Optional
    
    global   // Optional
    
    rule "rule name"
        // Attributes
        when
            // Conditions
        then
            // Actions
    end
    
    rule "rule2 name"
    
    ...

    • 软件包 :(自动)当您创建 DRL 文件并选择了软件包时,已为您定义。
    • import :使用它来识别来自此软件包的数据对象,或者您要在 DRL 文件中使用的其他软件包。以 packageName.objectName 格式指定软件包和数据对象,在单独的行中有多个导入。

      导入数据对象

      import org.mortgages.LoanApplication;

    • 功能 :(可选)使用它来在 DRL 文件中包括规则要使用的功能。DRL 文件中的功能将语义代码放到规则源文件中,而不是放在 Java 类中。如果重复使用规则的操作(then)部分并且只有参数因每个规则而异,则函数特别有用。在 DRL 文件中的规则之上,您可以声明函数或从帮助程序类导入静态方法作为函数,然后在规则部分操作(then)部分中使用函数。

      声明并使用规则的功能(选择 1)

      function String hello(String applicantName) {
          return "Hello " + applicantName + "!";
      }
      
      rule "Using a function"
        when
          // Empty
        then
          System.out.println( hello( "James" ) );
      end

      导入并使用规则的功能(选项 2)

      import function my.package.applicant.hello;
      
      rule "Using a function"
        when
          // Empty
        then
          System.out.println( hello( "James" ) );
      end

    • query :(可选)使用它来搜索决策引擎,以查找与 DRL 文件中规则相关的事实。您可以在 DRL 文件中添加查询定义,然后在应用程序代码中获取匹配的结果。查询搜索一组定义的条件,无需在或之后 指定 规格。查询名称对于 KIE 基础而言是全局的,因此在项目中的所有规则查询之间必须是唯一的。要返回查询的结果,请使用 ksession.get QueryResults ("name") 构建传统的 QueryResults 定义,其中 "name" 是查询名称。这会返回查询结果列表,它可让您检索与查询匹配的对象。在 DRL 文件中的规则之上定义查询和查询结果参数。

      DRL 文件中的查询定义示例

      query "people under the age of 21"
          $person : Person( age < 21 )
      end

      获取查询结果的应用程序代码示例

      QueryResults results = ksession.getQueryResults( "people under the age of 21" );
      System.out.println( "we have " + results.size() + " people under the age  of 21" );

    • 声明 :(可选)使用它来声明 DRL 文件中规则要使用的新事实类型。Red Hat Process Automation Manager 的 java.lang 软件包中的默认事实类型是 Object,但您可以根据需要在 DRL 文件中声明其他类型。在 DRL 文件中声明事实类型可让您直接在决策引擎中定义新的事实模型,而无需像 Java 一样使用较低语言创建模型。

      声明并使用新的事实类型

      declare Person
        name : String
        dateOfBirth : java.util.Date
        address : Address
      end
      
      rule "Using a declared type"
        when
          $p : Person( name == "James" )
        then   // Insert Mark, who is a customer of James.
          Person mark = new Person();
          mark.setName( "Mark" );
          insert( mark );
      end

    • 全局 :(可选)使用它来包含在 DRL 文件中规则使用的全局变量。全局变量通常为规则提供数据或服务,如规则结果中使用的应用程序服务,并从规则返回数据,如日志或规则添加的值。通过 KIE 会话配置或 REST 操作在决策引擎工作内存中设置全局值,声明 DRL 文件中的规则上面的全局变量,然后在规则的操作(然后)部分中使用它。对于多个全局变量,请使用 DRL 文件中的单独的行。

      为决策引擎设置全局列表配置

      List<String> list = new ArrayList<>();
      KieSession kieSession = kiebase.newKieSession();
      kieSession.setGlobal( "myGlobalList", list );

      在规则中定义全局列表

      global java.util.List myGlobalList;
      
      rule "Using a global"
        when
          // Empty
        then
          myGlobalList.add( "My global list" );
      end

      警告

      除非全局变量具有恒定的不可变值,否则请不要使用全局变量来建立规则中的条件。全局变量不会插入到决策引擎的工作内存中,因此决策引擎无法跟踪变量的值更改。

      不要使用全局变量在规则间共享数据。规则始终原因并响应工作内存状态,因此,如果要将数据从规则传递给规则,把数据作为事实处理到决策引擎的工作内存中。

    • 规则 :使用它来定义 DRL 文件中的每个规则。规则由格式 规则"name" 的规则组成,后跟定义规则行为(如 salienceno-loop)的可选属性,后跟 when 然后定义。每个规则都必须在 rule 软件包中具有唯一名称。规则的 when 部分包含执行操作必须满足的条件。例如,如果某个公司需要 loan applicants 的时间超过 21 年,那么 "Underage" 规则的 when 条件将是 Applicant (age < 21)。规则的 然后 部分包含在满足规则条件部分时要执行的操作。例如,当 loan applicant 旧于 21 年时,然后操作将 设为 setApproved (false),从而取消了 loan,因为 applicant 处于年龄。

      loan 应用程序年龄限制的规则

      rule "Underage"
        salience 15
        when
          $application : LoanApplication()
          Applicant( age < 21 )
        then
          $application.setApproved( false );
          $application.setExplanation( "Underage" );
      end

      至少,每个 DRL 文件必须 指定软件包导入和 规则 组件。所有其他组件都是可选的。

      以下是 loan 应用程序决策服务中的一个 DRL 文件示例:

      loan 应用程序的 DRL 文件示例

      package org.mortgages;
      
      import org.mortgages.LoanApplication;
      import org.mortgages.Bankruptcy;
      import org.mortgages.Applicant;
      
      rule "Bankruptcy history"
      	salience 10
      	when
      		$a : LoanApplication()
      		exists (Bankruptcy( yearOfOccurrence > 1990 || amountOwed > 10000 ))
      	then
      		$a.setApproved( false );
      		$a.setExplanation( "has been bankrupt" );
      		delete( $a );
      end
      
      rule "Underage"
      	salience 15
      	when
      		$application : LoanApplication()
      		Applicant( age < 21 )
      	then
      		$application.setApproved( false );
      		$application.setExplanation( "Underage" );
      		delete( $application );
      end

      图 16.1. Business Central 中 loan 应用程序的 DRL 文件示例

      带有所需组件的 DRL 文件示例
  7. 在定义了规则的所有组件后,单击 DRL 设计器右上角的 Validate 以验证 DRL 文件。如果文件验证失败,请解决错误消息中描述的任何问题,检查 DRL 文件中的所有语法和组件,然后重试验证该文件直到文件通过为止。
  8. 在 DRL Designer 中点 Save 来保存您的工作。

16.1. 在 DRL 规则中添加 WHEN 条件

规则的 when 部分包含执行操作必须满足的条件。例如,如果某个公司需要 loan applicants 的时间超过 21 年,那么 "Underage" 规则的 when 条件将是 Applicant (age < 21)。根据软件包中的可用数据对象,由一系列声明模式和约束组成,以及可选的绑定和其他支持的 DRL 元素。

先决�件

  • 软件包在 DRL 文件的顶部定义。创建该文件时,应该已为您完成此操作。
  • 规则中使用的数据对象导入 列表在 DRL 文件的 package 行下定义。数据对象可以来自此软件包,也可以来自 Business Central 中的其他软件包。
  • 规则 名称采用 软件包导入 以及其他应用到整个 DRL 文件的格式 规则"name" 定义。同一软件包中不能多次使用相同的规则名称。定义规则行为的可选规则属性(如 salienceno-loop)在 when 部分之前位于规则名称下。

�程

  1. 在 DRL 设计程序中,在规则中输入时,以开始添加条件语句。when 部分包含零个或更多事实模式,这些模式为规则定义条件。

    如果 when 部分为空,则条件被视为 true,并且首先在决策引擎中执行 fireAllRules () 调用时,将执行 部分中的操作。如果要使用规则设置决策引擎状态,这非常有用。

    没有条件的规则示例

    rule "Always insert applicant"
      when
        // Empty
      then   // Actions to be executed once
        insert( new Applicant() );
    end
    
    // The rule is internally rewritten in the following way:
    
    rule "Always insert applicant"
      when
        eval( true )
      then
        insert( new Applicant() );
    end

  2. 为要满足的第一个条件输入一个模式,带有可选约束、绑定和其他支持的 DRL 元素。基本模式格式为 < patternBinding> : <patternType> (<constraints>)。模式基于软件包中的可用数据对象,并定义要满足的条件,以便在 then 部分中触发操作。

    • 简单模式: 一个简单的模式,没有约束与给定类型的事实匹配。例如,以下条件仅存在 applicant。

      when
        Applicant()
    • 带有限制的模式 : 带有约束的模式与给定类型的事实匹配,以及括号中的额外限制,即 true 或 false。例如,以下条件是 applicant 处于 21 的年龄下。

      when
        Applicant( age < 21 )
    • 使用绑定的模式 : 对模式的绑定是一个简短参考,该规则的其他组件可用于引用定义的模式。例如,以下在 Lo a nApplication 上的绑定用于处理 applicants 的相关操作。

      when
        $a : LoanApplication()
        Applicant( age < 21 )
      then
        $a.setApproved( false );
        $a.setExplanation( "Underage" )
  3. 继续定义适用于此规则的所有条件模式。以下是定义 DRL 条件的一些关键字选项:

    • :使用此选项将条件组件分组到逻辑组合中。在fix prefix 中被支持,并被支持。默认情况下,所有列出的模式都会与 合并,如果没有指定。

      // All of the following examples are interpreted the same way:
      $a : LoanApplication() and Applicant( age < 21 )
      
      $a : LoanApplication()
      and Applicant( age < 21 )
      
      $a : LoanApplication()
      Applicant( age < 21 )
      
      (and $a : LoanApplication() Applicant( age < 21 ))
    • :使用它来将条件组件分组到逻辑分布中。在fix 和 prefix 中不被支持。

      // All of the following examples are interpreted the same way:
      Bankruptcy( amountOwed == 100000 ) or IncomeSource( amount == 20000 )
      
      Bankruptcy( amountOwed == 100000 )
      or IncomeSource( amount == 20000 )
      
      (or Bankruptcy( amountOwed == 100000 ) IncomeSource( amount == 20000 ))
    • 存在 :使用它来指定必须存在的事实和约束。这个选项仅针对第一个匹配项触发,而不在以后的匹配项上触发。如果您将此元素与多种模式一起使用,请将模式与括号 () 括起来。

      exists ( Bankruptcy( yearOfOccurrence > 1990 || amountOwed > 10000 ) )
    • Not: 使用此选项指定不能存在的事实和约束。

      not ( Applicant( age < 21 ) )
    • forall :使用它来验证与第一个模式匹配的所有事实是否与所有剩余的模式匹配。当满足 forall 结构时,该规则将评估为 true

      forall( $app : Applicant( age < 21 )
                    Applicant( this == $app, status = 'underage' ) )
    • from :使用它来为模式指定数据源。

      Applicant( ApplicantAddress : address )
      Address( zipcode == "23920W" ) from ApplicantAddress
    • entry-point :使用它来定义与模式的数据源对应的条目 。通常使用 from 中的。

      Applicant() from entry-point "LoanApplication"
    • collect :使用它来定义规则可作为条件的一部分使用的对象集合。在示例中,每个给定月的决策引擎中的所有待处理应用程序都在一个 List 中分组。如果找到三个或更多待处理应用程序,则执行该规则。

      $m : Mortgage()
      $a : List( size >= 3 )
          from collect( LoanApplication( Mortgage == $m, status == 'pending' ) )
    • 累积 :使用它来迭代对象集合,为每个元素执行自定义操作,并返回一个或多个结果对象(如果约束评估为 true)。此选项是一种更灵活且强大的 收集 形式。使用格式 cate (<source pattern>; <functions> [;<constraints>])。在示例中,minmaxaverage 是在计算每个传感器的所有读取值的最小、最大值和平均温度值的功能。其他支持的功能包括 count,sum,variance,standardDeviation,collectList, 和 collectSet

      $s : Sensor()
      accumulate( Reading( sensor == $s, $temp : temperature );
                  $min : min( $temp ),
                  $max : max( $temp ),
                  $avg : average( $temp );
                  $min < 20, $avg > 70 )
    注意

    有关 DRL 规则条件的更多信息,请参阅 第 14.8 节 “DRL (WHEN)中的规则条件”

  4. 在定义了规则的所有条件组件后,单击 DRL 设计器右上角的 Validate 以验证 DRL 文件。如果文件验证失败,请解决错误消息中描述的任何问题,检查 DRL 文件中的所有语法和组件,然后重试验证该文件直到文件通过为止。
  5. 在 DRL Designer 中点 Save 来保存您的工作。

16.2. 在 DRL 规则中添加 THEN 操作

规则的 然后 部分包含在满足规则条件部分时要执行的操作。例如,当 loan applicant 旧于 21 年时,"Underage" 规则的 then 操作会被 设置Approved (false),从而 取消了 loan,因为 applicant 处于年龄下。操作由一个或多个根据规则条件和软件包中可用数据对象执行结果的方法组成。规则操作的主要用途是在决策引擎工作内存中插入、删除或修改数据。

先决条件

  • 软件包在 DRL 文件的顶部定义。创建该文件时,应该已为您完成此操作。
  • 规则中使用的数据对象导入 列表在 DRL 文件的 package 行下定义。数据对象可以来自此软件包,也可以来自 Business Central 中的其他软件包。
  • 规则 名称采用 软件包导入 以及其他应用到整个 DRL 文件的格式 规则"name" 定义。同一软件包中不能多次使用相同的规则名称。定义规则行为的可选规则属性(如 salienceno-loop)在 when 部分之前位于规则名称下。

�程

  1. 在 DRL 设计程序中 在规则的 when 部分输入,以开始添加操作语句。
  2. 根据规则的条件,输入要针对事实模式执行的一个或多个操作。

    以下是定义 DRL 操作的一些关键字选项:

    • 设置 :使用它来设置字段的值。

      $application.setApproved ( false );
      $application.setExplanation( "has been bankrupt" );
    • 修改 :使用此选项指定为事实修改的字段,并通知决策引擎的变化。这个方法提供了事实更新的结构化方法。它将 更新操作 与 setter 调用相结合,以更改对象字段。

      modify( LoanApplication ) {
              setAmount( 100 ),
              setApproved ( true )
      }
    • 更新 :使用此选项指定要更新的字段和整个相关事实,并通知决策引擎更改。更改事实后,您必须调用 更新,然后才能更改可能受到更新的值影响的另一个事实。要避免此添加的步骤,请使用 modify 方法。

      LoanApplication.setAmount( 100 );
      update( LoanApplication );
    • 插入 :使用此将新事实插入到决策引擎中。

      insert( new Applicant() );
    • insertLogical :使用它来以逻辑方式 将新的 事实插入到决策引擎中。决策引擎负责对事实的插入和重包进行逻辑决策。常规或声明的插入后,必须明确回收事实。逻辑插入后,插入的事实会在插入事实的规则中的条件不再满足满足时自动响应。

      insertLogical( new Applicant() );
    • 删除 :使用它来从决策引擎中删除对象。DRL 还支持关键字 retract 并执行相同的操作,但 删除 通常在 DRL 代码中首选,以便与关键字 插入 保持一致。

      delete( Applicant );
    注意

    有关 DRL 规则操作的详情,请参考 第 14.9 节 “DRL 中的规则操作(THEN)”

  3. 在定义了规则的所有操作组件后,单击 DRL 设计器右上角的 Validate 以验证 DRL 文件。如果文件验证失败,请解决错误消息中描述的任何问题,检查 DRL 文件中的所有语法和组件,然后重试验证该文件直到文件通过为止。
  4. 在 DRL Designer 中点 Save 来保存您的工作。

第 17 章 执行规则

在 Business Central 中识别示例规则或创建自己的规则后,您可以构建和部署关联的项目,并在 KIE 服务器上执行规则来测试规则。

先决�件

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. 在项目 资产 页面右上角,点 Deploy 以构建项目并将其部署到 KIE Server。如果构建失败,请解决屏幕底部的 Alerts 面板中描述的任何问题。

    有关项目部署选项的更多信息,请参阅 打包和部署 Red Hat Process Automation Manager 项目

    注意

    如果项目中的规则资产默认没有从可执行文件规则模型构建,请验证以下依赖项是否在项目的 pom.xml 文件中,并重建项目:

    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-model-compiler</artifactId>
      <version>${rhpam.version}</version>
    </dependency>

    默认情况下,Red Hat Process Automation Manager 中的规则资产需要此依赖项。此依赖项作为 Red Hat Process Automation Manager 核心打包的一部分包括,但取决于您的 Red Hat Process Automation Manager 升级历史记录,您可能需要手动添加此依赖项来启用可执行的规则模型行为。

    有关可执行规则模型的更多信息,请参阅 打包和部署 Red Hat Process Automation Manager 项目

  3. 在 Business Central 外部创建一个 Maven 或 Java 项目(如果尚未创建),您可以使用它在本地执行规则,或者作为客户端应用程序在 KIE 服务器上执行规则。该项目必须包含 pom.xml 文件和执行项目资源的任何其他必要的组件。

    有关 test 项目示例,请参阅 "创建和执行 DRL 规则的方法 "。

  4. 打开 test 项目或客户端应用程序的 pom.xml 文件,如果还没有添加以下依赖项:

    • kie-ci :使客户端应用程序能够使用 ReleaseId在本地加载 Business Central 项目数据
    • kie-server-client :启用客户端应用程序与 KIE 服务器上的资产远程交互
    • slf4j :(可选)使客户端应用程序能够使用简单日志记录 Facade for Java (SLF4J)在与 KIE 服务器交互后返回调试日志信息

    客户端应用程序 pom.xml 文件中的 Red Hat Process Automation Manager 7.9 的依赖项示例:

    <!-- For local execution -->
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-ci</artifactId>
      <version>7.44.0.Final-redhat-00006</version>
    </dependency>
    
    <!-- For remote execution on KIE Server -->
    <dependency>
      <groupId>org.kie.server</groupId>
      <artifactId>kie-server-client</artifactId>
      <version>7.44.0.Final-redhat-00006</version>
    </dependency>
    
    <!-- For debug logging (optional) -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-simple</artifactId>
      <version>1.7.25</version>
    </dependency>

    如需这些工件的可用版本,请在线搜索 Nexus Repository Manager 中的组 ID 和工件 ID。

    注意

    考虑将 Red Hat Business Automation Manager (BOM)依赖项添加到项目 pom.xml 文件,而不是为单个依赖项指定 Red Hat Process Automation Manager < version >。Red Hat Business Automation BOM 适用于 Red Hat Decision Manager 和 Red Hat Process Automation Manager。当您添加 BOM 文件时,项目中包含了来自提供的 Maven 存储库传输性依赖关系的正确版本。

    BOM 依赖项示例:

    <dependency>
      <groupId>com.redhat.ba</groupId>
      <artifactId>ba-platform-bom</artifactId>
      <version>7.9.1.redhat-00003</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>

    有关 Red Hat Business Automation BOM 的更多信息,请参阅 Red Hat Process Automation Manager 和 Maven 库版本之间的映射是什么?

  5. 确保包含模型类的工件的依赖项在客户端应用程序 pom.xml 文件中定义,因为它们出现在部署的项目的 pom.xml 文件中。如果模型类的依赖项因客户端应用程序和项目而异,则可能会出现执行错误。

    要访问 Business Central 中的项目 pom.xml 文件,请选择项目中的任何现有资产,然后在屏幕左侧的 Project Explorer 菜单中点击 Customize View gear 图标并选择 Repository Viewpom.xml

    例如,以下 Person 类依赖项同时出现在客户端和部署的项目 pom.xml 文件中:

    <dependency>
      <groupId>com.sample</groupId>
      <artifactId>Person</artifactId>
      <version>1.0.0</version>
    </dependency>
  6. 如果您在用于调试日志的客户端应用程序 pom.xml 文件中添加 slf4j 依赖项,请在相关 classpath 上 创建一个简单的logger.properties 文件(例如,在 Maven 中的 src/main/resources/META-INF 中),其中包含以下内容:

    org.slf4j.simpleLogger.defaultLogLevel=debug
  7. 在客户端应用程序中,创建一个包含必要的导入和 main () 方法的 .java 主类,来加载 KIE 基础、插入事实和执行规则。

    例如,项目中的 Person 对象包含 getter 和 setter 方法,用于设置和检索名字、姓氏、每小时率以及个人的 wage。项目中的以下 Wage 规则计算 wage 和每小时速率值,并根据结果显示一条消息:

    package com.sample;
    
    import com.sample.Person;
    
    dialect "java"
    
    rule "Wage"
      when
        Person(hourlyRate * wage > 100)
        Person(name : firstName, surname : lastName)
      then
        System.out.println("Hello" + " " + name + " " + surname + "!");
        System.out.println("You are rich!");
    end

    要在 KIE 服务器之外测试此规则(如果需要),请将 .java 类配置为导入 KIE 服务、KIE 容器和 KIE 会话,然后使用 main () 方法根据定义的事实模型触发所有规则:

    本地执行规则

    import org.kie.api.KieServices;
    import org.kie.api.builder.ReleaseId;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    import org.drools.compiler.kproject.ReleaseIdImpl;
    
    public class RulesTest {
    
      public static final void main(String[] args) {
        try {
          // Identify the project in the local repository:
          ReleaseId rid = new ReleaseIdImpl("com.myspace", "MyProject", "1.0.0");
    
          // Load the KIE base:
          KieServices ks = KieServices.Factory.get();
          KieContainer kContainer = ks.newKieContainer(rid);
          KieSession kSession = kContainer.newKieSession();
    
          // Set up the fact model:
          Person p = new Person();
          p.setWage(12);
          p.setFirstName("Tom");
          p.setLastName("Summers");
          p.setHourlyRate(10);
    
          // Insert the person into the session:
          kSession.insert(p);
    
          // Fire all rules:
          kSession.fireAllRules();
          kSession.dispose();
        }
    
        catch (Throwable t) {
          t.printStackTrace();
        }
      }
    }

    要在 KIE 服务器上测试此规则,请使用导入和规则执行信息配置 .java 类,以及指定 KIE 服务配置和 KIE 服务客户端详情:

    在 KIE 服务器上执行规则

    package com.sample;
    
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    import org.kie.api.command.BatchExecutionCommand;
    import org.kie.api.command.Command;
    import org.kie.api.KieServices;
    import org.kie.api.runtime.ExecutionResults;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    import org.kie.server.api.marshalling.MarshallingFormat;
    import org.kie.server.api.model.ServiceResponse;
    import org.kie.server.client.KieServicesClient;
    import org.kie.server.client.KieServicesConfiguration;
    import org.kie.server.client.KieServicesFactory;
    import org.kie.server.client.RuleServicesClient;
    
    import com.sample.Person;
    
    public class RulesTest {
    
      private static final String containerName = "testProject";
      private static final String sessionName = "myStatelessSession";
    
      public static final void main(String[] args) {
        try {
          // Define KIE services configuration and client:
          Set<Class<?>> allClasses = new HashSet<Class<?>>();
          allClasses.add(Person.class);
          String serverUrl = "http://$HOST:$PORT/kie-server/services/rest/server";
          String username = "$USERNAME";
          String password = "$PASSWORD";
          KieServicesConfiguration config =
            KieServicesFactory.newRestConfiguration(serverUrl,
                                                    username,
                                                    password);
          config.setMarshallingFormat(MarshallingFormat.JAXB);
          config.addExtraClasses(allClasses);
          KieServicesClient kieServicesClient =
            KieServicesFactory.newKieServicesClient(config);
    
          // Set up the fact model:
          Person p = new Person();
          p.setWage(12);
          p.setFirstName("Tom");
          p.setLastName("Summers");
          p.setHourlyRate(10);
    
          // Insert Person into the session:
          KieCommands kieCommands = KieServices.Factory.get().getCommands();
          List<Command> commandList = new ArrayList<Command>();
          commandList.add(kieCommands.newInsert(p, "personReturnId"));
    
          // Fire all rules:
          commandList.add(kieCommands.newFireAllRules("numberOfFiredRules"));
          BatchExecutionCommand batch = kieCommands.newBatchExecution(commandList, sessionName);
    
          // Use rule services client to send request:
          RuleServicesClient ruleClient = kieServicesClient.getServicesClient(RuleServicesClient.class);
          ServiceResponse<ExecutionResults> executeResponse = ruleClient.executeCommandsWithResults(containerName, batch);
          System.out.println("number of fired rules:" + executeResponse.getResult().getValue("numberOfFiredRules"));
        }
    
        catch (Throwable t) {
          t.printStackTrace();
        }
      }
    }

  8. 从项目目录运行配置的 .java 类。您可以在开发平台(如 Red Hat CodeReady Studio)或命令行中运行该文件。

    Maven 执行示例(带有项目目录):

    mvn clean install exec:java -Dexec.mainClass="com.sample.app.RulesTest"

    Java 执行示例(使用项目目录)

    javac -classpath "./$DEPENDENCIES/*:." RulesTest.java
    java -classpath "./$DEPENDENCIES/*:." RulesTest
  9. 在命令行和服务器日志中查看规则执行状态。如果有任何规则没有如预期执行,请查看项目中配置的规则和主类配置以验证所提供的数据。

第 18 章 创建和执行 DRL 规则的其他方法

作为在 Business Central 界面中创建和管理 DRL 规则的替代选择,您可以使用 Red Hat CodeReady Studio 或其他集成开发环境(IDE)在外部创建 DRL 规则文件。然后,这些独立项目可以作为 Business Central 中现有 Red Hat Process Automation Manager 项目中的知识 JAR (KJAR)依赖项集成。独立项目中的 DRL 文件必须至少包含 所需的软件包 规格、导入 列表和 规则定义。任何其它 DRL 组件(如全局变量和功能)都是可选的。与 DRL 规则相关的所有数据对象都必须包含在您的独立 DRL 项目或部署中。

您还可以使用 Maven 或 Java 项目中的可执行规则模型为构建时执行的规则提供基于 Java 的表示。可执行模型是 Red Hat Process Automation Manager 中打包的标准资产更高效的替代,并允许更快速创建 KIE 容器和 KIE 基础,特别是在具有大量 DRL (Drools Rule Language)文件和其他 Red Hat Process Automation Manager 资产列表时。

18.1. 在 Red Hat CodeReady Studio 中创建并执行 DRL 规则

您可以使用 Red Hat CodeReady Studio 创建带有规则的 DRL 文件,并将文件与 Red Hat Process Automation Manager 决策服务集成。如果您已将 Red Hat CodeReady Studio 用于决定服务并希望使用相同的工作流,则创建 DRL 规则的方法非常有用。如果您还没有使用这个方法,则建议创建 DRL 文件和其他规则资产,建议使用 Red Hat Process Automation Manager 的 Business Central 接口。

先决条件

流程

  1. 在 Red Hat CodeReady Studio 中,点击 FileNewProject
  2. 在打开的 New Project 窗口中,选择 dols → d Project 并点 Next
  3. 单击第二个图标,以 创建一个项目,并将它填充一些示例文件,以帮助您快速开始。点 Next
  4. 输入项目名称 并选择 Maven 单选按钮作为项目构建选项。GAV 值会自动生成。您可以根据项目的要求更新这些值:

    • 组 ID: com.sample
    • 工件 ID: my-project
    • Version: 1.0.0-SNAPSHOT
  5. Finish 以创建该项目。

    此配置设置基本项目结构、类路径和示例规则。以下是项目结构的概述:

    my-project
     `-- src/main/java
        | `-- com.sample
        |    `-- DecisionTableTest.java
        |    `-- DroolsTest.java
        |    `-- ProcessTest.java
        |
     `-- src/main/resources
        | `-- dtables
        |    `-- Sample.xls
        | `-- process
        |    `-- sample.bpmn
        | `-- rules
        |    `-- Sample.drl
        | `-- META-INF
        |
     `-- JRE System Library
        |
     `-- Maven Dependencies
        |
     `-- Drools Library
        |
     `-- src
        |
     `-- target
        |
     `-- pom.xml

    请注意以下元素:

    • src/main/resources 目录中的 Sample.drl 规则文件,包含 Hello WorldGoodBye 规则示例。
    • com .sample 软件包中的 src/main/java 目录下的 droolsTest.java 文件。drools 测试类可用于执行 Sample.drl 规则。
    • dr oy 库 目录,它充当包含执行所需的 JAR 文件的自定义类路径。

    您可以根据需要,使用新配置编辑现有的 Sample.drl 文件和 DroolsTest.java 文件,或者创建新规则和对象文件。在此过程中,您要创建新规则和新的 Java 对象。

  6. 创建一个 Java 对象,该规则或规则将在其上操作。

    在本例中,在 my-project/src/main/java/com.sample 中创建 Person.java 文件。Person 类包含 getter 和 setter 方法,用于设置和检索名字、姓氏、每小时率以及人的 wage:

      public class Person {
        private String firstName;
        private String lastName;
        private Integer hourlyRate;
        private Integer wage;
    
        public String getFirstName() {
          return firstName;
        }
    
        public void setFirstName(String firstName) {
          this.firstName = firstName;
        }
    
        public String getLastName() {
          return lastName;
        }
    
        public void setLastName(String lastName) {
          this.lastName = lastName;
        }
    
        public Integer getHourlyRate() {
          return hourlyRate;
        }
    
        public void setHourlyRate(Integer hourlyRate) {
          this.hourlyRate = hourlyRate;
        }
    
        public Integer getWage(){
          return wage;
        }
    
        public void setWage(Integer wage){
          this.wage = wage;
        }
      }
  7. FileSave 保存文件。
  8. my-project/src/main/resources/rules 格式创建一个规则文件。 DRL 文件必须至少包含软件包规格、规则或规则要使用的数据对象导入列表,以及一个或多个带有 when 条件的规则。

    以下 Wage.drl 文件包含 Wage 规则,用于导入 Person 类,计算 wage 和每小时速率值,并根据结果显示一个信息:

    package com.sample;
    
    import com.sample.Person;
    
    dialect "java"
    
    rule "Wage"
      when
        Person(hourlyRate * wage > 100)
        Person(name : firstName, surname : lastName)
      then
        System.out.println("Hello" + " " + name + " " + surname + "!");
        System.out.println("You are rich!");
    end
  9. FileSave 保存文件。
  10. 创建主类并将其保存到与您创建的 Java 对象相同的目录中。主类将加载 KIE 基础并执行规则。

    注意

    您还可以在单个 Java 对象文件中添加 main () 方法和 Person 类,类似于 dols Test.java 示例文件。

  11. 在主类中,添加所需的 导入 语句来导入 KIE 服务、KIE 容器和 KIE 会话。然后,加载 KIE 基础、插入事实,并从 main () 方法执行规则,将事实模型传递给规则。

    在本例中,使用所需的导入和 main () 方法在 my-project/src/main/java/com.sample 中创建 RulesTest.java 文件:

    package com.sample;
    
    import org.kie.api.KieServices;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    
    public class RulesTest {
      public static final void main(String[] args) {
        try {
          // Load the KIE base:
          KieServices ks = KieServices.Factory.get();
          KieContainer kContainer = ks.getKieClasspathContainer();
          KieSession kSession = kContainer.newKieSession();
    
          // Set up the fact model:
          Person p = new Person();
          p.setWage(12);
          p.setFirstName("Tom");
          p.setLastName("Summers");
          p.setHourlyRate(10);
    
          // Insert the person into the session:
          kSession.insert(p);
    
          // Fire all rules:
          kSession.fireAllRules();
          kSession.dispose();
        }
    
        catch (Throwable t) {
          t.printStackTrace();
        }
      }
    }
  12. FileSave 保存文件。
  13. 在项目中创建并保存所有 DRL 资产后,右键单击项目文件夹并选择 Run AsJava Application 以构建项目。如果项目构建失败,请解决 CodeReady Studio 中下窗口的 Problems 选项卡中描述的任何问题,然后重试验证项目,直到项目构建为止。
如果 Run AsJava Application 选项不可用

如果您右键点击项目并选择 Run As,然后进入 Run AsRun Configuration,请右键点击 Java Application ,然后点击 New。然后,在主 选项卡中,浏览并选择 您的项目 和相关 主类。点 Apply,然后点 Run 来测试该项目。下次右键点击项目文件夹时,将显示 Java Application 选项。

要将新规则资产与 Red Hat Process Automation Manager 中的现有项目集成,您可以将新项目编译为知识 JAR (KJAR),并将它作为依赖项添加到 Business Central 中项目的 pom.xml 文件中。要访问 Business Central 中的项目 pom.xml 文件,您可以在屏幕左侧的 Project Explorer 菜单中选择任何现有资产,然后点击 Customize View gear 图标并选择 Repository Viewpom.xml

18.2. 使用 Java 创建并执行 DRL 规则

您可以使用 Java 对象创建带有规则的 DRL 文件,并将对象与 Red Hat Process Automation Manager 决策服务集成。如果您已将外部 Java 对象用于决定服务并希望继续相同的工作流,则创建 DRL 规则的方法非常有用。如果您还没有使用这个方法,则建议创建 DRL 文件和其他规则资产,建议使用 Red Hat Process Automation Manager 的 Business Central 接口。

�程

  1. 创建一个 Java 对象,该规则或规则将在其上操作。

    在本例中,在 my-project 目录中创建 Person.java 文件。Person 类包含 getter 和 setter 方法,用于设置和检索名字、姓氏、每小时率以及人的 wage:

      public class Person {
        private String firstName;
        private String lastName;
        private Integer hourlyRate;
        private Integer wage;
    
        public String getFirstName() {
          return firstName;
        }
    
        public void setFirstName(String firstName) {
          this.firstName = firstName;
        }
    
        public String getLastName() {
          return lastName;
        }
    
        public void setLastName(String lastName) {
          this.lastName = lastName;
        }
    
        public Integer getHourlyRate() {
          return hourlyRate;
        }
    
        public void setHourlyRate(Integer hourlyRate) {
          this.hourlyRate = hourlyRate;
        }
    
        public Integer getWage(){
          return wage;
        }
    
        public void setWage(Integer wage){
          this.wage = wage;
        }
      }
  2. my-project 目录下,以 .drl 格式创建一个规则文件。DRL 文件必须至少包含软件包规格(如果适用),规则或规则要使用的数据对象导入列表,以及一个或多个带有 when 条件的规则。

    以下 Wage.drl 文件包含 Wage 规则,该规则计算 wage 和每小时速率值,并根据结果显示一条消息:

    package com.sample;
    
    import com.sample.Person;
    
    dialect "java"
    
    rule "Wage"
      when
        Person(hourlyRate * wage > 100)
        Person(name : firstName, surname : lastName)
      then
        System.out.println("Hello" + " " + name + " " + surname + "!");
        System.out.println("You are rich!");
    end
  3. 创建主类并将其保存到与您创建的 Java 对象相同的目录中。主类将加载 KIE 基础并执行规则。
  4. 在主类中,添加所需的 导入 语句来导入 KIE 服务、KIE 容器和 KIE 会话。然后,加载 KIE 基础、插入事实,并从 main () 方法执行规则,将事实模型传递给规则。

    在本例中,使用所需的导入和 main () 方法在 my-project 中创建 RulesTest.java 文件:

    import org.kie.api.KieServices;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    
    public class RulesTest {
      public static final void main(String[] args) {
        try {
          // Load the KIE base:
          KieServices ks = KieServices.Factory.get();
          KieContainer kContainer = ks.getKieClasspathContainer();
          KieSession kSession = kContainer.newKieSession();
    
          // Set up the fact model:
          Person p = new Person();
          p.setWage(12);
          p.setFirstName("Tom");
          p.setLastName("Summers");
          p.setHourlyRate(10);
    
          // Insert the person into the session:
          kSession.insert(p);
    
          // Fire all rules:
          kSession.fireAllRules();
          kSession.dispose();
        }
    
        catch (Throwable t) {
          t.printStackTrace();
        }
      }
    }
  5. 从红帽客户门户下载 Red Hat Process Automation Manager 7.9.1 Source Distribution ZIP 文件,并将它提取到 my-project/pam-engine-jars/ 下。
  6. my-project/META-INF 目录中,创建一个包含以下内容的 kmodule.xml 元数据文件:

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

    kmodule.xml 文件是一个 KIE 模块描述符,用于选择 KIE 基础并配置会话的资源。此文件允许您定义和配置一个或多个 KIE 基础,并在特定 KIE 基础中包含 特定软件包 中的 DRL 文件。您还可以从每个 KIE 基础创建一个或多个 KIE 会话。

    以下示例显示了更高级的 kmodule.xml 文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <kmodule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.drools.org/xsd/kmodule">
      <kbase name="KBase1" default="true" eventProcessingMode="cloud" equalsBehavior="equality" declarativeAgenda="enabled" packages="org.domain.pkg1">
        <ksession name="KSession1_1" type="stateful" default="true" />
        <ksession name="KSession1_2" type="stateful" default="true" beliefSystem="jtms" />
      </kbase>
      <kbase name="KBase2" default="false" eventProcessingMode="stream" equalsBehavior="equality" declarativeAgenda="enabled" packages="org.domain.pkg2, org.domain.pkg3" includes="KBase1">
        <ksession name="KSession2_1" type="stateless" default="true" clockType="realtime">
          <fileLogger file="debugInfo" threaded="true" interval="10" />
          <workItemHandlers>
            <workItemHandler name="name" type="new org.domain.WorkItemHandler()" />
          </workItemHandlers>
          <listeners>
            <ruleRuntimeEventListener type="org.domain.RuleRuntimeListener" />
            <agendaEventListener type="org.domain.FirstAgendaListener" />
            <agendaEventListener type="org.domain.SecondAgendaListener" />
            <processEventListener type="org.domain.ProcessListener" />
          </listeners>
        </ksession>
      </kbase>
    </kmodule>

    这个示例定义了两个 KIE 基础。两个 KIE 会话是从 KBase1 KIE 基础实例化的,来自 KBase2 的 KIE 会话。KBase2 中的 KIE 会话是一个 无状态 KIE 会话,这意味着之前调用 KIE 会话(之前会话状态)的数据在会话调用之间被丢弃。KIE 基础中包含特定规则资产 软件包。当以这种方式指定软件包时,您必须将 DRL 文件组织为反映指定软件包的文件夹结构。

  7. 在 Java 对象中创建并保存所有 DRL 资产后,在命令行中导航到 my-project 目录,并运行以下命令来构建您的 Java 文件。将 RulesTest.java 替换为 Java 主类的名称。

    javac -classpath "./pam-engine-jars/*:." RulesTest.java

    如果构建失败,请解决命令行错误消息中描述的任何问题,并尝试验证 Java 对象,直到对象通过为止。

  8. 在 Java 文件构建成功后,运行以下命令在本地执行规则。将 RulesTest 替换为 Java 主类的前缀。

    java -classpath "./pam-engine-jars/*:." RulesTest
  9. 检查规则以确保它们正确执行,并解决 Java 文件中所需的更改。

要将新规则资产与 Red Hat Process Automation Manager 中的现有项目集成,您可以将新的 Java 项目编译为 知识 JAR (KJAR),并将它作为依赖项添加到 Business Central 中项目的 pom.xml 文件中。要访问 Business Central 中的项目 pom.xml 文件,您可以在屏幕左侧的 Project Explorer 菜单中选择任何现有资产,然后点击 Customize View gear 图标并选择 Repository Viewpom.xml

18.3. 使用 Maven 创建并执行 DRL 规则

您可以使用 Maven 架构类型创建带有规则的 DRL 文件,并将 archetypes 与 Red Hat Process Automation Manager 决策服务集成。如果您已将外部 Maven archetypes 用于决策服务并希望继续相同的工作流,则创建 DRL 规则的方法非常有用。如果您还没有使用这个方法,则建议创建 DRL 文件和其他规则资产,建议使用 Red Hat Process Automation Manager 的 Business Central 接口。

�程

  1. 进入您要创建 Maven 架构类型的目录,并运行以下命令:

    mvn archetype:generate -DgroupId=com.sample.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

    这会创建一个具有以下结构的目录 my-app

    my-app
    |-- pom.xml
    `-- src
        |-- main
        |   `-- java
        |       `-- com
        |           `-- sample
        |               `-- app
        |                   `-- App.java
        `-- test
            `-- java
                `-- com
                    `-- sample
                        `-- app
                            `-- AppTest.java

    my-app 目录包含以下关键组件:

    • 用于存储应用程序源的 src/main 目录
    • 用于存储测试源的 src/test 目录
    • 带有项目配置的 pom.xml 文件
  2. 创建一个 Java 对象,该规则或规则将在 Maven archetype 中操作。

    在本例中,在 my-app/src/main/java/com/sample/app 目录中创建一个 Person.java 文件。Person 类包含 getter 和 setter 方法,用于设置和检索名字、姓氏、每小时率以及人的 wage:

    package com.sample.app;
    
      public class Person {
    
        private String firstName;
        private String lastName;
        private Integer hourlyRate;
        private Integer wage;
    
        public String getFirstName() {
          return firstName;
        }
    
        public void setFirstName(String firstName) {
          this.firstName = firstName;
        }
    
        public String getLastName() {
          return lastName;
        }
    
        public void setLastName(String lastName) {
          this.lastName = lastName;
        }
    
        public Integer getHourlyRate() {
          return hourlyRate;
        }
    
        public void setHourlyRate(Integer hourlyRate) {
          this.hourlyRate = hourlyRate;
        }
    
        public Integer getWage(){
          return wage;
        }
    
        public void setWage(Integer wage){
          this.wage = wage;
        }
      }
  3. my-app/src/main/resources/rules 格式创建一个规则文件。 DRL 文件必须至少包含软件包规格、规则或规则要使用的数据对象导入列表,以及一个或多个带有 when 条件的规则。

    以下 Wage.drl 文件包含 Wage 规则,用于导入 Person 类,计算 wage 和每小时速率值,并根据结果显示一个信息:

    package com.sample.app;
    
    import com.sample.app.Person;
    
    dialect "java"
    
    rule "Wage"
      when
        Person(hourlyRate * wage > 100)
        Person(name : firstName, surname : lastName)
      then
        System.out.println("Hello " + name + " " + surname + "!");
        System.out.println("You are rich!");
    end
  4. my-app/src/main/resources/META-INF 目录中,创建一个包含以下内容的 kmodule.xml 元数据文件:

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

    kmodule.xml 文件是一个 KIE 模块描述符,用于选择 KIE 基础并配置会话的资源。此文件允许您定义和配置一个或多个 KIE 基础,并在特定 KIE 基础中包含 特定软件包 中的 DRL 文件。您还可以从每个 KIE 基础创建一个或多个 KIE 会话。

    以下示例显示了更高级的 kmodule.xml 文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <kmodule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.drools.org/xsd/kmodule">
      <kbase name="KBase1" default="true" eventProcessingMode="cloud" equalsBehavior="equality" declarativeAgenda="enabled" packages="org.domain.pkg1">
        <ksession name="KSession1_1" type="stateful" default="true" />
        <ksession name="KSession1_2" type="stateful" default="true" beliefSystem="jtms" />
      </kbase>
      <kbase name="KBase2" default="false" eventProcessingMode="stream" equalsBehavior="equality" declarativeAgenda="enabled" packages="org.domain.pkg2, org.domain.pkg3" includes="KBase1">
        <ksession name="KSession2_1" type="stateless" default="true" clockType="realtime">
          <fileLogger file="debugInfo" threaded="true" interval="10" />
          <workItemHandlers>
            <workItemHandler name="name" type="new org.domain.WorkItemHandler()" />
          </workItemHandlers>
          <listeners>
            <ruleRuntimeEventListener type="org.domain.RuleRuntimeListener" />
            <agendaEventListener type="org.domain.FirstAgendaListener" />
            <agendaEventListener type="org.domain.SecondAgendaListener" />
            <processEventListener type="org.domain.ProcessListener" />
          </listeners>
        </ksession>
      </kbase>
    </kmodule>

    这个示例定义了两个 KIE 基础。两个 KIE 会话是从 KBase1 KIE 基础实例化的,来自 KBase2 的 KIE 会话。KBase2 中的 KIE 会话是一个 无状态 KIE 会话,这意味着之前调用 KIE 会话(之前会话状态)的数据在会话调用之间被丢弃。KIE 基础中包含特定规则资产 软件包。当以这种方式指定软件包时,您必须将 DRL 文件组织为反映指定软件包的文件夹结构。

  5. my-app/pom.xml 配置文件中,指定应用程序所需的库。提供 Red Hat Process Automation Manager 依赖项以及应用程序 的组ID、工件 ID 和版本 (GAV)。

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.sample.app</groupId>
    <artifactId>my-app</artifactId>
    <version>1.0.0</version>
    <repositories>
      <repository>
        <id>jboss-ga-repository</id>
        <url>http://maven.repository.redhat.com/ga/</url>
      </repository>
    </repositories>
    <dependencies>
      <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-compiler</artifactId>
        <version>VERSION</version>
      </dependency>
      <dependency>
        <groupId>org.kie</groupId>
        <artifactId>kie-api</artifactId>
        <version>VERSION</version>
      </dependency>
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
      </dependency>
    </dependencies>
    </project>

    有关 Red Hat Process Automation Manager 中的 Maven 依赖项和 BOM (Bill of Materials)的信息,请参阅 Red Hat Process Automation Manager 和 Maven 库版本之间的映射是什么?

  6. 使用 my-app/src/test/java/com/sample/app/AppTest.java 中的 testApp 方法来测试规则。默认情况下,AppTest.java 文件由 Maven 创建。
  7. AppTest.java 文件中,添加所需的 导入 语句来导入 KIE 服务、KIE 容器和 KIE 会话。然后,加载 KIE 基础、插入事实,并从 testApp () 方法执行规则,该方法将事实模型传递给规则。

    import org.kie.api.KieServices;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    
    public void testApp() {
    
      // Load the KIE base:
      KieServices ks = KieServices.Factory.get();
      KieContainer kContainer = ks.getKieClasspathContainer();
      KieSession kSession = kContainer.newKieSession();
    
      // Set up the fact model:
      Person p = new Person();
      p.setWage(12);
      p.setFirstName("Tom");
      p.setLastName("Summers");
      p.setHourlyRate(10);
    
      // Insert the person into the session:
      kSession.insert(p);
    
      // Fire all rules:
      kSession.fireAllRules();
      kSession.dispose();
    }
  8. 在 Maven archetype 中创建并保存所有 DRL 资产后,在命令行中进入 my-app 目录,并运行以下命令来构建您的文件:

    mvn clean install

    如果构建失败,请解决命令行错误消息中描述的任何问题,并尝试验证文件,直到构建成功为止。

  9. 文件构建成功后,运行以下命令在本地执行规则。将 com.sample.app 替换为您的软件包名称。

    mvn exec:java -Dexec.mainClass="com.sample.app"
  10. 检查规则以确保它们正确执行,并解决文件中所需的更改。

要将新规则资产与 Red Hat Process Automation Manager 中的现有项目集成,您可以将新的 Maven 项目编译为 知识 JAR (KJAR),并将它作为依赖项添加到 Business Central 中项目的 pom.xml 文件中。要访问 Business Central 中的项目 pom.xml 文件,您可以在屏幕左侧的 Project Explorer 菜单中选择任何现有资产,然后点击 Customize View gear 图标并选择 Repository Viewpom.xml

第 19 章 用于 IDE 的 Red Hat Process Automation Manager 决策示例

Red Hat Process Automation Manager 提供了作为 Java 类分发的示例决策,您可以将其导入到集成开发环境(IDE)中。您可以使用这些示例来更好地了解决策引擎功能,或者将其用作您在您自己的 Red Hat Process Automation Manager 项目中定义的决策参考。

以下示例决定集是 Red Hat Process Automation Manager 中的一些示例:

  • hello World 示例 :演示基本规则执行和使用 debug 输出
  • State 示例 :通过规则 salience 和 sales 组来演示转发链和冲突解析
  • Fibonacci 示例 :通过规则 salience 来演示递归和冲突解析
  • 示例 :演示模式匹配、基本排序和计算
  • pet Store 示例 :演示规则关联组、全局变量、回调和 GUI 集成
  • Sudoku 示例 :演示复杂模式匹配、问题问题、回调和 GUI 集成
  • Doom 示例的托管 :演示后链和递归
注意

有关 Red Hat Business Optimizer 提供的优化示例,请参阅开始使用 Red Hat Business Optimizer

19.1. 在 IDE 中导入和执行 Red Hat Process Automation Manager 示例决策

您可以将 Red Hat Process Automation Manager 示例决策导入到集成开发环境(IDE)中,并执行它们来探索规则和代码功能的方式。您可以使用这些示例来更好地了解决策引擎功能,或者将其用作您在您自己的 Red Hat Process Automation Manager 项目中定义的决策参考。

先决�件

  • 安装了 Java 8 或更高版本。
  • 已安装 Maven 3.5.x 或更高版本。
  • 已安装 IDE,如 Red Hat CodeReady Studio。

流程

  1. 从红帽客户门户网站下载 并解压 Red Hat Process Automation Manager 7.9.1 源 分发到临时目录,如 /rhpam-7.9.1-sources
  2. 打开 IDE 并选择 FileImportMavenExisting Maven Projects,或者导入 Maven 项目的等效选项。
  3. Browse,导航到 ~/rhpam-7.9.1-sources/src/drools-$VERSION/drools-examples (或,对于生命周期的 Conway 的 Game,~/rhpam-7.9.1-sources/src/droolsjbpm-integration-$VERSION/droolsjbpm-integration-examples),并导入项目。
  4. 导航到您要运行的示例软件包,并使用 main 方法查找 Java 类。
  5. 右键点击 Java 类并选择 Run AsJava Application 来运行示例。

    要通过基本用户界面运行所有示例,请运行 org.drools . examples 主类中的 drorools App.java 类(例如,Brorools.examples 主类)。

    图 19.1. drools-examples (DroolsExamplesApp.java)中的所有示例的接口

    drool 示例运行所有

    图 19.2. droolsjbpm-integration-examples (DroolsJbpmIntegrationExamplesApp.java)中的所有示例的接口

    droolsjbpm 示例运行所有

19.2. hello World 示例决策(基本规则和调试)

Hello World 示例决策演示了如何将对象插入到决策引擎工作内存中,如何使用规则匹配对象,以及如何配置日志记录来跟踪决策引擎的内部活动。

以下是 Hello World 示例的概述:

  • 名称helloworld
  • 主类org.drools.examples.novncproxy.HelloWorldExample (在 src/main/java中)
  • 模块drools-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.novncproxy.HelloWorld.drl (在 src/main/resources中)
  • 目标 :演示基本规则执行和使用 debug 输出

在 Hello World 示例中,生成 KIE 会话来启用规则执行。所有规则都需要一个 KIE 会话才能执行。

用于规则执行的 KIE 会话

KieServices ks = KieServices.Factory.get(); 1
KieContainer kc = ks.getKieClasspathContainer(); 2
KieSession ksession = kc.newKieSession("HelloWorldKS"); 3

1
获取 KieServices 工厂。这是应用程序用来与决策引擎交互的主要接口。
2
从项目类路径创建一个 KieContainer。这会检测一个 /META-INF/kmodule.xml 文件,该文件使用 KieModule 配置并实例化 KieContainer
3
根据 /META-INF/kmodule.xml 文件中定义的 "HelloWorldKS" KIE 会话配置创建一个 KieSession
注意

有关 Red Hat Process Automation Manager 项目打包的更多信息,请参阅 打包和部署 Red Hat Process Automation Manager 项目

Red Hat Process Automation Manager 有一个事件模型,可公开内部引擎活动。两个默认调试监听程序 DebugAgendaEventListenerDebugRuleRuntimeEventListener,将调试事件信息输出到 System.err 输出中。KieRuntimeLogger 提供执行审核,您可以在图形查看的结果。

调试监听程序和审计日志记录程序

// Set up listeners.
ksession.addEventListener( new DebugAgendaEventListener() );
ksession.addEventListener( new DebugRuleRuntimeEventListener() );

// Set up a file-based audit logger.
KieRuntimeLogger logger = KieServices.get().getLoggers().newFileLogger( ksession, "./target/helloworld" );

// Set up a ThreadedFileLogger so that the audit view reflects events while debugging.
KieRuntimeLogger logger = ks.getLoggers().newThreadedFileLogger( ksession, "./target/helloworld", 1000 );

日志记录器是在 AgendaRuleRuntime 侦听程序基础上构建的专用实现。当决策引擎完成执行后,会调用 logger.close ()

该示例创建含有消息 "Hello World" 的单个 Message 对象,将状态 HELLO 插入到 KieSession 中,执行带有 fireAllRules () 的规则。

数据插入和执行

// Insert facts into the KIE session.
final Message message = new Message();
message.setMessage( "Hello World" );
message.setStatus( Message.HELLO );
ksession.insert( message );

// Fire the rules.
ksession.fireAllRules();

规则执行使用数据模型将数据作为输入并输出到 KieSession。本例中的数据模型有两个字段: 消息,即 String,可以是 HELLOGOODBYE

数据模型类

public static class Message {
    public static final int HELLO   = 0;
    public static final int GOODBYE = 1;

    private String          message;
    private int             status;
    ...
}

这两个规则位于 src/main/resources/org/drools/examples/HelloWorld.drl 文件中。

"Hello World" 规则的 when 条件指出每个 Message 对象的规则被激活到 KIE 会话中,其状态为 Message.HELLO。此外,还创建两个变量绑定:变量 消息 绑定到 message 属性,变量 m 绑定到匹配的 Message 对象本身。

规则的 then 操作指定将绑定变量 消息 的内容输出到 System.out,然后更改绑定到 mMessage 对象 的消息 和状态 属性。规则使用 modify 语句在一个语句中应用分配块,并在块末尾通知决策引擎更改。

"hello World" 规则

rule "Hello World"
  when
    m : Message( status == Message.HELLO, message : message )
  then
    System.out.println( message );
    modify ( m ) { message = "Goodbye cruel world",
                   status = Message.GOODBYE };
end

"Good Bye" 规则类似于 "Hello World" 规则,但它与状态为 Message.GOODBYE 的 Message 对象匹配。

"good Bye" 规则

rule "Good Bye"
  when
    Message( status == Message.GOODBYE, message : message )
  then
    System.out.println( message );
end

要执行示例,请在 IDE 中作为 Java 应用程序运行 org.drools.examples.helloworld.HelloWorldExample 类。规则写入 System.out,调试侦听器写入 System.err,审计日志记录器会在 target/ the.log 中创建一个日志文件

IDE 控制台中的 system.out 输出

Hello World
Goodbye cruel world

IDE 控制台中的 system.err 输出

==>[ActivationCreated(0): rule=Hello World;
                   tuple=[fid:1:1:org.drools.examples.helloworld.HelloWorldExample$Message@17cec96]]
[ObjectInserted: handle=[fid:1:1:org.drools.examples.helloworld.HelloWorldExample$Message@17cec96];
                 object=org.drools.examples.helloworld.HelloWorldExample$Message@17cec96]
[BeforeActivationFired: rule=Hello World;
                   tuple=[fid:1:1:org.drools.examples.helloworld.HelloWorldExample$Message@17cec96]]
==>[ActivationCreated(4): rule=Good Bye;
                   tuple=[fid:1:2:org.drools.examples.helloworld.HelloWorldExample$Message@17cec96]]
[ObjectUpdated: handle=[fid:1:2:org.drools.examples.helloworld.HelloWorldExample$Message@17cec96];
                old_object=org.drools.examples.helloworld.HelloWorldExample$Message@17cec96;
                new_object=org.drools.examples.helloworld.HelloWorldExample$Message@17cec96]
[AfterActivationFired(0): rule=Hello World]
[BeforeActivationFired: rule=Good Bye;
                   tuple=[fid:1:2:org.drools.examples.helloworld.HelloWorldExample$Message@17cec96]]
[AfterActivationFired(4): rule=Good Bye]

为更好地了解本例的执行流程,您可以将审计日志文件从 target/helloworld.log 加载到 IDE debug 视图或 审计 视图(例如,在一些 IDE 中的 WindowShow View 中)。

在本例中,审计视图显示 插入了对象,它为 "Hello World" 规则创建一个激活。然后执行激活,它会更新 Message 对象,并导致 "Good Bye" 规则激活。最后,执行 "Good Bye" 规则。当您在 Audit View 中选择一个事件时,原始事件(本例中为 "Activation created" 事件)以绿色形式突出显示。

图 19.3. hello World 示例审计视图

helloworld auditview1

19.3. 状态示例决策(转发链和冲突解析)

State 示例决定集演示了决策引擎如何使用 forward 链,以及对工作内存中事实的任何更改,以解决序列中的规则的执行冲突。该示例重点通过您可以在规则中定义的可变值或通过电缆组解决冲突。

以下是 State 示例的概述:

  • 名称状态
  • 主类org.drools.examples.state.StateExampleUsingSalience,org.drools.examples.state.StateExampleUsingAgendaGroup (in src/main/java)
  • 模块drools-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.state114.drl (在 src/main/resources中)
  • 目标 :通过规则 salience 和 sales 组来演示转发链和冲突解析

转发链规则系统是一种数据驱动的系统,它以决策引擎工作内存中的事实开始,并对这一事实做出更改。当对象插入到工作内存中时,因更改计划执行而满足的任何规则条件。

相反,反向链规则系统是一个目标驱动的系统,从决策引擎尝试满足的公式开始,通常使用递归。如果系统无法访问语音或目标,它会搜索子组,这是完成当前目标的一部分。系统会继续这个过程,直到满足初始目标或满足所有子状态为止。

Red Hat Process Automation Manager 中的决策引擎使用正向和后链来评估规则。

下图演示了,决策引擎如何使用转发链和逻辑流中的向链段来评估规则:

图 19.4. 使用正向和后链的规则评估逻辑

RuleEvaluation Enterprise

在 State 示例中,每个 State 类都有其名称及其当前状态字段(请参阅类 org.drools.examples.state.State)。以下状态是每个对象的两个可能的状态:

  • NOTRUN
  • 完æˆ�

状态类

public class State {
    public static final int NOTRUN   = 0;
    public static final int FINISHED = 1;

    private final PropertyChangeSupport changes =
        new PropertyChangeSupport( this );

    private String name;
    private int    state;

    ... setters and getters go here...
}

State 示例包含两个相同的示例版本,用于解决规则执行冲突:

  • StateExampleUsingSalience 版本,它通过使用规则 salience 解决冲突
  • StateExampleUsingAgendaGroups 版本,该版本使用规则购买组解决冲突

状态示例的两个版本都涉及四个状态对象: ABCD最初,其状态设置为 NOTRUN,这是示例使用的构造器的默认值。

使用 salience 的 state 示例

State 示例的 StateExampleUsingSalience 版本在规则中使用 salience 值来解决规则执行冲突。在激活队列中排序时,具有较高 salience 值的规则会被赋予更高的优先级。

示例将每个 State 实例插入到 KIE 会话中,然后调用 fireAllRules ()

Salience State 示例执行

final State a = new State( "A" );
final State b = new State( "B" );
final State c = new State( "C" );
final State d = new State( "D" );

ksession.insert( a );
ksession.insert( b );
ksession.insert( c );
ksession.insert( d );

ksession.fireAllRules();

// Dispose KIE session if stateful (not required if stateless).
ksession.dispose();

要执行示例,请在 IDE 中作为 Java 应用程序运行 org.drools.examples.state.StateExampleUsingSalience 类。

执行后,以下输出会出现在 IDE 控制台窗口中:

IDE 控制台中的 Salience State 示例输出

A finished
B finished
C finished
D finished

存在四个规则。

首先,"Bootstrap" 规则将触发,将 A 设置为状态 FINISHED,然后会导致 B 将其状态更改为 FINISHED。对象 CD 都依赖于 B,从而导致由 salience 值解析的冲突。

为更好地了解本例的执行流程,您可以将审计日志文件从 target/state.log 加载到 IDE debug 视图或 审计 视图(例如,在一些 IDE 中的 WindowShow View 中)。

在本例中,审计视图显示 对象 A 处于 NOTRUN 的断言激活 "Bootstrap" 规则,而其他对象的断言无效。

图 19.5. Salience State 示例审计视图

状态示例 audit1

salience State 示例中的规则"Bootstrap"

rule "Bootstrap"
  when
    a : State(name == "A", state == State.NOTRUN )
  then
    System.out.println(a.getName() + " finished" );
    a.setState( State.FINISHED );
end

"Bootstrap" 规则的执行会将 A 的状态更改为 FINISHED,这会激活规则 "A to B "。

在 salience State 示例中的规则 "A to B"

rule "A to B"
  when
    State(name == "A", state == State.FINISHED )
    b : State(name == "B", state == State.NOTRUN )
  then
    System.out.println(b.getName() + " finished" );
    b.setState( State.FINISHED );
end

规则 "A to B" 的执行会将 B 的状态更改为 FINISHED,这会激活规则 "B to C""B to D",将其激活放在决策引擎上。

在 salience State 示例中,规则 "B to C" 和 "B to D"

rule "B to C"
    salience 10
  when
    State(name == "B", state == State.FINISHED )
    c : State(name == "C", state == State.NOTRUN )
  then
    System.out.println(c.getName() + " finished" );
    c.setState( State.FINISHED );
end

rule "B to D"
  when
    State(name == "B", state == State.FINISHED )
    d : State(name == "D", state == State.NOTRUN )
  then
    System.out.println(d.getName() + " finished" );
    d.setState( State.FINISHED );
end

此时,这两个规则都可能会触发,因此规则都冲突。冲突解析策略使决策引擎能够决定要触发的规则。规则 "B to C" 具有更高的 salience 值(10 而不是默认的 salience 值 0),因此它会首先触发,将对象 C 修改为状态 FINISHED

IDE 中的 审计 视图显示规则 "A to B" 中的 State 对象的修改,这会导致两个激活冲突。

您还可以使用 IDE 中的 Agenda View 来调查决策引擎模拟的状态。在本例中,Agenda View 显示规则 "A to B" 中的断点,以及带有两个冲突规则的电缆状态。规则 "B to D" 最后触发,将对象 D 修改为状态 FINISHED

图 19.6. Salience State 示例 Agenda View

State example sales1

使用电缆组的状态示例

State 示例的 StateExampleUsingAgendaGroups 版本使用规则中的 sales 组来解决规则执行冲突。通过电缆组,您可以对决策引擎人员进行分区,以提供更多对规则组的执行控制。默认情况下,所有规则都位于 products 组 MAIN 中。您可以使用 sales -group 属性为规则指定不同的 sales 组。

最初,工作内存将其重点放在电缆组 MAIN 上。只有组收到重点时,才会触发电缆组中的规则。您可以使用 setFocus () 或 rule 属性 auto-focus 设置重点。auto-focus 属性可让规则在匹配并激活规则时自动为其电缆组赋予一个重点。

在本例中,auto-focus 属性使规则 "B 到 C"在" B 到 D" 之前触发。

模拟组状态示例中的规则"B 到 C"

rule "B to C"
    agenda-group "B to C"
    auto-focus true
  when
    State(name == "B", state == State.FINISHED )
    c : State(name == "C", state == State.NOTRUN )
  then
    System.out.println(c.getName() + " finished" );
    c.setState( State.FINISHED );
    kcontext.getKnowledgeRuntime().getAgenda().getAgendaGroup( "B to D" ).setFocus();
end

数字组 "B 到 D" 上的规则"B 到 C " 调用 setFocus (),启用它触发的活动规则,然后使规则 "B 到 D" 触发。

模拟组状态示例中的规则"B 到 D"

rule "B to D"
    agenda-group "B to D"
  when
    State(name == "B", state == State.FINISHED )
    d : State(name == "D", state == State.NOTRUN )
  then
    System.out.println(d.getName() + " finished" );
    d.setState( State.FINISHED );
end

要执行示例,请在 IDE 中作为 Java 应用程序运行 org.drools.examples.state.StateExampleUsingAgendaGroups 类。

执行后,以下输出会出现在 IDE 控制台窗口中(与 State 示例的 salience 版本相同):

IDE 控制台中的组状态示例输出

A finished
B finished
C finished
D finished

State 示例中的动态事实

此状态示例中的另一个显著概念是根据实施 PropertyChangeListener 对象的对象 使用动态事实。要让决策引擎查看并对事实属性更改的响应,应用程序必须通知发生了变化的决策引擎。您可以使用 modify 语句明确在规则中配置此通信,或者通过指定事实实现 PropertyChangeSupport 接口来隐式配置。

本例演示了如何使用 PropertyChangeSupport 接口来避免对规则中显式 修改 语句的需求。要使用这个接口,请确保您的事实以类 org.drools.example.State 实施它的方式实现 PropertyChangeSupport,然后使用 DRL 规则文件中的以下代码将决策引擎配置为侦听这些事实上的属性更改:

声明动态事实

declare type State
  @propertyChangeSupport
end

当使用 PropertyChangeListener 对象时,每个 setter 必须为通知实施额外的代码。例如,以下 state 设置器位于类 org.drools.examples 中:

带有 PropertyChangeSupport 的 setter 示例

public void setState(final int newState) {
    int oldState = this.state;
    this.state = newState;
    this.changes.firePropertyChange( "state",
                                     oldState,
                                     newState );
}

19.4. Fibonacci 示例决策(递归和冲突解析)

Fibonacci 示例决策集演示了决策引擎如何使用递归来解析序列中规则的执行冲突。该示例重点通过您可以在规则中定义的 salience 值解决冲突。

以下是 Fibonacci 示例的概述:

  • 名称 :fibonacci
  • 主类org.drools.examples.fibonacci.FibonacciExample ( src/main/java)
  • 模块drools-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.fibonacci.Fibonacci.drl (在 src/main/resources中)
  • 目标 :通过规则 salience 来演示递归和冲突解析

Fibonacci Numbers 形成以 0 和 1 开头的序列。下一个 Fibonacci 号通过添加前面的两个 Fibonacci 号: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946 等。

Fibonacci 示例使用带有以下两个字段的单事实类 Fibonacci

  • sequence
  • value

sequence 字段表示对象在 Fibonacci 数字序列中的位置。value 字段显示该序列位置的 Fibonacci 对象的值,其中 -1 表示仍需要计算的值。

Fibonacci 类

public static class Fibonacci {
    private int  sequence;
    private long value;

    public Fibonacci( final int sequence ) {
        this.sequence = sequence;
        this.value = -1;
    }

    ... setters and getters go here...
}

要执行示例,请在 IDE 中作为 Java 应用程序运行 org.drools.examples.fibonacci.FibonacciExample 类。

执行后,以下输出会出现在 IDE 控制台窗口中:

IDE 控制台中的 Fibonacci 示例输出

recurse for 50
recurse for 49
recurse for 48
recurse for 47
...
recurse for 5
recurse for 4
recurse for 3
recurse for 2
1 == 1
2 == 1
3 == 2
4 == 3
5 == 5
6 == 8
...
47 == 2971215073
48 == 4807526976
49 == 7778742049
50 == 12586269025

为了在 Java 中实现此行为,示例将插入单个 Fibonacci 对象,序列字段为 50。然后,示例使用递归规则插入其他 49 Fibonacci 对象。

这个示例使用 MVEL dialect modify 关键字启用块 setter 操作并通知决策引擎更改,而不是实施 PropertyChangeSupport 接口来使用动态事实。

Fibonacci 示例执行

ksession.insert( new Fibonacci( 50 ) );
ksession.fireAllRules();

这个示例使用以下三个规则:

  • "Recurse"
  • "Bootstrap"
  • "calculate"

规则 "Recurse" 匹配每个断言的 Fibonacci 对象,值为 -1,创建并模拟一个新的 Fibonacci 对象,序列小于当前匹配的对象。每次添加 Fibonacci 对象时,如果一个序列字段等于 1,则该规则会重新匹配并再次触发。当您在内存中所有 50 个 Fibonacci 对象后,in 条件元素用于停止规则匹配。规则也具有 salience 值,因为您需要在执行 "Bootstrap" 规则前,所有 50 个 Fibonacci 对象都变为serted。

规则"递归"

rule "Recurse"
    salience 10
  when
    f : Fibonacci ( value == -1 )
    not ( Fibonacci ( sequence == 1 ) )
  then
    insert( new Fibonacci( f.sequence - 1 ) );
    System.out.println( "recurse for " + f.sequence );
end

为更好地了解本例的执行流程,您可以将审计日志文件从 target/fibonacci.log 加载到 IDE debug 视图或 审计 视图(例如,在 WindowShow View 中)。

在本例中,审计视图显示 Fibonacci 对象的原始断言,序列 字段为 50,从 Java 代码完成。从那里,审计视图显示 规则的持续递归,其中每个断言 Fibonacci 对象会导致 "递归" 规则激活并再次触发。

图 19.7. 审计视图中的规则"递归"

fibonacci1

Fibonacci 对象带有 2 序列 字段被断言时,"Bootstrap" 规则会与 "递归"规则匹配 并激活。请注意,对于字段 序列 的限制,测试使用 12 的相等性:

规则"Bootstrap"

rule "Bootstrap"
  when
    f : Fibonacci( sequence == 1 || == 2, value == -1 ) // multi-restriction
  then
    modify ( f ){ value = 1 };
    System.out.println( f.sequence + " == " + f.value );
end

您还可以使用 IDE 中的 Agenda View 来调查决策引擎模拟的状态。"Bootstrap" 规则尚未触发,因为 "递归" 规则具有更高的 salience 值。

图 19.8. Agenda View 1 中的规则"递归"和"Bootstrap"

fibonacci technology1

当带有 1 序列Fibonacci 对象被断言时,"Bootstrap" 规则会再次匹配,从而导致该规则的两个激活。"递归" 规则不匹配并激活,因为当存在带有 1 序列Fibonacci 对象后,t 条件元素会立即停止匹配。

图 19.9. Agenda View 2 中的规则"递归"和"Bootstrap"

fibonacci agenda2

"Bootstrap" 规则将 序列12 的对象设置为值 1。现在,您有两个 Fibonacci 对象的值不等于 -1, "Calculate" 规则可以匹配。

此时,工作内存中几乎有 50 个 Fibonacci 对象。您需要选择合适的 triple 来依次计算每个值。如果您在没有字段限制的规则中使用三种 Fibonacci 模式来限制可能的跨产品,则结果将是 50x49x48 可能的组合,从而导致大约 125,000 个可能的规则触发,大多数规则都不正确。

"Calculate" 规则使用字段限制来以正确顺序评估三种 Fibonacci 模式。此技术称为 跨产品匹配

第一个模式找到任何值为 != -1Fibonacci 对象,并绑定模式和字段。第二个 Fibonacci 对象执行同样的操作,但添加额外的字段约束,以确保其序列大于绑定到 f1Fibonacci 对象。当此规则第一次触发时,您知道只有序列 12 具有 1 值,并且两个限制可确保 f1 引用序列 1,以及 f2 引用序列 2

最终模式找到 Fibonacci 对象,值设为 -1, 以及一个大于 f2 的序列。

此时,可从可用的跨产品正确选择三个 Fibonacci 对象,您可以计算绑定到 f3 的第三个 Fibonacci 对象的值。

规则"Calculate"

rule "Calculate"
  when
    // Bind f1 and s1.
    f1 : Fibonacci( s1 : sequence, value != -1 )
    // Bind f2 and v2, refer to bound variable s1.
    f2 : Fibonacci( sequence == (s1 + 1), v2 : value != -1 )
    // Bind f3 and s3, alternative reference of f2.sequence.
    f3 : Fibonacci( s3 : sequence == (f2.sequence + 1 ), value == -1 )
  then
    // Note the various referencing techniques.
    modify ( f3 ) { value = f1.value + v2 };
    System.out.println( s3 + " == " + f3.value );
end

modify 语句更新绑定到 f3Fibonacci 对象的值。这意味着您现在有一个没有等于 -1 的新 Fibonacci 对象,这允许 "Calculate" 规则重新匹配并计算下一个 Fibonacci 号。

IDE 的 debug 视图或 审计 视图显示触发最后一个 "Bootstrap" 规则如何修改 Fibonacci 对象,启用 "Calculate" 规则匹配,然后修改另一个 Fibonacci 对象,以便 "Calculate" 规则再次匹配。这个过程会继续,直到为所有 Fibonacci 对象设置值。

图 19.10. 审计视图中的规则

fibonacci4

19.5. 定价示例决策(精确表)

账单示例决策演示了如何使用电子表格决策表来计算以 tabular 格式而不是直接在 DRL 文件中计算过期策略的成本。

以下是隔离示例的概述:

  • 名称:Decisiontable
  • 主类org.drools.examples.decisiontable.PricingRuleDTExample (在 src/main/java中)
  • 模块drools-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.decisiontable.ExamplePolicyPricing.xls (在 src/main/resources中)
  • 目标 :演示使用电子表格决策表来定义规则

电子表格决策表是 XLS 或 XLSX 电子表,其中包含以表格格式定义的新规则。您可以使用独立 Red Hat Process Automation Manager 项目包含电子表格决策表,或者在 Business Central 中将它们上传到项目。决策表中的每一行都是一条规则,每个列都是一个条件、操作或其他规则属性。创建决策表并将其上传到 Red Hat Process Automation Manager 项目后,您定义的规则会编译成带有所有其他规则资产的 dols 规则。

定价示例的目的是提供一组新规则来计算基本价格,以及适用于特定类型的销售政策的库存驱动程序的货币。驱动程序的年龄和历史记录以及策略类型包括计算基本 Premium 贡献,其他规则会计算该驱动程序可能有资格的潜在承诺。

要执行示例,请在 IDE 中作为 Java 应用程序运行 org.drools.examples.decisiontable.PricingRuleDTExample 类。

执行后,以下输出会出现在 IDE 控制台窗口中:

Cheapest possible
BASE PRICE IS: 120
DISCOUNT IS: 20

执行示例的代码遵循典型的执行模式:规则已加载,插入事实,并且创建了无状态 KIE 会话。本例中的区别在于,规则在 ExamplePolicyPricing.xls 文件中定义,而不是 DRL 文件或其他源。电子表格文件使用模板和 DRL 规则加载到决策引擎中。

电子表格决策设置

ExamplePolicyPricing.xls 电子表在第一个标签页中包含两个决策表:

  • 基本定价规则
  • 促销活动规则

在示例电子表格演示时,您只能使用电子表的第一个标签页来创建路由表,但多个表可以在单个标签页内。决策表不一定遵循顶层逻辑,但更容易地捕获导致规则的数据。对规则的评估不一定是以给定顺序的评估,因为决策引擎的所有正常机制仍适用。这就是您可以在电子表的同一标签页中有多个决策表的原因。

决策表通过对应的规则模板文件 BasePricing.drtPromotionalPricing.drt 执行。这些模板文件通过其模板参数引用决策表,并直接引用决策表中的条件和操作的各种标头。

BasePricing.drt 规则模板文件

template header
age[]
profile
priorClaims
policyType
base
reason

package org.drools.examples.decisiontable;

template "Pricing bracket"
age
policyType
base

rule "Pricing bracket_@{row.rowNumber}"
  when
    Driver(age >= @{age0}, age <= @{age1}
        , priorClaims == "@{priorClaims}"
        , locationRiskProfile == "@{profile}"
    )
    policy: Policy(type == "@{policyType}")
  then
    policy.setBasePrice(@{base});
    System.out.println("@{reason}");
end
end template

PromotionalPricing.drt 规则模板文件

template header
age[]
priorClaims
policyType
discount

package org.drools.examples.decisiontable;

template "discounts"
age
priorClaims
policyType
discount

rule "Discounts_@{row.rowNumber}"
  when
    Driver(age >= @{age0}, age <= @{age1}, priorClaims == "@{priorClaims}")
    policy: Policy(type == "@{policyType}")
  then
    policy.applyDiscount(@{discount});
end
end template

规则通过 KIE Session DTableWithTemplateKBkmodule.xml 引用执行,这专门提到 ExamplePolicyPricing.xls 电子表,它是成功执行规则所必需的。此执行方法允许您将规则作为独立单元(如本例中)执行,或者在打包知识 JAR (KJAR)文件中包含规则,以便电子表格与要执行的规则一起打包。

执行规则和电子表格才能成功完成 kmodule.xml 文件的以下部分:

    <kbase name="DecisionTableKB" packages="org.drools.examples.decisiontable">
        <ksession name="DecisionTableKS" type="stateless"/>
    </kbase>

    <kbase name="DTableWithTemplateKB" packages="org.drools.examples.decisiontable-template">
        <ruleTemplate dtable="org/drools/examples/decisiontable-template/ExamplePolicyPricingTemplateData.xls"
                      template="org/drools/examples/decisiontable-template/BasePricing.drt"
                      row="3" col="3"/>
        <ruleTemplate dtable="org/drools/examples/decisiontable-template/ExamplePolicyPricingTemplateData.xls"
                      template="org/drools/examples/decisiontable-template/PromotionalPricing.drt"
                      row="18" col="3"/>
        <ksession name="DTableWithTemplateKS"/>
    </kbase>

作为使用规则模板文件执行决策表的替代选择,您可以使用 DecisionTableConfiguration 对象并将输入电子表指定为输入类型,如 DecisionTableInputType.xls

DecisionTableConfiguration dtableconfiguration =
    KnowledgeBuilderFactory.newDecisionTableConfiguration();
        dtableconfiguration.setInputType( DecisionTableInputType.XLS );

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();

        Resource xlsRes = ResourceFactory.newClassPathResource( "ExamplePolicyPricing.xls",
                                                                getClass() );
        kbuilder.add( xlsRes,
                      ResourceType.DTABLE,
                      dtableconfiguration );

比较示例使用两种事实类型:

  • 驱动
  • 策略.

这个示例在对应的 Java 类 Driver.javaPolicy.java 中为事实设置默认值。驱动程序存在 30 年,没有之前的声明,目前具有风险配置文件 LOW驱动程序 所应用的策略是 COMPREHENSIVE

在任何决策表中,每行都被视为不同的规则,每个列都是一个条件或一个操作。每行在决策表中评估,除非在执行时清除了电缆。

决策表分布表(XLS 或 XLSX)需要两个关键区域来定义规则数据:

  • RuleSet 区域
  • RuleTable 区域

电子表格的 RuleSet 区域定义了您要全局应用到同一软件包中的所有规则的元素(不仅仅是电子表格),如规则集名称或通用规则属性。RuleTable 区域定义实际规则(箭头),以及组成指定规则集中的规则表的条件、操作和其他规则属性(columns)。决策表电子表格可以包含多个 RuleTable 区域,但只能包含一个 RuleSet 区域。

图 19.11. 决策表配置

DT Config

RuleTable 区域还定义规则属性应用到的对象,本例中为 DriverPolicy,以及对象的限制。例如,定义 Age Bracket 列的 Driver 对象约束是 age >= $1, age <= $2,其中以逗号分隔的范围在表列值中定义,如 18,24

基本定价规则

定价示例中的基本定价规则 决策表评估驱动程序的年龄、风险配置文件、声明数和策略类型,并根据这些条件生成策略的基本价格。

图 19.12. 基本价格计算

DT Table1

Driver 属性在下表中定义:

  • 年龄 Bracket :年龄括号包含条件 年龄 >=$1 的定义,年龄 <=$2,它定义了驱动程序期限的条件边界。此条件列突出显示 $1 和 $2 的使用,后者在电子表格中用逗号分开。您可以将这些值写入 18、2418,且两个格式都在执行自定义规则中工作。
  • 位置风险配置文件 : risk 配置集是一个字符串,示例程序始终以 LOW 的形式传递,但可以更改为反映 MEDHIGH
  • 之前的声明数量 :声明的数量定义为 condition 列必须完全等于触发该操作的整数。该值不是范围,仅完全匹配。

决策表的策略用于条件和规则操作,并在下表中定义属性:

  • 应用的策略类型 :策略类型是一个条件,它作为字符串传递,用于定义覆盖范围类型:COMPREHENSIVE、FIRE_THEFT、或 THIRD_PARTY
  • Base $ AUDbasePrice 定义为一个 ACTION,它根据与此值对应的电子表格单元,通过约束 policy.setBasePrice ($param) 设置价格。当您为此决策表执行对应的 DRL 规则时,该规则部分对与事实匹配的 true 条件执行这个 action 语句,并将基本价格设置为对应的值。
  • 记录原因 :当规则成功执行时,此操作会在 System.out 控制台中生成输出消息,反映触发的规则。之后会在应用程序中捕获并打印。

该示例也使用左侧的第一列对规则进行分类。此列仅用于注解,不会影响规则执行。

促销活动规则

计费示例中的促销活动规则 决策表评估了驱动程序的年龄、之前声明数量和策略类型,以根据销售政策价格产生潜在的参与。

图 19.13. 主要计算

DT Table2

此决策表包含该驱动程序可能有资格的条件。与基本价格计算类似,此表评估驱动程序的期限、之前声明的数量以及应用 Policy 类型 以确定要应用的 Discount % 速率。例如,如果驱动程序存在 30 年,没有之前的声明,并且针对 COMPREHENSIVE 策略应用,则驱动程序被指定为 20 百分比。

19.6. pet Store 示例决策(genda 组、全局变量、回调和 GUI 集成)

Pet Store 示例决定集演示了如何在规则中使用电缆组和全局变量,以及如何将 Red Hat Process Automation Manager 规则与图形用户界面(GUI)集成。在这种情况下,基于 Swing 的桌面应用程序。这个示例还演示了如何使用回调与正在运行的决策引擎交互,根据运行时工作内存的更改更新 GUI。

以下是 Pet Store 示例的概述:

  • 名称 :petstore
  • 主类org.drools.examples.petstore.PetStoreExample (在 src/main/java中)
  • 模块drools-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.petstore.PetStore.drl (在 src/main/resources中)
  • 目标 :演示规则关联组、全局变量、回调和 GUI 集成

在 Pet Store 示例中,P etStoreExample.java 类定义了以下主体类(除了处理 Swing 事件的多个类外):

  • Petstore 包含 main () 方法。
  • PetStoreUI 负责创建和显示基于 Swing 的 GUI。此类包含几个较小的类,主要用于响应各种 GUI 事件,如用户鼠标点击。
  • TableModel 包含表数据。此类基本上是一个 JavaBean,它扩展了 Swing 类 AbstractTableModel
  • 签出回调 可让 GUI 与规则交互。
  • Ordershow 保留您要购买的项目。
  • 购买 存储您购买的订购和产品的详细信息。
  • 产品 是一种 JavaBean,其中包含可用于购买的产品及其价格。

本例中的许多 Java 代码是基于普通 JavaBean 或 Swing 的普通代码。有关 Swing 组件的更多信息,请参阅有关 使用 JFC/Swing 创建 GUI 的 Java 指南。

Pet Store 示例中的规则执行行为

与其他示例决定,事实被立即触发,Petet Store 示例不会执行规则,直到基于用户交互收集更多事实。示例通过由构造器创建的 PetStoreUI 对象执行规则,该对象接受用于收集产品的 Vector 对象。然后,示例使用 CheckoutCallback 类的实例,其中包含之前载入的规则基础。

pet Store KIE 容器和事实执行设置

// KieServices is the factory for all KIE services.
KieServices ks = KieServices.Factory.get();

// Create a KIE container on the class path.
KieContainer kc = ks.getKieClasspathContainer();

// Create the stock.
Vector<Product> stock = new Vector<Product>();
stock.add( new Product( "Gold Fish", 5 ) );
stock.add( new Product( "Fish Tank", 25 ) );
stock.add( new Product( "Fish Food", 2 ) );

// A callback is responsible for populating the working memory and for firing all rules.
PetStoreUI ui = new PetStoreUI( stock,
                                new CheckoutCallback( kc ) );
ui.createAndShowGUI();

触发规则的 Java 代码位于 CheckoutCallBack.checkout () 方法中。当用户在 UI 中点 Checkout 时触发此方法。

从 CheckoutCallBack.checkout ()执行规则

public String checkout(JFrame frame, List<Product> items) {
    Order order = new Order();

    // Iterate through list and add to cart.
    for ( Product p: items ) {
        order.addItem( new Purchase( order, p ) );
    }

    // Add the JFrame to the ApplicationData to allow for user interaction.

    // From the KIE container, a KIE session is created based on
    // its definition and configuration in the META-INF/kmodule.xml file.
    KieSession ksession = kcontainer.newKieSession("PetStoreKS");

    ksession.setGlobal( "frame", frame );
    ksession.setGlobal( "textArea", this.output );

    ksession.insert( new Product( "Gold Fish", 5 ) );
    ksession.insert( new Product( "Fish Tank", 25 ) );
    ksession.insert( new Product( "Fish Food", 2 ) );

    ksession.insert( new Product( "Fish Food Sample", 0 ) );

    ksession.insert( order );

    // Execute rules.
    ksession.fireAllRules();

    // Return the state of the cart
    return order.toString();
}

示例代码将两个元素传递给 CheckoutCallBack.checkout () 方法。一个元素是 JFrame Swing 组件的处理,它包括输出文本帧,位于 GUI 的底部。第二个元素是订购项的列表,它来自 TableModel,它将信息从 GUI 右上角的 Table 区域存储。

for 循环将来自 GUI 的订购项列表转换为 Order JavaBean,也包含在 PetStoreExample.java 文件中。

在这种情况下,规则在无状态 KIE 会话中触发,因为所有数据都存储在 Swing 组件中,且不会执行,直到用户在 UI 中点 Checkout。每次点击 Checkout 时,列表的内容都会从 Swing TableModel 移到 KIE 会话工作内存中,然后使用 ksession.fireAllRules () 方法执行。

在此代码中,对 KieSession 有 9 个调用。首先从 KieContainer 创建一个新的 KieSession (此 KieContainer 中从 main () 方法中的 CheckoutCallBack 类传递的示例)。接下来的两个调用传递在规则中保存全局变量的两个对象:Swing 文本区域和用于编写消息的 Swing 帧。更多插入将产品的信息放在 KieSession 中,以及订购列表中。最后的调用是标准 fireAllRules ()

pet Store 规则文件导入、全局变量和 Java 功能

PetStore.drl 文件包含标准软件包和导入语句,供规则提供各种 Java 类。规则文件还包含 要在规则中使用的全局变量,定义为 和文本。全局变量包含对之前被名为 setGlobal () 方法的 Java 代码传递的 Swing 组件 JFrameJTextArea 组件的引用。与规则中的标准变量不同,当规则触发后马上过期,全局变量会在 KIE 会话生命周期中保留其值。这意味着这些全局变量的内容可用于评估所有后续规则。

Petstore.drl 软件包、导入和全局变量

package org.drools.examples;

import org.kie.api.runtime.KieRuntime;
import org.drools.examples.petstore.PetStoreExample.Order;
import org.drools.examples.petstore.PetStoreExample.Purchase;
import org.drools.examples.petstore.PetStoreExample.Product;
import java.util.ArrayList;
import javax.swing.JOptionPane;

import javax.swing.JFrame;

global JFrame frame
global javax.swing.JTextArea textArea

PetStore.drl 文件还包含文件中规则使用的两个功能:

PetStore.drl Java functions

function void doCheckout(JFrame frame, KieRuntime krt) {
        Object[] options = {"Yes",
                            "No"};

        int n = JOptionPane.showOptionDialog(frame,
                                             "Would you like to checkout?",
                                             "",
                                             JOptionPane.YES_NO_OPTION,
                                             JOptionPane.QUESTION_MESSAGE,
                                             null,
                                             options,
                                             options[0]);

       if (n == 0) {
            krt.getAgenda().getAgendaGroup( "checkout" ).setFocus();
       }
}

function boolean requireTank(JFrame frame, KieRuntime krt, Order order, Product fishTank, int total) {
        Object[] options = {"Yes",
                            "No"};

        int n = JOptionPane.showOptionDialog(frame,
                                             "Would you like to buy a tank for your " + total + " fish?",
                                             "Purchase Suggestion",
                                             JOptionPane.YES_NO_OPTION,
                                             JOptionPane.QUESTION_MESSAGE,
                                             null,
                                             options,
                                             options[0]);

       System.out.print( "SUGGESTION: Would you like to buy a tank for your "
                           + total + " fish? - " );

       if (n == 0) {
             Purchase purchase = new Purchase( order, fishTank );
             krt.insert( purchase );
             order.addItem( purchase );
             System.out.println( "Yes" );
       } else {
            System.out.println( "No" );
       }
       return true;
}

这两个功能执行以下操作:

  • doCheckout () 显示一个对话框,该对话框询问用户是否是她或他希望签出的。如果用户这样做,则重点设置为 checkout sales 组,使该组中的规则能够触发。
  • requireTank () 显示一个对话框,它要求用户在她或他希望购买 fish tank 时询问用户。如果用户这样做,会将一个新的 fish tank 产品 添加到工作内存的顺序列表中。
注意

在本例中,所有规则和功能都在同一个规则文件中有效。在生产环境中,您通常会在不同的文件中分隔规则和功能,或构建静态 Java 方法并使用导入功能导入文件,如 导入功能 my.package.name.hello

带有销售组的 pet 存储规则

Pet Store 示例中的大多数规则都使用电缆组来控制规则执行。通过电缆组,您可以对决策引擎人员进行分区,以提供更多对规则组的执行控制。默认情况下,所有规则都位于 products 组 MAIN 中。您可以使用 sales -group 属性为规则指定不同的 sales 组。

最初,工作内存将其重点放在电缆组 MAIN 上。只有组收到重点时,才会触发电缆组中的规则。您可以使用 setFocus () 或 rule 属性 auto-focus 设置重点。auto-focus 属性可让规则在匹配并激活规则时自动为其电缆组赋予一个重点。

Pet Store 示例对规则使用以下电缆组:

  • "init"
  • "evaluate"
  • "show items"
  • "checkout"

例如,示例规则 "Explode Cart" 使用 "init" cart 组来确保它有选择触发并插入 KIE 会话工作内存中:

规则"Explode Cart"

// Insert each item in the shopping cart into the working memory.
rule "Explode Cart"
    agenda-group "init"
    auto-focus true
    salience 10
  when
    $order : Order( grossTotal == -1 )
    $item : Purchase() from $order.items
  then
    insert( $item );
    kcontext.getKnowledgeRuntime().getAgenda().getAgendaGroup( "show items" ).setFocus();
    kcontext.getKnowledgeRuntime().getAgenda().getAgendaGroup( "evaluate" ).setFocus();
end

此规则与尚未计算其 grossTotal 的所有顺序匹配。每个购买项目的执行循环(按该顺序排列)。

规则使用与 leader 组相关的以下功能:

  • runlevel-group "init" 定义 products 组的名称。在这种情况下,只有一个规则位于组中。但是,Java 代码和规则结果都不适用于此组,因此它依赖于 auto-focus 属性来触发它。
  • auto-focus true 确保此规则虽然是 sales 组中的唯一规则,则在从 Java 代码调用 fireAllRules () 时获得触发的机会。
  • kcontext…​.setFocus () 将重点设置为 "显示项目 " 和"评估" 组,允许触发规则。在实践中,您将按顺序执行所有项目,将它们插入到内存中,然后在插入后触发其他规则。

"show items" products group 仅包含一条规则,"Show items"。对于 KIE 会话工作内存中当前顺序的每个购买,规则会根据规则文件中定义的 textArea 变量将详细信息记录到 GUI 底部的文本区域。

规则"Show items"

rule "Show Items"
    agenda-group "show items"
  when
    $order : Order()
    $p : Purchase( order == $order )
  then
   textArea.append( $p.product + "\n");
end

"评估" 公司组也从 "Explode Cart" 规则中获得了重点。此电话号码组包含两个规则 :"Free Fish Food Sample""Suggest Tank",它们按顺序执行。

规则 "Free Fish Food Sample"

// Free fish food sample when users buy a goldfish if they did not already buy
// fish food and do not already have a fish food sample.
rule "Free Fish Food Sample"
    agenda-group "evaluate" 1
  when
    $order : Order()
    not ( $p : Product( name == "Fish Food") && Purchase( product == $p ) ) 2
    not ( $p : Product( name == "Fish Food Sample") && Purchase( product == $p ) ) 3
    exists ( $p : Product( name == "Gold Fish") && Purchase( product == $p ) ) 4
    $fishFoodSample : Product( name == "Fish Food Sample" );
  then
    System.out.println( "Adding free Fish Food Sample to cart" );
    purchase = new Purchase($order, $fishFoodSample);
    insert( purchase );
    $order.addItem( purchase );
end

只有在满足以下条件时,规则 "Free Fish Food Sample" 才会触发:

1
在规则执行中,评估组 "evaluate" 组。
2
用户还没有 fish food。
3
用户还没有免费的 fish food 示例。
4
用户按顺序有一个黄金的fish。

如果顺序事实满足所有这些要求,则会创建一个新产品(Fish Food Sample),并添加到工作内存的顺序中。

规则"Suggest Tank"

// Suggest a fish tank if users buy more than five goldfish and
// do not already have a tank.
rule "Suggest Tank"
    agenda-group "evaluate"
  when
    $order : Order()
    not ( $p : Product( name == "Fish Tank") && Purchase( product == $p ) ) 1
    ArrayList( $total : size > 5 ) from collect( Purchase( product.name == "Gold Fish" ) ) 2
    $fishTank : Product( name == "Fish Tank" )
  then
    requireTank(frame, kcontext.getKieRuntime(), $order, $fishTank, $total);
end

只有在满足以下条件时,规则 "Suggest Tank" 才会触发:

1
用户的顺序没有 fish tank。
2
用户按顺序有超过五个 fish。

当规则触发时,它将调用规则文件中定义的 requireTank () 函数。此函数会显示一个对话框,它要求用户在她或他希望购买 fish tank 时询问用户。如果用户这样做,会将一个新的 fish tank 产品 添加到工作内存的顺序列表中。当规则调用 requireTank () 函数时,该规则会传递 全局变量,以便函数能够处理 Swing GUI。

Pet Store 示例中的 "do checkout" 规则没有 sales 组,且没有 when 条件,因此始终执行该规则并被视为默认 MAIN phone 组的一部分。

规则"do checkout"

rule "do checkout"
  when
  then
    doCheckout(frame, kcontext.getKieRuntime());
end

当规则触发时,它将调用规则文件中定义的 doCheckout () 函数。此函数会显示一个对话框,用于询问用户是否是她或他希望签出的对话框。如果用户这样做,则重点设置为 checkout sales 组,使该组中的规则能够触发。当规则调用 doCheckout () 函数时,该规则会传递 全局变量,以便函数能够处理 Swing GUI。

注意

本例还演示了一个故障排除技术,如果结果没有如您预期执行:您可以从规则的 when 语句中删除条件,并在 then 语句中测试操作以验证操作是否已正确执行。

"checkout" products 组包含三个规则,用于处理顺序签出并应用任何活动:" Gross Total", " Apply 5% Discount", 和 "Apply 10% Discount"

规则 "Gross Total", "Apply 5% Discount", 和 "Apply 10% Discount"

rule "Gross Total"
    agenda-group "checkout"
  when
    $order : Order( grossTotal == -1)
    Number( total : doubleValue ) from accumulate( Purchase( $price : product.price ),
                                                              sum( $price ) )
  then
    modify( $order ) { grossTotal = total }
    textArea.append( "\ngross total=" + total + "\n" );
end

rule "Apply 5% Discount"
    agenda-group "checkout"
  when
    $order : Order( grossTotal >= 10 && < 20 )
  then
    $order.discountedTotal = $order.grossTotal * 0.95;
    textArea.append( "discountedTotal total=" + $order.discountedTotal + "\n" );
end

rule "Apply 10% Discount"
    agenda-group "checkout"
  when
    $order : Order( grossTotal >= 20 )
  then
    $order.discountedTotal = $order.grossTotal * 0.90;
    textArea.append( "discountedTotal total=" + $order.discountedTotal + "\n" );
end

如果用户还没有计算 gross 总计,则 Gross Total 将产品价格聚合到总计,请将这个总数放在 KIE 会话中,并使用 textArea 全局变量通过 Swing JTextArea 显示它。

如果 gross 总数介于 1020 之间(策展单位),"Apply 5% Discount" 规则计算活动总数,将其添加到 KIE 会话中,并在文本区域中显示它。

如果 gross 总数不小于 20"Apply 10% Discount" 规则会计算参与总数,将其添加到 KIE 会话中,并在文本区域中显示它。

pet Store 示例执行

与其他 Red Hat Process Automation Manager 决策示例类似,您可以通过在 IDE 中作为 Java 应用程序运行 org.drools.examples.petstore.PetStoreExample 类来执行 Pet Store 示例。

当您执行 Pet Store 示例时,会出现 Pet Store Demo GUI 窗口。此窗口显示可用产品列表(左下),这是所选产品的空列表(右下)、checkout 和 Reset 按钮(中间)和空系统消息区域(bottom)。

图 19.14. 启动后,pet Store 示例 GUI

1 Petstore 开始屏幕

本例中发生以下事件来建立此执行行为:

  1. main () 方法已运行并加载规则基础,但还没有触发规则。目前,这是与已运行的规则连接的唯一代码。
  2. 创建了一个新的 PetStoreUI 对象,并授予规则基础的处理,以便稍后使用。
  3. 各种 Swing 组件已执行其功能,并显示初始 UI 屏幕并等待用户输入。

您可以点击列表中的各种产品来浏览 UI 设置:

图 19.15. 探索 Pet Store 示例 GUI

2 个库存添加到订购列表中

还没有触发规则代码。UI 使用 Swing 代码来检测用户鼠标点击,并将所选产品添加到 TableModel 对象中,以便在 UI 右上角显示。本例演示了 Model-View-Controller 设计模式。

当您点 Checkout 时,规则将以以下方式触发:

  1. 方法 CheckOutCallBack.checkout () 被 Swing 类调用(eventually),等待用户单击 Checkout。这会将来自 TableModel 对象(每个 UI 右上角)的数据插入到 KIE 会话工作内存中。然后,方法会触发规则。
  2. "Explode Cart" 规则是第一个触发,auto-focus 属性设置为 true。规则循环到 cart 中的所有产品,确保产品处于工作内存中,然后为 "显示项"和" 评估" 组提供触发的选项。这些组中的规则将 cart 的内容添加到文本区域( UI 不存在),评估您是否有资格免费 fish food,并决定是否希望购买 fish tank。

    图 19.16. fish tank mailbox

    3 购买建议
  3. "do checkout" 规则是触发的下一个规则,因为目前没有其他电缆组,因为它是默认的 MAIN farm 组的一部分。此规则始终调用 doCheckout () 函数,它要求您签出。
  4. doCheckout () 函数将重点设置为 "checkout" 电缆组,为该组中的规则提供要触发的选项。
  5. "checkout" 电缆组中的规则显示 cart 的内容,并应用适当的语音。
  6. 然后,Swing 会等待用户输入来选择更多产品(并导致规则再次触发)或关闭 UI。

    图 19.17. 所有规则触发后的 pet Store 示例 GUI

    4 Petstore 最终屏幕

您可以添加更多 System.out 调用来在 IDE 控制台中演示此事件流:

IDE 控制台中的 system.out 输出

Adding free Fish Food Sample to cart
SUGGESTION: Would you like to buy a tank for your 6 fish? - Yes

19.7. honest Politician 示例决策(非维护和风险)

Honest Politician 示例决定集演示了通过逻辑插入以及规则中的 salience 使用的真实维护的概念。

以下是 Honest Politician 示例的概述:

  • 名称:honestpolitician
  • 主类org.drools.examples.honestpolitician.HonestPoliticianExample (在 src/main/java中)
  • 模块drools-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.honestpolitician.HonestPolitician.drl (在 src/main/resources中)
  • 目标 :根据事实的逻辑插入和规则的使用,说明事实中的事实概念

Honest Politician 示例的基本内部是,只有语句为 true 时对象才能存在。规则结果可以在逻辑上插入带有 insertLogical () 方法的对象。这意味着,只要逻辑插入的规则保持在 KIE 会话工作内存中,对象仍保持在 KIE 会话工作内存中。当不再满足该规则时,对象会自动重新遍历。

在本例中,执行规则会导致一组 politicians 从 honest 变为 dishonest,从而导致一个被破坏的攻击。评估每个 politician 后,它们从设为 true 的 honesty 属性开始,但一条规则会触发使 politicians 不再休眠的规则。当它们的状态从 honest 切换到 dishonest 时,它们会被从工作内存中移除。规则 salience 通知决策引擎如何优先选择为它们定义了差异的任何规则,否则使用默认的 salience 值 0。在激活队列中排序时,具有较高 salience 值的规则会被赋予更高的优先级。

Politician 和 Hope 类

示例中的 Politician 示例是为 honest politician 配置的示例。Politician 类由 String 项 名称和 一个布尔值项组成:

Politician 类

public class Politician {
    private String name;
    private boolean honest;
    ...
}

Hope 类确定 Hope 对象是否存在。这类没有有意义的成员,但只要这个要求,就存在于工作内存中。

期望类

public class Hope {

    public Hope() {

    }
  }

politician honesty 的规则定义

在 Honest Politician 示例中,当工作内存中至少有一个 honest politician 时,"We 有一个 honest Politician" 规则逻辑插入一个新的 Hope 对象。当所有策略都变为 dishonest 后,H ope 对象会自动重新遍历。此规则具有值 10salience 属性,以确保它在任何其他规则之前触发,因为该阶段 "Hope 是 Dead" 规则为 true。

规则 "We 有一个 honest politician"

rule "We have an honest Politician"
    salience 10
  when
    exists( Politician( honest == true ) )
  then
    insertLogical( new Hope() );
end

一旦存在 Hope 对象,"Hope Lives" 规则会匹配并触发。此规则也具有 10salience 值,因此它优先于 "Conest" 规则。

规则"Hope Lives"

rule "Hope Lives"
    salience 10
  when
    exists( Hope() )
  then
    System.out.println("Hurrah!!! Democracy Lives");
end

最初,四个 honest politicians 存在,因此此规则有四个激活,它们都存在冲突。每个规则依次触发,破坏每个策略,使它们不再被休眠。当所有四个 politician 都损坏时,没有 politicians 属性 honest == true。规则 "We have a honest Politician" 不再为 true,其逻辑插入的对象(由于上次执行 新 Hope ())将自动重新遍历。

规则"Corrupt the Honest"

rule "Corrupt the Honest"
  when
    politician : Politician( honest == true )
    exists( Hope() )
  then
    System.out.println( "I'm an evil corporation and I have corrupted " + politician.getName() );
    modify ( politician ) { honest = false };
end

使用 Hope 对象会自动重新遍历事实维护系统,不适用于 Hope 的 condition 元素不再为 true,因此 "Hope 是 Dead" 规则匹配并触发。

规则"Hope 是 Dead"

rule "Hope is Dead"
  when
    not( Hope() )
  then
    System.out.println( "We are all Doomed!!! Democracy is Dead" );
end

执行和审核跟踪示例

HonestPoliticianExample.java 类中,会插入四个 politicians,并将 honest 状态设置为 true,以针对定义的自定义规则进行评估:

HonestPoliticianExample.java class execution

public static void execute( KieContainer kc ) {
        KieSession ksession = kc.newKieSession("HonestPoliticianKS");

        final Politician p1 = new Politician( "President of Umpa Lumpa", true );
        final Politician p2 = new Politician( "Prime Minster of Cheeseland", true );
        final Politician p3 = new Politician( "Tsar of Pringapopaloo", true );
        final Politician p4 = new Politician( "Omnipotence Om", true );

        ksession.insert( p1 );
        ksession.insert( p2 );
        ksession.insert( p3 );
        ksession.insert( p4 );

        ksession.fireAllRules();

        ksession.dispose();
    }

要执行示例,请在 IDE 中作为 Java 应用程序运行 org.drools.examples.honestpolitician.HonestPoliticianExample 类。

执行后,以下输出会出现在 IDE 控制台窗口中:

IDE 控制台中的执行输出

Hurrah!!! Democracy Lives
I'm an evil corporation and I have corrupted President of Umpa Lumpa
I'm an evil corporation and I have corrupted Prime Minster of Cheeseland
I'm an evil corporation and I have corrupted Tsar of Pringapopaloo
I'm an evil corporation and I have corrupted Omnipotence Om
We are all Doomed!!! Democracy is Dead

输出显示,尽管至少有一个 honest politician democracy lives。但是,由于每个 politician 都被一些公司损坏,所有策略都会变得不当,并且 democracy 都被死。

要更好地了解本例的执行流程,您可以修改 HonestPoliticianExample.java 类,使其包含 DebugRuleRuntimeEventListener 侦听器和一个审核日志记录器来查看执行详情:

带有审计日志记录器的 HonestPoliticianExample.java 类

package org.drools.examples.honestpolitician;

import org.kie.api.KieServices;
import org.kie.api.event.rule.DebugAgendaEventListener; 1
import org.kie.api.event.rule.DebugRuleRuntimeEventListener;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

public class HonestPoliticianExample {

    /**
     * @param args
     */
    public static void main(final String[] args) {
    	KieServices ks = KieServices.Factory.get(); 2
    	//ks = KieServices.Factory.get();
        KieContainer kc = KieServices.Factory.get().getKieClasspathContainer();
        System.out.println(kc.verify().getMessages().toString());
        //execute( kc );
        execute( ks, kc); 3
    }

    public static void execute( KieServices ks, KieContainer kc ) { 4
        KieSession ksession = kc.newKieSession("HonestPoliticianKS");

        final Politician p1 = new Politician( "President of Umpa Lumpa", true );
        final Politician p2 = new Politician( "Prime Minster of Cheeseland", true );
        final Politician p3 = new Politician( "Tsar of Pringapopaloo", true );
        final Politician p4 = new Politician( "Omnipotence Om", true );

        ksession.insert( p1 );
        ksession.insert( p2 );
        ksession.insert( p3 );
        ksession.insert( p4 );

        // The application can also setup listeners 5
        ksession.addEventListener( new DebugAgendaEventListener() );
        ksession.addEventListener( new DebugRuleRuntimeEventListener() );

        // Set up a file-based audit logger.
        ks.getLoggers().newFileLogger( ksession, "./target/honestpolitician" ); 6

        ksession.fireAllRules();

        ksession.dispose();
    }

}

1
在导入处理 DebugAgendaEventListenerDebugRuleRuntimeEventListener的软件包中添加
2
创建一个 KieServices Factoryks 元素来生成日志,因为此审计日志在 KieContainer 级别不可用
3
修改 execute 方法,以使用 KieServicesKieContainer
4
除了 KieContainer外,修改在 KieServices 中传递的 execute 方法
5
创建监听程序
6
构建在执行规则后可传递给 debug 视图或 审计 视图或 IDE 的日志

当您使用此修改后的日志记录功能运行 Honest Politician 时,您可以将 target/honestpolitician.log 中的审计日志文件加载到 IDE 调试视图或 审计 视图(例如,在一些 IDE 中显示 窗口Show View )。

在本例中,审计视图显示 执行流、插入和重新加载actions,如示例类和规则中定义的:

图 19.18. honest Politician 示例审计视图

honest politician 审计

插入第一个 politician 时,会发生两个激活。规则 "We 有一个 honest Politician" 首次插入的 politician 激活一次,因为它使用 exists 条件元素,它在插入至少一个 politician 时匹配。规则 "Hope is Dead" 也在这个阶段激活,因为 Hope 对象还没有插入。规则 "We 有一个 honest Politician" 触发,因为它具有高于规则 "Hope is Dead"salience 值,并插入 Hope 对象(以绿色表示)。Hope 对象的插入激活规则 "Hope Lives",并取消激活规则 "Hope is Dead "。插入还会激活每个插入的 honest politician 的规则 "Corrupt the Honest "。规则 "Hope Lives" 被执行并打印 "Hurrah!!!Democracy Lives"

接下来,对于每个策略,规则 "Corrupt the Honest" 触发,打印 "I'm a evil certification and I have damage X ",其中 X 是 politician 的名称,并将 politician honesty 值改为 false。当最后一个 honest politician 损坏时,H ope 会自动被事实维护系统(在蓝色中高)。绿色突出显示区域显示当前选定的蓝色突出显示区域的来源。重新遍历 Hope 事实后,规则 "Hope is dead" 会触发,打印 "We is all Doomed!!!!!!!Democracy 是 Dead"

19.8. Sudoku 示例决策(组合模式匹配、回调和 GUI 集成)

Sudoku 示例决定基于流行数量 puzzle Sudoku,演示了如何根据各种限制在 Red Hat Process Automation Manager 中使用规则来查找大型潜在解决方案空间的解决方案。本例还演示了如何将 Red Hat Process Automation Manager 规则集成到图形用户界面(GUI)中,在这种情况下,使用基于 Swing 的桌面应用程序,以及如何使用回调与正在运行的决策引擎交互,根据工作内存中的更改更新 GUI。

以下是 Sudoku 示例的概述:

  • 名称 :sudoku
  • 主类org.drools.examples.sudoku.SudokuExample (在 src/main/java中)
  • 模块drools-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.sudoku114.drl (在 src/main/resources中)
  • 目标 :演示复杂模式匹配、问题问题、回调和 GUI 集成

Sudoku 是一个基于逻辑的数字放置 puzzle。目标是填充 9x9 网格,以便每列、每行和每 9 个 3x3 区域都包含从 1 到 9 次的数字。puzzle setter 提供了部分完成的网格,puzzle solver 的任务是完成具有这些限制的网格。

解决问题的一般策略是确保在插入新数字时,必须在其特定的 3x3 区域、行和列中是唯一的。这个 Sudoku 示例决策使用 Red Hat Process Automation Manager 规则从各种困难级别解决 Sudoku puzzles,并尝试解决包含无效条目的缺陷。

Sudoku 示例执行和交互

与其他 Red Hat Process Automation Manager 决策示例类似,您可以通过在 IDE 中作为 Java 应用程序运行 org.drools.examples.sudoku.SudokuExample 类来执行 Sudoku 示例。

当您执行 Sudoku 示例时,会出现 droyku Example GUI 窗口。此窗口包含一个空的网格,但程序在内部存储各种您可以加载和解决。

FileSamplesSimple 加载其中一个示例。请注意,所有按钮都被禁用,直到网格加载为止。

图 19.19. 启动后,Sudoku 示例 GUI

sudoku1

当您加载 简单示例 时,网格会根据 puzzle 的初始状态填充。

图 19.20. 在载入简单示例后,Sudoku 示例 GUI

sudoku2

�以下选项中选择:

  • Solve 触发 Sudoku 示例中定义的规则,以填充剩余的值,并使按钮再次不活跃。

    图 19.21. 已解决简单示例

    sudoku3
  • Step 查看规则集找到的下一个数字。IDE 中的控制台窗口显示有关正在执行的规则的详细信息,以解决问题。

    IDE 控制台中的步骤执行输出

    single 8 at [0,1]
    column elimination due to [1,2]: remove 9 from [4,2]
    hidden single 9 at [1,2]
    row elimination due to [2,8]: remove 7 from [2,4]
    remove 6 from [3,8] due to naked pair at [3,2] and [3,7]
    hidden pair in row at [4,6] and [4,4]

  • 单击 Dump 以查看网格的状态,以及显示已建立的值或剩余值的单元格。

    在 IDE 控制台中转储执行输出

            Col: 0     Col: 1     Col: 2     Col: 3     Col: 4     Col: 5     Col: 6     Col: 7     Col: 8
    Row 0:  123456789  --- 5 ---  --- 6 ---  --- 8 ---  123456789  --- 1 ---  --- 9 ---  --- 4 ---  123456789
    Row 1:  --- 9 ---  123456789  123456789  --- 6 ---  123456789  --- 5 ---  123456789  123456789  --- 3 ---
    Row 2:  --- 7 ---  123456789  123456789  --- 4 ---  --- 9 ---  --- 3 ---  123456789  123456789  --- 8 ---
    Row 3:  --- 8 ---  --- 9 ---  --- 7 ---  123456789  --- 4 ---  123456789  --- 6 ---  --- 3 ---  --- 5 ---
    Row 4:  123456789  123456789  --- 3 ---  --- 9 ---  123456789  --- 6 ---  --- 8 ---  123456789  123456789
    Row 5:  --- 4 ---  --- 6 ---  --- 5 ---  123456789  --- 8 ---  123456789  --- 2 ---  --- 9 ---  --- 1 ---
    Row 6:  --- 5 ---  123456789  123456789  --- 2 ---  --- 6 ---  --- 9 ---  123456789  123456789  --- 7 ---
    Row 7:  --- 6 ---  123456789  123456789  --- 5 ---  123456789  --- 4 ---  123456789  123456789  --- 9 ---
    Row 8:  123456789  --- 4 ---  --- 9 ---  --- 7 ---  123456789  --- 8 ---  --- 3 ---  --- 5 ---  123456789

Sudoku 示例包含一个破坏的示例文件,在示例中定义的规则可以解析。

FileSamples!DELIBERATELY BROKEN! 加载有问题的示例。网格从某些问题开始,例如,第一行中的 5 值会出现两次,而这不允许使用。

图 19.22. broken Sudoku 示例初始状态

sudoku4

单击 Solve,以将过期规则应用到此无效的网格。Sudoku 示例中的关联规则会检测示例中的问题,并尝试尽可能解决 puzzle。这个过程没有完成,并保留一些单元为空。

过期规则活动显示在 IDE 控制台窗口中:

在有问题的示例中检测到问题

cell [0,8]: 5 has a duplicate in row 0
cell [0,0]: 5 has a duplicate in row 0
cell [6,0]: 8 has a duplicate in col 0
cell [4,0]: 8 has a duplicate in col 0
Validation complete.

图 19.23. 有问题的示例解决方案尝试

sudoku5

标记为 Hard 的 Sudoku 文件示例更为复杂,一般规则可能无法解决它们。IDE 控制台窗口中会显示失败的解决方案尝试:

未解析的硬链接

Validation complete.
...
Sorry - can't solve this grid.

解决损坏的样本的规则根据仍为单元候选者的值集合实施标准过期技术。例如,如果集合包含单个值,则这是单元的值。对于在 9 个单元组中出现一个值,规则会插入带有某些特定单元的解决方案值的类型 设置 事实。这将导致从单元所属的所有其他单元中分离这个值,并且该值会被重新遍历。

示例中的其他规则可减少某些单元的感知值。规则 "naked pair", "hidden pair in row", "hidden pair in column", and "hidden pair in physical" 会消除可能性,但不建立解决方案。规则 "X-wings in rows", "'X-wings in column"', "intersection removal row", 和 "intersection removal column" 会执行更复杂的背景。

Sudoku 示例类

软件包 org.drools.examples.sudoku.swing 包含以下核心类集合,该类实现了 Sudoku puzzles 的框架:

  • SudokuGridModel 类定义了一个接口,用来存储 Sudoku puzzle 作为 Cell 对象的 9x9 网格。
  • SudokuGridView 类是一个 Swing 组件,它可以视觉化 SudokuGridModel 类的任何实现。
  • SudokuGridEventSudokuGridListener 类在模型和视图之间进行通信状态更改。当单元值被解决或更改时,会触发事件。
  • SudokuGridSamples 类提供了部分填充 Sudoku puzzles 用于演示目的。
注意

这个软件包对 Red Hat Process Automation Manager 库没有任何依赖项。

软件包 org.drools.examples.sudoku 包含以下核心类集合,它们实现了元素 Cell 对象及其各种聚合:

  • CellFile 类,带有子类型 CellRowCellColCellSqr,它们都是 CellGroup 类的子类型。
  • SetOfNineCellCellGroup 子类,它提供了一个没有类型 Set & lt;Integer&gt; 的属性。对于 Cell 类,该集合代表单个候选集。对于 CellGroup 类,该集合是其单元的所有候选集合(仍需要分配的数字集)。

    在 Sudoku 示例中,有 81 Cell 和 27 CellGroup 对象,以及 Cell 属性 cellRowcellColcellSqr 以及 CellGroup 属性 单元 提供的链接。使用这些组件,您可以编写规则来检测特定情况,允许将值分配给单元,或从某些候选集中删除值。

  • Setting 类用于触发值分配附带的操作。所有规则中都会使用 设置 事实,以检测新情况以避免重新发生中间状态。
  • "Step" 不会定期终止时,在低优先级规则中使用 Stepping 类来执行紧急停止。这个行为表示程序无法解决模糊。
  • 主类 org.drools.examples.sudoku.SudokuExample 实施了组合了所有这些组件的 Java 应用程序。

Sudoku 验证规则(validate.drl)

Sudoku 示例中的 validate.drl 文件包含验证规则,用于检测单元组中重复数字。它们合并到一个 "validate" 站组中,允许用户在用户加载 puzzle 后明确激活该规则。

三种规则 "duplicate in cell …​" all 功能 的时间 条件如下:

  • 规则中的第一个条件会找到带有分配值的单元。
  • 规则中的第二个条件会拉取到该单元所属的三个单元组。
  • 根据规则,最终条件找到一个单元(除前一个除外),其值为第一个单元和同一行、列或方括号。

规则 "duplicate in cell …​"

rule "duplicate in cell row"
  when
    $c: Cell( $v: value != null )
    $cr: CellRow( cells contains $c )
    exists Cell( this != $c, value == $v, cellRow == $cr )
  then
    System.out.println( "cell " + $c.toString() + " has a duplicate in row " + $cr.getNumber() );
end

rule "duplicate in cell col"
  when
    $c: Cell( $v: value != null )
    $cc: CellCol( cells contains $c )
    exists Cell( this != $c, value == $v, cellCol == $cc )
  then
    System.out.println( "cell " + $c.toString() + " has a duplicate in col " + $cc.getNumber() );
end

rule "duplicate in cell sqr"
  when
    $c: Cell( $v: value != null )
    $cs: CellSqr( cells contains $c )
    exists Cell( this != $c, value == $v, cellSqr == $cs )
  then
    System.out.println( "cell " + $c.toString() + " has duplicate in its square of nine." );
end

规则 "terminate group" 是最后一个要触发的规则。此规则打印消息并停止序列。

规则 "terminate group"

rule "terminate group"
    salience -100
  when
  then
    System.out.println( "Validation complete." );
    drools.halt();
end

Sudokucertification rules (sudoku.drl)

Sudoku 示例中的 sudoku.drl 文件包含三种类型的规则:一个组处理到单元的数字分配,另一个组检测到可行的分配,第三个组从 candidate 集合中删除值。

规则 "set a value", "eliminate a value from Cell", 和 "retract setting" 取决于 Setting 对象的存在。第一个规则处理到单元的分配,以及从单元格的三个组 的空闲 集合中删除值的操作。这个组也会减少计数器,当零时,将控制返回到名为 fireUntilHalt () 的 Java 应用程序。

规则 "eliminate a value from Cell" 的目的是减少与新分配的单元相关的所有单元的候选列表。最后,当完成所有提升后,规则 " Retract 设置" 会重新遍历触发器 设置 事实。

规则 "set a value", "eliminate a value from a Cell", and "retract setting"

// A Setting object is inserted to define the value of a Cell.
// Rule for updating the cell and all cell groups that contain it
rule "set a value"
  when
    // A Setting with row and column number, and a value
    $s: Setting( $rn: rowNo, $cn: colNo, $v: value )

    // A matching Cell, with no value set
    $c: Cell( rowNo == $rn, colNo == $cn, value == null,
              $cr: cellRow, $cc: cellCol, $cs: cellSqr )

    // Count down
    $ctr: Counter( $count: count )
  then
    // Modify the Cell by setting its value.
    modify( $c ){ setValue( $v ) }
    // System.out.println( "set cell " + $c.toString() );
    modify( $cr ){ blockValue( $v ) }
    modify( $cc ){ blockValue( $v ) }
    modify( $cs ){ blockValue( $v ) }
    modify( $ctr ){ setCount( $count - 1 ) }
end

// Rule for removing a value from all cells that are siblings
// in one of the three cell groups
rule "eliminate a value from Cell"
  when
    // A Setting with row and column number, and a value
    $s: Setting( $rn: rowNo, $cn: colNo, $v: value )

    // The matching Cell, with the value already set
    Cell( rowNo == $rn, colNo == $cn, value == $v, $exCells: exCells )

    // For all Cells that are associated with the updated cell
    $c: Cell( free contains $v ) from $exCells
  then
    // System.out.println( "clear " + $v + " from cell " + $c.posAsString()  );
    // Modify a related Cell by blocking the assigned value.
    modify( $c ){ blockValue( $v ) }
end

// Rule for eliminating the Setting fact
rule "retract setting"
  when
    // A Setting with row and column number, and a value
    $s: Setting( $rn: rowNo, $cn: colNo, $v: value )

    // The matching Cell, with the value already set
    $c: Cell( rowNo == $rn, colNo == $cn, value == $v )

    // This is the negation of the last pattern in the previous rule.
    // Now the Setting fact can be safely retracted.
    not( $x: Cell( free contains $v )
         and
         Cell( this == $c, exCells contains $x ) )
  then
    // System.out.println( "done setting cell " + $c.toString() );
    // Discard the Setter fact.
    delete( $s );
    // Sudoku.sudoku.consistencyCheck();
end

双向规则会检测一个可能为单元分配数字的情况。规则 "single" 会为 Cell 触发一个包含单个数字的候选集。当单个候选不存在单元格时,规则 "hidden single" 会触发,但当单元存在包含候选者的单元格时,这个候选都不包括在单元格所属的三个组中。规则创建和插入 设置 事实。

规则"单一"和"隐藏单一"

// Detect a set of candidate values with cardinality 1 for some Cell.
// This is the value to be set.
rule "single"
  when
    // Currently no setting underway
    not Setting()

    // One element in the "free" set
    $c: Cell( $rn: rowNo, $cn: colNo, freeCount == 1 )
  then
    Integer i = $c.getFreeValue();
    if (explain) System.out.println( "single " + i + " at " + $c.posAsString() );
    // Insert another Setter fact.
    insert( new Setting( $rn, $cn, i ) );
end

// Detect a set of candidate values with a value that is the only one
// in one of its groups. This is the value to be set.
rule "hidden single"
  when
    // Currently no setting underway
    not Setting()
    not Cell( freeCount == 1 )

    // Some integer
    $i: Integer()

    // The "free" set contains this number
    $c: Cell( $rn: rowNo, $cn: colNo, freeCount > 1, free contains $i )

    // A cell group contains this cell $c.
    $cg: CellGroup( cells contains $c )
    // No other cell from that group contains $i.
    not ( Cell( this != $c, free contains $i ) from $cg.getCells() )
  then
    if (explain) System.out.println( "hidden single " + $i + " at " + $c.posAsString() );
    // Insert another Setter fact.
    insert( new Setting( $rn, $cn, $i ) );
end

来自最多组的规则,可以是独立或三组,可以手动实施用于手动的 Sudoku puzzles 的各种技术。

规则 "naked pair" 在组的两个单元中检测相同的大小为 2 的候选集合。这两个值可以从该组的所有其他候选集合中删除。

规则"naked pair"

// A "naked pair" is two cells in some cell group with their sets of
// permissible values being equal with cardinality 2. These two values
// can be removed from all other candidate lists in the group.
rule "naked pair"
  when
    // Currently no setting underway
    not Setting()
    not Cell( freeCount == 1 )

    // One cell with two candidates
    $c1: Cell( freeCount == 2, $f1: free, $r1: cellRow, $rn1: rowNo, $cn1: colNo, $b1: cellSqr )

    // The containing cell group
    $cg: CellGroup( freeCount > 2, cells contains $c1 )

    // Another cell with two candidates, not the one we already have
    $c2: Cell( this != $c1, free == $f1 /*** , rowNo >= $rn1, colNo >= $cn1 ***/ ) from $cg.cells

    // Get one of the "naked pair".
    Integer( $v: intValue ) from $c1.getFree()

    // Get some other cell with a candidate equal to one from the pair.
    $c3: Cell( this != $c1 && != $c2, freeCount > 1, free contains $v ) from $cg.cells
  then
    if (explain) System.out.println( "remove " + $v + " from " + $c3.posAsString() + " due to naked pair at " + $c1.posAsString() + " and " + $c2.posAsString() );
    // Remove the value.
    modify( $c3 ){ blockValue( $v ) }
end

三个规则 "hidden pair in …​" 函数类似于规则 "naked pair "。这些规则检测一个组的两个单元中有两个数字的子集,且在组的任何其他单元中不会发生值。这意味着,所有其他候选者可以从两个单元格中删除。

规则"hidden pair in …​"

// If two cells within the same cell group contain candidate sets with more than
// two values, with two values being in both of them but in none of the other
// cells, then we have a "hidden pair". We can remove all other candidates from
// these two cells.
rule "hidden pair in row"
  when
    // Currently no setting underway
    not Setting()
    not Cell( freeCount == 1 )

    // Establish a pair of Integer facts.
    $i1: Integer()
    $i2: Integer( this > $i1 )

    // Look for a Cell with these two among its candidates. (The upper bound on
    // the number of candidates avoids a lot of useless work during startup.)
    $c1: Cell( $rn1: rowNo, $cn1: colNo, freeCount > 2 && < 9, free contains $i1 && contains $i2, $cellRow: cellRow )

    // Get another one from the same row, with the same pair among its candidates.
    $c2: Cell( this != $c1, cellRow == $cellRow, freeCount > 2, free contains $i1 && contains $i2 )

    // Ascertain that no other cell in the group has one of these two values.
    not( Cell( this != $c1 && != $c2, free contains $i1 || contains $i2 ) from $cellRow.getCells() )
  then
    if( explain) System.out.println( "hidden pair in row at " + $c1.posAsString() + " and " + $c2.posAsString() );
    // Set the candidate lists of these two Cells to the "hidden pair".
    modify( $c1 ){ blockExcept( $i1, $i2 ) }
    modify( $c2 ){ blockExcept( $i1, $i2 ) }
end

rule "hidden pair in column"
  when
    not Setting()
    not Cell( freeCount == 1 )

    $i1: Integer()
    $i2: Integer( this > $i1 )
    $c1: Cell( $rn1: rowNo, $cn1: colNo, freeCount > 2 && < 9, free contains $i1 && contains $i2, $cellCol: cellCol )
    $c2: Cell( this != $c1, cellCol == $cellCol, freeCount > 2, free contains $i1 && contains $i2 )
    not( Cell( this != $c1 && != $c2, free contains $i1 || contains $i2 ) from $cellCol.getCells() )
  then
    if (explain) System.out.println( "hidden pair in column at " + $c1.posAsString() + " and " + $c2.posAsString() );
    modify( $c1 ){ blockExcept( $i1, $i2 ) }
    modify( $c2 ){ blockExcept( $i1, $i2 ) }
end

rule "hidden pair in square"
  when
    not Setting()
    not Cell( freeCount == 1 )

    $i1: Integer()
    $i2: Integer( this > $i1 )
    $c1: Cell( $rn1: rowNo, $cn1: colNo, freeCount > 2 && < 9, free contains $i1 && contains $i2,
               $cellSqr: cellSqr )
    $c2: Cell( this != $c1, cellSqr == $cellSqr, freeCount > 2, free contains $i1 && contains $i2 )
    not( Cell( this != $c1 && != $c2, free contains $i1 || contains $i2 ) from $cellSqr.getCells() )
  then
    if (explain) System.out.println( "hidden pair in square " + $c1.posAsString() + " and " + $c2.posAsString() );
    modify( $c1 ){ blockExcept( $i1, $i2 ) }
    modify( $c2 ){ blockExcept( $i1, $i2 ) }
end

两个规则处理行和 列中的"X-wings "。当两个不同的行(或列)中只有两个可能的值的单元,且这些候选者也位于同一列(或行),那么可以消除列(或行)中这个值的所有其他候选者。当您遵循其中一个规则中的模式序列时,请注意,如何按照单词(如 相同或 会导致带有适当约束或前缀的模式)表示的条件。

规则 "X-wings in …​"

rule "X-wings in rows"
  when
    not Setting()
    not Cell( freeCount == 1 )

    $i: Integer()
    $ca1: Cell( freeCount > 1, free contains $i,
                $ra: cellRow, $rano: rowNo,         $c1: cellCol,        $c1no: colNo )
    $cb1: Cell( freeCount > 1, free contains $i,
                $rb: cellRow, $rbno: rowNo > $rano,      cellCol == $c1 )
    not( Cell( this != $ca1 && != $cb1, free contains $i ) from $c1.getCells() )

    $ca2: Cell( freeCount > 1, free contains $i,
                cellRow == $ra, $c2: cellCol,       $c2no: colNo > $c1no )
    $cb2: Cell( freeCount > 1, free contains $i,
                cellRow == $rb,      cellCol == $c2 )
    not( Cell( this != $ca2 && != $cb2, free contains $i ) from $c2.getCells() )

    $cx: Cell( rowNo == $rano || == $rbno, colNo != $c1no && != $c2no,
               freeCount > 1, free contains $i )
  then
    if (explain) {
        System.out.println( "X-wing with " + $i + " in rows " +
            $ca1.posAsString() + " - " + $cb1.posAsString() +
            $ca2.posAsString() + " - " + $cb2.posAsString() + ", remove from " + $cx.posAsString() );
    }
    modify( $cx ){ blockValue( $i ) }
end

rule "X-wings in columns"
  when
    not Setting()
    not Cell( freeCount == 1 )

    $i: Integer()
    $ca1: Cell( freeCount > 1, free contains $i,
                $c1: cellCol, $c1no: colNo,         $ra: cellRow,        $rano: rowNo )
    $ca2: Cell( freeCount > 1, free contains $i,
                $c2: cellCol, $c2no: colNo > $c1no,      cellRow == $ra )
    not( Cell( this != $ca1 && != $ca2, free contains $i ) from $ra.getCells() )

    $cb1: Cell( freeCount > 1, free contains $i,
                cellCol == $c1, $rb: cellRow,  $rbno: rowNo > $rano )
    $cb2: Cell( freeCount > 1, free contains $i,
                cellCol == $c2,      cellRow == $rb )
    not( Cell( this != $cb1 && != $cb2, free contains $i ) from $rb.getCells() )

    $cx: Cell( colNo == $c1no || == $c2no, rowNo != $rano && != $rbno,
               freeCount > 1, free contains $i )
  then
    if (explain) {
        System.out.println( "X-wing with " + $i + " in columns " +
            $ca1.posAsString() + " - " + $ca2.posAsString() +
            $cb1.posAsString() + " - " + $cb2.posAsString() + ", remove from " + $cx.posAsString()  );
    }
    modify( $cx ){ blockValue( $i ) }
end

这两个规则 "intersection removal …​" 基于一个方括号中的某个数字的限制,可以在一行或单个列中出现。这意味着这个数字必须在行或列的两或三个单元之一,并且可以从组所有其他单元的候选集合中删除。模式建立受限发生,然后针对方括号和同一单元文件之外的每个单元触发。

规则 "intersection removal …​"

rule "intersection removal column"
  when
    not Setting()
    not Cell( freeCount == 1 )

    $i: Integer()
    // Occurs in a Cell
    $c: Cell( free contains $i, $cs: cellSqr, $cc: cellCol )
    // Does not occur in another cell of the same square and a different column
    not Cell( this != $c, free contains $i, cellSqr == $cs, cellCol != $cc )

    // A cell exists in the same column and another square containing this value.
    $cx: Cell( freeCount > 1, free contains $i, cellCol == $cc, cellSqr != $cs )
  then
    // Remove the value from that other cell.
    if (explain) {
        System.out.println( "column elimination due to " + $c.posAsString() +
                            ": remove " + $i + " from " + $cx.posAsString() );
    }
    modify( $cx ){ blockValue( $i ) }
end

rule "intersection removal row"
  when
    not Setting()
    not Cell( freeCount == 1 )

    $i: Integer()
    // Occurs in a Cell
    $c: Cell( free contains $i, $cs: cellSqr, $cr: cellRow )
    // Does not occur in another cell of the same square and a different row.
    not Cell( this != $c, free contains $i, cellSqr == $cs, cellRow != $cr )

    // A cell exists in the same row and another square containing this value.
    $cx: Cell( freeCount > 1, free contains $i, cellRow == $cr, cellSqr != $cs )
  then
    // Remove the value from that other cell.
    if (explain) {
        System.out.println( "row elimination due to " + $c.posAsString() +
                            ": remove " + $i + " from " + $cx.posAsString() );
    }
    modify( $cx ){ blockValue( $i ) }
end

这些规则对于许多但不是 Sudoku puzzles 而言已经足够了。为了解决非常困难,规则集需要更复杂的规则。(类似地,只有试用和错误才能解决一些模糊。)

19.9. 生命周期决策的整合方法(ruleflow 组和 GUI 集成)

Conway's Game of Life example 决策集基于 John Conway 的 famous cellular automaton,演示了如何在规则中使用 ruleflow 组来控制规则执行。这个示例还演示了如何将 Red Hat Process Automation Manager 规则与图形用户界面(GUI)集成,在本例中基于 Swing's Game of Life。

以下是 Conway's Game of Life (Conway)示例的概述:

  • Name:conway
  • 主类org.drools.examples.conway.ConwayRuleFlowGroupRun,org.drools.examples.conway.ConwayAgendaGroupRun (in src/main/java)
  • 模块droolsjbpm-integration-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.conway114.drl (在 src/main/resources中)
  • 目标 :演示 ruleflow 组和 GUI 集成
注意

The Conway's Game of Life example of the regularols jbpm-integration-examples in the Red Hat Process Automation Manager 7.9.1 source distribution from the Red Hat Customer Portal.

在 Conway's Game 的生命周期内,用户通过创建初始配置或具有定义属性的高级模式,然后观察初始状态的演进方式与游戏交互。游戏的目的是显示填充的开发,生成到生成。以上每个生成结果都基于所有单元的同时评估。

以下基本规则管理下一代内容,如下所示:

  • 如果实时单元少于两个实时邻居,它将划分掉 loneliness。
  • 如果实时单元有超过三个实时邻居,它将被过度分离。
  • 如果死单元具有三个实时邻居,则相当于生命周期。

任何不符合这些条件的单元都保留为在下一代位置中。

The Conway 的 Game of Life example 使用 Red Hat Process Automation Manager 规则和 ruleflow-group 属性来定义在游戏中实施的模式。该示例还包含一组决策集的版本,该版本通过电缆组实现相同的行为。通过电缆组,您可以对决策引擎人员进行分区,以提供对规则组的执行控制。默认情况下,所有规则都位于 products 组 MAIN 中。您可以使用 sales -group 属性为规则指定不同的 sales 组。

此概述不会探索使用电缆组的对比示例版本。有关销售组的更多信息,请参阅 Red Hat Process Automation Manager 决策集合,该设置专门解决电缆组。

执行和交互示例

与其他 Red Hat Process Automation Manager 决策示例类似,您可以通过在 IDE 中作为 Java 应用程序运行 org.drools.examples.conwayRuleFlowGroupRun 类来执行 Conway ruleflow 示例。

当您执行 Conway 示例时,会出现 Conway's Game of Life GUI 窗口。此窗口包含一个空的网格,或"arena",其中执行生命周期模拟。最初网格为空,因为系统上还没有实时单元。

图 19.24. 启动后的 GUI 示例

conway1

Pattern 下拉菜单中选择预定义的模式,然后单击 Next Generation 以点每个填充生成。每个单元都是 live 或 dead,其中实时单元包含一个绿色 ball。随着填充从初始模式增长时,根据游戏的规则,从初始模式增长或相对于邻居单元的单元格。

图 19.25. 一致性示例中的生成演进

conway2

邻居不仅包括左侧、右、顶部和底部连接的单元格,以及连接了 diagonly 的单元,因此每个单元格都有总计 8 个邻居。例外是角单元,其中只有三个邻居,以及四个边框的单元格,每个方都有五个邻居。

您可以通过单击单元来手动干预来创建或终止单元。

要从初始模式下运行,请单击 Start

使用带有 ruleflow 组的示例规则

ConwayRuleFlowGroupRun 示例中的规则使用 ruleflow 组来控制规则执行。ruleflow 组是由 rule flow-group rule 属性关联的一组规则。这些规则只能在组激活时触发。只有当 ruleflow 图的 Elaboration 到达代表组的节点时,组本身才能变为活动状态。

Conway 示例将以下 ruleflow 组用于规则:

  • "register neighbor"
  • "evaluate"
  • "calculate"
  • "reset calculate"
  • "birth"
  • "kill"
  • "kill all"

所有 Cell 对象都插入到 KIE 会话中,ruleflow 组 "register neighbor" 中的 "register …​" 规则可以被 ruleflow 进程执行。这个四个规则组会在某些单元格及其 northeastern、northern、northwestern 和 western neighbors 之间创建邻居关系。

这种关系是双向的,处理其他四个方向。边框单元不需要任何特殊处理。这些单元不会与没有邻居单元的邻居单元配对。

通过为这些规则触发所有激活的时间,所有单元都与所有邻居单元相关。

rules "register …​"

rule "register north east"
    ruleflow-group "register neighbor"
  when
    $cell: Cell( $row : row, $col : col )
    $northEast : Cell( row  == ($row - 1), col == ( $col + 1 ) )
  then
    insert( new Neighbor( $cell, $northEast ) );
    insert( new Neighbor( $northEast, $cell ) );
end

rule "register north"
    ruleflow-group "register neighbor"
  when
    $cell: Cell( $row : row, $col : col )
    $north : Cell( row  == ($row - 1), col == $col )
  then
    insert( new Neighbor( $cell, $north ) );
    insert( new Neighbor( $north, $cell ) );
end

rule "register north west"
    ruleflow-group "register neighbor"
  when
    $cell: Cell( $row : row, $col : col )
    $northWest : Cell( row  == ($row - 1), col == ( $col - 1 ) )
  then
    insert( new Neighbor( $cell, $northWest ) );
    insert( new Neighbor( $northWest, $cell ) );
end

rule "register west"
    ruleflow-group "register neighbor"
  when
    $cell: Cell( $row : row, $col : col )
    $west : Cell( row  == $row, col == ( $col - 1 ) )
  then
    insert( new Neighbor( $cell, $west ) );
    insert( new Neighbor( $west, $cell ) );
end

插入完所有单元后,一些 Java 代码会将模式应用到网格,将某些单元设置为 Live。然后,当用户单击 StartNext Generation 时,示例会执行 Generation ruleflow。此 ruleflow 管理每个生成周期中的单元的所有更改。

图 19.26. 生成 ruleflow

聚合规则流生成

ruleflow 进程输入 "evaluate" 规则流组,组中的任何活动规则都可以触发。这个组中的规则 "Kill the …​""Give Birth" 将游戏规则应用到 birth 或 kill 单元。这个示例使用 phase 属性根据特定规则组驱动 Cell 对象的原因。通常,阶段与 ruleflow 进程定义中的 ruleflow 组关联。

请注意,这个示例不会更改任何 Cell 对象的状态,因为它必须在应用更改前完成完整评估。示例将单元设置为 Phase.KILLPhase.114RTH阶段,稍后用于控制应用到 Cell 对象的操作。

规则 "Kill the …​" 和 "Give Birth"

rule "Kill The Lonely"
    ruleflow-group "evaluate"
    no-loop
  when
    // A live cell has fewer than 2 live neighbors.
    theCell: Cell( liveNeighbors < 2, cellState == CellState.LIVE,
                   phase == Phase.EVALUATE )
  then
    modify( theCell ){
        setPhase( Phase.KILL );
    }
end

rule "Kill The Overcrowded"
    ruleflow-group "evaluate"
    no-loop
  when
    // A live cell has more than 3 live neighbors.
    theCell: Cell( liveNeighbors > 3, cellState == CellState.LIVE,
                   phase == Phase.EVALUATE )
  then
    modify( theCell ){
        setPhase( Phase.KILL );
    }
end

rule "Give Birth"
    ruleflow-group "evaluate"
    no-loop
  when
    // A dead cell has 3 live neighbors.
    theCell: Cell( liveNeighbors == 3, cellState == CellState.DEAD,
                   phase == Phase.EVALUATE )
  then
    modify( theCell ){
        theCell.setPhase( Phase.BIRTH );
    }
end

评估网格中的所有 Cell 对象后,示例使用 "reset compute" 规则清除 " calculate" ruleflow 组中的任何激活。然后,在 ruleflow 中输入分割,如果 ruleflow 组被激活,使规则 "kill""birth" 触发。这些规则应用状态更改。

规则 "reset calculate", "kill", 和 "birth"

rule "reset calculate"
    ruleflow-group "reset calculate"
  when
  then
    WorkingMemory wm = drools.getWorkingMemory();
    wm.clearRuleFlowGroup( "calculate" );
end

rule "kill"
    ruleflow-group "kill"
    no-loop
  when
    theCell: Cell( phase == Phase.KILL )
  then
    modify( theCell ){
        setCellState( CellState.DEAD ),
        setPhase( Phase.DONE );
    }
end

rule "birth"
    ruleflow-group "birth"
    no-loop
  when
    theCell: Cell( phase == Phase.BIRTH )
  then
    modify( theCell ){
        setCellState( CellState.LIVE ),
        setPhase( Phase.DONE );
    }
end

在这个阶段,将几个 Cell 对象更改为 LIVEDEAD 状态。当单元格变为 live 或 dead 时,示例使用规则 "Calculate …​" 中的 邻居 关系来迭代所有周围的单元,增加或减少 liveNeighbor 数。更改了计数的任何单元都设置为 EVALUATE 阶段,以确保在 ruleflow 过程评估阶段将其包含在原因中。

在为所有单元决定和设置实时数后,ruleflow 进程将结束。如果用户最初点击 Start,则决策引擎会在此时重新启动 ruleflow。如果用户最初单击 Next Generation,用户可以请求另一个生成。

规则 "Calculate …​"

rule "Calculate Live"
    ruleflow-group "calculate"
    lock-on-active
  when
    theCell: Cell( cellState == CellState.LIVE )
    Neighbor( cell == theCell, $neighbor : neighbor )
  then
    modify( $neighbor ){
        setLiveNeighbors( $neighbor.getLiveNeighbors() + 1 ),
        setPhase( Phase.EVALUATE );
    }
end

rule "Calculate Dead"
    ruleflow-group "calculate"
    lock-on-active
  when
    theCell: Cell( cellState == CellState.DEAD )
    Neighbor( cell == theCell, $neighbor : neighbor )
  then
    modify( $neighbor ){
        setLiveNeighbors( $neighbor.getLiveNeighbors() - 1 ),
        setPhase( Phase.EVALUATE );
    }
end

19.10. 定制 Doom 示例决策(返回链和递归)

Doom 示例决策集的 House 演示了决策引擎如何使用向后兼容性和递归来访问分层系统中定义的目标或子组。

以下是 Doom 示例 House 的概述:

  • 名称后链
  • 主类org.drools.examples.backwardchaining.HouseOfDoomMain (在 src/main/java中)
  • 模块drools-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.backwardchaining.BC-Example.drl (在 src/main/resources中)
  • 目标 :演示后链和递归

后链规则系统是一个目标驱动的系统,从决策引擎尝试满足的目标驱动的系统开始,通常使用递归。如果系统无法访问语音或目标,它会搜索子组,这是完成当前目标的一部分。系统会继续这个过程,直到满足初始目标或满足所有子状态为止。

相反,转发链规则系统是一个数据驱动的系统,它以决策引擎的工作内存中的事实开始,并对这一事实的更改做出响应。当对象插入到工作内存中时,因更改计划执行而满足的任何规则条件。

Red Hat Process Automation Manager 中的决策引擎使用正向和后链来评估规则。

下图演示了,决策引擎如何使用转发链和逻辑流中的向链段来评估规则:

图 19.27. 使用正向和后链的规则评估逻辑

RuleEvaluation Enterprise

Doom 示例的 House 使用各种类型的查询的规则来查找托管中的房间和项目的位置。示例类 Location.java 包含示例中使用的 和位置 元素。示例类 HouseOfDoomMain.java 将项目或房间插入到其各自的位置,并执行规则。

HouseOfDoomMain.java 类的项目和位置

ksession.insert( new Location("Office", "House") );
ksession.insert( new Location("Kitchen", "House") );
ksession.insert( new Location("Knife", "Kitchen") );
ksession.insert( new Location("Cheese", "Kitchen") );
ksession.insert( new Location("Desk", "Office") );
ksession.insert( new Location("Chair", "Office") );
ksession.insert( new Location("Computer", "Desk") );
ksession.insert( new Location("Drawer", "Desk") );

示例规则依赖于向向链和递归来确定托管结构中的所有项目和房间的位置。

下图演示了 Doom 的 House 的结构,以及其中的项目和房间:

图 19.28. Doom 结构的托管

TransitiveReasoning Enterprise

要执行示例,请在 IDE 中作为 Java 应用程序运行 org.drools.examples.backwardchaining.HouseOfDoomMain 类。

执行后,以下输出会出现在 IDE 控制台窗口中:

IDE 控制台中的执行输出

go1
Office is in the House
---
go2
Drawer is in the House
---
go3
---
Key is in the Office
---
go4
Chair is in the Office
Desk is in the Office
Key is in the Office
Computer is in the Office
Drawer is in the Office
---
go5
Chair is in Office
Desk is in Office
Drawer is in Desk
Key is in Drawer
Kitchen is in House
Cheese is in Kitchen
Knife is in Kitchen
Computer is in Desk
Office is in House
Key is in Office
Drawer is in House
Computer is in House
Key is in House
Desk is in House
Chair is in House
Knife is in House
Cheese is in House
Computer is in Office
Drawer is in Office
Key is in Desk

示例中的所有规则都触发,以检测托管中的所有项目的位置,并在输出中打印各个项目的位置。

递归查询重复搜索数据结构的层次结构,以获取元素之间的关系。

在 Doom 示例中的 House 中,BC-Example.drl 文件包含一个 isContainedIn 查询,该查询中大多数规则都使用它递归评估插入到决策引擎中的数据的数据结构:

BC-Example.drl 中的递归查询

query isContainedIn( String x, String y )
  Location( x, y; )
  or
  ( Location( z, y; ) and isContainedIn( x, z; ) )
end

规则 "go" 会输出插入到系统中的每个字符串,以确定如何实施项目,规则 "go1" 调用查询 是ContainedIn

规则 "go" 和 "go1"

rule "go" salience 10
  when
    $s : String()
  then
    System.out.println( $s );
end

rule "go1"
  when
    String( this == "go1" )
    isContainedIn("Office", "House"; )
  then
    System.out.println( "Office is in the House" );
end

示例将 "go1" 字符串插入到决策引擎中,并激活 "go1" 规则来检测该项目 响应者 位于位置 House 中:

插入字符串和触发规则

ksession.insert( "go1" );
ksession.fireAllRules();

IDE 控制台中的规则 "go1" 输出

go1
Office is in the House

传输冲突规则

传输是父元素中包含的元素之间的关系,它在分级结构中有多个级别。

规则 "go2" 标识 DrawerHouse 的传输关系,即 Drawer 位于 House 内的 Desk 中。

rule "go2"
  when
    String( this == "go2" )
    isContainedIn("Drawer", "House"; )
  then
    System.out.println( "Drawer is in the House" );
end

示例将 "go2" 字符串插入到决策引擎中,并激活 "go2" 规则来检测该项目 Drawer 最终会在位置 House 中:

插入字符串和触发规则

ksession.insert( "go2" );
ksession.fireAllRules();

IDE 控制台中的规则"go2"输出

go2
Drawer is in the House

决策引擎根据以下逻辑决定此结果:

  1. 查询递归搜索存放中的多个级别,以检测 DrawerHouse 之间的传输冲突。
  2. 查询使用 Location (x, y;),而是使用 (z, y;),因为 Drawer 不直接在 House 中。
  3. z 参数当前未绑定,这意味着它没有值并返回参数中的所有内容。
  4. y 参数当前绑定到 House,因此 z 返回 OfficeKitchen
  5. 如果 Drawer 位于 响应者,查询会从印度收集信息并递归检查。为这些参数调用查询行 isContainedIn (x, z;)
  6. 印度没有直接存在 Drawer 实例,因此找不到任何匹配项。
  7. 使用 z unbound 时,查询会返回响应者中的数据,并确定 z == Desk

    isContainedIn(x==drawer, z==desk)
  8. isContainedIn 查询递归搜索三次,第三个时间则查询会检测 Desk 中的 Drawer 实例。

    Location(x==drawer, y==desk)
  9. 在第一个位置上匹配后,查询会递归搜索结构,以确定 Drawer 是否在 Desk 中,De sk 位于印度,且响应者位于 House 中。 因此,Drawer 位于 House 中,规则满足。

重新主动查询规则

被动查询搜索数据结构的层次结构,以获取元素之间的关系,并在修改结构中的元素时动态更新。

规则 "go3" 的功能作为一个重新主动查询,它通过传输冲突来检测响应中是否存在新项目密钥:该机构中的 Drawer 中的密钥

规则 "go3"

rule "go3"
  when
    String( this == "go3" )
    isContainedIn("Key", "Office"; )
  then
    System.out.println( "Key is in the Office" );
end

示例将 "go3" 字符串插入到决策引擎中,并激活 "go3" 规则。最初,此规则不满足,因为托管结构中没有项目密钥,因此规则不会生成任何输出。

插入字符串和触发规则

ksession.insert( "go3" );
ksession.fireAllRules();

IDE 控制台中的规则"go3"输出(不满意)

go3

然后,该示例在位置 Drawer 中插入一个新项目密钥,它位于 印度这个更改满足 "go3" 规则中的传输冲突,输出会相应地填充。

插入新项目位置和触发规则

ksession.insert( new Location("Key", "Drawer") );
ksession.fireAllRules();

IDE 控制台中的规则"go3"输出(满意)

Key is in the Office

此更改还在查询包含在后续递归搜索的结构中添加另一个级别。

在规则中使用未绑定参数的查询

具有一个或多个未绑定参数的查询会返回查询定义的(绑定)参数中的所有未定义(unbound)项目。如果查询中的所有参数都未绑定,则查询会返回查询范围内的所有项目。

规则 "go4" 使用 unbound 参数操作来搜索绑定参数 响应中的 所有项目,而不是使用 bound 参数搜索响应者中的特定项目:

规则"go4"

rule "go4"
  when
    String( this == "go4" )
    isContainedIn(thing, "Office"; )
  then
    System.out.println( thing + "is in the Office" );
end

示例将 "go4" 字符串插入到决策引擎中,并激活 "go4" 规则,以返回响应者中的所有项目:

插入字符串和触发规则

ksession.insert( "go4" );
ksession.fireAllRules();

IDE 控制台中的规则"go4"输出

go4
Chair is in the Office
Desk is in the Office
Key is in the Office
Computer is in the Office
Drawer is in the Office

规则 "go5" 使用 unbound 参数 和位置 在整个 House 数据结构中搜索所有项目及其位置:

规则 "go5"

rule "go5"
  when
    String( this == "go5" )
    isContainedIn(thing, location; )
  then
    System.out.println(thing + " is in " + location );
end

示例将 "go5" 字符串插入到决策引擎中,并激活 "go5" 规则来返回 House 数据结构中的所有项目及其位置:

插入字符串和触发规则

ksession.insert( "go5" );
ksession.fireAllRules();

IDE 控制台中的规则"go5"输出

go5
Chair is in Office
Desk is in Office
Drawer is in Desk
Key is in Drawer
Kitchen is in House
Cheese is in Kitchen
Knife is in Kitchen
Computer is in Desk
Office is in House
Key is in Office
Drawer is in House
Computer is in House
Key is in House
Desk is in House
Chair is in House
Knife is in House
Cheese is in House
Computer is in Office
Drawer is in Office
Key is in Desk

第 20 章 DRL 的性能调优注意事项

以下主要概念或推荐做法可帮助您优化 DRL 规则和决策引擎性能。本节中总结了这些概念,并在适用的情况下在跨引用文档中进行更详细的说明。本节将根据新版本的 Red Hat Process Automation Manager 根据需要扩展或更改。

定义从左到右的模式约束的属性和值

在 DRL 模式限制中,确保事实属性名称位于 Operator 左侧的,并且值(constant 或变量)位于右侧。属性名称必须是索引中的键,而不是值。例如,写 Person (firstName == "John") 而不是 Person ("John" == firstName)。从右到左的定义约束属性和值可能会隐藏决策引擎性能。

有关 DRL 模式和约束的详情,请参考 第 14.8 节 “DRL (WHEN)中的规则条件”

在可能的情况下,在模式约束中使用相等的运算符类型
虽然决策引擎支持许多 DRL 操作器类型,但可用于定义业务逻辑的很多 DRL 操作器类型,但平等运算符 == 由决策引擎最有效评估。在实际情况时,请使用此操作器而不是其他 Operator 类型。例如,模式 Person (firstName == "John")Person (firstName != "OtherName") 更高效。在某些情况下,只使用相等的运算符可能并不切实际,因此在使用 DRL 运算符时,请考虑所有业务逻辑需求和选项。
首先列出限制性最严格的规则条件

对于具有多个条件的规则,列出最多限制条件,以便在不满足更严格的条件时,决策引擎可以避免评估整个条件集。

例如,以下条件是批量书规则的一部分,适用于将 flight 和 hotel 组合在一起的电信者。在这种情况下,客户很少有 flights 的热线来接收此活动,因此很少满足 hotel 条件,且规则很少被执行。因此,第一个条件排序效率更高,因为它可防止决策引擎经常评估 flight 条件,当不满足 hotel 条件时不必要。

首选条件顺序: hotel 和 flight

when
  $h:hotel() // Rarely booked
  $f:flight()

低效率状况顺序:flight 和 hotel

when
  $f:flight()
  $h:hotel() // Rarely booked

有关 DRL 模式和约束的详情,请参考 第 14.8 节 “DRL (WHEN)中的规则条件”

避免使用过量条款来迭代大量对象集合

避免使用 DRL 规则中的 from condition 元素迭代大型对象集合,如下例所示:

from 子句的条件示例

when
  $c: Company()
  $e : Employee ( salary > 100000.00) from $c.employees

在这种情况下,每当评估规则条件并提升规则评估时,决策引擎都会迭代大型图形。

另外,除了添加带有决定引擎必须频繁迭代的大型图形的对象,而是直接将集合添加到 KIE 会话中,然后在条件中加入集合,如下例所示:

没有 来自 条款的条件示例

when
  $c: Company();
  Employee (salary > 100000.00, company == $c)

在本例中,决策引擎只迭代列表一次,并可更有效地评估规则。

有关 from 元素或其他 DRL 条件元素的更多信息,请参阅 第 14.8.7 节 “DRL 中支持的规则条件元素(关键字)”

在规则中使用决策引擎事件监听程序而不是 System.out.println 语句进行调试日志

您可以在规则操作中使用 System.out.println 语句来调试日志和控制台输出,但对许多规则执行此操作可能会妨碍规则评估。作为效率更高的替代方案,请尽可能使用内置的决策引擎事件监听程序。如果这些监听程序不满足您的要求,请使用决策引擎支持的系统日志实用程序,如 Logback、Apache Commons Logging 或 Apache Log4j。

有关支持的决策引擎事件监听程序和日志记录工具的更多信息,请参阅 Red Hat Process Automation Manager 中的决策引擎

使用 drools-metric 模块来识别规则中的 obstruction

您可以使用 drools-metric 模块来识别在处理多个规则时的慢规则。drools-metric 模块也可以协助分析决策引擎性能。请注意,drools-metric 模块不用于生产环境。但是,您可以在测试环境中执行分析。

要使用 drools-metrics 分析决策引擎性能,请将 drools-metric 添加到项目依赖项中,并为 org.drools.metric.util.MetricLogUtils 启用追踪日志记录,如下例所示:

drools-metric的项目依赖项示例

<dependency>
  <groupId>org.drools</groupId>
  <artifactId>drools-metric</artifactId>
</dependency>

logback.xml 配置文件示例

<configuration>
  <logger name="org.drools.metric.util.MetricLogUtils" level="trace"/>
  ...
<configuration>

另外,通过将系统属性 drools.metric.logger.enabled 设置为 true 来启用 MetricLogUtils。另外,您可以通过设置 drools.metric.logger.threshold 系统属性来更改指标日志记录的微秒阈值。

注意

只有超过阈值的节点执行才会被记录。默认值为 500。

完成配置后,规则执行会生成日志,如下例所示:

规则执行输出示例

TRACE [JoinNode(6) - [ClassObjectType class=com.sample.Order]], evalCount:1000, elapsedMicro:5962
TRACE [JoinNode(7) - [ClassObjectType class=com.sample.Order]], evalCount:100000, elapsedMicro:95553
TRACE [ AccumulateNode(8) ], evalCount:4999500, elapsedMicro:2172836
TRACE [EvalConditionNode(9)]: cond=com.sample.Rule_Collect_expensive_orders_combination930932360Eval1Invoker@ee2a6922], evalCount:49500, elapsedMicro:18787

这个示例包括以下关键参数:

  • evalCount 是节点执行期间插入的事实的约束评估数量。
  • elapsedMicro 是节点执行的时间(以微秒为单位)。

如果您找到了未完成的 evalCountelapsedMicro 日志,请将节点名称与 ReteDumper.dumpAssociatedRulesRete () 输出相关联,以识别与节点关联的规则。

ReteDumper 使用示例

ReteDumper.dumpAssociatedRulesRete(kbase);

ReteDumper 输出示例

[ AccumulateNode(8) ] : [Collect expensive orders combination]
...

第 21 章 å��续步骤

部分 IV. 使用指导决策表设计决策服务

作为商业部门或业务逻辑开发人员,您可以使用指导决策表以向导的形式定义新规则。这些规则编译为 dols 规则语言(DRL),并为您的项目形成决策服务的核心。

注意

您还可以使用决策模型和表示法(DMN)模型而不是基于规则的或基于表的资产来设计您的决策服务。有关 Red Hat Process Automation Manager 7.9 中的 DMN 支持的详情,请查看以下资源:

先决�件

  • 指导决策表的空间和项目已在 Business Central 中创建。每个资产都与分配给空间的项目关联。详情请参阅 开始使用决策服务。

第 22 章 Red Hat Process Automation Manager 中的决策授权资产

Red Hat Process Automation Manager 支持多个资产,可用于为您的决策服务定义决策。每个决定授权资产都有不同的优点,您可能需要根据您的目标和需求使用多个资产的组合。

下表重点介绍 Red Hat Process Automation Manager 项目支持的主要决策授权资产,以帮助您决定或确认在决策服务中定义决策的最佳方法。

表 22.1. Red Hat Process Automation Manager 支持的决策授予资产

assethighlight编写工具Documentation

决策模型和表示法(DMN)模型

  • 是根据对象管理组(OMG)定义的表示法标准决定模型。
  • 使用代表部分或所有决策要求图(DRG)的图形决策要求图(DRG)来跟踪业务决策流程
  • 使用允许在 DMN 兼容平台之间共享 DMN 模型的 XML 模式
  • 支持 Friendly Enough Expression Language (FEEL),以在 DMN 决策表和其他 DMN 框表达式中定义决策逻辑
  • 可以与 Business Process Model 和 Notation (DSLN)进程模型有效集成
  • 是创建全面、演示和稳定的决策流程的最佳选择

Business Central 或其他与 DMN 兼容的编辑器

使用 DMN 模型设计决策服务

主要决策表

  • 是您在 Business Central 的基于 UI 的表设计程序中创建的规则表
  • 是电子表格决策表的向导替代方法
  • 为可接受的输入提供字段和选项
  • 支持用于创建规则模板的模板键和值
  • 支持点击策略、实时验证以及其他资产不支持的其他额外功能
  • 最好以受控的 tabular 格式创建规则,以最小化编译错误

Business Central

使用指导决策表设计决策服务

电子表格决策表

  • 是 XLS 或 XLSX 电子表格决策表,您可以上传到 Business Central
  • 支持用于创建规则模板的模板键和值
  • 最好在 Business Central 外部管理的路由表中创建规则
  • 对于在上传时正确编译的规则具有严格的语法要求

电子表格编辑器

使用电子表格决策表设计决策服务

指导规则

  • 是您在 Business Central 中基于 UI 的规则设计程序中创建的单个规则
  • 为可接受的输入提供字段和选项
  • 最好以受控格式创建单个规则,以最小化编译错误

Business Central

使用指导规则设计决策服务

指导规则模板

  • 是您在 Business Central 中的基于 UI 的模板设计程序中创建的可重复使用的规则结构
  • 为可接受的输入提供字段和选项
  • 支持用于创建规则模板的模板键和值(与资产相关的目的不同)
  • 最好创建具有相同规则结构但具有不同定义的字段值的规则

Business Central

使用指导规则模板设计决策服务

DRL 规则

  • 是直接在 .drl 文本文件中定义的单个规则
  • 提供定义规则和其他规则行为的最灵活
  • 可以在某些独立环境中创建,并与 Red Hat Process Automation Manager 集成
  • 最好创建需要高级 DRL 选项的规则
  • 具有正确编译的规则具有严格的语法要求

Business Central 或集成开发环境(IDE)

使用 DRL 规则设计决策服务

预测模型标记语言(PMML)模型

  • 是预测的 data-analytic 模型,它基于由 Data Mining Group (DMG)定义的表示法标准
  • 使用一个 XML 模式,允许在 PMML 兼容平台之间共享 PMML 模型
  • 支持 Regression、Scorecard、Tree、Ming 和其他模型类型
  • 可以包含独立 Red Hat Process Automation Manager 项目,也可以导入到 Business Central 中的项目中
  • 最好在 Red Hat Process Automation Manager 中将预测数据整合到决策服务中

pmML 或 XML 编辑器

使用 PMML 模型设计决策服务

第 23 章 主要决策表

指导决策表是一个向导的替代方案,用于以表格格式定义新规则的电子表格。借助指导决策表,您在 Business Central 中由基于 UI 的向导造成的,它可帮助您根据项目中的指定数据对象定义规则属性、元数据、条件和操作。创建指导决策表后,您定义的规则会编译为 dols 规则语言(DRL)规则,与其他规则资产一样。

与指导决策表相关的所有数据对象都必须与指导决策表位于同一个项目软件包中。默认情况下导入同一软件包中的资产。创建必要的数据对象和指导决策表后,您可以使用指导决策表设计器的 Data Objects 选项卡来验证所有必需的数据对象是否已列出,或通过添加新 项目 来导入其他现有数据对象。

第 24 章 数据对象

数据对象是您创建的规则资产的构建块。数据对象是在项目的指定软件包中作为 Java 对象实现的自定义数据类型。例如,您可以创建一个带有数据字段 Name, Address, 和 DateOfBirthPerson 对象,以指定 loan 应用程序规则的个人详情。这些自定义数据类型决定了您的资产和您决定服务所基于的数据。

24.1. 创建数据对象

以下流程是创建数据对象的通用概述。它不特定于特定的业务资产。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetData Object
  3. 输入唯一 数据对象 名称并选择 您希望 数据对象可用于其他规则资产的软件包。同一软件包中不能存在具有相同名称的数据对象。在指定的 DRL 文件中,您可以从任何软件包导入数据对象。

    从其他软件包导入数据对象

    您可以直接将现有数据对象从另一个软件包导入到资产设计人员,如指导规则或指导决策表设计器。选择项目中的相关规则资产和资产设计器,转至 Data Objects → New 项 以选择要导入的对象。

  4. 要使数据对象持久,请选择 Persistable 复选框。Persistable 数据对象可以根据 JPA 规范存储在数据库中。默认 JPA 是 Hibernate。
  5. 点 确定。
  6. 在数据对象设计器中,单击 add 字段,将字段添加到带有属性 Id,Label, 和 Type 的对象。所需属性被标记为星号。

    • id : 输入字段的唯一 ID。
    • label : (可选)输入字段的标签
    • type : 输入字段的数据类型。
    • 列表: (可选)选择此复选框来启用该字段为指定类型保存多个项目。

      图 24.1. 在数据对象中添加数据字段

      在数据对象中添加数据字段
  7. Create 添加新字段,或者点 Create 并继续 添加新字段,并继续添加新字段。

    注意

    要编辑字段,请选择字段行,并使用屏幕右侧的 常规属性

第 25 章 创建指导决策表

您可以使用指导决策表来定义可添加到自定义规则项目中的规则属性、元数据、条件和操作。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetDatacenter Decision Table
  3. 输入 说明性决策表 名称并选择适当的 软件包。您指定的软件包必须是分配所需数据对象或将被分配的软件包。
  4. 选择 Use Wizard 来完成向导中的表设置,或者保留此选项未选择以完成创建表并在指导决策表设计程序中指定剩余的配置。
  5. 选择表中规则行符合的点击策略。详情请查看 第 26 章 按指导决策表的策略。
  6. 指定您是否希望 扩展条目有限条目 表。详情请查看 第 26.1.1 节 “指导决策表的类型”。
  7. 单击 Ok 以完成设置。如果您选择了 Use Wizard,则会显示相关的决策表向导。如果您没有选择 Use Wizard 选项,则不会显示这个提示,并直接进入表设计器。

    例如,以下向导设置是 loan 应用程序决策服务的指导决策表:

    图 25.1. 创建指导决策表

    6326 1
  8. 如果您使用向导,请添加所有可用的导入、事实模式、约束和操作,并选择表列是否应扩展。点击 Finish 关闭向导并查看表设计器。

    图 25.2. 主要决策表向导

    6328 1

在指导决策表格设计器中,您可以添加或编辑列和行,并进行其他最终调整。

第 26 章 按指导决策表的策略

按策略决定应用指导决策表中的规则(箭头)的顺序,无论是从下到下、每个指定优先级还是其他选项。

可用的命中策略如下:

  • none : (默认点击策略)可以执行多行,验证警告了冲突的行。已上传的任何决策表(使用非指导决策表)都将采用此点击策略。
  • 解决的 Hit : 根据指定优先级只能执行一行,无论列表顺序是什么(例如,您可以给行 10 个优先级提供行 10 个)。这意味着您可以保留您想要进行视觉可读性的行顺序,但指定了优先级例外。
  • 唯一 Hit : 每次只能执行一行,每行必须是唯一的,且不满足条件重叠。如果执行多个行,则验证会在开发时生成警告。
  • 第一个 Hit: 根据表中列出的顺序,可以一次只执行一行,按上到下的顺序执行。
  • 规则顺序: 可以执行多个行和验证不会报告行之间冲突,因为它们预期发生。

图 26.1. 可用的命中策略

按策略镜像 1

26.1. 按策略示例:用于销售月的决策表

以下是基于客户年龄、或状态或全部状态的电池的示例决策表。

表 26.1. 有关 movie 票据可用销售的决策表示例

端口号领导类型领导

1

高级实验室(超过 60+)

10%

2

opendoi

10%

3

法国

10%

在本例中,结尾要应用的总活动将因表指定的点击策略而异:

  • none/Rule Order: 使用 NoneRule Order hit 策略,所有适用的规则都会合并,在这种情况下,允许为每个客户进行堆栈。

    示例:一个高级账单,也是 veteran 的高级 veteran 将收到所有三个销售者,总计为 30%。

    关键区别:如果没有 会为应用的多行创建警告。使用 Rule Order 时,不会创建这些警告。

  • 第一个 Hit/Resolved Hit: 使用第一个 HitResolved Hit 策略,只能应用其中一个参与。

    对于 First Hit,首先在列表中满足的承诺将被应用,其他用户将被忽略。

    示例:一个高级实验室,也是 veteran 的高级 veteran 将只收到 10% 的高级部门,因为该技术在表中首先列出。

    对于 Resolved Hit,需要一个修改后的表。无论您为表中的优先级例外分配优先级例外,无论列出的顺序是什么,都将首先应用。要分配此异常,请包括一个新的列,用于指定其他参与(箭头)的优先级。

    示例:如果在列出的顺序高,那么如果参与时间高于年龄,则即使列出的顺序,那么无论年龄或 veteran 仍收到 10% 的人员,无论年龄如何,都会收到 10% 的人员。

    请考虑以下修改的决策表,其中包含一个 Resolved Hit 策略:

    表 26.2. 修改了适合 已解决 Hit 策略的决策表

    端口号领导类型具有优先级超过 Row领导

    1

    高级实验室(超过 60+)

     

    10%

    2

    opendoi

     

    10%

    3

    法国

    1

    10%

    在此修改的表格中,活动基本上是新行 1,因此优先于年龄和站的承诺,以及稍后添加的任何其他活动。您不需要在行 "1 和 2" 上指定优先级,只用行为 "1"。这会将行按顺序改为 3 → 1 → 2 → …​,因为表增加。

    注意

    如果您实际将参与移动到行 1,并将第一个 Hit 策略应用到表,则行顺序将以相同的方式更改。但是,如果您希望以某种方式列出的规则,并以不同的方式应用,比如在字母表中应用,则 Resolved Hit 策略很有用。

    主要区别:如果 第一个 Hit,规则按列出的顺序严格应用。使用 Resolved Hit 时,规则按列出的顺序应用,除非指定了优先级例外。

  • unique Hit : 需要修改的表。使用 唯一 Hit 策略时,必须以一次无法满足多个规则的方式创建行。但是,您仍然可以指定行,无论是否应用一条规则。这样,对于 唯一 Hit 策略,您可以更精细地将决策表设置为更精细的,并防止重叠警告。

    请考虑以下修改的决策表,该表适合 唯一 Hit 策略:

    表 26.3. 修改了适合 唯一 Hit 策略的决策表

    端口号Sphone Citizen (age 65+)受位is Military领导

    1

    是

    �

    10%

    2

    �

    �

    10%

    3

    �

    是

    10%

    4

    是

    �

    20%

    5

    是

    是

    20%

    6

    �

    是

    20%

    7

    是

    是

    30%

    在这个修改的表中,每行都是唯一的,无允许重叠,并且任何单一部门或任何组合均适用。

26.1.1. 指导决策表的类型

Red Hat Process Automation Manager 支持两种类型的路由表:扩展条目和有限条目表。

  • Extended entry: 一个扩展条目决策表是列定义指定 Pattern、field 和 Operator,但没有值。值或状态本身保存在路由表的正文中。

    扩展条目
  • 有限条目: 有限条目决策表是列定义除 Pattern、field 和 Operator 之外指定值的一个。保持在表正文的决策表状态是布尔值,其中正值(标记为复选框)具有应用列或匹配的含义。负值(清除复选框)表示该列不适用。

    有限条目

第 27 章 添加列以指导决策表

创建指导决策表后,您可以在指导决策表设计器中定义和添加各种列。

先决条件

  • 任何将用于列参数的数据对象(如事实和字段)已在找到指导决策表的同一软件包中创建,或者从指导决策表的 Data ObjectsNew 项中 从另一个软件包导入。

有关这些列参数的描述,请查看 第 28 章 指导决策表中的列类型 中的每种列类型的"Required 列参数"片段。

有关创建数据对象的详情,请参考 第 24.1 节 “创建数据对象”

流程

  1. 在指导决策表设计程序中,点击 ColumnsInsert Column
  2. Include advanced options 查看列选项的完整列表。

    图 27.1. 添加列

    查看 IceAdd a new column 192.168.1.0/24 窗口中的列选项
  3. 选择您要添加的列类型,点 Next,然后按照向导中的步骤指定添加该列所需的数据。

    有关每个列类型和设置所需参数的描述,请参阅 第 28 章 指导决策表中的列类型

  4. Finish 添加配置的列。

添加所有列后,您可以开始添加与列分离的规则行来完成决策表。详情请查看 第 31 章 在指导决策表中添加行和定义规则。

以下是 loan 应用程序决策服务的示例决策表:

图 27.2. 完成指导决策表示例

完成指导决策表示例

第 28 章 指导决策表中的列类型

指导决策表的 Add a new 列 向导提供了以下列选项。(选择 Include advanced options 来查看所有选项。)

这些列类型和 Add a new 列向导中每个列 所需的参数在后续小节中进行了描述。

重要信息:列参数所需的数据对象

本节中描述的一些列参数(如事实模式和字段)提供仅包含已找到指导决策表的同一软件包中已定义的数据对象的下拉列表选项。软件包的可用数据对象列在 Project Explorer 的 Data Objects 面板中,并在指导决策表设计器的 Data Objects 选项卡中列出。您可以根据需要在软件包中创建附加数据对象,或者在指导决策表设计器的 Data ObjectsNew 项中 从另一个软件包导入它们。有关创建数据对象的详情,请参考 第 24.1 节 “创建数据对象”

28.1. "add a Condition"

条件代表规则左侧的"WHEN"部分中定义的事实模式。使用此列选项,您可以定义一个或多个 condition 列,来检查是否存在带有特定字段值的数据对象,以及这会影响规则的操作("THEN")部分。您可以在 condition 表中为事实定义绑定,或者选择一个之前已定义的绑定。您还可以选择对模式进行优化。

规则条件示例

when
  $i : IncomeSource( type == "Asset" ) // Binds the IncomeSource object to the $i variable
then
  ...
end

when
  not IncomeSource( type == "Asset" ) // Negates matching pattern
then
  ...
end

指定绑定后,您可以定义字段约束。如果使用相同的事实模式绑定定义了两个或多个列,则字段约束会成为同一模式的复合字段约束。如果您为单个模型类定义了多个绑定,每个绑定都会成为规则条件("WHEN")侧的独立模型类。

所需的列参数

Add a new column 向导中需要以下参数来设置此列类型:

  • Pattern : 从表中条件中使用的事实模式列表中选择,或创建新的事实模式。事实模式是软件包中可用数据对象的组合(请参阅所需数据 对象的备注 )以及您指定的模型类绑定。(示例: LoanApplication [application]IncomeSource [income],其中括号部分是绑定到给定事实类型的绑定)
  • 入口点 : 定义事实模式的入口点(如果适用)。入口点是事实进入决策引擎的最低要求或流(如果指定)。(示例: Application Stream,Credit Check Stream
  • 计算类型 : 选择以下计算类型之一:

    • literal value : 单元中的值将使用 operator 与字段进行比较。
    • 公式: 将评估单元格中的表达式,然后与字段进行比较。
    • predicate: 不需要字段;表达式将评估为 truefalse
  • 字段 : 从之前指定的事实模式中选择一个字段。字段选项在项目的 Data Objects 面板中的 fact 文件中定义。(示例: LoanApplication 事实类型中 的数量长度 字段)
  • binding (可选): 根据需要为之前选择的字段定义绑定。(例如:对于模式 LoanApplication [application], field amount, 和 等于,如果绑定被设置为 $amount,则结束条件将是 应用程序 : LoanAppplication ($amount : number == [value]).)
  • Operator: 选择要应用到之前指定的事实模式和字段的 Operator。
  • value list (可选): 输入以逗号和空格分隔的值选项列表,以限制规则的条件"WHEN")部分的表输入数据。当定义了这个值列表时,该值将在该列的表中作为下拉列表提供,用户只能选择一个选项。(示例列表: 周三,周三,仅指定这三个选项)
  • 默认值(可选): 选择之前定义的值选项之一作为默认值,该值将自动出现在新行中。如果没有指定默认值,表单元将默认为空。您还可以从项目中任何配置的数据枚举中选择一个默认值,在 Project Explorer 的 Enumeration Definitions 面板中列出。(您可以在 MenuDesignProjects[select project]Add AssetEnumeration 中创建枚举。)
  • header (description): 为列添加标头文本。
  • hidden 列 : 选择此项来隐藏列,或清除此项以显示列。

28.1.1. 在状况列单元中插入任何其他值

对于指导决策表中的简单条件列,如果设置了以下参数,您可以对列中的表单元应用 任何其他值

  • 条件列的 计算类型 已设置为 Literal 值
  • Operator 已设置为 equality == 或 inequality !=

任何其他值 可让为表中尚未明确定义的任何其他字段值定义一个规则。在 DRL 源中,任何其他没有包括在 中

没有用于任何其他 规则 条件的示例

when
  IncomeSource( type not in ("Asset", "Job") )
  ...
then
  ...
end

�程

  1. 选择使用 ==!= 运算符的条件列的单元。
  2. 在表设计器右上角,点击 EditInsert "any other" 值

28.2. "添加 Condition BRL 片段"

业务逻辑语言(BRL)片段是使用指导规则设计器创建的规则的一部分。条件 BRL 片段是规则的"WHEN"部分,操作 BRL 片段 是规则的"THEN"部分。使用这个列选项,您可以定义在规则左侧要使用的条件 BRL 片段("WHEN")侧。更简单列类型可以引用 BRL 片段中绑定的事实和事实字段,反之亦然。

以下示例是 loan 应用程序的 BRL 片段的条件:

图 28.1. 使用嵌入式指导规则设计程序添加条件 BRL 片段

指导决策表设计器的条件 BRL theagment 列

您也可以从条件选项列表中选择 Free form DRL,以定义没有嵌入式指导规则设计器的 BRL 片段。

图 28.2. 添加一个带有自由形式的 BRL 片段

指导决策表设计器的条件 BRL theagment 列
指导决策表设计器的条件 BRL theagment 列
模板键

当您为条件 BRL 片段添加字段时,其中一个值选项为 Template 键 (而不是 LiteralFormula)。模板键是生成指导决策表时与指定的值交换的占位符变量,并在指定每个模板键值的表中形成单独的列。您可以在 Value options 页面中指定 Template 键的默认值。虽然 Literal 和 Formula 值在决策表中是静态的,但可以根据需要修改 Template 键值。

在嵌入式指导规则设计程序中,您可以通过选择 Template key 字段选项并在编辑器中输入值,以 $key 格式输入值。例如,$age 在决策表中创建一个 $age 列。

在自由形式 DRL 中,您可以将模板键值添加到事实中,格式为 @{key}。例如,Person (age > @{age}) 在决策表中创建一个 $age 列。

数据类型是使用模板密钥添加的新列的字符串。

所需的列参数

Add a new column 向导中需要以下参数来设置此列类型:

  • rule Modeller: 为规则定义条件 BRL 片段("WHEN" 部分)。
  • header (description): 为列添加标头文本。
  • hidden 列 : 选择此项来隐藏列,或清除此项以显示列。

28.3. "添加元数据列"

使用这个列选项,您可以在决策表中定义一个 metadata 元素作为列。每条列代表 DRL 规则中的正常元数据注解。默认情况下,metadata 列是隐藏的。要显示列,请单击指导决策表中的 Edit Columns 并清除 Hide 列 复选框。

所需的列参数

Add a new column 向导中需要以下参数来设置此列类型:

  • Metadata : 输入 Java 变量形式的元数据项的名称(即,它不能以数字或包含空格或特殊字符开头)。

28.4. "添加 Action BRL 片段"

业务逻辑语言(BRL)片段是使用指导规则设计器创建的规则的一部分。条件 BRL 片段 是规则的"WHEN"部分,操作 BRL 片段是规则的"THEN"部分。通过此列选项,您可以定义要在规则右侧的"THEN")"侧使用的操作 BRL 片段。更简单列类型可以引用 BRL 片段中绑定的事实和事实字段,反之亦然。

以下示例是 loan 应用程序的 BRL 片段的操作:

图 28.3. 使用嵌入式指导规则设计程序添加一个操作 BRL 片段

指导决策表格中的操作 BRLDemoagment

您也可以从操作选项列表中选择 Add free form DRL,以定义操作 BRL 片段,而无需嵌入的规则设计器。

图 28.4. 添加一个带有自由形式的 BRL 片段

指导决策表设计器的操作 BRL agment 列
指导决策表设计器的操作 BRL agment 列
模板键

当您为操作 BRL 片段添加字段时,其中一个值选项为 Template 键 (而不是 LiteralFormula)。模板键是生成指导决策表时与指定的值交换的占位符变量,并在指定每个模板键值的表中形成单独的列。您可以在 Value options 页面中指定 Template 键的默认值。虽然 Literal 和 Formula 值在决策表中是静态的,但可以根据需要修改 Template 键值。

在嵌入式指导规则设计程序中,您可以通过选择 Template key 字段选项并在编辑器中输入值,以 $key 格式输入值。例如,$age 在决策表中创建一个 $age 列。

在自由形式 DRL 中,您可以将模板键值添加到事实中,格式为 @{key}。例如,Person (age > @{age}) 在决策表中创建一个 $age 列。

数据类型是使用模板密钥添加的新列的字符串。

所需的列参数

Add a new column 向导中需要以下参数来设置此列类型:

  • rule Modeller : 定义规则的 BRL 片段("THEN" 部分)的操作。
  • header (description): 为列添加标头文本。
  • hidden 列 : 选择此项来隐藏列,或清除此项以显示列。

28.5. "添加属性列"

使用这个列选项,您可以添加代表任何 DRL 规则属性的一个或多个属性列,如 Saliance、Enabled、Date-Effective 等。

例如,以下指导决策表使用 salience 属性来指定规则优先级和 enabled 属性,以启用或禁用评估的规则。首先评估具有更高 salience 值的规则,只有在选择了复选框时,才会评估具有 enabled 属性的规则。

图 28.5. 带有 salienceenabled 属性的规则示例,以定义评估行为

带有 'salience' 和 'enabled' 属性的指导决策表

带有规则属性的规则源示例

rule "Row 1 Pricing loans"
  salience 100
  enabled true
  when
    ...
  then
    ...
end
...
rule "Row 3 Pricing loans"
  enabled false
  when
    ...
  then
    ...
end

有关每个属性的描述,请从向导中的列表中选择属性。

按策略和属性

请注意,根据您为路由表定义的点击策略,可能会禁用一些属性,因为它们由 hit 策略在内部使用。例如,如果您为这个表分配了 Resolved Hit 策略,以便根据表中指定的优先级顺序应用行(rules),则 Salience 属性将被弃用。原因是 Salience 属性根据定义的 salience 值升级规则优先级,该值将被表中的 Resolved Hit 策略覆盖。

所需的 Column 参数

Add a new column 向导中需要以下参数来设置此列类型:

  • attribute 选择要应用到列的属性。

28.6. "删除现有事实"

使用这个列选项,您可以实施一个操作来删除之前添加为表中的事实模式的事实。创建此列时,事实类型会在该列的表中作为下拉列表提供,用户只能选择一个选项。

所需的列参数

Add a new column 向导中需要以下参数来设置此列类型:

  • header (description): 为列添加标头文本。
  • hidden 列 : 选择此项来隐藏列,或清除此项以显示列。

28.7. "执行工作站"

使用这个列选项,您可以根据 Business Central 中的预定义工作项目定义来执行工作项目处理程序。(您可以在 MenuDesignProjects[select project]Add AssetWork Item 定义.)中创建工作项目。)

所需的列参数

Add a new column 向导中需要以下参数来设置此列类型:

  • 工作站 : 从预定义的工作项目列表中选择。
  • header (description): 为列添加标头文本。
  • hidden 列 : 选择此项来隐藏列,或清除此项以显示列。

28.8. "设置字段的值"

使用这个列选项,您可以实施一个操作来为之前绑定的 "THEN" 部分设置字段值。您可以选择通知决策引擎修改的值,这可能会导致其他规则被重新激活。

所需的列参数

Add a new column 向导中需要以下参数来设置此列类型:

  • Pattern : 从表中条件或条件 BRL 片段中使用的事实模式列表中选择,或创建新的事实模式。事实模式是软件包中可用数据对象的组合(请参阅所需数据 对象的备注 )以及您指定的模型类绑定。(示例: LoanApplication [application]IncomeSource [income],其中括号部分是绑定到给定事实类型的绑定)
  • 字段 : 从之前指定的事实模式中选择一个字段。字段选项在项目的 Data Objects 面板中的 fact 文件中定义。(示例: LoanApplication 事实类型中 的数量长度 字段)
  • value list (可选): 输入以逗号和空格分隔的值选项列表,以限制规则的表输入数据("THEN")部分)。当定义了这个值列表时,该值将在该列的表中作为下拉列表提供,用户只能选择一个选项。(示例列表: Accepted, Declined, Pending
  • 默认值(可选): 选择之前定义的值选项之一作为默认值,该值将自动出现在新行中。如果没有指定默认值,表单元将默认为空。您还可以从项目中任何配置的数据枚举中选择一个默认值,在 Project Explorer 的 Enumeration Definitions 面板中列出。(您可以在 MenuDesignProjects[select project]Add AssetEnumeration 中创建枚举。)
  • header (description): 为列添加标头文本。
  • hidden 列 : 选择此项来隐藏列,或清除此项以显示列。
  • logically insert : 当所选事实模式目前在指导决策表中的另一列中没有使用时显示这个选项(请参阅下一字段描述)。选择此选项以逻辑方式插入决策引擎中的事实模式,或者清除它以定期插入它。决策引擎负责对事实的插入和重包进行逻辑决策。常规或声明的插入后,必须明确重新遍历事实。在逻辑插入后,当提示第一个位置中的事实不再满足时,会自动重新传输事实。
  • 更新引擎具有更改: 当指导决策表中的另一列中已使用所选事实模式时,会显示此选项。选择此项以使用修改后的字段值更新决策引擎,或者清除它以不会更新决策引擎。

28.9. "设置字段的值,并带有 Work Item 结果"

使用这个列选项,您可以实施一个操作,将之前定义的 fact 字段的值设置为规则"THEN"部分的工作项目处理程序的结果。work 项必须定义一个与绑定事实上的字段相同的数据类型的 result 参数,以便将字段设置为 return 参数。(您可以在 MenuDesignProjects[select project]Add AssetWork Item 定义.)中创建工作项目。)

必须在 表中创建执行 一列列,才能创建此列选项。

所需的列参数

Add a new column 向导中需要以下参数来设置此列类型:

  • Pattern : 从表中已使用的事实模式列表中选择,或创建新的事实模式。事实模式是软件包中可用数据对象的组合(请参阅所需数据 对象的备注 )以及您指定的模型类绑定。(示例: LoanApplication [application]IncomeSource [income],其中括号部分是绑定到给定事实类型的绑定)
  • 字段 : 从之前指定的事实模式中选择一个字段。字段选项在项目的 Data Objects 面板中的 fact 文件中定义。(示例: LoanApplication 事实类型中 的数量长度 字段)
  • 工作站 : 从预定义的工作项目列表中选择。(工作项目必须定义一个与绑定事实上字段相同的数据类型的 result 参数,以便您将字段设置为 return 参数。)
  • header (description): 为列添加标头文本。
  • hidden 列 : 选择此项来隐藏列,或清除此项以显示列。
  • logically insert : 当所选事实模式目前在指导决策表中的另一列中没有使用时显示这个选项(请参阅下一字段描述)。选择此选项以逻辑方式插入决策引擎中的事实模式,或者清除它以定期插入它。决策引擎负责对事实的插入和重包进行逻辑决策。常规或声明的插入后,必须明确重新遍历事实。在逻辑插入后,当提示第一个位置中的事实不再满足时,会自动重新传输事实。
  • 更新引擎具有更改: 当指导决策表中的另一列中已使用所选事实模式时,会显示此选项。选择此项以使用修改后的字段值更新决策引擎,或者清除它以不会更新决策引擎。

第 29 章 查看指导决策表中的规则名称列

如果需要,您可以在指导决策表中查看 Rule Name 列。

�程

  1. 在指导决策表格设计程序中,单击 Columns
  2. 选中 Show rule name 列 复选框。
  3. Finish 保存。

默认规则名称格式为 Row (row_number) (table_name)。如果没有指定规则名称,则 Source 包含默认值。在指导决策表中,您可以在 Rule Name 列中添加一个规则名称,并覆盖默认值。

第 30 章 在指导决策表中编辑或删除列

您可以在指导决策表设计程序随时编辑或删除您创建的列。

�程

  1. 在指导决策表格设计程序中,单击 Columns
  2. 展开适当的部分,再单击列名称旁边的 EditDelete

    图 30.1. 编辑或删除列

    编辑或删除指导决策表设计器中的列。
    注意

    如果现有 action 列使用与 condition 列相同的模式参数,则无法删除条件列。

  3. 任何列更改后,点向导中的 Finish 保存。

第 31 章 在指导决策表中添加行和定义规则

在指导决策表中创建了列后,您可以在指导决策表设计程序中添加行并定义规则。

先决�件

流程

  1. 在指导决策表设计程序中,点 InsertAppend 行 或一个 Insert 行 选项。(您也可以单击 Insert 列 来打开列向导并定义新列。)

    图 31.1. 添加 Rows

    在指导决策表设计程序中添加行
  2. 双击每个单元并输入数据。对于带有指定值的单元,请从单元下拉列表中选择。

    图 31.2. 在每个单元中输入输入数据

    在独立单元中输入数据
  3. 在指导决策表中定义数据的所有行后,单击指导决策表右上角的 Validate 以验证表。如果表验证失败,请解决错误消息中描述的任何问题,查看表中的所有组件,然后重试验证表直到表通过为止。

    注意

    虽然指导的决策表有实时验证和验证,但您仍应手动验证已完成的决策表以确保最佳结果。

  4. 点表设计器中的 Save 来保存您的更改。

    在定义了指导决策表内容后,在指导决策表设计器右上角,如果需要搜索在指导决策表中出现的文本,您可以使用搜索栏。搜索功能在带有许多值的复杂指导表中特别有用:

    图 31.3. 搜索指导决策表内容

    搜索指导决策表内容

第 32 章 在规则资产中为下拉列表定义枚举

Business Central 中的枚举定义决定了指导规则、指导规则模板和指导决策表中的条件或操作的可能值。Enumeration 定义包含一个 fact.field 映射到支持的值列表,这些值在规则资产的相关字段中显示为下拉列表。当用户选择基于与枚举定义相同的事实和字段时,会显示定义值的下拉列表。

您可以在 Business Central 或 Red Hat Process Automation Manager 项目的 DRL 源中定义枚举。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetEnumeration
  3. 输入说明性 枚举 名称并选择适当的 软件包。您指定的软件包必须是分配所需数据对象和相关规则资产的同一软件包。
  4. Ok 创建枚举。

    新的枚举现在列在 Project ExplorerEnumeration Definitions 面板中。

  5. 在枚举设计器的 Model 选项卡中,点 Add enum 并为枚举定义以下值:

    • 事实 :在您要将此枚举的项目的同一软件包中指定现有数据对象。打开 Project Explorer 中的 Data Objects 面板,以查看可用的数据对象,或者根据需要将相关数据对象创建为新资产。
    • 字段 :指定您定义为您为 事实 选择的数据对象一部分的现有字段标识符。打开 Project Explorer 中的 Data Objects 面板,以选择相关数据对象并查看可用 标识符选项列表。如果需要,您可以为数据对象创建相关标识符。
    • Context: 指定您要映射到 FactField 定义的格式 ['string1','string2','string3'][integer1,integer2,integer3] 的值列表。这些值将显示为规则资产相关字段的下拉列表。

    例如,以下枚举在 loan 应用程序决策服务中定义 applicant 信信评级的下拉值:

    图 32.1. Business Central 中应用程序信信评级的枚举示例

    EnumConfig

    DRL 源中适用信信评级的枚举示例

    'Applicant.creditRating' : ['AA', 'OK', 'Sub prime']

    在本例中,对于任何在项目相同的软件包中的指导规则、指导规则模板或指导的决策表,其使用 Applicant 数据对象和 creditRating 字段,配置的值可作为下拉列表选项提供:

    图 32.2. 指导规则或指导规则模板中枚举的下拉列表选项示例

    EnumDropDown

    图 32.3. 指导决策表中的 enumeration 下拉菜单选项示例

    EnumDropDownGDT

32.1. 规则资产的高级枚举选项

对于 Red Hat Process Automation Manager 项目中带有枚举定义的高级用例,请考虑以下扩展选项来定义枚举:

Business Central 中的 DRL 值和值之间的映射

如果您希望枚举值在 Business Central 界面中显示不同或更完全出现在 DRL 源中,请使用格式 'fact.field' : ['sourceValue1=UIValue1','sourceValue2=UIValue2', …​ ] 作为您的枚举定义值。

例如,在以下 loan 状态的枚举定义中,DRL 文件中使用了选项 AD,但 Business Central 中会显示 ApprovedDeclined 选项:

'Loan.status' : ['A=Approved','D=Declined']
Enumeration 值依赖项

如果您希望一个下拉列表中选择的值来确定后续下拉列表中的可用选项,请使用 'fact.fieldB[fieldA=value1]' : ['value2', 'value3', …​ ] 进行您的枚举定义。

例如,在以下代表策略的 enumeration 定义中,policyType 字段接受 Home 或 the 值。用户选择的策略类型决定了可用的策略 范围 字段选项:

'Insurance.policyType' : ['Home', 'Car']
'Insurance.coverage[policyType=Home]' : ['property', 'liability']
'Insurance.coverage[policyType=Car]' : ['collision', 'fullCoverage']
注意

在规则条件和操作中不会应用枚举的依赖关系。例如,在这种情况下,规则条件中选择的策略不会决定规则操作中的可用覆盖范围选项(如果适用)。

枚举中的外部数据源

如果要从外部数据源检索枚举值列表,而不是直接在枚举定义中定义值,在项目的类路径上,添加一个帮助程序类,它返回一个返回字符串的 java.util.List 列表的帮助类。在枚举定义中,而不是指定值列表,而是指定您配置为外部检索值的帮助类。

例如,在 Lan applicant 区域的以下枚举定义中,而不是以 'Applicant.region' : ['country1', 'country2', …​ ] 格式明确定义 applicant 区域:

'Applicant.region' : (new com.mycompany.DataHelper()).getListOfRegions()

在本例中,DataHelper 类包含一个 getListOfRegions () 方法,该方法返回字符串列表。枚举会在规则资产中相关字段的下拉列表中加载。

您还可以以常常方式识别依赖字段并在引号中保护调用,从帮助程序类动态加载依赖的枚举定义:

'Applicant.region[countryCode]' : '(new com.mycompany.DataHelper()).getListOfRegions("@{countryCode}")'

如果要从外部数据源(如关系数据库)完全加载所有枚举数据,您可以实施返回 Map<String, List<String>> 映射的 Java 类。映射的键是 fact.field 映射,值为 java.util.List<String&gt; 列表。

例如,以下 Java 类定义了相关枚举的 loan applicant 区域:

public class SampleDataSource {

  public Map<String, List<String>> loadData() {
    Map data = new HashMap();

    List d = new ArrayList();
    d.add("AU");
    d.add("DE");
    d.add("ES");
    d.add("UK");
    d.add("US");
    ...
    data.put("Applicant.region", d);

    return data;
  }

}

以下枚举定义与这个示例 Java 类相关联。Enumeration 不包含对事实或字段名称的引用,因为它们在 Java 类中定义:

=(new SampleDataSource()).loadData()

= 运算符可让 Business Central 从 helper 类加载所有枚举数据。当请求在编辑器中使用枚举定义时,帮助程序方法会被静态评估。

注意

目前 Business Central 不支持在没有事实和字段定义的情况下定义枚举。要以这种方式为关联的 Java 类定义枚举,请在 Red Hat Process Automation Manager 项目中使用 DRL 源。

第 33 章 指导决策表的实时验证和验证

Business Central 为指导决策表提供了一个实时验证和验证功能,以确保您的表已完成并可用错误。指导决策表在每次单元更改后都会验证。如果检测到逻辑出现问题,则会出现错误通知并描述问题。

33.1. 指导决策表中的问题类型

验证和验证功能检测到以下类型的问题:

冗余
当决策表中的两行对同一组事实执行同样的结果时,会发生冗余。例如,检查客户端的生日行,并提供一个周五的发票可能会导致双引号。
Subsumption

Subsumption 与冗余类似,当两个规则执行同样的结果时,会发生,但对另一个事实的一部分执行。例如,考虑这两个规则:

  • 当 Person age > 10 时,增加计数器
  • 当 Person age > 20 时,增加计数器

在这种情况下,如果人是 15 年,则只会触发一条规则,如果人为 20 年,则这两个规则都会触发。这种情况会在运行时出现类似的问题,因为冗余。

Conflicts

当两个类似条件具有不同的结果时,会发生冲突的情况。在决策表中的两行(rules)或两个单元之间可能会发生冲突。

以下示例演示了决策表中的两行之间冲突:

  • when Deposit > 20000 then Approve Loan
  • when Deposit > 20000 then Refuse Loan

在这种情况下,无法知道是否批准 loan。

以下示例演示了决策表中的两个单元之间冲突:

  • when Age > 25
  • 当 Age < 25

不执行冲突单元的行。

有问题 的唯一 Hit 策略

当将 唯一 Hit 策略应用到一个路由表时,一次只能执行一行,每行必须是唯一的,且不满足条件重叠。如果执行多个行,则验证报告标识了有问题的点击策略。例如,在表中考虑以下条件决定了价格领导的资格:

  • when Is\":\" = true
  • when Is Military = true

如果客户同时是 192.168.1.0/24 和在站中,则应用这两个条件并破坏 唯一 Hit 策略。因此,这种表中的行必须以不允许一次触发多个规则的方式创建。有关点击策略的详情,请参考 第 26 章 按指导决策表的策略

deficiency

deficiency 与冲突类似,并在决策表中发生规则的逻辑不完整。例如,请考虑以下两个适当的规则:

  • 当 Age > 20 then Approve Loan
  • 当 Deposit < 20000 then Refuse Loan 时

这两个规则可能会对超过 20 年的人造成混淆,并且被认为少于 20000。您可以添加更多限制以避免冲突。

缺少 Columns
当删除的列会导致逻辑不完整或不正确的逻辑时,规则无法正确触发。这会检测到它,以便您可以处理缺少的列,或者调整逻辑使其不依赖于意外删除的条件或操作。
不完整的范围
如果表包含可能字段值的限制,但没有定义所有可能的值,则字段值的范围不完整。验证报告标识了提供的任何不完整的范围。例如,如果您的表是否有应用程序被批准的检查,验证报告将提醒您处理未批准应用程序的情况。

33.2. é€šçŸ¥ç±»å�‹

验证和验证功能使用三种类型的通知:

  • gdtValidationVerificationIconError 错误:一个严重的问题,可能会导致指导决策表无法按照运行时设计工作。例如,冲突会报告为错误。
  • gdtValidationVerificationIconWarning 警告:一个严重的问题,可能不会阻止指导决策表正常工作,但需要注意。例如,subsumptions 报告为警告。
  • gdtValidationVerificationIconInfo 信息 :可能不会阻止指导决策表正常工作但需要注意的中等问题。例如,缺少列作为信息报告。
注意

Business Central 验证和验证不会阻止您保存不正确的更改。该功能仅在编辑时报告问题,您仍然可以继续接管这些问题并保存您的更改。

33.3. 禁用指导决策表的验证和验证

Business Central 的决策表验证和验证功能会被默认启用。此功能可帮助您验证指导的决策表,但具有复杂的指导决策表,此功能可能会隐藏决策引擎性能。您可以通过在 Red Hat Process Automation Manager 发行版本中将 org.kie.verification.disable-dtable-realtime-verification 系统属性值设置为 true 来禁用此功能。

�程

进入 ~/standalone-full.xml 并添加以下系统属性:

<property name="org.kie.verification.disable-dtable-realtime-verification" value="true"/>

例如,在 Red Hat JBoss EAP 上,您可以在 $EAP_HOME/standalone/configuration/standalone-full.xml 中添加此系统属性。

第 34 章 将指导决策表转换为电子表格决策表

在 Business Central 中定义了指导决策表后,您可以将指导决策表转换为 XLS 电子表格决策文件,以获取离线参考和文件共享。指导决策表必须是扩展条目指导的决策表,才能转换。转换工具不支持有限的条目指导决策表。

有关电子表格决策表的更多信息,请参阅使用电子表格决策表设计决策服务

警告

主要的决策表和电子表格决策表是支持不同功能的表格式。将一个决策表格式转换为另一个格式时,修改或丢失两个决策表格式(例如,Hit 策略)之间支持的功能。

�程

在 Business Central 中,导航到您要转换的指导决策资产,并在决策表设计器右上角的工具中,点 Convert to XLS

图 34.1. 转换上传的决策表

决策表示例

转换后,转换的决策表会在项目中作为电子表格决策资产提供,供您下载以进行离线参考。

第 35 章 执行规则

在 Business Central 中识别示例规则或创建自己的规则后,您可以构建和部署关联的项目,并在 KIE 服务器上执行规则来测试规则。

先决�件

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. 在项目 资产 页面右上角,点 Deploy 以构建项目并将其部署到 KIE Server。如果构建失败,请解决屏幕底部的 Alerts 面板中描述的任何问题。

    有关项目部署选项的更多信息,请参阅 打包和部署 Red Hat Process Automation Manager 项目

    注意

    如果项目中的规则资产默认没有从可执行文件规则模型构建,请验证以下依赖项是否在项目的 pom.xml 文件中,并重建项目:

    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-model-compiler</artifactId>
      <version>${rhpam.version}</version>
    </dependency>

    默认情况下,Red Hat Process Automation Manager 中的规则资产需要此依赖项。此依赖项作为 Red Hat Process Automation Manager 核心打包的一部分包括,但取决于您的 Red Hat Process Automation Manager 升级历史记录,您可能需要手动添加此依赖项来启用可执行的规则模型行为。

    有关可执行规则模型的更多信息,请参阅 打包和部署 Red Hat Process Automation Manager 项目

  3. 在 Business Central 外部创建一个 Maven 或 Java 项目(如果尚未创建),您可以使用它在本地执行规则,或者作为客户端应用程序在 KIE 服务器上执行规则。该项目必须包含 pom.xml 文件和执行项目资源的任何其他必要的组件。

    有关 test 项目示例,请参阅 "创建和执行 DRL 规则的方法 "。

  4. 打开 test 项目或客户端应用程序的 pom.xml 文件,如果还没有添加以下依赖项:

    • kie-ci :使客户端应用程序能够使用 ReleaseId在本地加载 Business Central 项目数据
    • kie-server-client :启用客户端应用程序与 KIE 服务器上的资产远程交互
    • slf4j :(可选)使客户端应用程序能够使用简单日志记录 Facade for Java (SLF4J)在与 KIE 服务器交互后返回调试日志信息

    客户端应用程序 pom.xml 文件中的 Red Hat Process Automation Manager 7.9 的依赖项示例:

    <!-- For local execution -->
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-ci</artifactId>
      <version>7.44.0.Final-redhat-00006</version>
    </dependency>
    
    <!-- For remote execution on KIE Server -->
    <dependency>
      <groupId>org.kie.server</groupId>
      <artifactId>kie-server-client</artifactId>
      <version>7.44.0.Final-redhat-00006</version>
    </dependency>
    
    <!-- For debug logging (optional) -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-simple</artifactId>
      <version>1.7.25</version>
    </dependency>

    如需这些工件的可用版本,请在线搜索 Nexus Repository Manager 中的组 ID 和工件 ID。

    注意

    考虑将 Red Hat Business Automation Manager (BOM)依赖项添加到项目 pom.xml 文件,而不是为单个依赖项指定 Red Hat Process Automation Manager < version >。Red Hat Business Automation BOM 适用于 Red Hat Decision Manager 和 Red Hat Process Automation Manager。当您添加 BOM 文件时,项目中包含了来自提供的 Maven 存储库传输性依赖关系的正确版本。

    BOM 依赖项示例:

    <dependency>
      <groupId>com.redhat.ba</groupId>
      <artifactId>ba-platform-bom</artifactId>
      <version>7.9.1.redhat-00003</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>

    有关 Red Hat Business Automation BOM 的更多信息,请参阅 Red Hat Process Automation Manager 和 Maven 库版本之间的映射是什么?

  5. 确保包含模型类的工件的依赖项在客户端应用程序 pom.xml 文件中定义,因为它们出现在部署的项目的 pom.xml 文件中。如果模型类的依赖项因客户端应用程序和项目而异,则可能会出现执行错误。

    要访问 Business Central 中的项目 pom.xml 文件,请选择项目中的任何现有资产,然后在屏幕左侧的 Project Explorer 菜单中点击 Customize View gear 图标并选择 Repository Viewpom.xml

    例如,以下 Person 类依赖项同时出现在客户端和部署的项目 pom.xml 文件中:

    <dependency>
      <groupId>com.sample</groupId>
      <artifactId>Person</artifactId>
      <version>1.0.0</version>
    </dependency>
  6. 如果您在用于调试日志的客户端应用程序 pom.xml 文件中添加 slf4j 依赖项,请在相关 classpath 上 创建一个简单的logger.properties 文件(例如,在 Maven 中的 src/main/resources/META-INF 中),其中包含以下内容:

    org.slf4j.simpleLogger.defaultLogLevel=debug
  7. 在客户端应用程序中,创建一个包含必要的导入和 main () 方法的 .java 主类,来加载 KIE 基础、插入事实和执行规则。

    例如,项目中的 Person 对象包含 getter 和 setter 方法,用于设置和检索名字、姓氏、每小时率以及个人的 wage。项目中的以下 Wage 规则计算 wage 和每小时速率值,并根据结果显示一条消息:

    package com.sample;
    
    import com.sample.Person;
    
    dialect "java"
    
    rule "Wage"
      when
        Person(hourlyRate * wage > 100)
        Person(name : firstName, surname : lastName)
      then
        System.out.println("Hello" + " " + name + " " + surname + "!");
        System.out.println("You are rich!");
    end

    要在 KIE 服务器之外测试此规则(如果需要),请将 .java 类配置为导入 KIE 服务、KIE 容器和 KIE 会话,然后使用 main () 方法根据定义的事实模型触发所有规则:

    本地执行规则

    import org.kie.api.KieServices;
    import org.kie.api.builder.ReleaseId;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    import org.drools.compiler.kproject.ReleaseIdImpl;
    
    public class RulesTest {
    
      public static final void main(String[] args) {
        try {
          // Identify the project in the local repository:
          ReleaseId rid = new ReleaseIdImpl("com.myspace", "MyProject", "1.0.0");
    
          // Load the KIE base:
          KieServices ks = KieServices.Factory.get();
          KieContainer kContainer = ks.newKieContainer(rid);
          KieSession kSession = kContainer.newKieSession();
    
          // Set up the fact model:
          Person p = new Person();
          p.setWage(12);
          p.setFirstName("Tom");
          p.setLastName("Summers");
          p.setHourlyRate(10);
    
          // Insert the person into the session:
          kSession.insert(p);
    
          // Fire all rules:
          kSession.fireAllRules();
          kSession.dispose();
        }
    
        catch (Throwable t) {
          t.printStackTrace();
        }
      }
    }

    要在 KIE 服务器上测试此规则,请使用导入和规则执行信息配置 .java 类,以及指定 KIE 服务配置和 KIE 服务客户端详情:

    在 KIE 服务器上执行规则

    package com.sample;
    
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    import org.kie.api.command.BatchExecutionCommand;
    import org.kie.api.command.Command;
    import org.kie.api.KieServices;
    import org.kie.api.runtime.ExecutionResults;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    import org.kie.server.api.marshalling.MarshallingFormat;
    import org.kie.server.api.model.ServiceResponse;
    import org.kie.server.client.KieServicesClient;
    import org.kie.server.client.KieServicesConfiguration;
    import org.kie.server.client.KieServicesFactory;
    import org.kie.server.client.RuleServicesClient;
    
    import com.sample.Person;
    
    public class RulesTest {
    
      private static final String containerName = "testProject";
      private static final String sessionName = "myStatelessSession";
    
      public static final void main(String[] args) {
        try {
          // Define KIE services configuration and client:
          Set<Class<?>> allClasses = new HashSet<Class<?>>();
          allClasses.add(Person.class);
          String serverUrl = "http://$HOST:$PORT/kie-server/services/rest/server";
          String username = "$USERNAME";
          String password = "$PASSWORD";
          KieServicesConfiguration config =
            KieServicesFactory.newRestConfiguration(serverUrl,
                                                    username,
                                                    password);
          config.setMarshallingFormat(MarshallingFormat.JAXB);
          config.addExtraClasses(allClasses);
          KieServicesClient kieServicesClient =
            KieServicesFactory.newKieServicesClient(config);
    
          // Set up the fact model:
          Person p = new Person();
          p.setWage(12);
          p.setFirstName("Tom");
          p.setLastName("Summers");
          p.setHourlyRate(10);
    
          // Insert Person into the session:
          KieCommands kieCommands = KieServices.Factory.get().getCommands();
          List<Command> commandList = new ArrayList<Command>();
          commandList.add(kieCommands.newInsert(p, "personReturnId"));
    
          // Fire all rules:
          commandList.add(kieCommands.newFireAllRules("numberOfFiredRules"));
          BatchExecutionCommand batch = kieCommands.newBatchExecution(commandList, sessionName);
    
          // Use rule services client to send request:
          RuleServicesClient ruleClient = kieServicesClient.getServicesClient(RuleServicesClient.class);
          ServiceResponse<ExecutionResults> executeResponse = ruleClient.executeCommandsWithResults(containerName, batch);
          System.out.println("number of fired rules:" + executeResponse.getResult().getValue("numberOfFiredRules"));
        }
    
        catch (Throwable t) {
          t.printStackTrace();
        }
      }
    }

  8. 从项目目录运行配置的 .java 类。您可以在开发平台(如 Red Hat CodeReady Studio)或命令行中运行该文件。

    Maven 执行示例(带有项目目录):

    mvn clean install exec:java -Dexec.mainClass="com.sample.app.RulesTest"

    Java 执行示例(使用项目目录)

    javac -classpath "./$DEPENDENCIES/*:." RulesTest.java
    java -classpath "./$DEPENDENCIES/*:." RulesTest
  9. 在命令行和服务器日志中查看规则执行状态。如果有任何规则没有如预期执行,请查看项目中配置的规则和主类配置以验证所提供的数据。

第 36 章 å��续步骤

部分 V. 使用电子表格决策表设计决策服务

作为商业部门或业务规则开发人员,您可以使用表格决策表来定义业务逻辑,然后在 Business Central 中将电子表格上传到您的项目。这些规则编译为 dols 规则语言(DRL),并为您的项目形成决策服务的核心。

注意

您还可以使用决策模型和表示法(DMN)模型而不是基于规则的或基于表的资产来设计您的决策服务。有关 Red Hat Process Automation Manager 7.9 中的 DMN 支持的详情,请查看以下资源:

先决�件

  • 决策表的空间和项目已在 Business Central 中创建。每个资产都与分配给空间的项目关联。详情请参阅 开始使用决策服务。

第 37 章 Red Hat Process Automation Manager 中的决策授权资产

Red Hat Process Automation Manager 支持多个资产,可用于为您的决策服务定义决策。每个决定授权资产都有不同的优点,您可能需要根据您的目标和需求使用多个资产的组合。

下表重点介绍 Red Hat Process Automation Manager 项目支持的主要决策授权资产,以帮助您决定或确认在决策服务中定义决策的最佳方法。

表 37.1. Red Hat Process Automation Manager 支持的决策授予资产

assethighlight编写工具Documentation

决策模型和表示法(DMN)模型

  • 是根据对象管理组(OMG)定义的表示法标准决定模型。
  • 使用代表部分或所有决策要求图(DRG)的图形决策要求图(DRG)来跟踪业务决策流程
  • 使用允许在 DMN 兼容平台之间共享 DMN 模型的 XML 模式
  • 支持 Friendly Enough Expression Language (FEEL),以在 DMN 决策表和其他 DMN 框表达式中定义决策逻辑
  • 可以与 Business Process Model 和 Notation (DSLN)进程模型有效集成
  • 是创建全面、演示和稳定的决策流程的最佳选择

Business Central 或其他与 DMN 兼容的编辑器

使用 DMN 模型设计决策服务

主要决策表

  • 是您在 Business Central 的基于 UI 的表设计程序中创建的规则表
  • 是电子表格决策表的向导替代方法
  • 为可接受的输入提供字段和选项
  • 支持用于创建规则模板的模板键和值
  • 支持点击策略、实时验证以及其他资产不支持的其他额外功能
  • 最好以受控的 tabular 格式创建规则,以最小化编译错误

Business Central

使用指导决策表设计决策服务

电子表格决策表

  • 是 XLS 或 XLSX 电子表格决策表,您可以上传到 Business Central
  • 支持用于创建规则模板的模板键和值
  • 最好在 Business Central 外部管理的路由表中创建规则
  • 对于在上传时正确编译的规则具有严格的语法要求

电子表格编辑器

使用电子表格决策表设计决策服务

指导规则

  • 是您在 Business Central 中基于 UI 的规则设计程序中创建的单个规则
  • 为可接受的输入提供字段和选项
  • 最好以受控格式创建单个规则,以最小化编译错误

Business Central

使用指导规则设计决策服务

指导规则模板

  • 是您在 Business Central 中的基于 UI 的模板设计程序中创建的可重复使用的规则结构
  • 为可接受的输入提供字段和选项
  • 支持用于创建规则模板的模板键和值(与资产相关的目的不同)
  • 最好创建具有相同规则结构但具有不同定义的字段值的规则

Business Central

使用指导规则模板设计决策服务

DRL 规则

  • 是直接在 .drl 文本文件中定义的单个规则
  • 提供定义规则和其他规则行为的最灵活
  • 可以在某些独立环境中创建,并与 Red Hat Process Automation Manager 集成
  • 最好创建需要高级 DRL 选项的规则
  • 具有正确编译的规则具有严格的语法要求

Business Central 或集成开发环境(IDE)

使用 DRL 规则设计决策服务

预测模型标记语言(PMML)模型

  • 是预测的 data-analytic 模型,它基于由 Data Mining Group (DMG)定义的表示法标准
  • 使用一个 XML 模式,允许在 PMML 兼容平台之间共享 PMML 模型
  • 支持 Regression、Scorecard、Tree、Ming 和其他模型类型
  • 可以包含独立 Red Hat Process Automation Manager 项目,也可以导入到 Business Central 中的项目中
  • 最好在 Red Hat Process Automation Manager 中将预测数据整合到决策服务中

pmML 或 XML 编辑器

使用 PMML 模型设计决策服务

第 38 章 电子表格决策表

电子表格决策表是 XLS 或 XLSX 电子表,其中包含以表格格式定义的新规则。您可以使用独立 Red Hat Process Automation Manager 项目包含电子表格决策表,或者在 Business Central 中将它们上传到项目。决策表中的每一行都是一条规则,每个列都是一个条件、操作或其他规则属性。创建并上传电子表格决策表后,您定义的规则会编译为无需规则语言(DRL)规则,与其他规则资产一样。

与电子表格决策表相关的所有数据对象都必须与电子表格决策表位于同一个项目软件包中。默认情况下导入同一软件包中的资产。可使用路由表导入其他软件包中的现有资产。

第 39 章 数据对象

数据对象是您创建的规则资产的构建块。数据对象是在项目的指定软件包中作为 Java 对象实现的自定义数据类型。例如,您可以创建一个带有数据字段 Name, Address, 和 DateOfBirthPerson 对象,以指定 loan 应用程序规则的个人详情。这些自定义数据类型决定了您的资产和您决定服务所基于的数据。

39.1. 创建数据对象

以下流程是创建数据对象的通用概述。它不特定于特定的业务资产。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetData Object
  3. 输入唯一 数据对象 名称并选择 您希望 数据对象可用于其他规则资产的软件包。同一软件包中不能存在具有相同名称的数据对象。在指定的 DRL 文件中,您可以从任何软件包导入数据对象。

    从其他软件包导入数据对象

    您可以直接将现有数据对象从另一个软件包导入到资产设计人员,如指导规则或指导决策表设计器。选择项目中的相关规则资产和资产设计器,转至 Data Objects → New 项 以选择要导入的对象。

  4. 要使数据对象持久,请选择 Persistable 复选框。Persistable 数据对象可以根据 JPA 规范存储在数据库中。默认 JPA 是 Hibernate。
  5. 点 确定。
  6. 在数据对象设计器中,单击 add 字段,将字段添加到带有属性 Id,Label, 和 Type 的对象。所需属性被标记为星号。

    • id : 输入字段的唯一 ID。
    • label : (可选)输入字段的标签
    • type : 输入字段的数据类型。
    • 列表: (可选)选择此复选框来启用该字段为指定类型保存多个项目。

      图 39.1. 在数据对象中添加数据字段

      在数据对象中添加数据字段
  7. Create 添加新字段,或者点 Create 并继续 添加新字段,并继续添加新字段。

    注意

    要编辑字段,请选择字段行,并使用屏幕右侧的 常规属性

第 40 章 决策表用例

在线网站列出了订购项目的计费费用。站点在以下条件下提供免费提供的:

  • 排序的项目数量为 4 个或更多,签出总数为 $300 或更多。
  • 选择标准交付(自购买之日起4或 5 个工作日)。

以下是这些条件下的发送率:

表 40.1. 少于 $300 的订购

项目数交付日期USD, N = 数项目的支付费用

3 个或更少

下一日

第二天

Standard(标准)

35

15

10

4 个或更多

下一日

第二天

Standard(标准)

N*7.50

N*3.50

N*2.50

表 40.2. 订购超过 $300

项目数交付日期USD, N = 数项目的支付费用

3 个或更少

下一日

第二天

Standard(标准)

25

10

N*1.50

4 个或更多

下一日

第二天

Standard(标准)

N*5

N*2

FREE

这些条件和率在以下示例电子表格决定表中显示:

图 40.1. 销售费用的决策表

决策表示例

为了在 Business Central 中上传决策表,表必须符合 XLS 或 XLSX 电子表格中的特定结构和语法要求,如下例所示。更多信æ�¯è¯·å�‚阅 第 41 章 定义电子表决策表。

第 41 章 定义电子表决策表

电子表格决策表(XLS 或 XLSX)需要两个关键区域来定义规则数据: RuleSet 区域和 RuleTable 区域。电子表格的 RuleSet 区域定义了您要全局应用到同一软件包中的所有规则的元素(不仅仅是电子表格),如规则集名称或通用规则属性。RuleTable 区域定义实际规则(箭头),以及组成指定规则集中的规则表的条件、操作和其他规则属性(columns)。电子表格可以包含多个 RuleTable 区域,但只能包含一个 RuleSet 区域。

重要

您通常只根据 Business Central 中的规则软件包上传一个电子的决策表,其中包含所有必要的 RuleTable 定义。您可以为单独的软件包上传单独的路由表电子表,但在同一软件包中上传多个电子表可能会导致 RuleSetRuleTable 属性中的编译错误,因此不建议这样做。

在定义路由表时,请参考以下示例电子表:

图 41.1. 电子表格决策表示例

决策表示例

�程

  1. 在新的 XLS 或 XLSX 电子表格中,转至第二列或第三列,并标记单元 RuleSet (例如 1 )。为描述性元数据保留左侧列或列(可选)。
  2. 在右侧的下一个单元中,为 RuleSet 输入一个名称。此命名规则集将包含 rule 软件包中定义的所有 RuleTable 规则。
  3. RuleSet cell 下,定义您要全局应用到软件包中的所有规则表的任何规则属性(每个单元一个)。在右侧的单元格中指定属性值。例如,您可以输入 Import 标签并在右侧的单元格中,指定您要导入到决策表的软件包(格式为 package.name.object.name)中的相关数据对象。有关支持的单元标签和值,请参阅 第 41.1 节 “规则集定义”
  4. RuleSet 区域下,以及与 RuleSet 单元相同的列中,跳过一行并标记一个新的单元 RuleTable (示例中为 7),并在同一单元中输入表名称。名称用作此规则表中派生的所有规则的初始部分,并附加行号以提供区别。您可以通过插入 NAME 属性列来覆盖这个自动命名。
  5. 根据需要使用接下来的四行来定义以下元素(示例中为 8-11):

    • 规则属性: Conditions、action 或其他属性。有关支持的单元标签和值,请参阅 第 41.2 节 “RuleTable 定义”
    • 对象类型 : 规则属性应用到的数据对象。如果同一对象类型应用到多个列,请将对象单元合并到多个列(如示例决策表中所示),而不是在多个单元中重复对象类型。合并对象类型时,合并范围下面的所有列都将合并到单一模式中的一组限制中,以便一次匹配单个事实。当对象以单独的列重复时,单独的列可以创建不同的模式,可能会匹配不同的或相同的事实。
    • 约束: 对对象类型的限制。
    • 列标签: (可选)列的任何描述性标签,作为视觉 aid。如果未使用,请留空。

      注意

      作为填充对象类型和约束单元的替代选择,您可以将对象类型单元或单元留空,并在对应的约束单元或单元中输入完整表达式。例如,您可以将对象类型和 itemsCount > $1 作为约束(separate cells),而是将对象类型单元留空,然后在约束单元中输入 Order (itemsCount > $1),然后对其他约束单元执行相同的操作。

  6. 在定义了所有必要的规则属性(columns)后,根据需要为每个列输入值(例如,按行行),以生成规则(示例为 12-17)。没有数据的单元(比如当条件或操作不适用时)。

    如果您需要在这个决策表上添加更多规则表,请在上表中的最后一个规则后跳过一行,在前面 RuleTableRuleSet 单元相同的列中标记另一个 RuleTable 单元,按照本节中的相同步骤创建新表(示例中为 19-29)。

  7. 保存 XLS 或 XLSX 电子表格以完成。
注意

默认情况下,当您上传 Business Central 中的电子表格时,只有电子表格中的第一个工作表才会作为决策表进行处理。每个 RuleSet 名称与 RuleTable 名称相结合,必须在同一软件包中的所有路由表文件中唯一。

如果要处理多个工作表决策表,请创建一个与电子表格相同名称的 .properties 文件。.properties 文件必须包含一个带有工作表名称的以逗号分隔的值(CSV)的属性表,例如:

sheets=Sheet1,Sheet2

在 Business Central 中上传决策表后,规则将呈现为类似以下示例的 DRL 规则:

//row 12
rule "Basic_12"
salience 10
  when
    $order : Order( itemsCount > 0, itemsCount <= 3, deliverInDays == 1 )
  then
    insert( new Charge( 35 ) );
end
启用单元值中使用的空格

默认情况下,在决策引擎处理决策表前或之后,将删除决策表单元中的任何空格。要保留您在单元中的值之前或之后使用的空格,请在 Red Hat Process Automation Manager 发行版本中将 drools.trimCellsInDTable 系统属性设置为 false

例如,如果您在 Red Hat JBoss EAP 中使用 Red Hat Process Automation Manager,请将以下系统属性添加到 $EAP_HOME/standalone/configuration/standalone-full.xml 文件中:

<property name="drools.trimCellsInDTable" value="false"/>

如果您使用嵌入在 Java 应用程序中的决策引擎,请使用以下命令添加系统属性:

java -jar yourApplication.jar -Ddrools.trimCellsInDTable=false

41.1. 规则集定义

决策表的 RuleSet 区域中的条目定义了 DRL 结构和规则属性,它们应用到软件包中的所有规则(不仅仅是电子表格中)。条目必须位于单元格对的垂直堆栈序列中,其中第一个单元包含一个标签,右侧的单元包含值。决策表电子表格只能有一个 RuleSet 区域。

下表列出了 RuleSet 定义支持的标签和值:

表 41.1. 支持的 RuleSet 定义

标签值使用方法

ruleset

生成的 DRL 文件的软件包名称。可选,默认值为 rule_table

必须是第一个条目。

sequential

true 或 false。如果为 true,则使用 salience 来确保规则从上线触发。

可选,最多一次。如果省略,则不会应用触发顺序。

SequentialMaxPriority

整数值

可选,最多一次。在后续模式中,此选项用于设置 salience 的起始值。如果省略,则默认值为 65535。

SequentialMinPriority

整数值

可选,最多一次。在后续模式中,此选项用于检查这个最小 salience 值是否没有违反。如果省略,则默认值为 0。

EscapeQuotes

true 或 false。如果为 true,则转义引号,以便在 DRL 中显示它们。

可选,最多一次。如果省略,则会转义引号。

Import

从另一个软件包导入的、以逗号分隔的 Java 类列表。

可选,可以重复使用。

��

DRL 全局声明(类型后跟变量名称)。多个全局定义必须以逗号分开。

可选,可以重复使用。

Functions

根据 DRL 语法,一个或多个功能定义。

可选,可以重复使用。

查询

根据 DRL 语法,一个或多个查询定义。

可选,可以重复使用。

声明

根据 DRL 语法,一个或多个声明性类型。

可选,可以重复使用。

警告

在某些情况下,Microsoft Office、LibreOffice 和 Ice 可能会以不同的方式对双引号进行编码,从而导致编译错误。例如,"A" 将失败,但 "A" 将传递。

41.2. RuleTable 定义

决策表的 RuleTable 区域中的条目为该规则表中的规则定义条件、操作和其他规则属性。电子表格可以包含多个 RuleTable 区域。

下表列出了 RuleTable 定义支持的标签(列标头)和值。对于列标头,您可以使用给定标签或以表中列出的字母开头的任何自定义标签。

表 41.2. 支持的 RuleTable 定义

标签或以 开头的自定义标签值使用方法

NAME

N

为从该行生成的规则提供名称。默认由 RuleTable 标签和行号后面的文本组成。

最多一个列。

描述

I

在生成的规则中产生注释。

最多一个列。

条件

C

代码片段和交集值,用于在条件的模式内构建约束。

每个规则表至少有一个。

�作

A

用于构建规则结果操作的代码片段和交集值。

每个规则表至少有一个。

元数�

@

用于为规则构建元数据条目的代码片段和交集值。

可选,任意数量的列。

以下小节详细介绍了状况、操作和元数据列如何使用单元数据:

Conditions

对于头的 CONDITION 的列,连续行中的单元格会导致条件元素:

  • 单元: CONDITION 下的第一个单元格中的文本为规则条件的模式,并使用下一行中的代码片段作为约束。如果单元与一个或多个邻居单元合并,则会形成一个带有多个约束的单一模式。所有约束都合并到一个父列表中,并附加到此单元的文本中。

    如果这个单元为空,则单元格中的代码片段必须自行生成有效的 condition 元素。例如,您可以将对象类型和 itemsCount > $1 作为约束(包括单元)保留,而是将对象类型单元留空,然后在约束单元中输入 Order (itemsCount > $1),然后对任何其他约束单元执行相同的操作。

    要包括没有限制的模式,您可以在另一模式文本前面写入模式,使用或不使用空括号对。您还可以将 from 子句附加到模式。

    如果模式以 eval 结尾,代码片段会生成布尔值表达式,用于在 eval 后包含在一组括号中。

    您可以使用 @watch 注释终止模式,该注释用于自定义模式重新主动的属性。

  • 第二个单元: CONDITION 下的第二个单元中的文本作为第一个单元中对象引用的约束进行处理。此单元中的代码片段通过区分列中单元的值来修改。如果要创建由使用 == 与以下单元中的值的比较组成的约束,则仅字段选择器就足够了。必须将任何其他比较运算符指定为代码片段中的最后一个项目,并附加以下单元中的值。对于所有其他约束形式,您必须标记位置,使其包含带有符号 $param 的单元格的内容。如果您使用符号 $1$2 等,以及以下单元中的以逗号分隔的值列表,则可以多个插入。但是,不要用逗号分开 $1$2 等,或者以逗号分隔,否则表将无法处理。

    要根据 all ( $ delimiter){ $snippet } 的模式扩展文本,请对以下每个单元中的每个值重复一次 $ snippet。请注意,forall 结构可能会被其他文本括起。

    如果第一个单元包含一个对象,则完成的代码片段将添加到该单元中的 conditions 元素中。自动提供一对括号以及分隔逗号(如果将多个约束添加到合并的单元中的模式)。如果第一个单元为空,则此单元中的代码片段必须自行生成有效的 condition 元素。例如,您可以将对象类型和 itemsCount > $1 作为约束(包括单元)保留,而是将对象类型单元留空,然后在约束单元中输入 Order (itemsCount > $1),然后对任何其他约束单元执行相同的操作。

  • 第三个单元: CONDITION 下面的第三个单元中的文本是您为列定义的描述性标签,作为视觉辅助性。
  • 第四个单元: 从第四行,非内置条目提供数据进行插入。空白单元省略此规则的条件或约束。
Actions

对于头的 columns,连续行中的单元格会导致 action 语句:

  • 第一个单元:ACTION 以下的第一个单元中的文本是可选的。如果存在,则文本将解释为对象引用。
  • 第二个单元: 以下第二个单元中的文本是代码片段,其通过区分列中单元格的值来修改。对于单数插入,请标记位置,使其包含带有符号 $param 的单元格的内容。如果您使用符号 $1$2 等,以及以下单元中的以逗号分隔的值列表,则可以多个插入。但是,不要用逗号分开 $1$2 等,或者以逗号分隔,否则表将无法处理。

    没有标记符号的文本可以执行方法调用,而无需反过。在这种情况下,在单元格下面一行中使用任何非 blank 条目来包括该语句。支持 forall 结构。

    如果第一个单元包含一个对象,则单元文本(由句点跟踪)、第二个单元中的文本,而终止分号将一起停止,从而导致作为结果的操作声明添加的方法调用。如果第一个单元为空,则此单元中的代码片段必须自行生成有效的 action 元素。

  • 第三个单元: 以下第三个单元中的文本是您为列定义的描述性标签,作为视觉目的。
  • 第四个单元: 从第四行,非内置条目提供数据进行插入。空白单元省略此规则的条件或约束。
元数�

对于头的 METADATA 的列,连续行中的单元格会为生成的规则生成元数据注解:

  • 第一个单元: METADATA 下面的第一个单元中的文本将被忽略。
  • 第二个单元: METADATA 下的第二个单元中的文本使用规则行中的单元值。元数据标记字符 @ 会自动作为前缀,因此您不需要将该字符包含在此单元的文本中。
  • 第三个单元: METADATA 下面的第三个单元中的文本是您为列定义的描述性标签,它是一个可视化的辅助性。
  • 第四个单元: 从第四行,非内置条目提供数据进行插入。空白单元会导致此规则的元数据注解混淆。

41.3. RuleSet 或 RuleTable 定义的额外规则属性

RuleSetRuleTable 区域还支持其他规则属性的标签和注解和值,如 PRIORITYNO-LOOPRuleSet 区域中指定的规则属性将影响同一软件包中的所有规则资产(不仅仅是电子表格中)。RuleTable 区域中指定的规则属性将仅影响该规则表中的规则。您只能在 RuleSet 区域中使用每个 rule 属性,并在 RuleTable 区域中使用一次。如果在电子表中的 RuleSetRuleTable 区域使用相同的属性,则 RuleTable 具有 priorityTable,并且 RuleSet 区域中的属性被覆盖。

下表列出了附加 RuleSetRuleTable 定义支持的标签(列标头)和值。对于列标头,您可以使用给定标签或以表中列出的字母开头的任何自定义标签。

表 41.3. RuleSetRuleTable 定义的额外规则属性

标签或以 开头的自定义标签值

PRIORITY

P

定义规则 salience 值的整数。在激活队列中排序时,具有较高 salience 值的规则会被赋予更高的优先级。被 Sequential 标志覆盖。

示例: PRIORITY 10

DATE-EFFECTIVE

V

包含日期和时间定义的字符串。只有在当前日期和时间是 DATE-EFFECTIVE 属性后才能激活该规则。

示例: DATE-EFFECTIVE "4-Sep-2018"

DATE-EXPIRES

Z

包含日期和时间定义的字符串。如果当前日期和时间在 DATE-EXPIRES 属性后面,则无法激活该规则。

示例: DATE-EXPIRES "4-Oct-2018"

NO-LOOP

U

布尔值。当此选项设为 true 时,如果规则重新触发之前满足的条件,则无法重新激活(循环)规则。

示例: NO-LOOP true

TELE-GROUP

G

标识您要为其分配该规则的席位组的字符串。通过电缆组,您可以对员工进行分区,以提供更多对规则组的执行控制。只有购买重点组中的规则才能激活。

示例: AGENDA-GROUP "GroupName"

ACTIVATION-GROUP

X

标识您要为其分配该规则的激活(或 XOR)组的字符串。在激活组中,只能激活一条规则。触发的第一个规则将取消激活组中所有规则的所有待处理激活。

示例: ACTIVATION-GROUP "GroupName"

DURATION

D

较长的整数值,如果仍然满足规则条件,定义规则可以激活的时间(毫秒)。

示例: DURATION 10000

TIMER

T

标识 int (interval)或用于调度该规则的 cron 计时器定义的字符串。

示例: TIMER " TIME/5HQ HQ" (每 5 分钟)

日历

E

用于调度规则的 Quartz 日历定义。

示例: CALENDAR ",1 月 0-7,18-23 ?账单" (不包括非工作小时)

AUTO-FOCUS

F

布尔值,仅适用于购买组内的规则。当此选项设置为 true 时,下一次激活规则时,将自动给分配该规则的电缆组提供重点。

示例: AUTO-FOCUS true

LOCK-ON-ACTIVE

L

布尔值,仅适用于规则流组或电缆组内的规则。当此选项设置为 true 时,规则的规则的 ruleflow 组变为 active 或 rule 接收重点组时,规则无法再次激活,直到 ruleflow 组不再活跃,或者其电缆组丢失了重点。这是 no-loop 属性的更强大的版本,因为无论更新的来源(不仅仅是规则本身)都会丢弃匹配的规则激活。此属性适用于计算规则,您可以有多个修改事实的规则,您不希望任何规则重新匹配并再次触发。

示例: LOCK-ON-ACTIVE true

RULEFLOW-GROUP

R

标识规则流组的字符串。在规则流中,规则只能在由关联规则流激活组时触发。

示例: RULEFLOW-GROUP "GroupName"

图 41.2. 带有属性列的决策表示例

带有所用定义的决策表示例

第 42 章 将电子表格决策表上传到 Business Central

在外部 XLS 或 XLSX 电子表格中定义规则后,您可以在 Business Central 中将电子表格文件上传到您的项目。

重要

您通常只根据 Business Central 中的规则软件包上传一个电子的决策表,其中包含所有必要的 RuleTable 定义。您可以为单独的软件包上传单独的路由表电子表,但在同一软件包中上传多个电子表可能会导致 RuleSetRuleTable 属性中的编译错误,因此不建议这样做。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetDecision Table (Spreadsheet)
  3. 输入 说明表名称 并选择适当的 软件包
  4. 单击 Choose File 图标,然后选择电子表格。单击确定 上传。
  5. 在决策表设计器中,单击右上角的 Validate 来验证表。如果表验证失败,请打开 XLS 或 XLSX 文件并解决任何语法错误。有关语法帮助,请参阅 第 41 章 定义电子表决策表

    您可以上传决策表的新版本或下载当前版本:

    图 42.1. 上传的决策表选项

    决策表示例

第 43 章 将上传的电子表格决策表转换为 Business Central 中的指导决策表

将 XLS 或 XLSX 电子表格决策文件上传到 Business Central 中的项目后,您可以将决策表转换为您可以在 Business Central 中直接修改的指导决策表。

有关指导决策表的更多信息,请参阅使用指导决策表设计决策服务

警告

主要的决策表和电子表格决策表是支持不同功能的决策表格式。当您将一个决策表格式转换为另一个格式时,两个决策表格式之间的任何支持功能都会被修改或丢失。

�程

在 Business Central 中,导航到您要转换的上传的决策表资产,并在决策表设计器的右上角,点 Convert

图 43.1. 转换上传的决策表

决策表示例

转换后,转换的决策表将作为项目中的指导决策表资产提供,您可以在 Business Central 中直接修改。

第 44 章 执行规则

在 Business Central 中识别示例规则或创建自己的规则后,您可以构建和部署关联的项目,并在 KIE 服务器上执行规则来测试规则。

先决�件

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. 在项目 资产 页面右上角,点 Deploy 以构建项目并将其部署到 KIE Server。如果构建失败,请解决屏幕底部的 Alerts 面板中描述的任何问题。

    有关项目部署选项的更多信息,请参阅 打包和部署 Red Hat Process Automation Manager 项目

    注意

    如果项目中的规则资产默认没有从可执行文件规则模型构建,请验证以下依赖项是否在项目的 pom.xml 文件中,并重建项目:

    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-model-compiler</artifactId>
      <version>${rhpam.version}</version>
    </dependency>

    默认情况下,Red Hat Process Automation Manager 中的规则资产需要此依赖项。此依赖项作为 Red Hat Process Automation Manager 核心打包的一部分包括,但取决于您的 Red Hat Process Automation Manager 升级历史记录,您可能需要手动添加此依赖项来启用可执行的规则模型行为。

    有关可执行规则模型的更多信息,请参阅 打包和部署 Red Hat Process Automation Manager 项目

  3. 在 Business Central 外部创建一个 Maven 或 Java 项目(如果尚未创建),您可以使用它在本地执行规则,或者作为客户端应用程序在 KIE 服务器上执行规则。该项目必须包含 pom.xml 文件和执行项目资源的任何其他必要的组件。

    有关 test 项目示例,请参阅 "创建和执行 DRL 规则的方法 "。

  4. 打开 test 项目或客户端应用程序的 pom.xml 文件,如果还没有添加以下依赖项:

    • kie-ci :使客户端应用程序能够使用 ReleaseId在本地加载 Business Central 项目数据
    • kie-server-client :启用客户端应用程序与 KIE 服务器上的资产远程交互
    • slf4j :(可选)使客户端应用程序能够使用简单日志记录 Facade for Java (SLF4J)在与 KIE 服务器交互后返回调试日志信息

    客户端应用程序 pom.xml 文件中的 Red Hat Process Automation Manager 7.9 的依赖项示例:

    <!-- For local execution -->
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-ci</artifactId>
      <version>7.44.0.Final-redhat-00006</version>
    </dependency>
    
    <!-- For remote execution on KIE Server -->
    <dependency>
      <groupId>org.kie.server</groupId>
      <artifactId>kie-server-client</artifactId>
      <version>7.44.0.Final-redhat-00006</version>
    </dependency>
    
    <!-- For debug logging (optional) -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-simple</artifactId>
      <version>1.7.25</version>
    </dependency>

    如需这些工件的可用版本,请在线搜索 Nexus Repository Manager 中的组 ID 和工件 ID。

    注意

    考虑将 Red Hat Business Automation Manager (BOM)依赖项添加到项目 pom.xml 文件,而不是为单个依赖项指定 Red Hat Process Automation Manager < version >。Red Hat Business Automation BOM 适用于 Red Hat Decision Manager 和 Red Hat Process Automation Manager。当您添加 BOM 文件时,项目中包含了来自提供的 Maven 存储库传输性依赖关系的正确版本。

    BOM 依赖项示例:

    <dependency>
      <groupId>com.redhat.ba</groupId>
      <artifactId>ba-platform-bom</artifactId>
      <version>7.9.1.redhat-00003</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>

    有关 Red Hat Business Automation BOM 的更多信息,请参阅 Red Hat Process Automation Manager 和 Maven 库版本之间的映射是什么?

  5. 确保包含模型类的工件的依赖项在客户端应用程序 pom.xml 文件中定义,因为它们出现在部署的项目的 pom.xml 文件中。如果模型类的依赖项因客户端应用程序和项目而异,则可能会出现执行错误。

    要访问 Business Central 中的项目 pom.xml 文件,请选择项目中的任何现有资产,然后在屏幕左侧的 Project Explorer 菜单中点击 Customize View gear 图标并选择 Repository Viewpom.xml

    例如,以下 Person 类依赖项同时出现在客户端和部署的项目 pom.xml 文件中:

    <dependency>
      <groupId>com.sample</groupId>
      <artifactId>Person</artifactId>
      <version>1.0.0</version>
    </dependency>
  6. 如果您在用于调试日志的客户端应用程序 pom.xml 文件中添加 slf4j 依赖项,请在相关 classpath 上 创建一个简单的logger.properties 文件(例如,在 Maven 中的 src/main/resources/META-INF 中),其中包含以下内容:

    org.slf4j.simpleLogger.defaultLogLevel=debug
  7. 在客户端应用程序中,创建一个包含必要的导入和 main () 方法的 .java 主类,来加载 KIE 基础、插入事实和执行规则。

    例如,项目中的 Person 对象包含 getter 和 setter 方法,用于设置和检索名字、姓氏、每小时率以及个人的 wage。项目中的以下 Wage 规则计算 wage 和每小时速率值,并根据结果显示一条消息:

    package com.sample;
    
    import com.sample.Person;
    
    dialect "java"
    
    rule "Wage"
      when
        Person(hourlyRate * wage > 100)
        Person(name : firstName, surname : lastName)
      then
        System.out.println("Hello" + " " + name + " " + surname + "!");
        System.out.println("You are rich!");
    end

    要在 KIE 服务器之外测试此规则(如果需要),请将 .java 类配置为导入 KIE 服务、KIE 容器和 KIE 会话,然后使用 main () 方法根据定义的事实模型触发所有规则:

    本地执行规则

    import org.kie.api.KieServices;
    import org.kie.api.builder.ReleaseId;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    import org.drools.compiler.kproject.ReleaseIdImpl;
    
    public class RulesTest {
    
      public static final void main(String[] args) {
        try {
          // Identify the project in the local repository:
          ReleaseId rid = new ReleaseIdImpl("com.myspace", "MyProject", "1.0.0");
    
          // Load the KIE base:
          KieServices ks = KieServices.Factory.get();
          KieContainer kContainer = ks.newKieContainer(rid);
          KieSession kSession = kContainer.newKieSession();
    
          // Set up the fact model:
          Person p = new Person();
          p.setWage(12);
          p.setFirstName("Tom");
          p.setLastName("Summers");
          p.setHourlyRate(10);
    
          // Insert the person into the session:
          kSession.insert(p);
    
          // Fire all rules:
          kSession.fireAllRules();
          kSession.dispose();
        }
    
        catch (Throwable t) {
          t.printStackTrace();
        }
      }
    }

    要在 KIE 服务器上测试此规则,请使用导入和规则执行信息配置 .java 类,以及指定 KIE 服务配置和 KIE 服务客户端详情:

    在 KIE 服务器上执行规则

    package com.sample;
    
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    import org.kie.api.command.BatchExecutionCommand;
    import org.kie.api.command.Command;
    import org.kie.api.KieServices;
    import org.kie.api.runtime.ExecutionResults;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    import org.kie.server.api.marshalling.MarshallingFormat;
    import org.kie.server.api.model.ServiceResponse;
    import org.kie.server.client.KieServicesClient;
    import org.kie.server.client.KieServicesConfiguration;
    import org.kie.server.client.KieServicesFactory;
    import org.kie.server.client.RuleServicesClient;
    
    import com.sample.Person;
    
    public class RulesTest {
    
      private static final String containerName = "testProject";
      private static final String sessionName = "myStatelessSession";
    
      public static final void main(String[] args) {
        try {
          // Define KIE services configuration and client:
          Set<Class<?>> allClasses = new HashSet<Class<?>>();
          allClasses.add(Person.class);
          String serverUrl = "http://$HOST:$PORT/kie-server/services/rest/server";
          String username = "$USERNAME";
          String password = "$PASSWORD";
          KieServicesConfiguration config =
            KieServicesFactory.newRestConfiguration(serverUrl,
                                                    username,
                                                    password);
          config.setMarshallingFormat(MarshallingFormat.JAXB);
          config.addExtraClasses(allClasses);
          KieServicesClient kieServicesClient =
            KieServicesFactory.newKieServicesClient(config);
    
          // Set up the fact model:
          Person p = new Person();
          p.setWage(12);
          p.setFirstName("Tom");
          p.setLastName("Summers");
          p.setHourlyRate(10);
    
          // Insert Person into the session:
          KieCommands kieCommands = KieServices.Factory.get().getCommands();
          List<Command> commandList = new ArrayList<Command>();
          commandList.add(kieCommands.newInsert(p, "personReturnId"));
    
          // Fire all rules:
          commandList.add(kieCommands.newFireAllRules("numberOfFiredRules"));
          BatchExecutionCommand batch = kieCommands.newBatchExecution(commandList, sessionName);
    
          // Use rule services client to send request:
          RuleServicesClient ruleClient = kieServicesClient.getServicesClient(RuleServicesClient.class);
          ServiceResponse<ExecutionResults> executeResponse = ruleClient.executeCommandsWithResults(containerName, batch);
          System.out.println("number of fired rules:" + executeResponse.getResult().getValue("numberOfFiredRules"));
        }
    
        catch (Throwable t) {
          t.printStackTrace();
        }
      }
    }

  8. 从项目目录运行配置的 .java 类。您可以在开发平台(如 Red Hat CodeReady Studio)或命令行中运行该文件。

    Maven 执行示例(带有项目目录):

    mvn clean install exec:java -Dexec.mainClass="com.sample.app.RulesTest"

    Java 执行示例(使用项目目录)

    javac -classpath "./$DEPENDENCIES/*:." RulesTest.java
    java -classpath "./$DEPENDENCIES/*:." RulesTest
  9. 在命令行和服务器日志中查看规则执行状态。如果有任何规则没有如预期执行,请查看项目中配置的规则和主类配置以验证所提供的数据。

第 45 章 å��续步骤

部分 VI. 使用指导规则设计决策服务

作为商业公司或业务规则开发人员,您可以使用 Business Central 中的指导规则设计程序来定义新规则。这些指导规则被编译到 dols 规则语言(DRL)中,并为您的项目形成决策服务的核心。

注意

您还可以使用决策模型和表示法(DMN)模型而不是基于规则的或基于表的资产来设计您的决策服务。有关 Red Hat Process Automation Manager 7.9 中的 DMN 支持的详情,请查看以下资源:

先决�件

  • 在 Business Central 中创建了指导规则的空间和项目。每个资产都与分配给空间的项目关联。详情请参阅 开始使用决策服务。

第 46 章 Red Hat Process Automation Manager 中的决策授权资产

Red Hat Process Automation Manager 支持多个资产,可用于为您的决策服务定义决策。每个决定授权资产都有不同的优点,您可能需要根据您的目标和需求使用多个资产的组合。

下表重点介绍 Red Hat Process Automation Manager 项目支持的主要决策授权资产,以帮助您决定或确认在决策服务中定义决策的最佳方法。

表 46.1. Red Hat Process Automation Manager 支持的决策授予资产

assethighlight编写工具Documentation

决策模型和表示法(DMN)模型

  • 是根据对象管理组(OMG)定义的表示法标准决定模型。
  • 使用代表部分或所有决策要求图(DRG)的图形决策要求图(DRG)来跟踪业务决策流程
  • 使用允许在 DMN 兼容平台之间共享 DMN 模型的 XML 模式
  • 支持 Friendly Enough Expression Language (FEEL),以在 DMN 决策表和其他 DMN 框表达式中定义决策逻辑
  • 可以与 Business Process Model 和 Notation (DSLN)进程模型有效集成
  • 是创建全面、演示和稳定的决策流程的最佳选择

Business Central 或其他与 DMN 兼容的编辑器

使用 DMN 模型设计决策服务

主要决策表

  • 是您在 Business Central 的基于 UI 的表设计程序中创建的规则表
  • 是电子表格决策表的向导替代方法
  • 为可接受的输入提供字段和选项
  • 支持用于创建规则模板的模板键和值
  • 支持点击策略、实时验证以及其他资产不支持的其他额外功能
  • 最好以受控的 tabular 格式创建规则,以最小化编译错误

Business Central

使用指导决策表设计决策服务

电子表格决策表

  • 是 XLS 或 XLSX 电子表格决策表,您可以上传到 Business Central
  • 支持用于创建规则模板的模板键和值
  • 最好在 Business Central 外部管理的路由表中创建规则
  • 对于在上传时正确编译的规则具有严格的语法要求

电子表格编辑器

使用电子表格决策表设计决策服务

指导规则

  • 是您在 Business Central 中基于 UI 的规则设计程序中创建的单个规则
  • 为可接受的输入提供字段和选项
  • 最好以受控格式创建单个规则,以最小化编译错误

Business Central

使用指导规则设计决策服务

指导规则模板

  • 是您在 Business Central 中的基于 UI 的模板设计程序中创建的可重复使用的规则结构
  • 为可接受的输入提供字段和选项
  • 支持用于创建规则模板的模板键和值(与资产相关的目的不同)
  • 最好创建具有相同规则结构但具有不同定义的字段值的规则

Business Central

使用指导规则模板设计决策服务

DRL 规则

  • 是直接在 .drl 文本文件中定义的单个规则
  • 提供定义规则和其他规则行为的最灵活
  • 可以在某些独立环境中创建,并与 Red Hat Process Automation Manager 集成
  • 最好创建需要高级 DRL 选项的规则
  • 具有正确编译的规则具有严格的语法要求

Business Central 或集成开发环境(IDE)

使用 DRL 规则设计决策服务

预测模型标记语言(PMML)模型

  • 是预测的 data-analytic 模型,它基于由 Data Mining Group (DMG)定义的表示法标准
  • 使用一个 XML 模式,允许在 PMML 兼容平台之间共享 PMML 模型
  • 支持 Regression、Scorecard、Tree、Ming 和其他模型类型
  • 可以包含独立 Red Hat Process Automation Manager 项目,也可以导入到 Business Central 中的项目中
  • 最好在 Red Hat Process Automation Manager 中将预测数据整合到决策服务中

pmML 或 XML 编辑器

使用 PMML 模型设计决策服务

第 47 章 指导规则

指导规则是您在 Business Central 中基于 UI 的指导规则设计人员创建的新规则,可帮助您完成规则创建过程。指导规则设计器根据所定义的规则的数据对象,为可接受的输入提供字段和选项。您定义的指导规则被编译到 drools 规则中,与其他规则资产一样。

与指导规则相关的所有数据对象都必须与指导规则位于同一个项目中。默认情况下导入同一软件包中的资产。创建必要的数据对象和指导规则后,您可以使用指导规则设计器的 Data Objects 选项卡来验证所有必需的数据对象是否已列出,或通过添加新 项目 来导入其他现有数据对象。

第 48 章 数据对象

数据对象是您创建的规则资产的构建块。数据对象是在项目的指定软件包中作为 Java 对象实现的自定义数据类型。例如,您可以创建一个带有数据字段 Name, Address, 和 DateOfBirthPerson 对象,以指定 loan 应用程序规则的个人详情。这些自定义数据类型决定了您的资产和您决定服务所基于的数据。

48.1. 创建数据对象

以下流程是创建数据对象的通用概述。它不特定于特定的业务资产。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetData Object
  3. 输入唯一 数据对象 名称并选择 您希望 数据对象可用于其他规则资产的软件包。同一软件包中不能存在具有相同名称的数据对象。在指定的 DRL 文件中,您可以从任何软件包导入数据对象。

    从其他软件包导入数据对象

    您可以直接将现有数据对象从另一个软件包导入到资产设计人员,如指导规则或指导决策表设计器。选择项目中的相关规则资产和资产设计器,转至 Data Objects → New 项 以选择要导入的对象。

  4. 要使数据对象持久,请选择 Persistable 复选框。Persistable 数据对象可以根据 JPA 规范存储在数据库中。默认 JPA 是 Hibernate。
  5. 点 确定。
  6. 在数据对象设计器中,单击 add 字段,将字段添加到带有属性 Id,Label, 和 Type 的对象。所需属性被标记为星号。

    • id : 输入字段的唯一 ID。
    • label : (可选)输入字段的标签
    • type : 输入字段的数据类型。
    • 列表: (可选)选择此复选框来启用该字段为指定类型保存多个项目。

      图 48.1. 在数据对象中添加数据字段

      在数据对象中添加数据字段
  7. Create 添加新字段,或者点 Create 并继续 添加新字段,并继续添加新字段。

    注意

    要编辑字段,请选择字段行,并使用屏幕右侧的 常规属性

第 49 章 创建指导规则

通过指导规则,您可以根据与规则关联的数据对象,以结构化格式定义新规则。您可以单独为项目创建和定义指导规则。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetDatacenter Rule
  3. 输入 说明性规则 名称并选择相应的 软件包。您指定的软件包必须是分配所需数据对象或将被分配的软件包。

    如果在项目中定义了任何域特定语言( DSL)资产,您也可以选择 Show claim DSL 句子。这些 DSL 资产将成为您在指导规则设计器中定义的条件和操作的可用对象。

  4. Ok 创建规则资产。

    现在,新的指导规则列在 Project Explorer 的指导规则面板中,或者如果您选择了 Show issued DSL sentences 选项,则在实验室规则(带有 DSL 面板中列出。

  5. Data Objects 选项卡,并确认您的规则所需的所有数据对象都已列出。如果没有,点 New item 从其他软件包导入数据对象,或者在软件包中 创建数据对象
  6. 所有数据对象都就位后,返回到指导规则设计器的 Model 选项卡,并使用窗口右侧的按钮来添加和定义规则的 WHEN (condition)和 kiosk N (action)部分,基于可用的数据对象。

    图 49.1. 指导规则设计器

    指导规则设计器

    规则的 WHEN 部分包含执行操作必须满足的条件。例如,如果某个公司需要 loan applicants 需要超过 21 年的时间,那么 Underage 规则的 WHEN 条件将 比 | 21 小

    规则的 wordpressN 部分包含在满足规则条件部分时要执行的操作。例如,当 loan applicant 旧于 21 年时,T uterN 操作会将 approve 设置为 false,从而因为 applicant 处于年龄。

    您还可以为更复杂的规则指定例外,例如当涉及保证者时,公司可能会批准被入侵的 applicant。在这种情况下,您可以创建或导入一个 保证数据对象,然后将字段添加到指导规则中。

  7. 在定义了规则的所有组件后,单击指导规则设计器右上角的 Validate 以验证指导规则。如果规则验证失败,请解决错误消息中描述的任何问题,检查规则中的所有组件,然后重试验证规则直到规则通过为止。
  8. 单击指导规则设计器中的 Save,以保存您的工作。

49.1. 在指导规则中添加 WHEN 条件

规则的 WHEN 部分包含执行操作必须满足的条件。例如,如果某个公司需要 loan applicants 需要超过 21 年的时间,那么 Underage 规则的 WHEN 条件将 比 | 21 小。您可以设置简单或复杂的条件,以确定如何应用规则。

先决�件

  • 您的规则所需的所有数据对象已创建或导入,并在指导规则设计器的 Data Objects 选项卡中列出。

流程

  1. 在指导规则设计程序中,点击 WHEN 部分右侧的加号图标 5686

    此时会打开可用 condition 元素的规则窗口中添加一个条件

    图 49.2. 在规则中添加条件

    在规则中添加条件

    该列表包括指导规则设计器的 Data Objects 选项卡中的数据对象、为软件包定义的 DSL 对象(如果您在创建此指导规则时选择了 Show 声明 DSL 发送)以及以下标准选项:

    • 以下不存在:使用它来指定不能存在 的事实和约束。
    • 存在: 使用它来指定必须存在的事实和约束。这个选项仅针对第一个匹配项触发,而不在以后的匹配项上触发。
    • 以下任何一个是 true : 使用它来列出所有必须为 true 的事实或约束。
    • from : 使用它来为 规则定义 From condition 元素。
    • 从 Accumulate : 使用它来为规则定义 Accumulate 条件元素。
    • from Collect : 使用它来为规则定义 Collect 条件元素。
    • from Entry Point 使用它来为模式定义条目点。
    • free form DRL :使用它来插入自由格式 的 DRL 字段,您可以在其中自由定义条件元素,而无需指导规则设计器。
  2. 选择一个 condition 元素(如 LoanApplication),然后单击 Ok
  3. 点指导规则设计器中的 condition 元素,并使用 LoanApplication 窗口的修改 限制来对字段添加限制,应用多个字段约束、添加新的公式风格表达式、应用表达式编辑器或设置变量名称。

    图 49.3. 修改条件

    修改条件
    注意

    变量名称允许您识别指导规则中的其他结构的事实或字段。例如,您可以将 LoanApplication 的变量设置为 a 然后在单独的 约束中引用,用于指定公司基于哪个应用程序。

    a : LoanApplication()
    Bankruptcy( application == a ).

    选择约束后,窗口会自动关闭。

  4. 从添加的限制旁的下拉菜单中选择限制(例如,大于)的运算符。
  5. 点编辑图标( 6191 )定义字段值。字段值可以是字面值、公式或完整的 MVEL 表达式。
  6. 要应用多个字段限制,点条件并在 LoanApplication 窗口中的 Modify 约束,从 Multiple field constraint 下拉菜单中选择 All of (And)Any of (Or)

    图 49.4. 添加多个字段约束

    修改条件
  7. 点指导规则设计器中的约束,并进一步定义字段值。
  8. 在定义了规则的所有条件组件后,单击指导规则设计器右上角的 Validate 以验证指导规则条件。如果规则验证失败,请解决错误消息中描述的任何问题,检查规则中的所有组件,然后重试验证规则直到规则通过为止。
  9. 单击指导规则设计器中的 Save,以保存您的工作。

49.2. 在指导规则中添加 THEN 操作

规则的 wordpressN 部分包含满足规则的 WHEN 条件时要执行的操作。例如,当 loan applicant 旧于 21 年时,stratN 操作可能会被设置为 false,从而取消冻结 loan,因为 applicant 处于年龄下。 您可以设置简单或复杂的操作,以确定如何应用规则。

先决�件

  • 您的规则所需的所有数据对象已创建或导入,并在指导规则设计器的 Data Objects 选项卡中列出。

流程

  1. 在指导规则设计器中,点击 the the rightN 部分右侧的加号图标 5686

    此时会打开 Add a new action 窗口,并打开了可用 action 元素。

    图 49.5. 向规则添加新操作

    向规则添加新操作

    该列表包括基于指导规则设计器的 Data Objects 选项卡中的数据对象的插入和修改选项,以及为该软件包定义的任何 DSL 对象(如果您在创建此指导规则时选择了 Show 声明的 DSL 句子 ):

    • 更改字段值: 使用它来设置事实上的字段值(如 LoanApplication),而不通知更改的决策引擎。
    • 删除 : 使用它来删除事实。
    • 修改 : 使用它来为事实指定要修改的字段,并通知决策引擎的变化。
    • 插入事实 : 使用它来插入事实,并为事实定义生成的字段和值。
    • 逻辑语言事实: 使用它来以逻辑方式将事实插入到决策引擎中,并为事实定义生成的字段和值。决策引擎负责对事实的插入和重包进行逻辑决策。常规或声明的插入后,必须明确重新遍历事实。逻辑插入后,当最初成为事实的条件不再满足时,会自动重新传输事实。
    • 添加免费形式 DRL : 使用它来插入自由格式的 DRL 字段,您可以在其中自由定义条件元素,而无需指导规则设计器。
    • 调用方法 : 使用它来从另一个事实调用方法。
  2. 选择 action 元素(如 Modify)并单击 Ok
  3. 点指导规则设计器中的 action 元素,并使用 Add a field 窗口来选择字段。

    图 49.6. 添加字段

    添加字段

    选择一个字段后,窗口会自动关闭。

  4. 点编辑图标( 6191 )定义字段值。field 值可以是字面值或公式。
  5. 在定义了规则的所有操作组件后,单击指导规则设计器右上角的 Validate 以验证指导规则操作。如果规则验证失败,请解决错误消息中描述的任何问题,检查规则中的所有组件,然后重试验证规则直到规则通过为止。
  6. 单击指导规则设计器中的 Save,以保存您的工作。

49.3. 在规则资产中为下拉列表定义枚举

Business Central 中的枚举定义决定了指导规则、指导规则模板和指导决策表中的条件或操作的可能值。Enumeration 定义包含一个 fact.field 映射到支持的值列表,这些值在规则资产的相关字段中显示为下拉列表。当用户选择基于与枚举定义相同的事实和字段时,会显示定义值的下拉列表。

您可以在 Business Central 或 Red Hat Process Automation Manager 项目的 DRL 源中定义枚举。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetEnumeration
  3. 输入说明性 枚举 名称并选择适当的 软件包。您指定的软件包必须是分配所需数据对象和相关规则资产的同一软件包。
  4. Ok 创建枚举。

    新的枚举现在列在 Project ExplorerEnumeration Definitions 面板中。

  5. 在枚举设计器的 Model 选项卡中,点 Add enum 并为枚举定义以下值:

    • 事实 :在您要将此枚举的项目的同一软件包中指定现有数据对象。打开 Project Explorer 中的 Data Objects 面板,以查看可用的数据对象,或者根据需要将相关数据对象创建为新资产。
    • 字段 :指定您定义为您为 事实 选择的数据对象一部分的现有字段标识符。打开 Project Explorer 中的 Data Objects 面板,以选择相关数据对象并查看可用 标识符选项列表。如果需要,您可以为数据对象创建相关标识符。
    • Context: 指定您要映射到 FactField 定义的格式 ['string1','string2','string3'][integer1,integer2,integer3] 的值列表。这些值将显示为规则资产相关字段的下拉列表。

    例如,以下枚举在 loan 应用程序决策服务中定义 applicant 信信评级的下拉值:

    图 49.7. Business Central 中应用程序信信评级的枚举示例

    EnumConfig

    DRL 源中适用信信评级的枚举示例

    'Applicant.creditRating' : ['AA', 'OK', 'Sub prime']

    在本例中,对于任何在项目相同的软件包中的指导规则、指导规则模板或指导的决策表,其使用 Applicant 数据对象和 creditRating 字段,配置的值可作为下拉列表选项提供:

    图 49.8. 指导规则或指导规则模板中枚举的下拉列表选项示例

    EnumDropDown

    图 49.9. 指导决策表中的 enumeration 下拉菜单选项示例

    EnumDropDownGDT

49.3.1. 规则资产的高级枚举选项

对于 Red Hat Process Automation Manager 项目中带有枚举定义的高级用例,请考虑以下扩展选项来定义枚举:

Business Central 中的 DRL 值和值之间的映射

如果您希望枚举值在 Business Central 界面中显示不同或更完全出现在 DRL 源中,请使用格式 'fact.field' : ['sourceValue1=UIValue1','sourceValue2=UIValue2', …​ ] 作为您的枚举定义值。

例如,在以下 loan 状态的枚举定义中,DRL 文件中使用了选项 AD,但 Business Central 中会显示 ApprovedDeclined 选项:

'Loan.status' : ['A=Approved','D=Declined']
Enumeration 值依赖项

如果您希望一个下拉列表中选择的值来确定后续下拉列表中的可用选项,请使用 'fact.fieldB[fieldA=value1]' : ['value2', 'value3', …​ ] 进行您的枚举定义。

例如,在以下代表策略的 enumeration 定义中,policyType 字段接受 Home 或 the 值。用户选择的策略类型决定了可用的策略 范围 字段选项:

'Insurance.policyType' : ['Home', 'Car']
'Insurance.coverage[policyType=Home]' : ['property', 'liability']
'Insurance.coverage[policyType=Car]' : ['collision', 'fullCoverage']
注意

在规则条件和操作中不会应用枚举的依赖关系。例如,在这种情况下,规则条件中选择的策略不会决定规则操作中的可用覆盖范围选项(如果适用)。

枚举中的外部数据源

如果要从外部数据源检索枚举值列表,而不是直接在枚举定义中定义值,在项目的类路径上,添加一个帮助程序类,它返回一个返回字符串的 java.util.List 列表的帮助类。在枚举定义中,而不是指定值列表,而是指定您配置为外部检索值的帮助类。

例如,在 Lan applicant 区域的以下枚举定义中,而不是以 'Applicant.region' : ['country1', 'country2', …​ ] 格式明确定义 applicant 区域:

'Applicant.region' : (new com.mycompany.DataHelper()).getListOfRegions()

在本例中,DataHelper 类包含一个 getListOfRegions () 方法,该方法返回字符串列表。枚举会在规则资产中相关字段的下拉列表中加载。

您还可以以常常方式识别依赖字段并在引号中保护调用,从帮助程序类动态加载依赖的枚举定义:

'Applicant.region[countryCode]' : '(new com.mycompany.DataHelper()).getListOfRegions("@{countryCode}")'

如果要从外部数据源(如关系数据库)完全加载所有枚举数据,您可以实施返回 Map<String, List<String>> 映射的 Java 类。映射的键是 fact.field 映射,值为 java.util.List<String&gt; 列表。

例如,以下 Java 类定义了相关枚举的 loan applicant 区域:

public class SampleDataSource {

  public Map<String, List<String>> loadData() {
    Map data = new HashMap();

    List d = new ArrayList();
    d.add("AU");
    d.add("DE");
    d.add("ES");
    d.add("UK");
    d.add("US");
    ...
    data.put("Applicant.region", d);

    return data;
  }

}

以下枚举定义与这个示例 Java 类相关联。Enumeration 不包含对事实或字段名称的引用,因为它们在 Java 类中定义:

=(new SampleDataSource()).loadData()

= 运算符可让 Business Central 从 helper 类加载所有枚举数据。当请求在编辑器中使用枚举定义时,帮助程序方法会被静态评估。

注意

目前 Business Central 不支持在没有事实和字段定义的情况下定义枚举。要以这种方式为关联的 Java 类定义枚举,请在 Red Hat Process Automation Manager 项目中使用 DRL 源。

49.4. 添加其他规则选项

您还可以使用规则设计器在规则中添加元数据,定义额外的规则属性(如 salienceno-loop),以及规则冻结区域来限制对条件或操作的修改。

流程

  1. 在规则设计器中,单击 the shows options…​)( 在 wordpress N 部分下)。
  2. 点击窗口右侧的加号图标 5686 来添加选项。
  3. 选择要添加到规则中的选项:

    • Metadata : 输入元数据标签并点击加号图标( 5686 )。然后,在规则设计程序中提供的字段中输入任何所需的数据。
    • attribute: 从规则属性列表中选择。然后进一步在字段或规则设计器中显示的选项中定义值。
    • 用于编辑的冻结区域: 选择 ConditionsActions 以限制规则设计器中修改的区域。

      图 49.10. 规则选项

      其他规则选项
  4. 在规则设计器中点 Save 来保存您的工作。

49.4.1. 规则属性

规则属性是您可以添加到新规则中的额外规格,以修改规则行为。

下表列出了您可以分配给规则的属性的名称和支持值:

表 49.1. 规则属性

�性值

salience

定义规则优先级的整数。在激活队列中排序时,具有较高 salience 值的规则会被赋予更高的优先级。

示例: salience 10

enabled

布尔值。选择选项时,将启用该规则。如果没有选择该选项,则禁用该规则。

示例: enabled true

date-effective

包含日期和时间定义的字符串。只有在当前日期和时间在日期 有效属性后,才能激活 该规则。

示例: date-effective "4-Sep-2018"

date-expires

包含日期和时间定义的字符串。如果当前日期和时间在 date-expires 属性后面,则无法激活该规则。

示例: date-expires "4-Oct-2018"

no-loop

布尔值。选择选项时,如果规则重新触发之前满足的条件,则无法重新激活(循环)规则。如果没有选择条件,则在以下情况下可以循环该规则。

示例: no-loop true

agenda-group

标识您要为其分配该规则的席位组的字符串。通过电缆组,您可以对员工进行分区,以提供更多对规则组的执行控制。只有购买重点组中的规则才能激活。

示例:M ickice-group "GroupName"

activation-group

标识您要为其分配该规则的激活(或 XOR)组的字符串。在激活组中,只能激活一条规则。触发的第一个规则将取消激活组中所有规则的所有待处理激活。

示例: activation-group "GroupName"

duration

较长的整数值,如果仍然满足规则条件,定义规则可以激活的时间(毫秒)。

示例: 持续时间 10000

timer

标识 int (interval)或用于调度该规则的 cron 计时器定义的字符串。

示例: 计时器(cron:9455114 ? ?) (每 15 分钟)

日历

用于调度规则的 Quartz 日历定义。

示例: calendars " IANA047 0-7,18-23 ?账单" (不包括非工作小时)

auto-focus

布尔值,仅适用于购买组内的规则。选择选项后,下一次规则被激活时,会自动向分配该规则的电缆组提供重点。

示例: auto-focus true

lock-on-active

布尔值,仅适用于规则流组或电缆组内的规则。选择选项后,规则的 ruleflow 组变为 active 或该规则的 sales 组会收到重点,直到 ruleflow 组不再活跃,否则该规则将丢失。这是 no-loop 属性的更强大的版本,因为无论更新的来源(不仅仅是规则本身)都会丢弃匹配的规则激活。此属性适用于计算规则,您可以有多个修改事实的规则,您不希望任何规则重新匹配并再次触发。

示例: lock-on-active true

ruleflow-group

标识规则流组的字符串。在规则流中,规则只能在由关联规则流激活组时触发。

示例: ruleflow-group "GroupName"

dialect

JAVAMVEL 识别为规则中代码表达式的语言。默认情况下,该规则使用在软件包级别指定的 dialect。此处指定的任何 dialect 都会覆盖规则的软件包分开设置。

示例: dialect "JAVA"

注意

当您使用没有可执行模型的 Red Hat Process Automation Manager 时,dialect "JAVA" 规则结果只支持 Java 5 语法。有关可执行模型的更多信息,请参阅 打包和部署 Red Hat Process Automation Manager 项目

第 50 章 执行规则

在 Business Central 中识别示例规则或创建自己的规则后,您可以构建和部署关联的项目,并在 KIE 服务器上执行规则来测试规则。

先决�件

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. 在项目 资产 页面右上角,点 Deploy 以构建项目并将其部署到 KIE Server。如果构建失败,请解决屏幕底部的 Alerts 面板中描述的任何问题。

    有关项目部署选项的更多信息,请参阅 打包和部署 Red Hat Process Automation Manager 项目

    注意

    如果项目中的规则资产默认没有从可执行文件规则模型构建,请验证以下依赖项是否在项目的 pom.xml 文件中,并重建项目:

    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-model-compiler</artifactId>
      <version>${rhpam.version}</version>
    </dependency>

    默认情况下,Red Hat Process Automation Manager 中的规则资产需要此依赖项。此依赖项作为 Red Hat Process Automation Manager 核心打包的一部分包括,但取决于您的 Red Hat Process Automation Manager 升级历史记录,您可能需要手动添加此依赖项来启用可执行的规则模型行为。

    有关可执行规则模型的更多信息,请参阅 打包和部署 Red Hat Process Automation Manager 项目

  3. 在 Business Central 外部创建一个 Maven 或 Java 项目(如果尚未创建),您可以使用它在本地执行规则,或者作为客户端应用程序在 KIE 服务器上执行规则。该项目必须包含 pom.xml 文件和执行项目资源的任何其他必要的组件。

    有关 test 项目示例,请参阅 "创建和执行 DRL 规则的方法 "。

  4. 打开 test 项目或客户端应用程序的 pom.xml 文件,如果还没有添加以下依赖项:

    • kie-ci :使客户端应用程序能够使用 ReleaseId在本地加载 Business Central 项目数据
    • kie-server-client :启用客户端应用程序与 KIE 服务器上的资产远程交互
    • slf4j :(可选)使客户端应用程序能够使用简单日志记录 Facade for Java (SLF4J)在与 KIE 服务器交互后返回调试日志信息

    客户端应用程序 pom.xml 文件中的 Red Hat Process Automation Manager 7.9 的依赖项示例:

    <!-- For local execution -->
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-ci</artifactId>
      <version>7.44.0.Final-redhat-00006</version>
    </dependency>
    
    <!-- For remote execution on KIE Server -->
    <dependency>
      <groupId>org.kie.server</groupId>
      <artifactId>kie-server-client</artifactId>
      <version>7.44.0.Final-redhat-00006</version>
    </dependency>
    
    <!-- For debug logging (optional) -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-simple</artifactId>
      <version>1.7.25</version>
    </dependency>

    如需这些工件的可用版本,请在线搜索 Nexus Repository Manager 中的组 ID 和工件 ID。

    注意

    考虑将 Red Hat Business Automation Manager (BOM)依赖项添加到项目 pom.xml 文件,而不是为单个依赖项指定 Red Hat Process Automation Manager < version >。Red Hat Business Automation BOM 适用于 Red Hat Decision Manager 和 Red Hat Process Automation Manager。当您添加 BOM 文件时,项目中包含了来自提供的 Maven 存储库传输性依赖关系的正确版本。

    BOM 依赖项示例:

    <dependency>
      <groupId>com.redhat.ba</groupId>
      <artifactId>ba-platform-bom</artifactId>
      <version>7.9.1.redhat-00003</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>

    有关 Red Hat Business Automation BOM 的更多信息,请参阅 Red Hat Process Automation Manager 和 Maven 库版本之间的映射是什么?

  5. 确保包含模型类的工件的依赖项在客户端应用程序 pom.xml 文件中定义,因为它们出现在部署的项目的 pom.xml 文件中。如果模型类的依赖项因客户端应用程序和项目而异,则可能会出现执行错误。

    要访问 Business Central 中的项目 pom.xml 文件,请选择项目中的任何现有资产,然后在屏幕左侧的 Project Explorer 菜单中点击 Customize View gear 图标并选择 Repository Viewpom.xml

    例如,以下 Person 类依赖项同时出现在客户端和部署的项目 pom.xml 文件中:

    <dependency>
      <groupId>com.sample</groupId>
      <artifactId>Person</artifactId>
      <version>1.0.0</version>
    </dependency>
  6. 如果您在用于调试日志的客户端应用程序 pom.xml 文件中添加 slf4j 依赖项,请在相关 classpath 上 创建一个简单的logger.properties 文件(例如,在 Maven 中的 src/main/resources/META-INF 中),其中包含以下内容:

    org.slf4j.simpleLogger.defaultLogLevel=debug
  7. 在客户端应用程序中,创建一个包含必要的导入和 main () 方法的 .java 主类,来加载 KIE 基础、插入事实和执行规则。

    例如,项目中的 Person 对象包含 getter 和 setter 方法,用于设置和检索名字、姓氏、每小时率以及个人的 wage。项目中的以下 Wage 规则计算 wage 和每小时速率值,并根据结果显示一条消息:

    package com.sample;
    
    import com.sample.Person;
    
    dialect "java"
    
    rule "Wage"
      when
        Person(hourlyRate * wage > 100)
        Person(name : firstName, surname : lastName)
      then
        System.out.println("Hello" + " " + name + " " + surname + "!");
        System.out.println("You are rich!");
    end

    要在 KIE 服务器之外测试此规则(如果需要),请将 .java 类配置为导入 KIE 服务、KIE 容器和 KIE 会话,然后使用 main () 方法根据定义的事实模型触发所有规则:

    本地执行规则

    import org.kie.api.KieServices;
    import org.kie.api.builder.ReleaseId;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    import org.drools.compiler.kproject.ReleaseIdImpl;
    
    public class RulesTest {
    
      public static final void main(String[] args) {
        try {
          // Identify the project in the local repository:
          ReleaseId rid = new ReleaseIdImpl("com.myspace", "MyProject", "1.0.0");
    
          // Load the KIE base:
          KieServices ks = KieServices.Factory.get();
          KieContainer kContainer = ks.newKieContainer(rid);
          KieSession kSession = kContainer.newKieSession();
    
          // Set up the fact model:
          Person p = new Person();
          p.setWage(12);
          p.setFirstName("Tom");
          p.setLastName("Summers");
          p.setHourlyRate(10);
    
          // Insert the person into the session:
          kSession.insert(p);
    
          // Fire all rules:
          kSession.fireAllRules();
          kSession.dispose();
        }
    
        catch (Throwable t) {
          t.printStackTrace();
        }
      }
    }

    要在 KIE 服务器上测试此规则,请使用导入和规则执行信息配置 .java 类,以及指定 KIE 服务配置和 KIE 服务客户端详情:

    在 KIE 服务器上执行规则

    package com.sample;
    
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    import org.kie.api.command.BatchExecutionCommand;
    import org.kie.api.command.Command;
    import org.kie.api.KieServices;
    import org.kie.api.runtime.ExecutionResults;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    import org.kie.server.api.marshalling.MarshallingFormat;
    import org.kie.server.api.model.ServiceResponse;
    import org.kie.server.client.KieServicesClient;
    import org.kie.server.client.KieServicesConfiguration;
    import org.kie.server.client.KieServicesFactory;
    import org.kie.server.client.RuleServicesClient;
    
    import com.sample.Person;
    
    public class RulesTest {
    
      private static final String containerName = "testProject";
      private static final String sessionName = "myStatelessSession";
    
      public static final void main(String[] args) {
        try {
          // Define KIE services configuration and client:
          Set<Class<?>> allClasses = new HashSet<Class<?>>();
          allClasses.add(Person.class);
          String serverUrl = "http://$HOST:$PORT/kie-server/services/rest/server";
          String username = "$USERNAME";
          String password = "$PASSWORD";
          KieServicesConfiguration config =
            KieServicesFactory.newRestConfiguration(serverUrl,
                                                    username,
                                                    password);
          config.setMarshallingFormat(MarshallingFormat.JAXB);
          config.addExtraClasses(allClasses);
          KieServicesClient kieServicesClient =
            KieServicesFactory.newKieServicesClient(config);
    
          // Set up the fact model:
          Person p = new Person();
          p.setWage(12);
          p.setFirstName("Tom");
          p.setLastName("Summers");
          p.setHourlyRate(10);
    
          // Insert Person into the session:
          KieCommands kieCommands = KieServices.Factory.get().getCommands();
          List<Command> commandList = new ArrayList<Command>();
          commandList.add(kieCommands.newInsert(p, "personReturnId"));
    
          // Fire all rules:
          commandList.add(kieCommands.newFireAllRules("numberOfFiredRules"));
          BatchExecutionCommand batch = kieCommands.newBatchExecution(commandList, sessionName);
    
          // Use rule services client to send request:
          RuleServicesClient ruleClient = kieServicesClient.getServicesClient(RuleServicesClient.class);
          ServiceResponse<ExecutionResults> executeResponse = ruleClient.executeCommandsWithResults(containerName, batch);
          System.out.println("number of fired rules:" + executeResponse.getResult().getValue("numberOfFiredRules"));
        }
    
        catch (Throwable t) {
          t.printStackTrace();
        }
      }
    }

  8. 从项目目录运行配置的 .java 类。您可以在开发平台(如 Red Hat CodeReady Studio)或命令行中运行该文件。

    Maven 执行示例(带有项目目录):

    mvn clean install exec:java -Dexec.mainClass="com.sample.app.RulesTest"

    Java 执行示例(使用项目目录)

    javac -classpath "./$DEPENDENCIES/*:." RulesTest.java
    java -classpath "./$DEPENDENCIES/*:." RulesTest
  9. 在命令行和服务器日志中查看规则执行状态。如果有任何规则没有如预期执行,请查看项目中配置的规则和主类配置以验证所提供的数据。

第 51 章 å��续步骤

部分 VII. 使用指导规则模板设计决策服务

作为商业公司或业务规则开发人员,您可以使用 Business Central 中的指导规则模板来定义新规则模板。这些指导规则模板为编译到 dols 规则语言(DRL)的多个规则提供可重复使用的规则结构,并为项目形成决策服务的核心。

注意

您还可以使用决策模型和表示法(DMN)模型而不是基于规则的或基于表的资产来设计您的决策服务。有关 Red Hat Process Automation Manager 7.9 中的 DMN 支持的详情,请查看以下资源:

先决�件

  • 在 Business Central 中创建了指导规则模板的空间和项目。每个资产都与分配给空间的项目关联。详情请参阅 开始使用决策服务。

第 52 章 Red Hat Process Automation Manager 中的决策授权资产

Red Hat Process Automation Manager 支持多个资产,可用于为您的决策服务定义决策。每个决定授权资产都有不同的优点,您可能需要根据您的目标和需求使用多个资产的组合。

下表重点介绍 Red Hat Process Automation Manager 项目支持的主要决策授权资产,以帮助您决定或确认在决策服务中定义决策的最佳方法。

表 52.1. Red Hat Process Automation Manager 支持的决策授予资产

assethighlight编写工具Documentation

决策模型和表示法(DMN)模型

  • 是根据对象管理组(OMG)定义的表示法标准决定模型。
  • 使用代表部分或所有决策要求图(DRG)的图形决策要求图(DRG)来跟踪业务决策流程
  • 使用允许在 DMN 兼容平台之间共享 DMN 模型的 XML 模式
  • 支持 Friendly Enough Expression Language (FEEL),以在 DMN 决策表和其他 DMN 框表达式中定义决策逻辑
  • 可以与 Business Process Model 和 Notation (DSLN)进程模型有效集成
  • 是创建全面、演示和稳定的决策流程的最佳选择

Business Central 或其他与 DMN 兼容的编辑器

使用 DMN 模型设计决策服务

主要决策表

  • 是您在 Business Central 的基于 UI 的表设计程序中创建的规则表
  • 是电子表格决策表的向导替代方法
  • 为可接受的输入提供字段和选项
  • 支持用于创建规则模板的模板键和值
  • 支持点击策略、实时验证以及其他资产不支持的其他额外功能
  • 最好以受控的 tabular 格式创建规则,以最小化编译错误

Business Central

使用指导决策表设计决策服务

电子表格决策表

  • 是 XLS 或 XLSX 电子表格决策表,您可以上传到 Business Central
  • 支持用于创建规则模板的模板键和值
  • 最好在 Business Central 外部管理的路由表中创建规则
  • 对于在上传时正确编译的规则具有严格的语法要求

电子表格编辑器

使用电子表格决策表设计决策服务

指导规则

  • 是您在 Business Central 中基于 UI 的规则设计程序中创建的单个规则
  • 为可接受的输入提供字段和选项
  • 最好以受控格式创建单个规则,以最小化编译错误

Business Central

使用指导规则设计决策服务

指导规则模板

  • 是您在 Business Central 中的基于 UI 的模板设计程序中创建的可重复使用的规则结构
  • 为可接受的输入提供字段和选项
  • 支持用于创建规则模板的模板键和值(与资产相关的目的不同)
  • 最好创建具有相同规则结构但具有不同定义的字段值的规则

Business Central

使用指导规则模板设计决策服务

DRL 规则

  • 是直接在 .drl 文本文件中定义的单个规则
  • 提供定义规则和其他规则行为的最灵活
  • 可以在某些独立环境中创建,并与 Red Hat Process Automation Manager 集成
  • 最好创建需要高级 DRL 选项的规则
  • 具有正确编译的规则具有严格的语法要求

Business Central 或集成开发环境(IDE)

使用 DRL 规则设计决策服务

预测模型标记语言(PMML)模型

  • 是预测的 data-analytic 模型,它基于由 Data Mining Group (DMG)定义的表示法标准
  • 使用一个 XML 模式,允许在 PMML 兼容平台之间共享 PMML 模型
  • 支持 Regression、Scorecard、Tree、Ming 和其他模型类型
  • 可以包含独立 Red Hat Process Automation Manager 项目,也可以导入到 Business Central 中的项目中
  • 最好在 Red Hat Process Automation Manager 中将预测数据整合到决策服务中

pmML 或 XML 编辑器

使用 PMML 模型设计决策服务

第 53 章 指导规则模板

指导规则模板是带有占位符值(模板键)的规则结构,它们与单独的数据表中定义的实际值进行交换。该模板的对应数据表中定义的每行值都会生成规则。当许多规则具有相同的条件、操作和其他属性,但事实或约束的值有所不同时,最后的规则模板是理想的选择。在这种情况下,您可以在每个规则中创建许多类似的指导规则和定义值,您可以创建一个适用于每个规则的规则结构,然后在 data 表中定义不同值。

指导规则模板设计器根据所定义的规则模板的数据对象以及添加模板键值的对应数据表,为可接受的模板输入提供字段和选项。创建指导规则模板并在对应的数据表中添加值后,您定义的规则会编译成无需规则语言(DRL)规则,与所有其他规则资产相同。

与指导规则模板相关的所有数据对象都必须与指导规则模板位于同一个项目中。默认情况下导入同一软件包中的资产。创建必要的数据对象和指导规则模板后,您可以使用指导规则模板设计器的 Data Objects 选项卡来验证所有必需的数据对象是否已列出,或通过添加新 项目 来导入其他现有数据对象。

第 54 章 数据对象

数据对象是您创建的规则资产的构建块。数据对象是在项目的指定软件包中作为 Java 对象实现的自定义数据类型。例如,您可以创建一个带有数据字段 Name, Address, 和 DateOfBirthPerson 对象,以指定 loan 应用程序规则的个人详情。这些自定义数据类型决定了您的资产和您决定服务所基于的数据。

54.1. 创建数据对象

以下流程是创建数据对象的通用概述。它不特定于特定的业务资产。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetData Object
  3. 输入唯一 数据对象 名称并选择 您希望 数据对象可用于其他规则资产的软件包。同一软件包中不能存在具有相同名称的数据对象。在指定的 DRL 文件中,您可以从任何软件包导入数据对象。

    从其他软件包导入数据对象

    您可以直接将现有数据对象从另一个软件包导入到资产设计人员,如指导规则或指导决策表设计器。选择项目中的相关规则资产和资产设计器,转至 Data Objects → New 项 以选择要导入的对象。

  4. 要使数据对象持久,请选择 Persistable 复选框。Persistable 数据对象可以根据 JPA 规范存储在数据库中。默认 JPA 是 Hibernate。
  5. 点 确定。
  6. 在数据对象设计器中,单击 add 字段,将字段添加到带有属性 Id,Label, 和 Type 的对象。所需属性被标记为星号。

    • id : 输入字段的唯一 ID。
    • label : (可选)输入字段的标签
    • type : 输入字段的数据类型。
    • 列表: (可选)选择此复选框来启用该字段为指定类型保存多个项目。

      图 54.1. 在数据对象中添加数据字段

      在数据对象中添加数据字段
  7. Create 添加新字段,或者点 Create 并继续 添加新字段,并继续添加新字段。

    注意

    要编辑字段,请选择字段行,并使用屏幕右侧的 常规属性

第 55 章 创建指导规则模板

您可以使用指导规则模板来定义规则结构,其中包含与数据表中定义的实际值对应的占位符值(模板键)。指导规则模板是单独定义使用相同结构的多种指导规则集的有效替代方案。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetDatacenter Rule Template
  3. 输入 说明性规则模板名称 并选择相应的 软件包。您指定的软件包必须是分配所需数据对象或将被分配的软件包。
  4. 单击 Ok 以创建规则模板。

    新的指导规则模板现在列在 Project Explorer 的关键规则 面板中。

  5. Data Objects 选项卡,并确认您的规则所需的所有数据对象都已列出。如果没有,点 New item 从其他软件包导入数据对象,或者在软件包中 创建数据对象
  6. 所有数据对象都就位后,返回到 Model 选项卡,并使用窗口右侧的按钮来添加和定义规则模板的 WHEN (condition)和 theN (action)部分,基于可用的数据对象。对于每个规则的不同字段值,以规则设计器或 @{key} 格式使用 $key 格式的模板密钥,使用自由格式 DRL (如果使用)。

    图 55.1. 指导规则模板示例

    指导规则模板示例
    关于模板键的备注

    模板键是指导规则模板的基本信息。模板键是将模板中启用字段值与您在对应数据表中定义的实际值进行交换,以从同一模板生成不同的规则。对于属于基于该模板的所有规则的规则结构的一部分,您可以使用其他值类型,如 LiteralFormula。但是,对于规则之间差异的任何值,请使用带有指定键的 Template key 字段类型。在指导规则模板中没有模板密钥,则模板设计程序中不会生成对应的数据表,模板基本上作为单独的指导规则的功能。

    规则模板的 WHEN 部分是执行操作必须满足的条件。例如,如果电信公司根据他们订阅服务的服务(互联网、电话和 TV)收取客户,那么其中一个 WHEN 条件将是 InternetService | 等于 | $hasInternetService。模板键 $hasInternetService 与模板的数据表中定义的实际布尔值(truefalse)进行交换。

    规则模板的 wordpressN 部分是满足规则条件部分时要执行的操作。例如,如果客户只订阅互联网服务,则删除模板键 $amountRecurring N 操作会将实际每月数量设置为数据表中为互联网服务收费定义的整数值。

  7. 在定义了规则的所有组件后,点指导规则模板设计器中的 Save 来保存您的更改。

55.1. 在指导规则模板中添加 WHEN 条件

规则的 WHEN 部分包含执行操作必须满足的条件。例如,如果电信公司根据他们订阅服务的服务(互联网、电话和 TV)收取客户,那么其中一个 WHEN 条件将是 InternetService | 等于 | $hasInternetService。模板键 $hasInternetService 与模板的数据表中定义的实际布尔值(truefalse)进行交换。

先决�件

  • 您的规则所需的所有数据对象已创建或导入,并在指导规则模板设计器的 Data Objects 选项卡中列出。

流程

  1. 在指导规则模板设计器中,点击 WHEN 部分右侧的加号图标 5686

    此时会打开可用 condition 元素的规则窗口中添加一个条件

    图 55.2. 在规则中添加条件

    在规则中添加条件

    该列表包括指导规则模板设计器的 Data Objects 选项卡中的数据对象、为软件包定义的任何 DSL 对象以及以下标准选项:

    • 以下不存在:使用它来指定不能存在 的事实和约束。
    • 存在: 使用它来指定必须存在的事实和约束。这个选项仅针对第一个匹配项触发,而不在以后的匹配项上触发。
    • 以下任何一个是 true : 使用它来列出所有必须为 true 的事实或约束。
    • from : 使用它来为 规则定义 From condition 元素。
    • 从 Accumulate : 使用它来为规则定义 Accumulate 条件元素。
    • from Collect : 使用它来为规则定义 Collect 条件元素。
    • from Entry Point 使用它来为模式定义条目点。
    • free form DRL :使用它来插入自由格式 的 DRL 字段,您可以在其中自由定义条件元素,而无需指导规则设计器。对于自由形式的模板密钥,请使用 @{key} 格式。
  2. 选择一个 condition 元素(如 Customer)并单击 Ok
  3. 点指导规则模板设计器中的 condition 元素,为客户窗口使用修改 限制来对字段添加限制、应用多个字段约束、添加新的公式风格表达式、应用表达式编辑器或设置变量名称。

    图 55.3. 修改条件

    修改条件
    注意

    变量名称允许您识别指导规则中的其他结构的事实或字段。例如,您可以将 customer 变量设置为 c,然后在单独的 Applicant 约束中引用 c,指定 客户Applicant

    c : Customer()
    Applicant( this == c )

    选择约束后,窗口会自动关闭。

  4. 从添加的限制旁的下拉菜单中选择限制(例如,等于)的运算符。
  5. 点编辑图标( 6191 )定义字段值。
  6. 如果这个值因基于此模板的规则而异,请选择 Template key 并在 $key 格式添加模板密钥。这允许将字段值与您在对应数据表中定义的实际值进行交换,以从同一模板生成不同的规则。对于不是规则的一部分且是规则模板的一部分的字段值,您可以使用任何其他值类型。
  7. 要应用多个字段限制,点条件并在 customer 窗口中的 Modify 约束,从 Multiple field constraint 下拉菜单中选择 All of (And)Any of (Or)

    图 55.4. 添加多个字段约束

    添加多个字段约束
  8. 点指导规则模板设计器中的约束,并进一步定义字段值。
  9. 在定义了所有条件元素后,点指导规则模板设计器中的 Save 来保存您的工作。

55.2. 在指导规则模板中添加 THEN 操作

规则模板的 wordpressN 部分是满足规则条件部分时要执行的操作。例如,如果客户只订阅互联网服务,则删除模板键 $amountRecurring N 操作会将实际每月数量设置为数据表中为互联网服务收费定义的整数值。

先决�件

  • 您的规则所需的所有数据对象已创建或导入,并在指导规则模板设计器的 Data Objects 选项卡中列出。

流程

  1. 在指导规则模板设计器中,点击 the the rightN 部分右侧的加号图标( 5686 )。

    此时会打开 Add a new action 窗口,并打开了可用 action 元素。

    图 55.5. 向规则添加新操作

    向规则添加新操作

    该列表包括基于指导规则模板设计器的 Data Objects 选项卡中的数据对象的插入和修改选项,以及为该软件包定义的任何 DSL 对象:

    • 插入事实 : 使用它来插入事实,并为事实定义生成的字段和值。
    • 逻辑语言事实: 使用它来以逻辑方式将事实插入到决策引擎中,并为事实定义生成的字段和值。决策引擎负责对事实的插入和重包进行逻辑决策。常规或声明的插入后,必须明确重新遍历事实。逻辑插入后,当最初成为事实的条件不再满足时,会自动重新传输事实。
    • 添加免费形式 DRL : 使用它来插入自由格式的 DRL 字段,您可以在其中自由定义条件元素,而无需指导规则设计器。对于自由形式的模板密钥,请使用 @{key} 格式。
  2. 选择 action 元素(例如,Logically Insert RecurringPayment),然后单击 Ok
  3. 点指导规则模板设计器中的 action 元素,并使用 Add a field 窗口来选择字段。

    图 55.6. 添加字段

    添加字段

    选择一个字段后,窗口会自动关闭。

  4. 点编辑图标( 6191 )定义字段值。
  5. 如果这个值因基于此模板的规则而异,请选择 Template key 并在 $key 格式添加模板密钥。这允许将字段值与您在对应数据表中定义的实际值进行交换,以从同一模板生成不同的规则。对于不是规则的一部分且是规则模板的一部分的字段值,您可以使用任何其他值类型。
  6. 在定义了所有操作元素后,点指导规则模板设计器中的 Save 来保存您的工作。

55.3. 在规则资产中为下拉列表定义枚举

Business Central 中的枚举定义决定了指导规则、指导规则模板和指导决策表中的条件或操作的可能值。Enumeration 定义包含一个 fact.field 映射到支持的值列表,这些值在规则资产的相关字段中显示为下拉列表。当用户选择基于与枚举定义相同的事实和字段时,会显示定义值的下拉列表。

您可以在 Business Central 或 Red Hat Process Automation Manager 项目的 DRL 源中定义枚举。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetEnumeration
  3. 输入说明性 枚举 名称并选择适当的 软件包。您指定的软件包必须是分配所需数据对象和相关规则资产的同一软件包。
  4. Ok 创建枚举。

    新的枚举现在列在 Project ExplorerEnumeration Definitions 面板中。

  5. 在枚举设计器的 Model 选项卡中,点 Add enum 并为枚举定义以下值:

    • 事实 :在您要将此枚举的项目的同一软件包中指定现有数据对象。打开 Project Explorer 中的 Data Objects 面板,以查看可用的数据对象,或者根据需要将相关数据对象创建为新资产。
    • 字段 :指定您定义为您为 事实 选择的数据对象一部分的现有字段标识符。打开 Project Explorer 中的 Data Objects 面板,以选择相关数据对象并查看可用 标识符选项列表。如果需要,您可以为数据对象创建相关标识符。
    • Context: 指定您要映射到 FactField 定义的格式 ['string1','string2','string3'][integer1,integer2,integer3] 的值列表。这些值将显示为规则资产相关字段的下拉列表。

    例如,以下枚举在 loan 应用程序决策服务中定义 applicant 信信评级的下拉值:

    图 55.7. Business Central 中应用程序信信评级的枚举示例

    EnumConfig

    DRL 源中适用信信评级的枚举示例

    'Applicant.creditRating' : ['AA', 'OK', 'Sub prime']

    在本例中,对于任何在项目相同的软件包中的指导规则、指导规则模板或指导的决策表,其使用 Applicant 数据对象和 creditRating 字段,配置的值可作为下拉列表选项提供:

    图 55.8. 指导规则或指导规则模板中枚举的下拉列表选项示例

    EnumDropDown

    图 55.9. 指导决策表中的 enumeration 下拉菜单选项示例

    EnumDropDownGDT

55.3.1. 规则资产的高级枚举选项

对于 Red Hat Process Automation Manager 项目中带有枚举定义的高级用例,请考虑以下扩展选项来定义枚举:

Business Central 中的 DRL 值和值之间的映射

如果您希望枚举值在 Business Central 界面中显示不同或更完全出现在 DRL 源中,请使用格式 'fact.field' : ['sourceValue1=UIValue1','sourceValue2=UIValue2', …​ ] 作为您的枚举定义值。

例如,在以下 loan 状态的枚举定义中,DRL 文件中使用了选项 AD,但 Business Central 中会显示 ApprovedDeclined 选项:

'Loan.status' : ['A=Approved','D=Declined']
Enumeration 值依赖项

如果您希望一个下拉列表中选择的值来确定后续下拉列表中的可用选项,请使用 'fact.fieldB[fieldA=value1]' : ['value2', 'value3', …​ ] 进行您的枚举定义。

例如,在以下代表策略的 enumeration 定义中,policyType 字段接受 Home 或 the 值。用户选择的策略类型决定了可用的策略 范围 字段选项:

'Insurance.policyType' : ['Home', 'Car']
'Insurance.coverage[policyType=Home]' : ['property', 'liability']
'Insurance.coverage[policyType=Car]' : ['collision', 'fullCoverage']
注意

在规则条件和操作中不会应用枚举的依赖关系。例如,在这种情况下,规则条件中选择的策略不会决定规则操作中的可用覆盖范围选项(如果适用)。

枚举中的外部数据源

如果要从外部数据源检索枚举值列表,而不是直接在枚举定义中定义值,在项目的类路径上,添加一个帮助程序类,它返回一个返回字符串的 java.util.List 列表的帮助类。在枚举定义中,而不是指定值列表,而是指定您配置为外部检索值的帮助类。

例如,在 Lan applicant 区域的以下枚举定义中,而不是以 'Applicant.region' : ['country1', 'country2', …​ ] 格式明确定义 applicant 区域:

'Applicant.region' : (new com.mycompany.DataHelper()).getListOfRegions()

在本例中,DataHelper 类包含一个 getListOfRegions () 方法,该方法返回字符串列表。枚举会在规则资产中相关字段的下拉列表中加载。

您还可以以常常方式识别依赖字段并在引号中保护调用,从帮助程序类动态加载依赖的枚举定义:

'Applicant.region[countryCode]' : '(new com.mycompany.DataHelper()).getListOfRegions("@{countryCode}")'

如果要从外部数据源(如关系数据库)完全加载所有枚举数据,您可以实施返回 Map<String, List<String>> 映射的 Java 类。映射的键是 fact.field 映射,值为 java.util.List<String&gt; 列表。

例如,以下 Java 类定义了相关枚举的 loan applicant 区域:

public class SampleDataSource {

  public Map<String, List<String>> loadData() {
    Map data = new HashMap();

    List d = new ArrayList();
    d.add("AU");
    d.add("DE");
    d.add("ES");
    d.add("UK");
    d.add("US");
    ...
    data.put("Applicant.region", d);

    return data;
  }

}

以下枚举定义与这个示例 Java 类相关联。Enumeration 不包含对事实或字段名称的引用,因为它们在 Java 类中定义:

=(new SampleDataSource()).loadData()

= 运算符可让 Business Central 从 helper 类加载所有枚举数据。当请求在编辑器中使用枚举定义时,帮助程序方法会被静态评估。

注意

目前 Business Central 不支持在没有事实和字段定义的情况下定义枚举。要以这种方式为关联的 Java 类定义枚举,请在 Red Hat Process Automation Manager 项目中使用 DRL 源。

55.4. 添加其他规则选项

您还可以使用规则设计器在规则中添加元数据,定义额外的规则属性(如 salienceno-loop),以及规则冻结区域来限制对条件或操作的修改。

流程

  1. 在规则设计器中,单击 the shows options…​)( 在 wordpress N 部分下)。
  2. 点击窗口右侧的加号图标 5686 来添加选项。
  3. 选择要添加到规则中的选项:

    • Metadata : 输入元数据标签并点击加号图标( 5686 )。然后,在规则设计程序中提供的字段中输入任何所需的数据。
    • attribute: 从规则属性列表中选择。然后进一步在字段或规则设计器中显示的选项中定义值。
    • 用于编辑的冻结区域: 选择 ConditionsActions 以限制规则设计器中修改的区域。

      图 55.10. 规则选项

      其他规则选项
  4. 在规则设计器中点 Save 来保存您的工作。

55.4.1. 规则属性

规则属性是您可以添加到新规则中的额外规格,以修改规则行为。

下表列出了您可以分配给规则的属性的名称和支持值:

表 55.1. 规则属性

�性值

salience

定义规则优先级的整数。在激活队列中排序时,具有较高 salience 值的规则会被赋予更高的优先级。

示例: salience 10

enabled

布尔值。选择选项时,将启用该规则。如果没有选择该选项,则禁用该规则。

示例: enabled true

date-effective

包含日期和时间定义的字符串。只有在当前日期和时间在日期 有效属性后,才能激活 该规则。

示例: date-effective "4-Sep-2018"

date-expires

包含日期和时间定义的字符串。如果当前日期和时间在 date-expires 属性后面,则无法激活该规则。

示例: date-expires "4-Oct-2018"

no-loop

布尔值。选择选项时,如果规则重新触发之前满足的条件,则无法重新激活(循环)规则。如果没有选择条件,则在以下情况下可以循环该规则。

示例: no-loop true

agenda-group

标识您要为其分配该规则的席位组的字符串。通过电缆组,您可以对员工进行分区,以提供更多对规则组的执行控制。只有购买重点组中的规则才能激活。

示例:M ickice-group "GroupName"

activation-group

标识您要为其分配该规则的激活(或 XOR)组的字符串。在激活组中,只能激活一条规则。触发的第一个规则将取消激活组中所有规则的所有待处理激活。

示例: activation-group "GroupName"

duration

较长的整数值,如果仍然满足规则条件,定义规则可以激活的时间(毫秒)。

示例: 持续时间 10000

timer

标识 int (interval)或用于调度该规则的 cron 计时器定义的字符串。

示例: 计时器(cron:9455114 ? ?) (每 15 分钟)

日历

用于调度规则的 Quartz 日历定义。

示例: calendars " IANA047 0-7,18-23 ?账单" (不包括非工作小时)

auto-focus

布尔值,仅适用于购买组内的规则。选择选项后,下一次规则被激活时,会自动向分配该规则的电缆组提供重点。

示例: auto-focus true

lock-on-active

布尔值,仅适用于规则流组或电缆组内的规则。选择选项后,规则的 ruleflow 组变为 active 或该规则的 sales 组会收到重点,直到 ruleflow 组不再活跃,否则该规则将丢失。这是 no-loop 属性的更强大的版本,因为无论更新的来源(不仅仅是规则本身)都会丢弃匹配的规则激活。此属性适用于计算规则,您可以有多个修改事实的规则,您不希望任何规则重新匹配并再次触发。

示例: lock-on-active true

ruleflow-group

标识规则流组的字符串。在规则流中,规则只能在由关联规则流激活组时触发。

示例: ruleflow-group "GroupName"

dialect

JAVAMVEL 识别为规则中代码表达式的语言。默认情况下,该规则使用在软件包级别指定的 dialect。此处指定的任何 dialect 都会覆盖规则的软件包分开设置。

示例: dialect "JAVA"

注意

当您使用没有可执行模型的 Red Hat Process Automation Manager 时,dialect "JAVA" 规则结果只支持 Java 5 语法。有关可执行模型的更多信息,请参阅 打包和部署 Red Hat Process Automation Manager 项目

第 56 章 为指导规则模板定义数据表

创建指导规则模板并为字段值添加模板密钥后,会在指导规则模板设计器的 Data 表中显示数据表。data 表中的每一列都对应于您在指导规则模板中添加的模板键。使用此表按行为每个模板键行定义值。您在该模板的数据表中定义的每行值都会生成规则。

�程

  1. 在指导规则模板设计器中,点 Data 选项卡查看数据表。data 表中的每一列都对应于您在指导规则模板中添加的模板键。

    注意

    如果您没有在规则模板中添加任何模板密钥,则不会显示此数据表,模板不能充当 genuine 模板,但基本上是单独的指导规则。因此,模板密钥在创建指导规则模板中非常重要。

  2. Add 行,并为每个模板键列定义 data 值来生成该规则(箭头)。
  3. 继续添加行并为将生成的每个规则定义 data 值。您可以点每个新 行的 Add 行,或者点击加号图标 5686 或减号图标来添加或删除行。

    图 56.1. 指导规则模板的数据表示例

    指导规则模板的数据表示例

    要查看 DRL 代码,请单击指导规则模板设计器中的 Source 选项卡。

    例如:

    rule "PaymentRules_6"
    	when
    		Customer( internetService == false ,
    			phoneService == false ,
    			TVService == true )
    	then
    		RecurringPayment fact0 = new RecurringPayment();
    		fact0.setAmount( 5 );
    		insertLogical( fact0 );
    end
    
    rule "PaymentRules_5"
    	when
    		Customer( internetService == false ,
    			phoneService == true ,
    			TVService == false )
    	then
    		RecurringPayment fact0 = new RecurringPayment();
    		fact0.setAmount( 5 );
    		insertLogical( fact0 );
    end
    ...
    //Other rules omitted for brevity.
  4. 作为视觉帮助,单击数据表左上角的网格图标,以便根据需要切换和关闭单元合并。同一列中的单元格合并到一个单元中。

    图 56.2. 数据表中的合并单元

    数据表中的合并单元

    然后,您可以使用每个新合并的单元左上角的展开/折叠图标 [+/-] 来折叠与合并的单元对应的行,或者重新检查折叠行。

    图 56.3. 折叠合并的单元

    折叠合并的单元
  5. 为所有规则定义模板密钥数据并根据需要调整表显示后,单击指导规则模板右上角的 Validate 以验证指导规则模板。如果规则模板验证失败,请解决错误消息中描述的任何问题,检查数据表中定义的所有组件和数据,然后重试验证规则模板直到规则模板通过为止。
  6. 在指导规则模板设计器中点 Save 来保存您的更改。

第 57 章 执行规则

在 Business Central 中识别示例规则或创建自己的规则后,您可以构建和部署关联的项目,并在 KIE 服务器上执行规则来测试规则。

先决�件

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. 在项目 资产 页面右上角,点 Deploy 以构建项目并将其部署到 KIE Server。如果构建失败,请解决屏幕底部的 Alerts 面板中描述的任何问题。

    有关项目部署选项的更多信息,请参阅 打包和部署 Red Hat Process Automation Manager 项目

    注意

    如果项目中的规则资产默认没有从可执行文件规则模型构建,请验证以下依赖项是否在项目的 pom.xml 文件中,并重建项目:

    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-model-compiler</artifactId>
      <version>${rhpam.version}</version>
    </dependency>

    默认情况下,Red Hat Process Automation Manager 中的规则资产需要此依赖项。此依赖项作为 Red Hat Process Automation Manager 核心打包的一部分包括,但取决于您的 Red Hat Process Automation Manager 升级历史记录,您可能需要手动添加此依赖项来启用可执行的规则模型行为。

    有关可执行规则模型的更多信息,请参阅 打包和部署 Red Hat Process Automation Manager 项目

  3. 在 Business Central 外部创建一个 Maven 或 Java 项目(如果尚未创建),您可以使用它在本地执行规则,或者作为客户端应用程序在 KIE 服务器上执行规则。该项目必须包含 pom.xml 文件和执行项目资源的任何其他必要的组件。

    有关 test 项目示例,请参阅 "创建和执行 DRL 规则的方法 "。

  4. 打开 test 项目或客户端应用程序的 pom.xml 文件,如果还没有添加以下依赖项:

    • kie-ci :使客户端应用程序能够使用 ReleaseId在本地加载 Business Central 项目数据
    • kie-server-client :启用客户端应用程序与 KIE 服务器上的资产远程交互
    • slf4j :(可选)使客户端应用程序能够使用简单日志记录 Facade for Java (SLF4J)在与 KIE 服务器交互后返回调试日志信息

    客户端应用程序 pom.xml 文件中的 Red Hat Process Automation Manager 7.9 的依赖项示例:

    <!-- For local execution -->
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-ci</artifactId>
      <version>7.44.0.Final-redhat-00006</version>
    </dependency>
    
    <!-- For remote execution on KIE Server -->
    <dependency>
      <groupId>org.kie.server</groupId>
      <artifactId>kie-server-client</artifactId>
      <version>7.44.0.Final-redhat-00006</version>
    </dependency>
    
    <!-- For debug logging (optional) -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-simple</artifactId>
      <version>1.7.25</version>
    </dependency>

    如需这些工件的可用版本,请在线搜索 Nexus Repository Manager 中的组 ID 和工件 ID。

    注意

    考虑将 Red Hat Business Automation Manager (BOM)依赖项添加到项目 pom.xml 文件,而不是为单个依赖项指定 Red Hat Process Automation Manager < version >。Red Hat Business Automation BOM 适用于 Red Hat Decision Manager 和 Red Hat Process Automation Manager。当您添加 BOM 文件时,项目中包含了来自提供的 Maven 存储库传输性依赖关系的正确版本。

    BOM 依赖项示例:

    <dependency>
      <groupId>com.redhat.ba</groupId>
      <artifactId>ba-platform-bom</artifactId>
      <version>7.9.1.redhat-00003</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>

    有关 Red Hat Business Automation BOM 的更多信息,请参阅 Red Hat Process Automation Manager 和 Maven 库版本之间的映射是什么?

  5. 确保包含模型类的工件的依赖项在客户端应用程序 pom.xml 文件中定义,因为它们出现在部署的项目的 pom.xml 文件中。如果模型类的依赖项因客户端应用程序和项目而异,则可能会出现执行错误。

    要访问 Business Central 中的项目 pom.xml 文件,请选择项目中的任何现有资产,然后在屏幕左侧的 Project Explorer 菜单中点击 Customize View gear 图标并选择 Repository Viewpom.xml

    例如,以下 Person 类依赖项同时出现在客户端和部署的项目 pom.xml 文件中:

    <dependency>
      <groupId>com.sample</groupId>
      <artifactId>Person</artifactId>
      <version>1.0.0</version>
    </dependency>
  6. 如果您在用于调试日志的客户端应用程序 pom.xml 文件中添加 slf4j 依赖项,请在相关 classpath 上 创建一个简单的logger.properties 文件(例如,在 Maven 中的 src/main/resources/META-INF 中),其中包含以下内容:

    org.slf4j.simpleLogger.defaultLogLevel=debug
  7. 在客户端应用程序中,创建一个包含必要的导入和 main () 方法的 .java 主类,来加载 KIE 基础、插入事实和执行规则。

    例如,项目中的 Person 对象包含 getter 和 setter 方法,用于设置和检索名字、姓氏、每小时率以及个人的 wage。项目中的以下 Wage 规则计算 wage 和每小时速率值,并根据结果显示一条消息:

    package com.sample;
    
    import com.sample.Person;
    
    dialect "java"
    
    rule "Wage"
      when
        Person(hourlyRate * wage > 100)
        Person(name : firstName, surname : lastName)
      then
        System.out.println("Hello" + " " + name + " " + surname + "!");
        System.out.println("You are rich!");
    end

    要在 KIE 服务器之外测试此规则(如果需要),请将 .java 类配置为导入 KIE 服务、KIE 容器和 KIE 会话,然后使用 main () 方法根据定义的事实模型触发所有规则:

    本地执行规则

    import org.kie.api.KieServices;
    import org.kie.api.builder.ReleaseId;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    import org.drools.compiler.kproject.ReleaseIdImpl;
    
    public class RulesTest {
    
      public static final void main(String[] args) {
        try {
          // Identify the project in the local repository:
          ReleaseId rid = new ReleaseIdImpl("com.myspace", "MyProject", "1.0.0");
    
          // Load the KIE base:
          KieServices ks = KieServices.Factory.get();
          KieContainer kContainer = ks.newKieContainer(rid);
          KieSession kSession = kContainer.newKieSession();
    
          // Set up the fact model:
          Person p = new Person();
          p.setWage(12);
          p.setFirstName("Tom");
          p.setLastName("Summers");
          p.setHourlyRate(10);
    
          // Insert the person into the session:
          kSession.insert(p);
    
          // Fire all rules:
          kSession.fireAllRules();
          kSession.dispose();
        }
    
        catch (Throwable t) {
          t.printStackTrace();
        }
      }
    }

    要在 KIE 服务器上测试此规则,请使用导入和规则执行信息配置 .java 类,以及指定 KIE 服务配置和 KIE 服务客户端详情:

    在 KIE 服务器上执行规则

    package com.sample;
    
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    import org.kie.api.command.BatchExecutionCommand;
    import org.kie.api.command.Command;
    import org.kie.api.KieServices;
    import org.kie.api.runtime.ExecutionResults;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    import org.kie.server.api.marshalling.MarshallingFormat;
    import org.kie.server.api.model.ServiceResponse;
    import org.kie.server.client.KieServicesClient;
    import org.kie.server.client.KieServicesConfiguration;
    import org.kie.server.client.KieServicesFactory;
    import org.kie.server.client.RuleServicesClient;
    
    import com.sample.Person;
    
    public class RulesTest {
    
      private static final String containerName = "testProject";
      private static final String sessionName = "myStatelessSession";
    
      public static final void main(String[] args) {
        try {
          // Define KIE services configuration and client:
          Set<Class<?>> allClasses = new HashSet<Class<?>>();
          allClasses.add(Person.class);
          String serverUrl = "http://$HOST:$PORT/kie-server/services/rest/server";
          String username = "$USERNAME";
          String password = "$PASSWORD";
          KieServicesConfiguration config =
            KieServicesFactory.newRestConfiguration(serverUrl,
                                                    username,
                                                    password);
          config.setMarshallingFormat(MarshallingFormat.JAXB);
          config.addExtraClasses(allClasses);
          KieServicesClient kieServicesClient =
            KieServicesFactory.newKieServicesClient(config);
    
          // Set up the fact model:
          Person p = new Person();
          p.setWage(12);
          p.setFirstName("Tom");
          p.setLastName("Summers");
          p.setHourlyRate(10);
    
          // Insert Person into the session:
          KieCommands kieCommands = KieServices.Factory.get().getCommands();
          List<Command> commandList = new ArrayList<Command>();
          commandList.add(kieCommands.newInsert(p, "personReturnId"));
    
          // Fire all rules:
          commandList.add(kieCommands.newFireAllRules("numberOfFiredRules"));
          BatchExecutionCommand batch = kieCommands.newBatchExecution(commandList, sessionName);
    
          // Use rule services client to send request:
          RuleServicesClient ruleClient = kieServicesClient.getServicesClient(RuleServicesClient.class);
          ServiceResponse<ExecutionResults> executeResponse = ruleClient.executeCommandsWithResults(containerName, batch);
          System.out.println("number of fired rules:" + executeResponse.getResult().getValue("numberOfFiredRules"));
        }
    
        catch (Throwable t) {
          t.printStackTrace();
        }
      }
    }

  8. 从项目目录运行配置的 .java 类。您可以在开发平台(如 Red Hat CodeReady Studio)或命令行中运行该文件。

    Maven 执行示例(带有项目目录):

    mvn clean install exec:java -Dexec.mainClass="com.sample.app.RulesTest"

    Java 执行示例(使用项目目录)

    javac -classpath "./$DEPENDENCIES/*:." RulesTest.java
    java -classpath "./$DEPENDENCIES/*:." RulesTest
  9. 在命令行和服务器日志中查看规则执行状态。如果有任何规则没有如预期执行,请查看项目中配置的规则和主类配置以验证所提供的数据。

第 58 章 å��续步骤

部分 VIII. 使用测试场景测试决策服务

作为商业部门或业务规则开发人员,您可以在部署项目前使用 Business Central 中的测试场景测试决策服务。您可以测试基于 DMN 和基于规则的决策服务,以确保这些服务正常工作。另外,您可以在项目开发期间随时测试决策服务。

先决�件

注意

在测试情境中,已定义的新规则并不是一个技术先决条件,因为场景可以测试构成了必要规则的定义的数据。但是,首先创建规则会很有用,以便在测试场景中测试整个规则,以便场景更加接近预期的决定服务。对于基于 DMN 的测试场景,请确保为决策服务定义了 DMN 决策逻辑及其关联的自定义数据类型。

第 59 章 测试场景

Red Hat Process Automation Manager 中的测试场景可让您在将新规则和新规则数据(用于基于规则的测试场景)或 DMN 模型(用于 DMN 的测试场景)之前验证这些规则和新规则数据的功能,然后再在生产环境中。通过测试场景,您可以使用项目中的数据根据一个或多个定义的警报规则设置给定的条件和预期结果。运行场景时,会比较规则实例的预期结果和实际结果。如果预期的结果与实际结果匹配,则测试可以成功。如果预期结果与实际结果不匹配,则测试会失败。

Red Hat Process Automation Manager 包括新的 测试方案设计和 之前的 测试场景(Legacy) 设计程序。默认设计器是新的测试场景设计器,它支持测试规则和 DMN 模型,并提供测试场景的整体用户体验。如果需要,您可以继续使用旧的测试场景设计程序,它只支持基于规则的测试场景。

重要

旧的测试场景设计程序已从 Red Hat Process Automation Manager 版本 7.3.0 中弃用。它将在以后的 Red Hat Process Automation Manager 发行版本中删除。改为使用新的测试场景设计程序。

您可以通过多种方法运行定义的测试场景,例如,您可以在项目级别或特定测试场景资产中运行可用的测试场景。测试场景是独立的,不会影响或修改其他测试场景。您可以在 Business Central 中的项目开发期间随时运行测试场景。您不必编译或部署您的决定服务来运行测试场景。

您可以将数据对象从不同的软件包导入到与测试场景相同的项目软件包。默认情况下导入同一软件包中的资产。创建必要的数据对象和测试场景后,您可以使用测试场景设计器的 Data Objects 选项卡来验证所有必需的数据对象是否已列出,或通过添加新 项目 来导入其他现有数据对象。

重要

在测试场景文档中,所有对 测试场景 的引用 和测试场景设计 程序都适用于新版本,除非明确记录为旧版本。

第 60 章 数据对象

数据对象是您创建的规则资产的构建块。数据对象是在项目的指定软件包中作为 Java 对象实现的自定义数据类型。例如,您可以创建一个带有数据字段 Name, Address, 和 DateOfBirthPerson 对象,以指定 loan 应用程序规则的个人详情。这些自定义数据类型决定了您的资产和您决定服务所基于的数据。

60.1. 创建数据对象

以下流程是创建数据对象的通用概述。它不特定于特定的业务资产。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetData Object
  3. 输入唯一 数据对象 名称并选择 您希望 数据对象可用于其他规则资产的软件包。同一软件包中不能存在具有相同名称的数据对象。在指定的 DRL 文件中,您可以从任何软件包导入数据对象。

    从其他软件包导入数据对象

    您可以直接将现有数据对象从另一个软件包导入到资产设计人员,如指导规则或指导决策表设计器。选择项目中的相关规则资产和资产设计器,转至 Data Objects → New 项 以选择要导入的对象。

  4. 要使数据对象持久,请选择 Persistable 复选框。Persistable 数据对象可以根据 JPA 规范存储在数据库中。默认 JPA 是 Hibernate。
  5. 点 确定。
  6. 在数据对象设计器中,单击 add 字段,将字段添加到带有属性 Id,Label, 和 Type 的对象。所需属性被标记为星号。

    • id : 输入字段的唯一 ID。
    • label : (可选)输入字段的标签
    • type : 输入字段的数据类型。
    • 列表: (可选)选择此复选框来启用该字段为指定类型保存多个项目。

      图 60.1. 在数据对象中添加数据字段

      在数据对象中添加数据字段
  7. Create 添加新字段,或者点 Create 并继续 添加新字段,并继续添加新字段。

    注意

    要编辑字段,请选择字段行,并使用屏幕右侧的 常规属性

第 61 章 在 Business Central 中测试场景设计器

测试场景设计器提供了一个表格布局,可帮助您定义场景模板以及所有相关测试案例。Designer 布局由一个表组成,其中包含标头和单个行。标头由三个部分、GIVENEXPECT 行、带有实例的行以及带有对应字段的行组成。标头也称为测试场景模板,单独行称为测试场景定义。

测试场景模板或标头有两个部分:

  • GIVEN 数据对象及其字段 - 代表输入信息
  • EXPECT 数据对象及其字段 - 代表对象及其字段,它们根据给定的信息检查其准确值,并构成预期的结果。

测试场景定义表示模板的单独测试情况。

您可以从设计人员左侧面板中访问 Project Explorer,从右侧面板中访问 Settings,Test Tools,Scenario Cheatsheet,Test Report 和 Scope Report 标签页。您可以访问 Settings 选项卡来查看和编辑基于规则和基于 DMN 的测试场景的全局设置。您可以使用 Test 工具 配置数据对象映射。场景 Cheatsheet 选项卡包含说明和 cheat sheet,您可以用作参考。Test Report 选项卡显示测试概述以及场景状态。要查看测试覆盖统计信息,您可以使用测试场景设计器右侧的 覆盖范围报告 选项卡。

61.1. 导入数据对象

测试场景设计程序加载位于与测试场景相同的软件包中的所有数据对象。您可以从设计器的 Data Objects 选项卡中查看所有数据对象。加载的数据对象也会显示在 Test Tools 面板中。

当数据对象发生变化时,您需要关闭并重新打开设计程序(例如,创建新数据对象或删除现有数据对象时)。从列表中选择一个数据对象,以显示其字段和字段类型。

如果要使用位于与测试场景不同的软件包中的数据对象,则需要首先导入数据对象。按照以下步骤为基于规则的测试场景导入数据对象。

注意

您无法在创建基于 DMN 的测试场景时导入任何数据对象。基于 DMN 的测试场景不使用项目中的任何数据对象,而是使用 DMN 文件中定义的自定义数据类型。

�程

  1. 在测试场景设计器中进入 Project Explorer 面板。
  2. Test Scenario 中选择一个测试场景。
  3. 选择 Data Objects 选项卡,然后单击 New Item
  4. Add import 窗口中,从下拉列表中选择 data 对象。
  5. 单击 Ok,然后保存
  6. 关闭并重新打开测试场景设计程序,从数据对象列表中查看新数据对象。

61.2. 导入测试场景

您可以使用项目视图中的 Asset 选项卡中的 Import Asset 按钮导入现有的测试场景。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. 在项目 资产 选项卡中点击 Import Asset
  3. Create new Import Asset 窗口中,

    • 输入导入资产的名称。
    • Package 下拉列表中选择软件包。
    • Please select a file to upload,单击 Choose File…​ to browse to test scenario file。
  4. 选择文件并点击 Open
  5. Ok 并在测试场景设计程序中打开测试场景。

61.3. 保存测试场景

您可以在创建测试场景模板或定义测试场景时随时保存测试场景。

�程

  1. 从右上角的测试场景设计器工具栏中,单击 Save
  2. Confirm Save 窗口中,

    1. 如果要添加关于测试场景的评论,请点击 添加注释
    2. 再次点 Save

显示测试场景被成功保存的消息出现在屏幕上。

61.4. 复制测试场景

您可以使用右上角的 Copy 按钮将现有测试场景复制到同一软件包或其它软件包中。

�程

  1. 从右上角的测试场景设计器工具栏中,单击 Copy
  2. Make a Copy 窗口中,

    1. New Name 字段中输入名称。
    2. 选择您要复制测试场景的软件包。
    3. 可选: 要添加注释,请点击 添加注释
    4. Make a Copy

表示测试场景被成功复制的消息出现在屏幕上。

61.5. 下载测试场景

您可以将测试场景的副本下载到本地机器,以备将来参考或作为备份。

�程

在右上角的测试场景设计器工具栏中,点 Download 图标。

.scesim 文件下载到您的本地机器中。

61.6. 在测试场景版本间切换

Business Central 可让您在测试场景的不同版本之间进行切换。每次保存场景时,该场景的新版本都会列在 Latest Versions 下。要使用这个功能,您必须至少保存测试场景文件一次。

�程

  1. 从右上角的测试场景设计器工具栏中,单击 Latest Version。如果存在,该文件的所有版本都会列在 Latest Version 下。
  2. 点击您要使用的版本。

    测试场景的所选版本会在测试场景设计程序中打开。

  3. 在设计器工具栏中点 Restore
  4. Confirm Restore 中,

    1. 要添加注释,请点击 添加注释
    2. Restore 确认。

表示所选版本在设计人员中成功重新加载的消息会出现在屏幕上。

61.7. 查看或隐藏警报面板

Alerts 面板会出现在测试场景设计器或项目视图的底部。它包含执行测试失败时的构建信息和错误消息。

�程

从右上角的设计器工具栏中,点 Hide Alerts/View Alerts 来启用或禁用报告面板。

61.8. 上下文菜单选项

测试场景设计器提供上下文菜单选项,允许您对表执行基本操作,如添加、删除和复制行和列。要使用上下文菜单,您需要右键单击表元素。菜单选项因您选择的表元素而异。

表 61.1. 上下文菜单选项

table 元素cell 标签可用的上下文菜单选项

标头

过程,场景描述

下面的插入行

给定,预期

插入最左列、最旧的列,在下面的 Insert 行

实例 1、实例 2、属性 1、属性 2

insert column left, Insert column right, Delete column, Duplicate Instance, Insert row below

rows

所有带有行号、测试场景描述或测试场景定义的单元

插入上面的行,在下面插入行、Duplicate 行、删除行、运行场景

表 61.2. 表交互的描述

表交互æ��è¿°

insert left most column

插入一个新的左侧列(基于用户选择,在表的 GIVEN 或 EXPECT 部分中)。

插入最右列

插入一个新的最右列(在表的 GIVEN 或 EXPECT 部分中基于用户选择)。

左面插入列

将新列插入到所选列的左侧。新列与所选列相同类型(在表的 GIVEN 或 EXPECT 部分中基于用户选择)。

插入列右

将新列插入到所选列的右侧。新列与所选列相同类型(在表的 GIVEN 或 EXPECT 部分中基于用户选择)。

删除列

删除所选列。

上面的插入行

在所选行的上面插入一个新行。

下面的插入行

在所选行后插入一个新行。如果从标头单元调用,请使用索引 1 插入一个新行。

重复行

重复所选行。

重复实例

复制所选实例。

删除行

删除所选行。

运行场景

运行单个测试场景。

Insert 列右Insert 列 的上下文菜单选项的行为不同。

  • 如果所选列没有定义类型,则会添加没有类型的新列。
  • 如果所选列定义了类型,则创建新的空列或具有父实例类型的列。

    • 如果操作从实例标头执行,则会创建一个没有类型的新列。
    • 如果操作是从属性标头中执行的操作,则会创建一个具有父实例类型的新列。

61.9. 测试场景的全局设置

您可以使用测试场景设计器右侧的 global Settings 选项卡来设置和修改资产的额外属性。

61.9.1. 为基于规则的测试场景配置全局设置

按照以下步骤查看和编辑基于规则的测试场景的全局设置。

�程

  1. 点测试场景设计器右侧的 Settings 选项卡来显示属性。
  2. Settings 面板中配置以下属性:

    • 名称 :您可以使用设计器右上角的 Rename 选项更改现有测试场景的名称。
    • type :此属性指定它是一个基于规则的测试场景,它是只读的。
    • 无状态会话 :选择或清除此复选框,以指定 KieSession 是否无状态。

      注意

      如果当前的 KieSession 是无状态的,并且未选择复选框,则测试将失败。

    • KieSession :(可选)为测试场景输入 KieSession。
    • RuleFlowGroup/AgendaGroup: (可选)为测试场景输入 RuleFlowGroup 或 AgendaGroup。
  3. 可选: 要在测试执行后从项目级别跳过整个模拟,请选择复选框。
  4. 点击 Save。

61.9.2. 为基于 DMN 的测试场景配置全局设置

按照以下步骤查看和编辑基于 DMN 的测试场景的全局设置。

�程

  1. 点测试场景设计器右侧的 Settings 选项卡来显示属性。
  2. Settings 面板中配置以下属性:

    • 名称 :您可以使用设计器右上角的 Rename 选项更改现有测试场景的名称。
    • type :此属性指定基于 DMN 的测试场景,它是只读的。
    • DMN 模型 :(可选)为测试场景输入 DMN 模型。
    • DMN name :这是 DMN 模型的名称,它是只读的。
    • DMN 命名空间 :这是 DMN 模型的默认命名空间,它是只读的。
  3. 可选: 要在测试执行后从项目级别跳过整个模拟,请选择复选框。
  4. 点击 Save。

第 62 章 测试场景模板

在指定测试场景定义前,您需要创建一个测试场景模板。测试场景表的标头为每个场景定义模板。您需要为 GIVEN 和 EXPECT 部分设置 instance 和 property 标头的类型。实例标头映射到特定的数据对象(事实),而属性标头映射到对应数据对象的特定字段。

使用测试场景设计器,您可以为基于规则和基于 DMN 的测试场景创建测试场景模板。

62.1. 为基于规则的测试场景创建测试场景模板

按照以下步骤为基于规则的测试场景创建一个测试场景模板,以验证您的规则和数据。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击您要为其创建测试场景的项目。
  2. Add AssetTest Scenario
  3. 输入 Test Scenario name 并选择适当的 软件包。您选择的软件包必须包含所有所需的数据对象和规则资产。
  4. 选择 RULE 作为 Source 类型
  5. Ok 在测试场景设计程序中创建并打开测试场景。
  6. GIVEN 列标头映射到数据对象:

    图 62.1. 测试场景 GIVEN 标头单元

    测试场景 GIVEN 标头单元
    1. GIVEN 部分中选择实例标头单元。
    2. Test Tools 选项卡中选择数据对象。
    3. 单击 Insert Data Object
  7. EXPECT 列标头映射到数据对象:

    图 62.2. 测试场景 EXPECT 标头单元

    测试场景 EXPECT 标头单元
    1. EXPECT 部分中选择一个实例标头单元。
    2. Test Tools 选项卡中选择数据对象。
    3. 单击 Insert Data Object
  8. 将数据对象字段映射到属性单元:

    1. 选择实例标头单元或属性标头单元。
    2. Test Tools 选项卡中选择 data 对象字段。
    3. 单击 Insert Data Object
  9. 要插入 data 对象的额外属性,请右键点击属性标头,再根据需要选择 Insert 列右Insert 列
  10. 在测试场景执行期间定义到属性单元的 java 方法:

    1. 选择实例标头单元或属性标头单元。
    2. Test Tools 选项卡中选择 data 对象字段。
    3. 单击 Insert Data Object
    4. 使用带前缀的 MVEL 表达式来定义测试场景执行的 java 方法。
    5. 要插入数据对象的更多属性,请右键点击属性标头单元,再根据需要选择 Insert 列右Insert 列
  11. 根据需要,使用上下文菜单添加或删除列和行。

有关基于规则的场景中表达式语法的详情,请参考 第 67.1 节 “基于规则的测试场景中的表达式语法”

62.2. 在基于规则的测试场景中使用别名

在测试场景设计程序中,当您使用数据对象映射标头单元后,数据对象会从 Test Tools 选项卡中删除。您可以使用别名将数据对象重新映射到另一个标头单元。别名允许您在测试场景中指定多个数据对象实例。您还可以创建属性别名来直接在表中重命名已使用的属性。

�程

在 Business Central 中的测试场景设计程序中,双击标头单元并手动更改名称。确保别名被唯一命名。

实例现在会出现在 Test Tools 选项卡中的数据对象列表中。

第 63 章 为基于 DMN 的测试场景测试模板

Business Central 会自动为每个基于 DMN 的测试场景资产生成模板,其中包含相关 DMN 模型的所有指定输入和输出。对于 DMN 模型中的每个输入节点,添加了 GIVEN 列,而每个决策节点都由 EXPECT 列表示。您可以根据需要随时修改默认模板。另外,为了只测试整个 DMN 模型的特定部分,可以删除生成的列,并将决策节点从 EXPECT 移到 GIVEN 部分。

63.1. 为基于 DMN 的测试场景创建测试场景模板

按照以下步骤为基于 DMN 的场景创建测试场景模板,以验证您的 DMN 模型。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击您要为其创建测试场景的项目。
  2. Add AssetTest Scenario
  3. 输入 Test Scenario name 并选择适当的 软件包
  4. 选择 DMN 作为 Source 类型
  5. 使用 Choose DMN asset 选项选择现有的 DMN 资产。
  6. Ok 在测试场景设计程序中创建并打开测试场景。

    模板会自动生成,您可以根据需要进行修改。

  7. 在测试场景执行期间定义到属性单元的 java 方法:

    1. 点实例标头单元或属性标头单元。
    2. Test Tools 选项卡中选择 data 对象字段。
    3. 单击 Insert Data Object
    4. 使用表达式来定义测试场景执行的 java 方法。
    5. 要向数据对象添加更多属性,请右键点击属性标头单元,再根据需要选择 Insert 列右Insert 列
  8. 根据需要,使用上下文菜单添加或删除列和行。

有关基于 DMN 的场景中表达式语法的详情,请参考 第 67.2 节 “基于 DMN 的测试场景中的表达式语法”

第 64 章 定义测试场景

创建测试场景模板后,您必须定义测试场景。测试场景表的行定义了单个测试场景。测试场景具有唯一的索引号、描述、输入值( Given 值)和一组输出值( Expect 值)。

先决�件

  • 为所选测试场景创建了测试场景模板。

�程

  1. 在测试场景设计程序中打开测试场景。
  2. 输入测试场景的描述,并在行的每个单元中输入所需的值。
  3. 根据需要,使用上下文菜单添加或删除行。

    双击单元以开始内联编辑。要从测试评估跳过特定的单元,请将其留空。

定义测试方案后,您可以在下次运行测试。

第 65 章 测试场景中的后台实例

在测试场景设计器中,您可以使用 Background 选项卡为基于规则和基于 DMN 的测试场景添加和设置后台数据。您可以根据可用的数据对象,添加和定义整个测试场景模拟的 GIVEN 数据。背景 选项卡能够在每个测试场景中添加和共享数据。使用 Background 选项卡添加的数据不能被 Model 标签页数据覆盖。

例如,如果测试场景示例在所有测试场景中都需要 person Age 的值相同,您可以在 Background 页面中定义 Age 值,并从测试场景表模板中排除该列。在这种情况下,所有测试 场景的期限都设为 25

图 65.1. 带有重复值为 Age 的测试场景示例

为 Age 测试带有重复值的场景

图 65.2. Age 重复值的后台定义示例

期限重复值的后台定义

图 65.3. 带有排除 Age 列的修改测试场景模板

带有排除 Age 列的修改测试场景模板
注意

Background 选项卡中定义的 GIVEN 数据只能在同一 scesim 文件的测试场景之间共享,且不会在不同的测试场景中共享。

65.1. 在基于规则的测试场景中添加后台数据

按照以下步骤在基于规则的测试场景中添加和设置后台数据。

先决�件

�程

  1. 在测试场景设计程序中,打开基于规则的测试场景。
  2. 点测试场景设计器的背景选项卡。
  3. GIVEN 部分中选择实例标头单元,以添加后台数据对象字段。
  4. Test Tools 面板中选择数据对象。
  5. 单击 Insert Data Object
  6. 选择属性标头单元来添加后台数据对象字段。
  7. Test Tools 面板中选择数据对象。
  8. 单击 Insert Data Object
  9. 要向数据对象添加更多属性,请右键点击属性标头单元,再根据需要选择 Insert 列右Insert 列
  10. 根据需要,使用上下文菜单添加或删除列和行。
  11. 运行定义的测试场景。

65.2. 在基于 DMN 的测试场景中添加后台数据

按照以下步骤在基于 DMN 的测试场景中添加和设置后台数据。

先决�件

�程

  1. 在测试场景设计程序中,打开基于 DMN 的测试场景。
  2. 点测试场景设计器的背景选项卡。
  3. GIVEN 部分中选择实例标头单元,以添加后台数据对象字段。
  4. Test Tools 面板中选择数据对象。
  5. 单击 Insert Data Object
  6. 选择属性标头单元来添加后台数据对象字段。
  7. Test Tools 面板中选择数据对象。
  8. 单击 Insert Data Object
  9. 要向数据对象添加更多属性,请右键点击属性标头单元,再根据需要选择 Insert 列右Insert 列
  10. 根据需要,使用上下文菜单添加或删除列和行。
  11. 运行定义的测试场景。

第 66 章 在测试场景中使用列表和映射集合

测试场景设计程序支持基于 DMN 和基于规则的测试场景的列表和映射集合。您可以创建并定义集合,如列表或映射 ​ 作为 GIVENEXPECT 列中特定单元的值。

注意

对于映射条目,条目键必须是 String 数据类型。

要在基于 Rule 的 collection 编辑器的 EXPECT 列中传递参数,请使用基于 DMN 的测试场景中的 ? 关键字。

�程

  1. 首先设置列类型(使用类型为一个列表或映射的字段)。
  2. 双击列中的单元以输入值。
  3. 要在集合编辑器中为 data 对象创建列表值:

    1. 选择 Create List
    2. 单击 Add new item
    3. 输入所需值并点击检查图标 dmn datatype constraints tickmark 来保存您添加的每个集合项目。
    4. 点击 Save。
    5. 要从集合中编辑项目,请点击集合弹出窗口中的铅笔图标。
    6. 点 Save Changes。
    7. 要从集合中删除项目,请点击集合弹出窗口中的 bin 图标。
  4. 在集合编辑器中定义 data 对象的列表值:

    1. 选择 定义列表
    2. 使用 MVEL 或 FEEL 表达式在文本字段中定义列表值。

      基于规则的测试场景使用 MVEL 表达式语言,基于 DMN 的测试场景使用 FEEL 表达式语言。

    3. 点击 Save。
  5. 要在集合编辑器中为 data 对象创建映射值:

    1. 选择 Create Map
    2. 单击 Add new item
    3. 输入所需值并点击检查图标 dmn datatype constraints tickmark 来保存您添加的每个集合项目。
    4. 点击 Save。
    5. 要从集合中编辑项目,请点击集合弹出窗口中的铅笔图标。
    6. 点 Save Changes。
    7. 要从集合中删除项目,请点击集合弹出窗口中的 bin 图标。
  6. 在集合编辑器中定义 data 对象的映射值:

    1. 选择 define Map
    2. 使用 MVEL 或 FEEL 表达式在文本字段中定义映射值。

      基于规则的测试场景使用 MVEL 表达式语言,基于 DMN 的测试场景使用 FEEL 表达式语言。

    3. 点击 Save。

      注意

      要为基于 DMN 的测试场景定义映射值,您可以添加事实并使用 FEEL 表达式,而不使用集合编辑器。

  7. Remove 以删除整个集合。

第 67 章 测试场景中的表达式语法

测试场景设计程序为基于规则和基于 DMN 的测试场景支持不同的表达式语言。虽然基于规则的测试场景支持 MVFLEX 表达式语言(MVEL)和基于 DMN 的测试场景支持 Friendly Enough Expression Language (FEEL)。

67.1. 基于规则的测试场景中的表达式语法

基于规则的测试场景支持以下内置数据类型:

  • 字符串
  • 布尔值
  • æ•´æ•°
  • Long
  • å�Œ
  • 浮点值
  • 字符
  • BYTE
  • LocalDate
注意

对于任何其他数据类型,请使用带前缀的 MVEL 表达式

按照测试场景设计器中的 BigDecimal 示例,以使用 sVirt 前缀来设置 java 表达式:

  • GIVEN 列值输入 192.168.1.0/24 java.math.BigDecimal.valueOf (10)
  • EXPECT 列值输入 192.168.1.0/24 actualValue.intValue ()== 10

您可以参考 java 表达式中的 EXPECT 列的实际值来执行条件。

测试场景设计程序支持以下基于规则的测试场景定义表达式:

表 67.1. 表达式语法的描述

Operator描述

=

指定等于一个值。这是所有列的默认值,是 GIVEN 列唯一支持的运算符。

=, =!, <>

指定一个值的不相等。此操作器可以与其他操作器结合使用。

<, >, <=, >=

指定比较: 小于或等于、小于或等于。

#

此运算符用于将 java 表达式值设置为属性标头单元,该单元可以作为 java 方法执行。

[value1, value2, value3]

指定值列表。如果一个或多个值有效,则场景定义将评估为 true。

expression1; expression2; expression3

指定表达式列表。如果所有表达式都有效,则场景定义将评估为 true。

注意

在评估基于规则的测试场景时,会从评估中跳过空单元。要定义一个空字符串,请使用 =[];,并定义 null 值,请使用 null

表 67.2. 表达式示例

表达��述

-1

实际值等于 -1。

< 0

实际值小于 0。

! > 0

实际值不大于 0。

[-1, 0, 1]

实际值等于 -1 或 0 或 1。

<> [1, -1]

实际值不能等于 1 或 -1。

!100; 0

实际值不等于 100,但等于 0。

!= < 0; <> > 1

实际值不能小于 0,或大于 1。

<> <= 0; >= 1

实际值不能小于或等于 0,但大于或等于 1。

您可以在基于规则的测试场景设计器右侧的 Scenario Cheatsheet 选项卡中引用支持的命令和语法。

67.2. 基于 DMN 的测试场景中的表达式语法

在测试场景设计程序中,基于 DMN 的测试场景支持以下数据类型:

表 67.3. 基于 DMN 的场景支持的数据类型

支持的数据类型æ��è¿°

number 和 string

字符串必须以引号分隔,例如:" John Doe", " Brno"""

布尔值

truefalsenull

日期和时间

例如,date ("2019-05-13")time ("14:10:00+02:00")

函数

支持内置数学函数,如 avgmax

context

例如,{x : 5、y : 3}

范围和列表

例如: [1 ...10][2, 3, 4, 5].

注意

在评估基于 DMN 的测试场景时,会从评估中跳过空单元。要在基于 DMN 的测试场景中定义一个空字符串,请使用 " " 和 定义 null 值,请使用 null

您可以在基于 DMN 的测试场景设计器右侧的 Scenario Cheatsheet 选项卡中引用支持的命令和语法。

第 68 章 运行测试场景

在创建了测试场景模板并定义测试场景后,您可以运行测试来验证您的新规则和数据。

�程

  1. 要运行定义的测试场景,请执行以下任务:

    • 要在多个资产内执行项目中的所有测试场景,请在项目页面右上角点击 Test

      图 68.1. 从项目视图运行所有测试场景

      从项目视图运行所有测试场景
    • 要执行 .scesim 文件中定义的所有可用测试场景,在 Test Scenario Designer 的顶部,点 Run Test Run Test icon 图标。
    • 要运行在单个 .scesim 文件中定义的单个测试场景,请右键点击您要运行的测试场景行并选择 运行场景
  2. Test Report 面板显示测试概述以及场景状态。

    测试执行后,如果测试场景表中输入的值与预期值不匹配,则突出显示对应的单元。

  3. 如果测试失败,您可以执行以下任务排除故障:

    • 要查看弹出窗口中的错误消息,请将鼠标光标悬停在高亮的单元上。
    • 要在设计人员底部的 Alerts 面板或错误消息的项目视图打开 Alerts 面板,请单击 View Alerts
    • 进行必要的更改,然后再次运行测试,直到场景通过为止。

第 69 章 本地运行测试场景

在 Red Hat Process Automation Manager 中,您可以直接使用命令行在 Business Central 中运行测试场景,也可以在本地运行测试场景。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. 在 Project 主页上,选择 Settings 选项卡。
  3. 选择 git URL 并点 Clipboard Copy to clipboard icon 复制 git url。
  4. 打开一个终端,再导航到要克隆 git 项目的目录。
  5. �行以下命令:

    git clone your_git_project_url

    your_git_project_url 替换为 git://localhost:9418/MySpace/ProjectTestScenarios 等相关数据。

  6. 成功克隆项目后,导航到 git 项目目录并执行以下命令:

    mvn clean test

    您的项目的构建信息和测试结果(如运行测试次数以及测试运行是成功)在命令终端中显示。如果出现故障,在 Business Central 中进行必要的更改,拉取更改并再次运行命令。

第 70 章 导出和导入测试场景电子表

这些部分演示了如何在测试场景设计程序中导出和导入测试场景电子表。您可以使用 Microsoft Excel 或 LibreOffice Calc 等软件分析和管理测试场景电子表格。测试场景设计器支持 .CSV 文件格式。有关 Comma-Separated 值(CSV)格式的 RFC 规格的更多信息,请参阅 用于 Comma-Separated 值(CSV)文件的通用格式和 MIME 类型

70.1. 导出测试场景电子表

按照以下步骤,使用 Test Scenario Designer 导出测试场景电子表。

�程

  1. 在右上角的 Test Scenario Designer 工具栏中,点 Export test scenarios export button 按钮。
  2. 在本地文件目录中选择一个目标,并确认保存 .CSV 文件。

.CSV 文件导出到本地机器。

70.2. 导入测试场景电子表

按照以下步骤,使用 Test Scenario Designer 导入测试场景电子表。

�程

  1. 在右上角的 Test Scenario Designer 工具栏中点 Import test scenarios import button 按钮。
  2. Select file to Import 提示中,点 Choose File…​ 并选择您要从本地文件目录中导入的 .CSV 文件。
  3. Import

.CSV 文件导入到 Test Scenario Designer 中。

警告

您不能修改所选 .CSV 文件中的标头。否则,电子表格可能无法成功导入。

第 71 章 测试场景的覆盖范围报告

测试场景设计器提供了一种明确且一致的方式,使用测试场景设计器右侧的 覆盖范围报告 选项卡来显示测试覆盖范围统计信息。您还可以下载覆盖范围报告来查看和分析测试覆盖范围统计信息。下载的测试场景覆盖报告支持 .CSV 文件格式。有关 Comma-Separated 值(CSV)格式的 RFC 规格的更多信息,请参阅 用于 Comma-Separated 值(CSV)文件的通用格式和 MIME 类型

您可以查看基于规则和基于 DMN 的测试场景的覆盖范围报告。

71.1. 为基于规则的测试场景生成覆盖报告

在基于规则的测试场景中,覆盖范围报告 选项卡包含有关以下的详细信息:

  • 可用规则数
  • 触发的规则数量
  • 触发规则的百分比
  • 以 pie chart 表示的已执行规则的百分比
  • 每个规则执行的次数
  • 为每个定义的测试场景执行的规则

按照以下步骤为基于规则的测试场景生成覆盖报告:

先决�件

�程

  1. 在测试场景设计程序中,打开基于规则的测试场景。
  2. 运行定义的测试场景。
  3. 单击测试场景设计器右侧的 覆盖范围报告,以显示测试覆盖范围统计信息。
  4. 可选: 要下载测试场景覆盖报告,请点 Download report

71.2. 为基于 DMN 的测试场景生成覆盖范围报告

在基于 DMN 的测试场景中,覆盖范围报告 选项卡包含有关以下内容的详细信息:

  • 可用决策数
  • 所执行决策数
  • 已执行决策的百分比
  • 已执行决策的百分比,以饼图表示
  • 每个决定执行的次数
  • 为每个定义的测试场景执行决策

按照以下步骤为基于 DMN 的测试场景生成覆盖范围报告:

先决�件

�程

  1. 在测试场景设计程序中,打开基于 DMN 的测试场景。
  2. 运行定义的测试场景。
  3. 单击测试场景设计器右侧的 覆盖范围报告,以显示测试覆盖范围统计信息。
  4. 可选: 要下载测试场景覆盖报告,请点 Download report

第 72 章 使用 KIE Server REST API 执行测试场景

直接与 KIE 服务器的 REST 端点交互,可在调用代码和决策逻辑定义之间提供最大的隔离。您可以使用 KIE Server REST API 在外部执行测试场景。它针对部署的项目执行测试场景。

注意

此功能默认为禁用,使用 org.kie.scenariosimulation.server.ext.disabled 系统属性启用它。

有关 KIE Server REST API 的更多信息,请参阅使用 KIE API 与 Red Hat Process Automation Manager 交互

先决�件

  • KIE 服务器已安装并配置,包括具有 kie-server 角色的用户的已知用户名和凭证。有关安装选项,请参阅 规划 Red Hat Process Automation Manager 安装
  • 您已将项目构建为 KJAR 工件,并将其部署到 KIE 服务器中。
  • 您有 KIE 容器的 ID。

�程

  1. 确定用于访问 KIE 服务器 REST API 端点的基本 URL。这需要了解以下值(默认本地部署值作为示例):

    • 主机(localhost)
    • 端口(8080)
    • 根上下文(kie-server)
    • 基本 REST 路径(services/rest/)

    流量违反项目的本地部署中的基本 URL 示例:

    http://localhost:8080/kie-server/services/rest/server/containers/traffic_1.0.0-SNAPSHOT

  2. 确定用户身份验证要求。

    当在 KIE 服务器配置中直接定义用户时,会使用 HTTP 基本身份验证,并且需要用户名和密码。成功请求要求用户具有 kie-server 角色。

    以下示例演示了如何在 curl 请求中添加凭证:

    curl -u username:password <request>

    如果使用 Red Hat Single Sign-On 配置 KIE 服务器,请求必须包含 bearer 令牌:

    curl -H "Authorization: bearer $TOKEN" <request>
  3. 指定请求和响应的格式。REST API 端点可用于 XML 格式,并使用请求标头设置:

    XML

    curl -H "accept: application/xml" -H "content-type: application/xml"

  4. 执行测试场景:

    [POST] server/containers/{containerId}/scesim

    curl 请求示例:

    curl -X POST "http://localhost:8080/kie-server/services/rest/server/containers/traffic_1.0.0-SNAPSHOT/scesim"\ -u 'wbadmin:wbadmin;' \ -H "accept: application/xml" -H "content-type: application/xml"\ -d @Violation.scesim

    XML 请求示例:

    <ScenarioSimulationModel version="1.8">
      <simulation>
        <scesimModelDescriptor>
          <factMappings>
            <FactMapping>
              <expressionElements/>
              <expressionIdentifier>
                <name>Index</name>
                <type>OTHER</type>
              </expressionIdentifier>
              <factIdentifier>
                <name>#</name>
                <className>java.lang.Integer</className>
              </factIdentifier>
              <className>java.lang.Integer</className>
              <factAlias>#</factAlias>
              <factMappingValueType>NOT_EXPRESSION</factMappingValueType>
              <columnWidth>70.0</columnWidth>
            </FactMapping>
            <FactMapping>
              <expressionElements/>
              <expressionIdentifier>
                <name>Description</name>
                <type>OTHER</type>
              </expressionIdentifier>
              <factIdentifier>
                <name>Scenario description</name>
                <className>java.lang.String</className>
              </factIdentifier>
              <className>java.lang.String</className>
              <factAlias>Scenario description</factAlias>
              <factMappingValueType>NOT_EXPRESSION</factMappingValueType>
              <columnWidth>300.0</columnWidth>
            </FactMapping>
            <FactMapping>
              <expressionElements>
                <ExpressionElement>
                  <step>Driver</step>
                </ExpressionElement>
                <ExpressionElement>
                  <step>Points</step>
                </ExpressionElement>
              </expressionElements>
              <expressionIdentifier>
                <name>0|1</name>
                <type>GIVEN</type>
              </expressionIdentifier>
              <factIdentifier>
                <name>Driver</name>
                <className>Driver</className>
              </factIdentifier>
              <className>number</className>
              <factAlias>Driver</factAlias>
              <expressionAlias>Points</expressionAlias>
              <factMappingValueType>NOT_EXPRESSION</factMappingValueType>
              <columnWidth>114.0</columnWidth>
            </FactMapping>
            <FactMapping>
              <expressionElements>
                <ExpressionElement>
                  <step>Violation</step>
                </ExpressionElement>
                <ExpressionElement>
                  <step>Type</step>
                </ExpressionElement>
              </expressionElements>
              <expressionIdentifier>
                <name>0|6</name>
                <type>GIVEN</type>
              </expressionIdentifier>
              <factIdentifier>
                <name>Violation</name>
                <className>Violation</className>
              </factIdentifier>
              <className>Type</className>
              <factAlias>Violation</factAlias>
              <expressionAlias>Type</expressionAlias>
              <factMappingValueType>NOT_EXPRESSION</factMappingValueType>
              <columnWidth>114.0</columnWidth>
            </FactMapping>
            <FactMapping>
              <expressionElements>
                <ExpressionElement>
                  <step>Violation</step>
                </ExpressionElement>
                <ExpressionElement>
                  <step>Speed Limit</step>
                </ExpressionElement>
              </expressionElements>
              <expressionIdentifier>
                <name>0|7</name>
                <type>GIVEN</type>
              </expressionIdentifier>
              <factIdentifier>
                <name>Violation</name>
                <className>Violation</className>
              </factIdentifier>
              <className>number</className>
              <factAlias>Violation</factAlias>
              <expressionAlias>Speed Limit</expressionAlias>
              <factMappingValueType>NOT_EXPRESSION</factMappingValueType>
              <columnWidth>114.0</columnWidth>
            </FactMapping>
            <FactMapping>
              <expressionElements>
                <ExpressionElement>
                  <step>Violation</step>
                </ExpressionElement>
                <ExpressionElement>
                  <step>Actual Speed</step>
                </ExpressionElement>
              </expressionElements>
              <expressionIdentifier>
                <name>0|8</name>
                <type>GIVEN</type>
              </expressionIdentifier>
              <factIdentifier>
                <name>Violation</name>
                <className>Violation</className>
              </factIdentifier>
              <className>number</className>
              <factAlias>Violation</factAlias>
              <expressionAlias>Actual Speed</expressionAlias>
              <factMappingValueType>NOT_EXPRESSION</factMappingValueType>
              <columnWidth>114.0</columnWidth>
            </FactMapping>
            <FactMapping>
              <expressionElements>
                <ExpressionElement>
                  <step>Fine</step>
                </ExpressionElement>
                <ExpressionElement>
                  <step>Points</step>
                </ExpressionElement>
              </expressionElements>
              <expressionIdentifier>
                <name>0|11</name>
                <type>EXPECT</type>
              </expressionIdentifier>
              <factIdentifier>
                <name>Fine</name>
                <className>Fine</className>
              </factIdentifier>
              <className>number</className>
              <factAlias>Fine</factAlias>
              <expressionAlias>Points</expressionAlias>
              <factMappingValueType>NOT_EXPRESSION</factMappingValueType>
              <columnWidth>114.0</columnWidth>
            </FactMapping>
            <FactMapping>
              <expressionElements>
                <ExpressionElement>
                  <step>Fine</step>
                </ExpressionElement>
                <ExpressionElement>
                  <step>Amount</step>
                </ExpressionElement>
              </expressionElements>
              <expressionIdentifier>
                <name>0|12</name>
                <type>EXPECT</type>
              </expressionIdentifier>
              <factIdentifier>
                <name>Fine</name>
                <className>Fine</className>
              </factIdentifier>
              <className>number</className>
              <factAlias>Fine</factAlias>
              <expressionAlias>Amount</expressionAlias>
              <factMappingValueType>NOT_EXPRESSION</factMappingValueType>
              <columnWidth>114.0</columnWidth>
            </FactMapping>
            <FactMapping>
              <expressionElements>
                <ExpressionElement>
                  <step>Should the driver be suspended?</step>
                </ExpressionElement>
              </expressionElements>
              <expressionIdentifier>
                <name>0|13</name>
                <type>EXPECT</type>
              </expressionIdentifier>
              <factIdentifier>
                <name>Should the driver be suspended?</name>
                <className>Should the driver be suspended?</className>
              </factIdentifier>
              <className>string</className>
              <factAlias>Should the driver be suspended?</factAlias>
              <expressionAlias>value</expressionAlias>
              <factMappingValueType>NOT_EXPRESSION</factMappingValueType>
              <columnWidth>114.0</columnWidth>
            </FactMapping>
          </factMappings>
        </scesimModelDescriptor>
        <scesimData>
          <Scenario>
            <factMappingValues>
              <FactMappingValue>
                <factIdentifier>
                  <name>Scenario description</name>
                  <className>java.lang.String</className>
                </factIdentifier>
                <expressionIdentifier>
                  <name>Description</name>
                  <type>OTHER</type>
                </expressionIdentifier>
                <rawValue class="string">Above speed limit: 10km/h and 30 km/h</rawValue>
              </FactMappingValue>
              <FactMappingValue>
                <factIdentifier>
                  <name>Driver</name>
                  <className>Driver</className>
                </factIdentifier>
                <expressionIdentifier>
                  <name>0|1</name>
                  <type>GIVEN</type>
                </expressionIdentifier>
                <rawValue class="string">10</rawValue>
              </FactMappingValue>
              <FactMappingValue>
                <factIdentifier>
                  <name>Violation</name>
                  <className>Violation</className>
                </factIdentifier>
                <expressionIdentifier>
                  <name>0|6</name>
                  <type>GIVEN</type>
                </expressionIdentifier>
                <rawValue class="string">&quot;speed&quot;</rawValue>
              </FactMappingValue>
              <FactMappingValue>
                <factIdentifier>
                  <name>Violation</name>
                  <className>Violation</className>
                </factIdentifier>
                <expressionIdentifier>
                  <name>0|7</name>
                  <type>GIVEN</type>
                </expressionIdentifier>
                <rawValue class="string">100</rawValue>
              </FactMappingValue>
              <FactMappingValue>
                <factIdentifier>
                  <name>Violation</name>
                  <className>Violation</className>
                </factIdentifier>
                <expressionIdentifier>
                  <name>0|8</name>
                  <type>GIVEN</type>
                </expressionIdentifier>
                <rawValue class="string">120</rawValue>
              </FactMappingValue>
              <FactMappingValue>
                <factIdentifier>
                  <name>Fine</name>
                  <className>Fine</className>
                </factIdentifier>
                <expressionIdentifier>
                  <name>0|11</name>
                  <type>EXPECT</type>
                </expressionIdentifier>
                <rawValue class="string">3</rawValue>
              </FactMappingValue>
              <FactMappingValue>
                <factIdentifier>
                  <name>Fine</name>
                  <className>Fine</className>
                </factIdentifier>
                <expressionIdentifier>
                  <name>0|12</name>
                  <type>EXPECT</type>
                </expressionIdentifier>
                <rawValue class="string">500</rawValue>
              </FactMappingValue>
              <FactMappingValue>
                <factIdentifier>
                  <name>Should the driver be suspended?</name>
                  <className>Should the driver be suspended?</className>
                </factIdentifier>
                <expressionIdentifier>
                  <name>0|13</name>
                  <type>EXPECT</type>
                </expressionIdentifier>
                <rawValue class="string">&quot;No&quot;</rawValue>
              </FactMappingValue>
              <FactMappingValue>
                <factIdentifier>
                  <name>#</name>
                  <className>java.lang.Integer</className>
                </factIdentifier>
                <expressionIdentifier>
                  <name>Index</name>
                  <type>OTHER</type>
                </expressionIdentifier>
                <rawValue class="string">1</rawValue>
              </FactMappingValue>
            </factMappingValues>
          </Scenario>
        </scesimData>
      </simulation>
      <background>
        <scesimModelDescriptor>
          <factMappings>
            <FactMapping>
              <expressionElements/>
              <expressionIdentifier>
                <name>1|1</name>
                <type>GIVEN</type>
              </expressionIdentifier>
              <factIdentifier>
                <name>Empty</name>
                <className>java.lang.Void</className>
              </factIdentifier>
              <className>java.lang.Void</className>
              <factAlias>Instance 1</factAlias>
              <expressionAlias>PROPERTY 1</expressionAlias>
              <factMappingValueType>NOT_EXPRESSION</factMappingValueType>
              <columnWidth>114.0</columnWidth>
            </FactMapping>
          </factMappings>
        </scesimModelDescriptor>
        <scesimData>
          <BackgroundData>
            <factMappingValues>
              <FactMappingValue>
                <factIdentifier>
                  <name>Empty</name>
                  <className>java.lang.Void</className>
                </factIdentifier>
                <expressionIdentifier>
                  <name>1|1</name>
                  <type>GIVEN</type>
                </expressionIdentifier>
              </FactMappingValue>
            </factMappingValues>
          </BackgroundData>
        </scesimData>
      </background>
      <settings>
        <dmnFilePath>src/main/resources/org/kie/example/traffic/traffic_violation/Traffic Violation.dmn</dmnFilePath>
        <type>DMN</type>
        <fileName></fileName>
        <dmnNamespace>https://github.com/kiegroup/drools/kie-dmn/_A4BCA8B8-CF08-433F-93B2-A2598F19ECFF</dmnNamespace>
        <dmnName>Traffic Violation</dmnName>
        <skipFromBuild>false</skipFromBuild>
        <stateless>false</stateless>
      </settings>
      <imports>
        <imports/>
      </imports>
    </ScenarioSimulationModel>

    XML 响应示例:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <response type="SUCCESS" msg="Test Scenario successfully executed">
          <scenario-simulation-result>
                <run-count>5</run-count>
                <ignore-count>0</ignore-count>
                <run-time>31</run-time>
          </scenario-simulation-result>
    </response>

第 73 章 使用示例 Mortgages 项目创建测试场景

本章演示了使用测试场景设计程序从 Business Central 提供的示例 Mortgages 项目创建并执行测试场景。本章中的测试场景示例基于 Mortgages 项目中的独立许可的决策表。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects 并点 Mortgages
  2. 如果项目没有在 Projects 下列出,从 MySpace 中,点 Try SamplesMortgagesOK

    此时会出现 Assets 窗口。

  3. Add AssetTest Scenario
  4. 输入 scenario_pricing_loans 作为 Test Scenario name,然后从 Package 下拉列表中选择默认的 mortgages.mortgages 软件包。

    您选择的软件包必须包含所有必需的规则资产。

  5. 选择 RULE 作为 Source 类型
  6. Ok 在测试场景设计程序中创建并打开测试场景。
  7. 展开 Project Explorer 并验证以下内容:

    • 是否存在 applicant、strisruptcyIncomeSourceLoanApplication 数据对象。
    • 存在 定价 loans 指导决策表。
    • 验证新测试场景是否列在 Test Scenario
  8. 验证所有内容是否已就位后,返回到测试场景设计器的 Model 选项卡,并根据可用的数据对象为场景定义 GIVENEXPECT 数据。

    图 73.1. 空白测试场景设计器

    测试场景空白预览编辑器
  9. 定义 GIVEN 列详情:

    1. GIVEN 列标题下,单击名为 INSTANCE 1 的单元。
    2. Test Tools 面板中,选择 LoanApplication 数据对象。
    3. 单击 Insert Data Object
  10. 要为数据对象创建属性,请右键点击属性标头单元,再根据需要选择 Insert 列右Insert 列。在本例中,您需要在 GIVEN 列下创建两个属性单元。
  11. 选择第一个属性标头单元:

    1. Test Tools 面板中,选择并扩展 LoanApplication 数据对象。
    2. 数量
    3. Insert Data Object 将 data 对象字段映射到属性标头单元。
  12. 选择第二个属性标头单元:

    1. Test Tools 面板中,选择并扩展 LoanApplication 数据对象。
    2. deposit
    3. 单击 Insert Data Object
  13. 选择第三个属性标头单元:

    1. Test Tools 面板中,选择并扩展 LoanApplication 数据对象。
    2. lengthYears
    3. 单击 Insert Data Object
  14. 右键点击 LoanApplication 标头单元,然后选择 Insert 列。右侧创建一个新的 GIVEN 列。
  15. 选择新的标头单元:

    1. Test Tools 面板中,选择 IncomeSource 数据对象。
    2. Insert Data Object 将数据对象映射到标头单元。
  16. 选择 IncomeSource 下的属性标头单元:

    1. Test Tools 面板中,选择并展开 IncomeSource 数据对象。
    2. 单击 类型
    3. Insert Data Object 将 data 对象字段映射到属性标头单元。

      您现在定义了所有 GIVEN 列单元。

  17. 接下来,定义 EXPECT 列详情:

    1. EXPECT 列标题下,单击名为 INSTANCE 2 的单元。
    2. Test Tools 面板中,选择 LoanApplication 数据对象。
    3. 单击 Insert Data Object
  18. 要为数据对象创建属性,请右键点击属性标头单元,再根据需要选择 Insert 列右Insert 列。在 EXPECT 列中创建两个属性单元。
  19. 选择第一个属性标头单元:

    1. Test Tools 面板中,选择并扩展 LoanApplication 数据对象。
    2. approved
    3. Insert Data Object 将 data 对象字段映射到属性标头单元。
  20. 选择第二个属性标头单元:

    1. Test Tools 面板中,选择并扩展 LoanApplication 数据对象。
    2. 单击 theCost
    3. Insert Data Object 将 data 对象字段映射到属性标头单元。
  21. 选择第三个属性标头单元:

    1. Test Tools 面板中,选择并扩展 LoanApplication 数据对象。
    2. approvedRate
    3. Insert Data Object 将 data 对象字段映射到属性标头单元。
  22. 要定义测试场景,请在第一行中输入以下数据:

    • 输入 Row 1 测试场景,作为 Scenario Description,150000 作为 数量,19000 作为 deposit,30 作为 lengthYears,以及 Asset 作为 GIVEN 列值 的类型
    • 输入 true 作为 批准的0 作为 mailboxCost2 作为 EXPECT 列值的批准。
  23. 接下来,在第二行中输入以下数据:

    • 输入 Row 2 测试场景,作为 Scenario Description,100002 作为 数量,2999 作为 deposit,20 作为 lengthYearsJob 作为 GIVEN 列值 的类型
    • 输入 true 作为 批准的10 作为 mailboxCost6 作为 EXPECT 列值的批准。
  24. 在定义了所有 GIVENEXPECT 和其他用于场景的数据后,单击测试方案设计器中的 Save 以保存您的工作。
  25. 单击右上角的 Run Test,以运行 .scesim 文件。

    测试结果显示在 Test Report 面板中。单击 View Alerts 以显示 Alerts 部分中的消息。如果测试失败,请参阅窗口底部的 Alerts 部分中的消息,检查并更正场景中的所有组件,然后重试验证场景直到场景通过为止。

  26. 在测试场景设计程序中,点 Save 在完成所有必要的更改后保存您的工作。

第 74 章 在 Business Central 中测试场景(传统)设计程序

Red Hat Process Automation Manager 目前支持新的 Test Scenarios 设计程序和之前的 测试场景(Legacy) 设计器。默认设计器是新的测试场景设计器,它支持测试规则和 DMN 模型,并提供测试场景的增强的整体用户体验。如果需要,您可以继续使用旧的测试场景设计程序,它只支持基于规则的测试场景。

74.1. 创建并运行测试场景(传统)

您可以在 Business Central 中创建测试场景,以在部署前测试新规则数据的功能。基本测试场景必须至少具有以下数据:

  • 相关数据对象
  • GIVEN 事实
  • EXPECT 结果
注意

传统测试场景设计器支持 LocalDate java 内置数据类型。您可以使用 dd-mmm-yyyy 日期格式的 LocalDate java 内置数据类型。例如,您可以使用 17-Oct-2020 日期格式进行设置。

使用这个数据,测试场景可以根据定义的事实验证该规则实例的预期和实际结果。您还可以向测试场景添加 CALL METHOD 以及任何可用的 全局范围,但这些场景设置是可选的。

流程

  1. 在 Business Central 中,进入 MenuDesignProjects,然后点击项目名称。
  2. Add AssetTest Scenarios (Legacy)
  3. 输入说明性 测试方案 名称并选择相应的 软件包。您指定的软件包必须是分配所需规则资产或将被分配相同的软件包。您可以将数据对象从任何软件包导入到资产的设计程序。
  4. Ok 创建测试场景。

    新的测试场景现在列在 Project ExplorerTest Scenarios 面板中,

  5. Data Objects 选项卡,验证您要测试的规则所需的所有数据对象是否已列出。如果没有,点 New item 从其他软件包导入所需的数据对象,或者 在软件包中创建数据对象
  6. 所有数据对象就位后,返回到测试场景设计器的 Model 选项卡,并根据可用的数据对象为场景定义 GIVENEXPECT 数据。

    图 74.1. 测试场景设计器

    测试场景编辑

    GIVEN 部分定义测试的输入事实。例如,如果在 21 的年龄下为 applicants 在项目 declines loan 应用程序中有一个 Under age 规则,那么测试场景中的 GIVEN 事实可能会适用于小于 21 的一些整数。

    EXPECT 部分根据 GIVEN 输入事实定义预期的结果。也就是说,GIVEN 输入事实 EXPECT 这些规则有效或整个规则被激活。例如,在场景的 21 年龄下给定应用程序事实(fact),EXPECT 结果可能是 LoanApplication,其 批准 设置为 false (因为部分应用的结果),也可以是整个 Underage 规则的激活。

  7. 另外,还可在测试场景中添加 CALL METHOD 和任何 全局

    • caLL METHOD : 在启动规则执行时,从另一个事实调用方法。点 CALL METHOD,选择一个事实,然后点击 6187 来选择要调用的方法。您可以从 Java 库或从为项目导入的 JAR 调用任何 Java 类方法(如来自 ArrayList 的方法)。
    • Globals : 使用它来在测试场景中验证的项目中添加任何全局变量。单击 globals 以选择要验证的变量,然后在测试场景设计器中,单击全局名称和定义字段值以应用到全局变量。如果没有全局变量可用,则必须在 Business Central 中作为新资产创建它们。全局变量是命名的对象,这些对象对决策引擎可见,但与对象不同以进行事实。全局对象的更改不会触发规则的重新评估。
  8. 点测试场景设计器底部的 More,根据需要将其他数据块添加到同一场景文件中。
  9. 在定义了所有 GIVENEXPECT 和其他用于场景的数据后,单击测试场景设计器中的 Save 以保存您的工作。
  10. 点右上角的 Run scenario 运行此 .scenario 文件,或者点击 Run all scenarios 在项目软件包中运行所有保存的 .scenario 文件(如果存在多个)。虽然 Run scenario 选项不需要保存单个 .scenario 文件,但 Run all scenarios 选项需要保存所有 .scenario 文件。

    如果测试失败,请解决窗口底部的 Alerts 消息中描述的任何问题,请查看场景中的所有组件,并尝试再次验证场景,直到场景通过为止。

  11. 在测试场景设计程序中,点 Save 在所有更改后保存您的工作。

74.1.1. 在测试场景中添加 GIVEN 事实(传统)

GIVEN 部分定义测试的输入事实。例如,如果在 21 的年龄下为 applicants 在项目 declines loan 应用程序中有一个 Under age 规则,那么测试场景中的 GIVEN 事实可能会适用于小于 21 的一些整数。

先决�件

  • 您的测试场景所需的所有数据对象已创建或导入,并在 Test Scenarios (Legacy) 设计器的 Data Objects 选项卡中列出。

�程

  1. Test Scenarios (Legacy) Designer 中,单击 GIVEN 以打开具有可用事实的新 输入 窗口。

    图 74.2. 在测试场景中添加 GIVEN 输入

    在测试场景中添加 GIVEN 输入

    该列表包括以下选项,具体取决于测试场景设计器的 Data Objects 选项卡中可用的数据对象:

    • 插入一个新事实: 使用它来添加事实并修改其字段值。输入事实的变量,作为 事实名称
    • 修改现有事实: (仅在添加另一个事实后应用)。) 使用这个选项指定要在执行场景之间的决策引擎中修改之前插入的事实。
    • 删除现有的事实: (仅在添加另一个事实后应用)。) 使用这个选项指定在执行场景之间从决策引擎中删除之前插入的事实。
    • 激活规则流组 : 使用它来指定要激活的规则流组,以便测试该组中的所有规则。
  2. 为所需输入选项选择一个事实,然后单击 Add。例如,将 Insert a new fact: 设置为 Applicant 并为 Fact 名称 输入 或 app 或任何其他变量。
  3. 单击测试场景设计器中的事实,再选择要修改的字段。

    图 74.3. 修改事实字段

    修改条件
  4. 点击编辑图标( 6191 )并从以下字段值中选择:

    • literal value : 创建一个 open 字段,在其中输入特定的字面值。
    • bound 变量: 将字段的值设置为绑定到所选变量的事实。字段类型必须与绑定的变量类型匹配。
    • 创建新事实 : 允许您创建新事实,并将其分配为父事实的字段值。然后,您可以在测试场景设计器中单击子事实,并同样分配字段值或嵌套其他事实。
  5. 继续为场景添加任何其他 GIVEN 输入数据,并在测试场景设计器中点 Save 来保存您的更改。

74.1.2. 添加 EXPECT 会导致测试场景(传统)

EXPECT 部分根据 GIVEN 输入事实定义预期的结果。也就是说,GIVEN 输入事实 EXPECT 其他指定的事实是有效的或整个规则。例如,在场景的 21 年龄下给定应用程序事实(fact),EXPECT 结果可能是 LoanApplication,其 批准 设置为 false (因为部分应用的结果),也可以是整个 Underage 规则的激活。

先决�件

  • 您的测试场景所需的所有数据对象已创建或导入,并在 Test Scenarios (Legacy) 设计器的 Data Objects 选项卡中列出。

�程

  1. Test Scenarios (Legacy) Designer 中,单击 EXPECT 以打开具有可用事实的新 预期 窗口。

    图 74.4. 在测试场景中添加 EXPECT 结果

    在测试场景中添加 EXPECT 结果

    该列表包括以下选项,具体取决于 GIVEN 部分中的数据以及测试场景设计器的 Data Objects 选项卡中可用的数据对象:

    • 规则: 使用它来在项目中指定预期因为 GIVEN 输入所激活的特定规则。键入应激活的规则的名称,或者从规则列表中选择,然后在测试场景设计程序中指定规则激活的次数。
    • 事实值 : 使用它来选择一个事实,并为它定义值,因为 GIVEN 部分中定义的事实而有效。事实由之前 GIVEN 输入定义的事实名称 列出。
    • 匹配的任何事实: 使用此选项验证至少一个带有指定的值的事实,因为 GIVEN 输入而存在。
  2. 为所需预期选择事实(如 事实值: 应用程序),然后单击 AddOK
  3. 单击测试场景设计器中的事实,再选择要添加的和修改字段。

    图 74.5. 修改事实字段

    修改事实字段
  4. 将字段值设置为预期因为 GIVEN 输入的结果(如 批准 | 等于 | false)而有效的值。

    注意

    在传统的测试场景设计程序中,您可以在 EXPECT 字段中使用 ["value1", "value2"] 字符串格式来验证字符串列表。

  5. 继续为场景添加任何其他 EXPECT 输入数据,并在测试场景设计程序中点 Save 来保存您的更改。
  6. 在定义并保存了所有 GIVENEXPECT 和其他用于场景的数据后,单击右上角的 Run scenario 以运行此 .scenario 文件,或者点击 Run all scenarios to run all saved .scenario 文件(如果存在多个)。虽然 Run scenario 选项不需要保存单个 .scenario 文件,但 Run all scenarios 选项需要保存所有 .scenario 文件。

    如果测试失败,请解决窗口底部的 Alerts 消息中描述的任何问题,请查看场景中的所有组件,并尝试再次验证场景,直到场景通过为止。

  7. 在测试场景设计程序中,点 Save 在所有更改后保存您的工作。

第 75 章 传统和新的测试场景设计程序的功能比较

Red Hat Process Automation Manager 支持新的测试场景设计程序和之前的测试场景(Legacy)设计程序。

默认设计器是新的测试场景设计器,它支持测试规则和 DMN 模型,并提供测试场景的整体用户体验。您可以继续使用旧的测试场景设计器,它只支持基于规则的测试场景。

重要

新的测试场景设计器改进了布局和功能集,并继续开发。但是,旧的测试场景设计程序在 Red Hat Process Automation Manager 7.3.0 中已弃用,并将在以后的 Red Hat Process Automation Manager 发行版本中删除。

下表重点介绍了传统和新的测试方案设计器的主要功能,它们是 Red Hat Process Automation Manager 支持的,以帮助您决定项目中合适的测试场景设计器。

  • + 表示该功能存在于测试场景设计程序中。
  • - 表示测试场景设计程序中没有该功能。

表 75.1. 传统和新的测试方案的主要特性

特性和亮点新的设计程序旧设计器Documentation

创建并运行测试场景

  • 您可以在 Business Central 中创建测试场景,以在部署前测试新规则数据的功能。
  • 基本测试场景必须至少具有相关的数据对象、GIVEN 事实和 EXPECT 结果。
  • 您可以运行测试来验证您的新规则和数据。

+

+

在测试场景中添加 GIVEN 事实

  • 您可以插入并验证用于测试的 GIVEN 事实。

+

+

添加 EXPECT 会导致测试场景

  • EXPECT 部分根据 GIVEN 输入事实定义预期的结果。
  • 它代表对象及其字段,它们的具体值会根据提供的信息进行检查。

+

+

KIE 会话

  • 您可以在测试场景级别设置中设置 KIE 会话。

+

+

�适用

KIE 基础基于测试场景级别

  • 您可以在测试场景级别设置上设置 KIE 基础。

-

+

�适用

KIE 基础基于项目级别

  • 您可以在项目级别设置上设置 KIE 基础。

+

+

�适用

模拟日期和时间

  • 您可以为旧的测试场景设计程序设置模拟的日期和时间。

-

+

�适用

规则流组

  • 您可以指定要激活的规则流组来测试该组中的所有规则。

+

+

全局变量

  • 全局变量是命名的对象,这些对象对决策引擎可见,但与对象不同以进行事实。
  • 为新测试场景设置全局变量已弃用。
  • 如果要为不同的场景重复使用数据集,您可以使用 Background 实例。

-

+

调用方法

  • 您可以在启动规则执行时,从另一个事实中调用方法。
  • 您可以从 Java 库或为项目导入的 JAR 调用任何 Java 类方法。

+

+

修改现有事实

  • 您可以在场景执行之间的决策引擎中修改之前插入的事实。

-

+

有关在测试场景中修改现有事实(传统)的更多信息,请参阅 第 74.1.1 节 “在测试场景中添加 GIVEN 事实(传统)”

bound 变量

  • 您可以将字段的值设置为绑定到所选变量的事实。
  • 在新的测试场景设计程序中,您无法在测试场景网格中定义变量,并在 GIVENEXPECTED 单元内重复使用它。

-

+

有关如何在测试场景中设置绑定变量(传统)的更多信息,请参阅 第 74.1.1 节 “在测试场景中添加 GIVEN 事实(传统)”

第 76 章 å��续步骤

打包和部署 Red Hat Process Automation Manager 项目

部分 IX. Red Hat Process Automation Manager 中的决策引擎

作为自定义规则开发人员,您了解 Red Hat Process Automation Manager 中的决策引擎可帮助您设计更有效的业务资产和更可扩展的决策管理架构。决策引擎是 Red Hat Process Automation Manager 组件,它存储、处理并评估数据来执行自定义规则,并达到您定义的决策。本文档描述了在 Red Hat Process Automation Manager 中创建必要规则系统和决策服务时需要考虑的决策引擎的基本概念和功能。

第 77 章 Red Hat Process Automation Manager 中的决策引擎

决策引擎是 Red Hat Process Automation Manager 中的容器引擎。决策引擎存储、处理并评估数据,以执行您定义的新规则或决策模型。决策引擎的基本功能是将传入数据或 事实 与规则条件匹配,并确定是否以及如何执行规则。

决策引擎使用以下基本组件运行:

  • 规则: 您定义的新规则或 DMN 决策。所有规则必须至少包含触发规则的条件,以及规则指定的操作。
  • 事实: 在决策引擎中输入或更改的数据,决策引擎与规则条件匹配来执行适用规则。
  • 生产环境内存: 将规则存储在决策引擎中的位置。
  • 工作内存 : 在决策引擎中保存事实的位置。
  • 办公室: 激活的规则的位置被注册并排序(如果适用)准备执行。

当业务用户或自动系统在 Red Hat Process Automation Manager 中添加或更新规则相关信息时,这些信息会以一个或多个事实的形式插入到决策引擎的工作内存中。决策引擎将这些事实与存储在生产内存中的规则条件匹配,以确定符合条件的规则执行。(此与规则匹配的事实过程通常被称为 模式匹配。) 满足规则条件后,决策引擎会在办公室中激活和注册规则,然后决策引擎然后对规则进行排序,以准备执行。

下图演示了决策引擎的这些基本组件:

图 77.1. 基本决策引擎组件概述

多集群引擎 inkscape enterprise

有关决策引擎中规则和事实行为的详情和示例,请参阅 第 79 章 决策引擎中的 inference 和 real Maintenance

这些核心概念可帮助您更好地了解决策引擎的其他更高级的组件、流程和子进程,并在 Red Hat Process Automation Manager 中设计更有效的业务资产。

第 78 章 KIE 会话

在 Red Hat Process Automation Manager 中,KIE 会话存储和执行运行时数据。如果您为项目定义了 KIE 模块描述符文件(kmodule.xml)中的 KIE 会话,则 KIE 会话是从 KIE 容器创建的 KIE 会话。

kmodule.xml 文件中的 KIE 会话配置示例

<kmodule>
  ...
  <kbase>
    ...
    <ksession name="KSession2_1" type="stateless" default="true" clockType="realtime">
    ...
  </kbase>
  ...
</kmodule>

KIE 基础是您在 KIE 模块描述符文件(kmodule.xml)中定义的存储库,包含 Red Hat Process Automation Manager 中的所有规则、进程和其他业务资产。

kmodule.xml 文件中的 KIE 基础配置示例

<kmodule>
  ...
  <kbase name="KBase2" default="false" eventProcessingMode="stream" equalsBehavior="equality" declarativeAgenda="enabled" packages="org.domain.pkg2, org.domain.pkg3" includes="KBase1">
    ...
  </kbase>
  ...
</kmodule>

KIE 会话可以是无状态或有状态的。在无状态 KIE 会话中,之前调用 KIE 会话(之前会话状态)的数据在会话调用之间被丢弃。在有状态 KIE 会话中,数据会被保留。您使用的 KIE 会话类型取决于您的项目要求,以及如何保留来自不同资产调用的数据。

78.1. 无状态 KIE 会话

无状态 KIE 会话是一个会话,它不会随着时间进行迭代更改。在无状态 KIE 会话中,之前调用 KIE 会话的数据(前面的会话状态)在会话调用之间丢弃,而在有状态 KIE 会话中,数据会被保留。无状态 KIE 会话的行为与一个功能相似,其生成的结果由 KIE 基础的内容决定,并由传递给 KIE 会话的数据,以便在特定时间点上执行。KIE 会话没有之前传递给 KIE 会话的任何数据的内存。

无状态 KIE 会话通常用于以下用例:

  • 验证,例如验证人是否有资格获得电池
  • 计算, 如计算一个月子(mortgage Premium)
  • 路由和过滤,例如将传入的电子邮件排序到文件夹中,或向目的地发送传入的电子邮件

例如,请考虑以下驱动程序的许可证数据模型和 DRL 规则示例:

驱动程序许可证应用程序的数据模型

public class Applicant {
  private String name;
  private int age;
  private boolean valid;
  // Getter and setter methods
}

驱动程序许可证应用程序的 DRL 规则示例

package com.company.license

rule "Is of valid age"
when
  $a : Applicant(age < 18)
then
  $a.setValid(false);
end

有效期限规则不限于 18 年以上的任何应用程序期限。当 Applicant 对象插入到决策引擎中时,决策引擎会评估每个规则的限制,并搜索匹配项。"objectType" 约束始终表示,之后评估任何数量的显式字段约束。变量 $a 是一个绑定变量,在规则结果中引用匹配对象。

注意

数字符号($)是可选的,有助于区分变量名称和字段名称。

在本例中,Red Hat Process Automation Manager 项目的 ~/resources 文件夹中的 ~/resources 文件夹中的示例规则和所有其他文件使用以下代码构建:

创建 KIE 容器

KieServices kieServices = KieServices.Factory.get();

KieContainer kContainer = kieServices.getKieClasspathContainer();

此代码编译类路径上找到的所有规则文件,并在 KieContainer 中添加此编译(一个 KieModule 对象)的结果。

最后,StatelessKieSession 对象从 KieContainer 实例化,并根据指定的数据执行:

实例化无状态 KIE 会话并输入数据

StatelessKieSession kSession = kContainer.newStatelessKieSession();

Applicant applicant = new Applicant("Mr John Smith", 16);

assertTrue(applicant.isValid());

ksession.execute(applicant);

assertFalse(applicant.isValid());

在无状态 KIE 会话配置中,exec () 调用充当实例化 KieSession 对象的组合方法,添加所有用户数据并执行用户数据,调用 fireAllRules (),然后调用 dispose ()。因此,使用无状态 KIE 会话,您不需要在会话调用有状态 KIE 会话后调用 fireAllRules () 或调用 dispose ()

在这种情况下,指定的 applicant 位于 18 的年龄下,因此应用程序会下降。

有关更复杂的用例,请参见以下示例。本例使用无状态 KIE 会话,并对可迭代的对象列表(如集合)执行规则。

为驱动程序许可证应用程序扩展数据模型

public class Applicant {
  private String name;
  private int age;
  // Getter and setter methods
}

public class Application {
  private Date dateApplied;
  private boolean valid;
  // Getter and setter methods
}

为驱动程序许可证应用程序展开的 DRL 规则集

package com.company.license

rule "Is of valid age"
when
  Applicant(age < 18)
  $a : Application()
then
  $a.setValid(false);
end

rule "Application was made this year"
when
  $a : Application(dateApplied > "01-jan-2009")
then
  $a.setValid(false);
end

在无状态 KIE 会话中扩展 Java 源

StatelessKieSession ksession = kbase.newStatelessKnowledgeSession();
Applicant applicant = new Applicant("Mr John Smith", 16);
Application application = new Application();

assertTrue(application.isValid());
ksession.execute(Arrays.asList(new Object[] { application, applicant }));  1
assertFalse(application.isValid());

ksession.execute
  (CommandFactory.newInsertIterable(new Object[] { application, applicant }));  2

List<Command> cmds = new ArrayList<Command>();  3
cmds.add(CommandFactory.newInsert(new Person("Mr John Smith"), "mrSmith"));
cmds.add(CommandFactory.newInsert(new Person("Mr John Doe"), "mrDoe"));

BatchExecutionResults results = ksession.execute(CommandFactory.newBatchExecution(cmds));
assertEquals(new Person("Mr John Smith"), results.getValue("mrSmith"));

1
Arrays.asList () 方法生成的对象的可迭代集合执行规则的方法。每个集合元素都会在执行任何匹配规则前插入。execute (Object object) 和执行(Iterable objects) 方法围绕来自 BatchExecutor 接口的 execute (Command command) 方法进行包装程序。
2
使用 CommandFactory 接口执行可划分的对象集合。
3
BatchExecutorCommandFactory 配置,用于处理许多不同的命令或结果输出标识符。CommandFactory 接口支持您可以在 BatchExecutor 中使用的其他命令,如 StartProcessQuerySetGlobal

78.1.1. 无状态 KIE 会话中的全局变量

StatelessKieSession 对象支持全局变量(全局),您可以将它们配置为作为会话范围的全局范围、委派全局或执行范围全局。

  • 会话范围全局: 对于会话范围全局,您可以使用方法 get Globals () 返回提供对 KIE 会话全局访问权限的 Globals 实例。这些全局组用于所有执行调用。请谨慎与可变全局使用,因为可以在不同的线程中同时执行调用。

    会话范围全局

    import org.kie.api.runtime.StatelessKieSession;
    
    StatelessKieSession ksession = kbase.newStatelessKieSession();
    
    // Set a global `myGlobal` that can be used in the rules.
    ksession.setGlobal("myGlobal", "I am a global");
    
    // Execute while resolving the `myGlobal` identifier.
    ksession.execute(collection);

  • 委托 全局: 为了委托全局值,您可以为全局分配值(使用 setGlobal (String, Object)),以便该值存储在将标识符映射到值的内部集合中。此内部集合中的标识符优先于任何提供的委托。如果无法在此内部集合中找到标识符,则使用委派全局(若有)。
  • 执行范围全局: 对于执行范围全局,您可以使用 Command 对象设置传递给 CommandExecutor 接口以进行特定执行的全局解析。

CommandExecutor 接口还允许您使用全局、插入的事实和查询结果的标识符导出数据:

超出全局、插入的事实和查询结果的标识符

import org.kie.api.runtime.ExecutionResults;

// Set up a list of commands.
List cmds = new ArrayList();
cmds.add(CommandFactory.newSetGlobal("list1", new ArrayList(), true));
cmds.add(CommandFactory.newInsert(new Person("jon", 102), "person"));
cmds.add(CommandFactory.newQuery("Get People" "getPeople"));

// Execute the list.
ExecutionResults results = ksession.execute(CommandFactory.newBatchExecution(cmds));

// Retrieve the `ArrayList`.
results.getValue("list1");
// Retrieve the inserted `Person` fact.
results.getValue("person");
// Retrieve the query as a `QueryResults` instance.
results.getValue("Get People");

78.2. 有状态 KIE 会话

有状态 KIE 会话是一个会话,用于随着时间的推移对事实进行迭代更改。在有状态 KIE 会话中,之前调用 KIE 会话(之前的会话状态)的数据会在会话调用之间保留,而在无状态 KIE 会话中,数据将被丢弃。

警告

在运行有状态 KIE 会话后,请确保调用 dispose () 方法,以便在会话调用之间没有内存泄漏。

有状态 KIE 会话通常用于以下用例:

  • 监控,如监控库存市场并自动化销售流程
  • 诊断,如运行错误查找进程或诊断诊断过程
  • 日志流,如 parcel 跟踪和交付配置
  • 确保合规性,例如验证市场的法律性

例如,请考虑以下触发的警报数据模型和 DRL 规则示例:

sprinklers 的数据模型并触发警报

public class Room {
  private String name;
  // Getter and setter methods
}

public class Sprinkler {
  private Room room;
  private boolean on;
  // Getter and setter methods
}

public class Fire {
  private Room room;
  // Getter and setter methods
}

public class Alarm { }

激活 sprinklers 和警报的 DRL 规则集示例

rule "When there is a fire turn on the sprinkler"
when
  Fire($room : room)
  $sprinkler : Sprinkler(room == $room, on == false)
then
  modify($sprinkler) { setOn(true) };
  System.out.println("Turn on the sprinkler for room "+$room.getName());
end

rule "Raise the alarm when we have one or more fires"
when
    exists Fire()
then
    insert( new Alarm() );
    System.out.println( "Raise the alarm" );
end

rule "Cancel the alarm when all the fires have gone"
when
    not Fire()
    $alarm : Alarm()
then
    delete( $alarm );
    System.out.println( "Cancel the alarm" );
end


rule "Status output when things are ok"
when
    not Alarm()
    not Sprinkler( on == true )
then
    System.out.println( "Everything is ok" );
end

对于发生 触发时,会打开 sprinkler 规则,当发生触发时,会为该空间创建 Fire 类的实例,并插入到 KIE 会话中。规则为 Fire 实例中的特定 空间 添加一个约束,以便仅检查该房间的 sprinkler。当执行此规则时,sprinkler 会激活。其他示例规则决定何时激活或取消激活警报。

无状态 KIE 会话依赖于标准 Java 语法来修改字段,而有状态 KIE 会话依赖于规则中的 modify 语句来通知变化的决策引擎。然后,决策引擎会对更改和评估影响后续规则执行的原因。此过程是决策引擎使用 inference事实维护 的一部分,在有状态 KIE 会话中非常重要。

在本例中,Red Hat Process Automation Manager 项目的 ~/resources 文件夹中的示例规则和所有其他文件会使用以下代码构建:

创建 KIE 容器

KieServices kieServices = KieServices.Factory.get();
KieContainer kContainer = kieServices.getKieClasspathContainer();

此代码编译类路径上找到的所有规则文件,并在 KieContainer 中添加此编译(一个 KieModule 对象)的结果。

最后,Ki eSession 对象从 KieContainer 实例化,并根据指定的数据执行:

实例化有状态 KIE 会话并输入数据

KieSession ksession = kContainer.newKieSession();

String[] names = new String[]{"kitchen", "bedroom", "office", "livingroom"};
Map<String,Room> name2room = new HashMap<String,Room>();
for( String name: names ){
    Room room = new Room( name );
    name2room.put( name, room );
    ksession.insert( room );
    Sprinkler sprinkler = new Sprinkler( room );
    ksession.insert( sprinkler );
}

ksession.fireAllRules();

�制�输出

> Everything is ok

添加数据后,决策引擎完成所有模式匹配但没有执行规则,因此会显示配置的验证消息。随着新数据触发规则条件,决策引擎执行规则来激活警报,并稍后取消已激活的警报:

输入新数据来触发规则

Fire kitchenFire = new Fire( name2room.get( "kitchen" ) );
Fire officeFire = new Fire( name2room.get( "office" ) );

FactHandle kitchenFireHandle = ksession.insert( kitchenFire );
FactHandle officeFireHandle = ksession.insert( officeFire );

ksession.fireAllRules();

�制�输出

> Raise the alarm
> Turn on the sprinkler for room kitchen
> Turn on the sprinkler for room office

ksession.delete( kitchenFireHandle );
ksession.delete( officeFireHandle );

ksession.fireAllRules();

�制�输出

> Cancel the alarm
> Turn off the sprinkler for room office
> Turn off the sprinkler for room kitchen
> Everything is ok

在这种情况下,为返回的 FactHandle 对象保留一个引用。事实处理是对插入实例的内部引擎引用,并允许以后重新处理或修改实例。

如本例所示,来自之前有状态 KIE 会话的数据和结果(激活的警报)会影响后续会话的调用(固定)。

78.3. KIE 会话池

在有大量 KIE 运行时数据和高系统活动的用例中,可能会创建并经常发生 KIE 会话。KIE 会话的大量消耗并非总是消耗时间,但当重复电池时,该过程可能会成为瓶颈,需要大量清理工作。

对于这些高容量情况,您可以使用 KIE 会话池,而不是多个单独的 KIE 会话。要使用 KIE 会话池,您可以从 KIE 容器获取 KIE 会话池,定义池中 KIE 会话的初始数量,并照常从该池中创建 KIE 会话:

KIE 会话池示例

// Obtain a KIE session pool from the KIE container
KieContainerSessionsPool pool = kContainer.newKieSessionsPool(10);

// Create KIE sessions from the KIE session pool
KieSession kSession = pool.newKieSession();

在本例中,KIE 会话池从 10 KIE 会话开始,但您可以指定您需要的 KIE 会话数量。这个整数值是仅初始在池中创建的 KIE 会话数。如果正在运行的应用程序需要,池中的 KIE 会话数量可能会动态增长超过该值。

定义了 KIE 会话池后,下次使用 KIE 会话,并经常调用 dispose (),则 KIE 会话会被重置并推送回池,而不是被销毁。

KIE 会话池通常适用于有状态 KIE 会话,但 KIE 会话池也可以影响您与多个 execute () 调用重复使用的无状态 KIE 会话。当您直接从 KIE 容器创建无状态 KIE 会话时,KIE 会话将继续在内部为每个 execute () 调用创建一个新的 KIE 会话。相反,当您从 KIE 会话池中创建无状态 KIE 会话时,KIE 会话内部只使用池提供的特定 KIE 会话。

使用 KIE 会话池完成后,您可以调用 shutdown () 方法以避免内存泄漏。或者,您可以在 KIE 容器上调用 dispose () 来关闭从 KIE 容器创建的所有池。

第 79 章 决策引擎中的 inference 和 real Maintenance

决策引擎的基本功能是将数据与新规则匹配,并确定是否以及如何执行规则。为确保将相关数据应用到适当的规则,决策引擎根据现有知识进行差异,并根据推断的信息执行操作。

例如,以下 DRL 规则决定了 adults 的年龄要求,比如在总线传递策略中:

定义年龄要求的规则

rule "Infer Adult"
when
  $p : Person(age >= 18)
then
  insert(new IsAdult($p))
end

根据此规则,决策引擎会推断人是行为还是子级,并执行指定的操作( 然后是结果 )。每个存在 18 年或更早的人都会在其工作内存中插入了 IsAdult 实例。然后,可以在任何规则中调用年龄和总线传递的关系,例如在以下规则片段中:

$p : Person()
IsAdult(person == $p)

在很多情况下,规则系统中的新数据是其他规则执行的结果,这种新数据可能会影响对其他规则的执行。如果作为执行规则而决策引擎数据,则决策引擎将使用真实维护来证明断言并在将信息应用到其他规则时强制实施真实性。实时维护还有助于识别不一致和处理拥塞。例如,如果执行两个规则并导致持续操作,则决策引擎会根据之前计算的方中的假设选择操作。

决策引擎使用声明或逻辑插入插入事实:

  • 上述插入: 使用 insert () 定义。在声明了插入后,通常会明确回收事实。(一般使用术语 插入.
  • 逻辑插入: 使用 insertLogical () 定义.逻辑插入后,插入的事实会在插入事实的规则中的条件不再满足满足时自动响应。当没有条件支持逻辑插入时,会重新传输事实。逻辑插入的事实被视为由 决策 引擎表示。

例如,以下示例 DRL 规则使用上述事实插入来确定发出子总线传递或 adult 总线传递的年龄要求:

发布总线传递的规则,声明插入

rule "Issue Child Bus Pass"
when
  $p : Person(age < 18)
then
  insert(new ChildBusPass($p));
end

rule "Issue Adult Bus Pass"
when
  $p : Person(age >= 18)
then
  insert(new AdultBusPass($p));
end

这些规则无法在决策引擎中轻松维护,因为总线 riders 在年龄内增加,并从子总线移到 adult 总线通过。作为替代方案,这些规则可以使用逻辑事实插入将这些规则分成总线 rider 年龄和规则,以用于总线传递类型。事实的逻辑插入使事实取决于 when 子句的真实情况。

以下 DRL 规则使用逻辑插入来确定子项和程序的年龄要求:

子项和临时年龄要求、逻辑插入

rule "Infer Child"
when
  $p : Person(age < 18)
then
  insertLogical(new IsChild($p))
end

rule "Infer Adult"
when
  $p : Person(age >= 18)
then
  insertLogical(new IsAdult($p))
end

重要

对于逻辑插入,您的事实对象必须根据 Java 标准覆盖 java.lang.Object 对象中的等同和 hashCode 方法。如果两个对象相互返回 true,且其 hashCode 方法返回相同的值,则两个对象是相等的。如需更多信息,请参阅 Java 版本的 Java API 文档。

当规则中的条件为 false 时,会自动重新传输事实。这个行为在本示例中很有用,因为两个规则是互斥的。在这个示例中,如果人员存在时间超过 18 年,则规则逻辑地插入了 IsChild 事实。人员为 18 年或更早的版本后,S raeChild 事实会自动重新处理,并插入 IsAdult 事实。

然后,以下 DRL 规则决定是否发出子总线通过还是一个临时总线通过,并逻辑插入 ChildBusPassAdultBusPass 事实。此规则配置是可能的,因为决策引擎中的事实维护系统支持对一组级联重新发送的逻辑插入链。

签发总线通过的规则,逻辑插入

rule "Issue Child Bus Pass"
when
  $p : Person()
    IsChild(person == $p)
then
  insertLogical(new ChildBusPass($p));
end

rule "Issue Adult Bus Pass"
when
  $p : Person()
    IsAdult(person =$p)
then
  insertLogical(new AdultBusPass($p));
end

当一个人接近 18 年时,会重新利用了 IsChild 事实和个人的 ChildBusPass 事实。对于这些条件,您可以关联另一个规则,说明个人在打开 18 年后必须返回子通过。当决策引擎自动重新遍历 ChildBusPass 对象时,将执行以下规则向人发送请求:

通知总线通过拥有者的新传递的规则

rule "Return ChildBusPass Request"
when
  $p : Person()
    not(ChildBusPass(person == $p))
then
  requestChildBusPass($p);
end

以下流图演示了声明和逻辑插入的生命周期:

图 79.1. 声明的插入

声明的断言企业

图 79.2. 逻辑插入

逻辑断言企业

当在规则执行期间以逻辑方式插入对象时,决策引擎通过执行规则来说明对象。对于每个逻辑插入,只能有一个相等的对象,每个后续相同的逻辑插入会增加该逻辑插入的简化计数器。当规则条件变为 untrue 时,会删除说明。如果没有更多原因,则会自动重新处理逻辑对象。

79.1. 决策引擎中的事实相等模式

决策引擎支持以下事实相等模式,它们决定了决策引擎如何存储和比较插入的事实:

  • 身份 :(默认)决策引擎使用 IdentityHashMap 来存储所有插入的事实。对于每个新事实插入,决策引擎会返回一个新的 factHandle 对象。如果再次插入事实,决策引擎会返回原始的 factHandle 对象,忽略同一事实的重复插入。在这个模式中,只有当它们具有相同的身份时,决策引擎的两个事实才相同。
  • 相等 : 决策引擎使用 HashMap 来存储所有插入的事实。只有在插入的事实不等于现有事实() 方法时,决策引擎才会返回一个新的 fact Handle 对象。在这个模式中,无论身份是什么,决策引擎的两种事实与决策引擎相同。当您希望根据功能相等而不是显式身份评估对象时,请使用此模式。

作为事实相等模式的一个说明,请考虑以下示例事实:

事实示例

Person p1 = new Person("John", 45);
Person p2 = new Person("John", 45);

身份 模式中,fact p1p2Person 类的不同实例,并被视为单独的对象,因为它们有单独的身份。在 相等 模式下,事实 p1p2 被视为同一对象,因为它们以相同的方式组成。这个行为差异会影响您可以如何与事实处理进行交互。

例如,假设您将事实 p1p2 插入到决策引擎中,您要检索 p1 的事实处理。在 身份 模式中,您必须指定 p1 来返回该精确对象的事实处理,而在 相等 模式下,您可以指定 p1、p2新的 Person ("John", 45) 来返回事实句柄。

插入事实代码并在 身份 模式下返回事实句柄的示例

ksession.insert(p1);

ksession.getFactHandle(p1);

插入事实和以 相等 模式返回事实句柄的代码示例

ksession.insert(p1);

ksession.getFactHandle(p1);

// Alternate option:
ksession.getFactHandle(new Person("John", 45));

要设置事实相等模式,请使用以下选项之一:

  • 将系统属性 drools.equalityBehavior 设置为 identity (默认)或 相等性
  • 在以编程方式创建 KIE 基础时设置相等模式:

    KieServices ks = KieServices.get();
    KieBaseConfiguration kieBaseConf = ks.newKieBaseConfiguration();
    kieBaseConf.setOption(EqualityBehaviorOption.EQUALITY);
    KieBase kieBase = kieContainer.newKieBase(kieBaseConf);
  • 在 KIE 模块描述符文件(kmodule.xml)中为特定的 Red Hat Process Automation Manager 项目设置相等模式:

    <kmodule>
      ...
      <kbase name="KBase2" default="false" equalsBehavior="equality" packages="org.domain.pkg2, org.domain.pkg3" includes="KBase1">
        ...
      </kbase>
      ...
    </kmodule>

第 80 章 在决策引擎中执行控制

当新规则数据进入决策引擎的工作内存时,规则可能会完全匹配并有资格执行。单个工作内存操作可能会导致多个有资格的规则执行。当规则完全匹配时,决策引擎会创建一个激活实例,引用规则和匹配的事实,并将激活添加到决策引擎计划中。用户使用冲突解析策略来控制这些规则激活的执行顺序。

在 Java 应用程序中第一次调用 fireAllRules () 后,决策引擎周期会重复到两个阶段:

  • 参与评估。在此阶段,决策引擎会选择可执行的所有规则。如果没有可执行规则,则执行周期将结束。如果找到可执行规则,则决策引擎会在电缆中注册激活,然后进入工作的内存操作阶段来执行规则结果操作。
  • 操作内存操作。在此阶段,决策引擎会对之前在电话中注册的所有激活的规则执行规则结果操作(每个规则部分)。完成所有结果操作后,或者主 Java 应用程序进程调用 fireAllRules () 再次调用 fireAllRules (),决策引擎将返回到销售评估阶段以重新处理规则。

图 80.1. 决策引擎中的两阶段执行过程

两个阶段企业

当电话上存在多个规则时,一个规则的执行可能会导致另一个规则从电缆中删除。要避免这种情况,您可以定义如何在决策引擎中执行规则。定义规则执行顺序的一些常见方法是,使用规则 salience、Mitment group、激活组或 DRL 规则集的规则单元。

80.1. 规则的 Salience

每个规则都有一个整数 salience 属性,用于决定执行顺序。在激活队列中排序时,具有较高 salience 值的规则会被赋予更高的优先级。规则的默认 salience 值为零,但 salience 可以是负数或正数。

例如,以下 DRL 规则示例列在决策引擎堆栈中,按所示的顺序列出:

rule "RuleA"
salience 95
when
    $fact : MyFact( field1 == true )
then
    System.out.println("Rule2 : " + $fact);
    update($fact);
end

rule "RuleB"
salience 100
when
   $fact : MyFact( field1 == false )
then
   System.out.println("Rule1 : " + $fact);
   $fact.setField1(true);
   update($fact);
end

RuleB 规则列出第二个,但它的 salience 值高于 RuleA 规则,因此首先执行。

80.2. 规则的电缆组

电缆组是一组规则,由相同的 sales -group rule 属性绑定在一起。在决策引擎动机上对分区规则进行分组。在任何时间点上,只有一个组具有 重点,为在其他销售组的规则之前执行的一组规则优先级。您确定对 sales 组的 setFocus () 调用。您还可以使用 auto-focus 属性定义规则,以便在下次激活规则时,重点会自动提供给分配该规则的整个电缆组。

每次在 Java 应用程序中发出 setFocus () 调用时,决策引擎会将指定的 sales 组添加到规则堆栈的顶部。默认电缆组 "MAIN" 包含所有不属于指定 leader 组的规则,除非另一个组具有重点,否则首先在堆栈中执行。

例如,以下示例 DRL 规则属于指定的电缆组,按所示的顺序在决策引擎堆栈中列出:

指导应用程序的 DRL 规则示例

rule "Increase balance for credits"
  agenda-group "calculation"
when
  ap : AccountPeriod()
  acc : Account( $accountNo : accountNo )
  CashFlow( type == CREDIT,
            accountNo == $accountNo,
            date >= ap.start && <= ap.end,
            $amount : amount )
then
  acc.balance  += $amount;
end

rule "Print balance for AccountPeriod"
  agenda-group "report"
when
  ap : AccountPeriod()
  acc : Account()
then
  System.out.println( acc.accountNo +
                      " : " + acc.balance );
end

在本例中,必须始终首先执行 "报告" 模拟组中的规则,并且 "计算"模拟 组中的规则必须始终执行第二个。然后,可以执行其他销售组中的所有规则。因此,"报告 "和"计算" 组必须按照该顺序执行,然后才能执行其他规则:

为销售组执行顺序设置重点

Agenda agenda = ksession.getAgenda();
agenda.getAgendaGroup( "report" ).setFocus();
agenda.getAgendaGroup( "calculation" ).setFocus();
ksession.fireAllRules();

您还可以使用 clear () 方法取消属于给定电缆组的规则生成的所有激活,然后才能执行:

取消所有其他规则激活

ksession.getAgenda().getAgendaGroup( "Group A" ).clear();

80.3. 规则激活组

激活组是由相同的 activation-group rules 属性绑定的一组规则。在这个组中,只能执行一条规则。在满足该组中某个规则的条件后,将从该激活组中删除所有其他待处理规则执行。

例如,以下示例 DRL 规则属于指定的激活组,按所示的顺序在决策引擎堆栈中列出:

用于参与的 DRL 规则示例

rule "Print balance for AccountPeriod1"
  activation-group "report"
when
  ap : AccountPeriod1()
  acc : Account()
then
  System.out.println( acc.accountNo +
                      " : " + acc.balance );
end

rule "Print balance for AccountPeriod2"
  activation-group "report"
when
  ap : AccountPeriod2()
  acc : Account()
then
  System.out.println( acc.accountNo +
                      " : " + acc.balance );
end

在本例中,如果执行 "报告" 激活组中的第一个规则,则组中的第二个规则以及办公室上的所有其他可执行文件规则将从电缆中移除。

80.4. 在决策引擎中的规则执行模式和线程安全

决策引擎支持以下规则执行模式,用于决定决策引擎如何和何时执行规则:

  • 被动模式 :(默认)当用户或应用显式调用 fireAllRules () 时,决策引擎评估规则。决策引擎中的被动模式最适合需要直接控制规则评估和执行的应用程序,或者用于使用决策引擎中伪时钟实现的复杂事件处理(CEP)应用程序。

    带有被动模式的决策引擎的 CEP 应用程序代码示例

    KieSessionConfiguration config = KieServices.Factory.get().newKieSessionConfiguration();
    config.setOption( ClockTypeOption.get("pseudo") );
    KieSession session = kbase.newKieSession( conf, null );
    SessionPseudoClock clock = session.getSessionClock();
    
    session.insert( tick1 );
    session.fireAllRules();
    
    clock.advanceTime(1, TimeUnit.SECONDS);
    session.insert( tick2 );
    session.fireAllRules();
    
    clock.advanceTime(1, TimeUnit.SECONDS);
    session.insert( tick3 );
    session.fireAllRules();
    
    session.dispose();

  • Active 模式 :如果用户或应用程序调用 fireUntilHalt (),决策引擎以 active 模式启动,并持续评估规则,直到用户或应用程序显式调用 halt ()。决策引擎中的活跃模式最适合将规则评估和执行控制委派给决策引擎,或用于在决策引擎中使用实时时钟实现的复杂事件处理(CEP)应用程序。Active 模式也是使用活跃查询的 CEP 应用程序的最佳模式。

    在活跃模式下带有决策引擎的 CEP 应用程序代码示例

    KieSessionConfiguration config = KieServices.Factory.get().newKieSessionConfiguration();
    config.setOption( ClockTypeOption.get("realtime") );
    KieSession session = kbase.newKieSession( conf, null );
    
    new Thread( new Runnable() {
      @Override
      public void run() {
          session.fireUntilHalt();
      }
    } ).start();
    
    session.insert( tick1 );
    
    ... Thread.sleep( 1000L ); ...
    
    session.insert( tick2 );
    
    ... Thread.sleep( 1000L ); ...
    
    session.insert( tick3 );
    
    session.halt();
    session.dispose();

    这个示例从专用执行线程调用 fireUntilHalt (),以防止在决策引擎继续评估规则时无限期阻止当前线程。专用线程还允许您在应用程序代码的后续阶段调用 halt ()

虽然您应该避免使用 fireAllRules ()fireUntilHalt () 调用,特别是来自不同线程,但决策引擎可以使用线程安全逻辑和内部状态机器安全地处理这样的情况。如果 fireAllRules () 调用正在进行中,并且您调用 fireUntilHalt (),则决策引擎将继续以被动模式运行,直到 fireAllRules () 操作完成,然后以主动模式运行以响应 fireUntilHalt () 调用。但是,如果决策引擎在 fireUntilHalt () 调用后以活跃模式运行,并且调用 fireAllRules (),则 fireAllRules () 调用将被忽略,并且决策引擎在调用 halt () 之前继续运行。

对于以活跃模式添加线程安全性,决策引擎支持 提交() 方法,您可以在线程安全、原子操作中对 KIE 会话进行分组和执行操作:

带有 commit () 方法的应用程序代码示例,用于在主动模式下执行原子操作

KieSession session = ...;

new Thread( new Runnable() {
  @Override
  public void run() {
      session.fireUntilHalt();
  }
} ).start();

final FactHandle fh = session.insert( fact_a );

... Thread.sleep( 1000L ); ...

session.submit( new KieSession.AtomicAction() {
  @Override
  public void execute( KieSession kieSession ) {
    fact_a.setField("value");
    kieSession.update( fh, fact_a );
    kieSession.insert( fact_1 );
    kieSession.insert( fact_2 );
    kieSession.insert( fact_3 );
  }
} );

... Thread.sleep( 1000L ); ...

session.insert( fact_z );

session.halt();
session.dispose();

从客户端角度而言,线程安全性和原子操作也很有用。例如,您可能需要在给定时间插入多个事实,但需要决策引擎将插入操作视为原子操作,并等待所有插入完成,然后再重新评估规则。

80.5. 决策引擎中的事实传播模式

决策引擎支持以下事实传播模式,它决定了决策引擎如何通过引擎网络完成插入的事实以准备规则执行:

  • lazy :(默认)事实会在规则执行时传播到批处理集合中,而不是实时传播,因为事实由用户或应用程序单独插入。因此,最终通过决策引擎传播事实的顺序可能与事实单独插入的顺序不同。
  • 即时 :日志会以用户或应用程序插入的顺序立即传播。
  • eager :事实将无限期传播(在批处理集合中),但在规则执行前。决策引擎将此传播行为用于具有 no-looplock-on-active 属性的规则。

默认情况下,决策引擎中的 Phreak 规则算法使用 lazy 事实传播来改进规则评估。然而,在一些情况下,这种 lazy 传播行为可能会改变某些需要立即或 eager 传播的规则执行的预期结果。

例如,以下规则使用带有 ? 前缀的指定的查询,以仅拉取或被动方式调用查询:

带有被动查询的规则示例

query Q (Integer i)
    String( this == i.toString() )
end

rule "Rule"
  when
    $i : Integer()
    ?Q( $i; )
  then
    System.out.println( $i );
end

在本例中,只有在满足查询的 StringInteger 前插入查询时,才应执行该规则,如下例所示:

应该触发规则执行的命令示例

KieSession ksession = ...
ksession.insert("1");
ksession.insert(1);
ksession.fireAllRules();

但是,由于 Phreak 中的默认 lazy 传播行为,决策引擎不会检测到两个事实的插入序列,因此无论 StringInteger 插入顺序是什么,都会执行该规则。在本例中,预期规则评估需要立即传播。

要更改决策引擎传播模式以实现预期的规则评估,您可以在规则中添加 @Propagation (<type>) 标签,并将 < type > 设置为 LAZYIMMEDIATEEAGER

在同一示例规则中,只有在 Integer 之前插入查询的字符串时,才会对规则进行评估,如预期所示:

带有被动查询和指定的传播模式的规则示例

query Q (Integer i)
    String( this == i.toString() )
end

rule "Rule" @Propagation(IMMEDIATE)
  when
    $i : Integer()
    ?Q( $i; )
  then
    System.out.println( $i );
end

80.6. 参与评估过滤器

决策引擎在过滤器接口中支持 AgendaFilter 对象,可用于在评估期间允许或拒绝指定规则的评估。作为 fireAllRules () 调用的一部分,您可以指定 salesAllRules ()。

以下示例代码只允许以字符串 "Test" 结尾的规则被评估并执行。所有其他规则都根据决策引擎人员进行过滤。

电缆过滤器定义示例

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

80.7. DRL 规则集中的规则单元

规则单元是数据源、全局变量和 DRL 规则组,适用于特定目的。您可以使用规则单元将规则集分区为较小的单元,将不同的数据源绑定到这些单元,然后执行单个单元。规则单元是规则组 DRL 属性的增强替代方案,如规则电缆组或执行控制的激活组。

当您要协调规则执行时,规则单元很有用,以便一个规则单元的完整执行会触发另一个规则单元的开始等。例如,假设您有一组用于数据增强的规则、处理该数据的一组规则,以及从处理的数据中提取输出的另一组规则。如果将这些规则集添加到三个不同的规则单元中,您可以协调这些规则单元,以便完成第一单元的执行会触发第二个单元的开始,第二个单元的完整执行会触发第三个单元的开始。

要定义规则单元,实施 RuleUnit 接口,如下例所示:

规则单元类示例

package org.mypackage.myunit;

public static class AdultUnit implements RuleUnit {
    private int adultAge;
    private DataSource<Person> persons;

    public AdultUnit( ) { }

    public AdultUnit( DataSource<Person> persons, int age ) {
        this.persons = persons;
        this.age = age;
    }

    // A data source of `Persons` in this rule unit:
    public DataSource<Person> getPersons() {
        return persons;
    }

    // A global variable in this rule unit:
    public int getAdultAge() {
        return adultAge;
    }

    // Life-cycle methods:
    @Override
    public void onStart() {
        System.out.println("AdultUnit started.");
    }

    @Override
    public void onEnd() {
        System.out.println("AdultUnit ended.");
    }
}

在本例中,人员 是类型为 Person 的事实来源。规则单元数据源是由给定规则单元处理的数据来源,代表决策引擎用于评估规则单元的入口点。adultAge 全局变量可从属于此规则单元的所有规则访问。最后两种方法是规则单元生命周期的一部分,由决策引擎调用。

决策引擎支持以下可选生命周期方法用于规则单元:

表 80.1. 规则单元生命周期方法

方法调用的时间

onStart()

规则单元执行开始

onEnd()

规则单元执行结束

onSuspend()

规则单元执行暂停(仅用于 runUntilHalt ()

onResume()

规则单元执行会被恢复(仅用于 runUntilHalt ()

onYield (RuleUnit other)

规则单元中规则的结果会触发执行不同的规则单元

您可以在规则单元中添加一个或多个规则。默认情况下,DRL 文件中的所有规则都与遵循 DRL 文件名命名约定的规则单元自动关联。如果 DRL 文件位于同一软件包中,且名称与实现 RuleUnit 接口的类相同,则 DRL 文件中的所有规则都会隐式属于该规则单元。例如,org.mypackage.myunit 软件包中的 AdultUnit.drl 文件中的所有规则都自动是规则单元 org.mypackage.myunit.AdultUnit 的一部分。

要覆盖此命名惯例并明确声明 DRL 文件中的规则单元,请使用 DRL 文件中的 unit 关键字。单元 声明必须立即遵循 package 声明,并包含 DRL 文件中规则所属的类名称。

DRL 文件中的规则单元声明示例

package org.mypackage.myunit
unit AdultUnit

rule Adult
  when
    $p : Person(age >= adultAge) from persons
  then
    System.out.println($p.getName() + " is adult and greater than " + adultAge);
end

警告

不要混合同一 KIE 基础中的规则单元和没有规则单元。将两个规则组合在 KIE 基础中会导致编译错误。

您还可以使用 OOPath 表示法以更方便的方式重写相同的模式,如下例所示:

使用 OOPath 表示法的 DRL 文件中的规则单元声明示例

package org.mypackage.myunit
unit AdultUnit

rule Adult
  when
    $p : /persons[age >= adultAge]
  then
    System.out.println($p.getName() + " is adult and greater than " + adultAge);
end

注意

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

在本例中,规则条件中的任何匹配事实都从规则单元类的 DataSource 定义中定义的个人数据源检索。规则条件和操作使用 adultAge 变量的方式与在 DRL 文件级别上定义全局变量的方式相同。

要执行 KIE 基础中定义的一个或多个规则单元,请创建一个新的 RuleUnitExecutor 类,从相关数据源创建规则单元,并运行规则单元执行器:

规则单元执行示例

// Create a `RuleUnitExecutor` class and bind it to the KIE base:
KieBase kbase = kieContainer.getKieBase();
RuleUnitExecutor executor = RuleUnitExecutor.create().bind( kbase );

// Create the `AdultUnit` rule unit using the `persons` data source and run the executor:
RuleUnit adultUnit = new AdultUnit(persons, 18);
executor.run( adultUnit );

规则由 RuleUnitExecutor 类执行。RuleUnitExecutor 类创建 KIE 会话,并将所需的 DataSource 对象添加到这些会话中,然后根据作为参数传递给 run () 方法的 RuleUnit 执行规则。

当相关的 Person 事实插入到个人数据源中时,执行代码会生成以下输出:

规则单元执行输出示例

org.mypackage.myunit.AdultUnit started.
Jane is adult and greater than 18
John is adult and greater than 18
org.mypackage.myunit.AdultUnit ended.

您可以将规则单元变量注册到 executor 中,而是明确创建规则单元实例,并传递给 executor 运行的规则单元类,然后 executor 创建规则单元的实例。然后,您可以在运行规则单元前根据需要设置 DataSource 定义和其他变量。

带有注册变量的替代规则单元执行选项

executor.bindVariable( "persons", persons );
        .bindVariable( "adultAge", 18 );
executor.run( AdultUnit.class );

您传递给 RuleUnitExecutor.bindVariable () 方法的名称在运行时将变量绑定到规则单元类的字段,其名称具有相同名称。在上例中,RuleUnitExecutor 将数据源插入到新规则单元中,其数据源绑定到 "persons" 名称,并将绑定到 String "adultAge" 的值插入到带有 AdultUnit 类中对应名称的字段中。

要覆盖此默认 variable-binding 行为,请使用 @UnitVar 注释为规则单元类的每个字段明确定义逻辑绑定名称。例如,以下类中的字段绑定使用其他名称重新定义:

使用 @UnitVar修改变量绑定名称的代码示例

package org.mypackage.myunit;

public static class AdultUnit implements RuleUnit {
    @UnitVar("minAge")
    private int adultAge = 18;

    @UnitVar("data")
    private DataSource<Person> persons;
}

然后,您可以使用这些替代名称将变量绑定到 executor,并运行规则单元:

使用修改后的变量名称执行规则单元示例

executor.bindVariable( "data", persons );
        .bindVariable( "minAge", 18 );
executor.run( AdultUnit.class );

您可以使用 run () 方法(等同于 KIE 会话上的 fireAllRules () )或使用 runUntilHalt () 方法(等同于 KIE 会话上的 fireUntilHalt () )在 被动模式下执行 规则单元。默认情况下,决策引擎以 被动模式 运行,仅当用户或应用程序明确调用 run () (或针对标准规则的 fireAllRules () )时评估规则单元。如果用户或应用程序调用 runUntilHalt () 用于规则单元(或 fireUntilHalt () 用于标准规则),则决策引擎以 活跃模式 启动并评估规则单元,直到用户或应用程序显式调用 halt ()

如果您使用 runUntilHalt () 方法,请在单独的执行线程上调用方法以避免阻塞主线程:

在单独的线程中使用 runUntilHalt () 执行规则单元示例

new Thread( () -> executor.runUntilHalt( adultUnit ) ).start();

80.7.1. 规则单元的数据源

规则单元数据源是由给定规则单元处理的数据来源,代表决策引擎用于评估规则单元的入口点。规则单元可以有零个或更多数据源,在规则单元中声明的每个 DataSource 定义可以对应于规则单元 executor 的不同入口点。多个规则单元可以共享一个数据源,但每个规则单元都必须使用插入同一对象的不同入口点。

您可以在规则单元类中使用固定数据集合创建 DataSource 定义,如下例所示:

数据源定义示例

DataSource<Person> persons = DataSource.create( new Person( "John", 42 ),
                                                new Person( "Jane", 44 ),
                                                new Person( "Sally", 4 ) );

因为数据源代表规则单元的入口点,您可以在规则单元中插入、更新或删除事实:

在规则单元中插入、修改和删除事实的代码示例

// Insert a fact:
Person john = new Person( "John", 42 );
FactHandle johnFh = persons.insert( john );

// Modify the fact and optionally specify modified properties (for property reactivity):
john.setAge( 43 );
persons.update( johnFh, john, "age" );

// Delete the fact:
persons.delete( johnFh );

80.7.2. 规则单元执行控制

当您要协调规则执行时,规则单元很有用,以便执行一个规则单元会触发另一个规则单元的开始等。

为便于规则单元执行控制,决策引擎支持以下规则单元方法,您可以在 DRL 规则操作中使用,以协调规则单元的执行:

  • drools.run () :触发指定规则单元类的执行。这个方法有意中断规则单元的执行,并激活其他指定的规则单元。
  • drools.guard (): Prevents (guards)指定的规则单元类执行,直到满足关联的规则条件。这个方法声明性地调度其他指定规则单元的执行。当决策引擎为保护规则中的条件至少生成一个匹配项时,保护的规则单元被视为活动状态。规则单元可以包含多个保护规则。

作为 drools.run () 方法的示例,考虑每个都属于指定的规则单元的以下 DRL 规则:NotAdult 规则使用 drools.run (AdultUnit.class) 方法触发 AdultUnit 规则单元的执行:

使用 drools.run ()控制执行的 DRL 规则示例

package org.mypackage.myunit
unit AdultUnit

rule Adult
  when
    Person(age >= 18, $name : name) from persons
  then
    System.out.println($name + " is adult");
end

package org.mypackage.myunit
unit NotAdultUnit

rule NotAdult
  when
    $p : Person(age < 18, $name : name) from persons
  then
    System.out.println($name + " is NOT adult");
    modify($p) { setAge(18); }
    drools.run( AdultUnit.class );
end

这个示例还使用从这些规则构建的 KIE 基础创建的 RuleUnitExecutor 类,以及绑定到它的 人员的 DataSource 定义:

规则执行器和数据源定义示例

RuleUnitExecutor executor = RuleUnitExecutor.create().bind( kbase );
DataSource<Person> persons = executor.newDataSource( "persons",
                                                     new Person( "John", 42 ),
                                                     new Person( "Jane", 44 ),
                                                     new Person( "Sally", 4 ) );

在本例中,示例直接从 RuleUnitExecutor 类创建 DataSource 定义,并将其绑定到单个语句中的 "persons" 变量。

当相关的 Person 事实插入到个人数据源中时,执行代码会生成以下输出:

规则单元执行输出示例

Sally is NOT adult
John is adult
Jane is adult
Sally is adult

NotAdult 规则在评估人员 "Sly" 时检测到匹配项,这些人员为 18 年。然后,该规则将自己的年龄修改为 18,并使用 drools.run (AdultUnit.class) 方法触发 AdultUnit 规则单元的执行。AdultUnit 规则单元包含一个规则,现在可以为 DataSource 定义中的所有 3 个人执行该规则。

作为 drools.guard () 方法的示例,请考虑以下 BoxOffice 类和 BoxOfficeUnit 规则单元类:

BoxOffice 类示例

public class BoxOffice {
    private boolean open;

    public BoxOffice( boolean open ) {
        this.open = open;
    }

    public boolean isOpen() {
        return open;
    }

    public void setOpen( boolean open ) {
        this.open = open;
    }
}

BoxOfficeUnit 规则单元类示例

public class BoxOfficeUnit implements RuleUnit {
    private DataSource<BoxOffice> boxOffices;

    public DataSource<BoxOffice> getBoxOffices() {
        return boxOffices;
    }
}

这个示例还使用以下 TicketIssuerUnit 规则单元类来保持活动的办公室框票据,只要至少有一个框办公室处于打开状态。这个规则单元 使用 人员和 票据 数据源定义

TicketIssuerUnit 规则单元类示例

public class TicketIssuerUnit implements RuleUnit {
    private DataSource<Person> persons;
    private DataSource<AdultTicket> tickets;

    private List<String> results;

    public TicketIssuerUnit() { }

    public TicketIssuerUnit( DataSource<Person> persons, DataSource<AdultTicket> tickets ) {
        this.persons = persons;
        this.tickets = tickets;
    }

    public DataSource<Person> getPersons() {
        return persons;
    }

    public DataSource<AdultTicket> getTickets() {
        return tickets;
    }

    public List<String> getResults() {
        return results;
    }
}

BoxOfficeUnit 规则单元包含一个 BoxOfficeIsOpen DRL 规则,它使用 drools.guard (TicketIssuerUnit.class) 方法来保护执行 TicketIssuerUnit 规则单元,如以下 DRL 规则示例所示:

使用 drools.guard ()控制执行的 DRL 规则示例

package org.mypackage.myunit;
unit TicketIssuerUnit;

rule IssueAdultTicket when
    $p: /persons[ age >= 18 ]
then
    tickets.insert(new AdultTicket($p));
end
rule RegisterAdultTicket when
    $t: /tickets
then
    results.add( $t.getPerson().getName() );
end

package org.mypackage.myunit;
unit BoxOfficeUnit;

rule BoxOfficeIsOpen
  when
    $box: /boxOffices[ open ]
  then
    drools.guard( TicketIssuerUnit.class );
end

在这个示例中,只要至少有一个框办公室 处于打开状态,则保护的 TicketIssuerUnit 规则单元处于活动状态并分发事件票据。如果没有更多框 处于打开状态,则防止执行 guarded TicketIssuerUnit 规则单元。

以下示例类演示了一个更加完整的办公室场景:

框办公室情境类示例

DataSource<Person> persons = executor.newDataSource( "persons" );
DataSource<BoxOffice> boxOffices = executor.newDataSource( "boxOffices" );
DataSource<AdultTicket> tickets = executor.newDataSource( "tickets" );

List<String> list = new ArrayList<>();
executor.bindVariable( "results", list );

// Two box offices are open:
BoxOffice office1 = new BoxOffice(true);
FactHandle officeFH1 = boxOffices.insert( office1 );
BoxOffice office2 = new BoxOffice(true);
FactHandle officeFH2 = boxOffices.insert( office2 );

persons.insert(new Person("John", 40));

// Execute `BoxOfficeIsOpen` rule, run `TicketIssuerUnit` rule unit, and execute `RegisterAdultTicket` rule:
executor.run(BoxOfficeUnit.class);

assertEquals( 1, list.size() );
assertEquals( "John", list.get(0) );
list.clear();

persons.insert(new Person("Matteo", 30));

// Execute `RegisterAdultTicket` rule:
executor.run(BoxOfficeUnit.class);

assertEquals( 1, list.size() );
assertEquals( "Matteo", list.get(0) );
list.clear();

// One box office is closed, the other is open:
office1.setOpen(false);
boxOffices.update(officeFH1, office1);
persons.insert(new Person("Mark", 35));
executor.run(BoxOfficeUnit.class);

assertEquals( 1, list.size() );
assertEquals( "Mark", list.get(0) );
list.clear();

// All box offices are closed:
office2.setOpen(false);
boxOffices.update(officeFH2, office2); // Guarding rule is no longer true.
persons.insert(new Person("Edson", 35));
executor.run(BoxOfficeUnit.class); // No execution

assertEquals( 0, list.size() );

80.7.3. 规则单元身份冲突

在带有保护的规则单元的规则单元执行场景中,规则可以保护多个规则单元,并同时保护规则单元,然后由多个规则激活。对于这些双向保护场景,规则单元必须具有明确定义的身份以避免身份冲突。

默认情况下,规则单元的身份是规则单元类名称,并被视为 RuleUnitExecutor 的单例类。这种识别行为在 RuleUnit 接口的 getUnitIdentity () 默认方法中进行编码:

RuleUnit 接口中的默认身份方法

default Identity getUnitIdentity() {
    return new Identity( getClass() );
}

在某些情况下,您可能需要覆盖此默认识别行为,以避免规则单元间的冲突。

例如,以下 RuleUnit 类包含一个接受任何类型的对象的 DataSource 定义:

unit 0 规则单元类示例

public class Unit0 implements RuleUnit {
    private DataSource<Object> input;

    public DataSource<Object> getInput() {
        return input;
    }
}

此规则单元包含以下 DRL 规则,该规则根据两个条件保护另一个规则单元(在 OOPath 表示法中):

规则单元中的 GuardAgeCheck DRL 规则示例

package org.mypackage.myunit
unit Unit0

rule GuardAgeCheck
  when
    $i: /input#Integer
    $s: /input#String
  then
    drools.guard( new AgeCheckUnit($i) );
    drools.guard( new AgeCheckUnit($s.length()) );
end

已保护的 AgeCheckUnit 规则单元验证一组人的年龄。AgeCheckUnit 包含要检查的人员的 DataSource 定义、它验证的 minAge 变量,以及收集结果的列表:

AgeCheckUnit 规则单元示例

public class AgeCheckUnit implements RuleUnit {
    private final int minAge;
    private DataSource<Person> persons;
    private List<String> results;

    public AgeCheckUnit( int minAge ) {
        this.minAge = minAge;
    }

    public DataSource<Person> getPersons() {
        return persons;
    }

    public int getMinAge() {
        return minAge;
    }

    public List<String> getResults() {
        return results;
    }
}

AgeCheckUnit 规则单元包含以下 DRL 规则,该规则执行数据源中的 人员 验证:

规则单元中的 CheckAge DRL 规则示例

package org.mypackage.myunit
unit AgeCheckUnit

rule CheckAge
  when
    $p : /persons{ age > minAge }
  then
    results.add($p.getName() + ">" + minAge);
end

这个示例创建了一个 RuleUnitExecutor 类,将类绑定到包含这两个规则单元的 KIE 基础,并为同一规则单元创建两个 DataSource 定义:

executor 和数据源定义示例

RuleUnitExecutor executor = RuleUnitExecutor.create().bind( kbase );

DataSource<Object> input = executor.newDataSource( "input" );
DataSource<Person> persons = executor.newDataSource( "persons",
                                                     new Person( "John", 42 ),
                                                     new Person( "Sally", 4 ) );

List<String> results = new ArrayList<>();
executor.bindVariable( "results", results );

现在,您可以将一些对象插入到输入数据源中,并执行 unit 0 规则单元:

使用插入的对象执行规则单元示例

ds.insert("test");
ds.insert(3);
ds.insert(4);
executor.run(Unit0.class);

执行的结果列表示例

[Sally>3, John>3]

在本例中,名为 AgeCheckUnit 的规则单元被视为单例类,然后仅执行一次,minAge 变量设为 3。插入到输入数据源中的字符串 "test" 和 Integer 4 也可以触发第二个执行,并将 minAge 变量设置为 4。但是,第二个执行不会发生,因为已评估具有相同身份的另一个规则单元。

要解决此规则单元身份冲突,请覆盖 AgeCheckUnit 类的 getUnitIdentity () 方法,以便在规则单元身份中包含 minAge 变量:

修改 AgeCheckUnit 规则单元,以覆盖 getUnitIdentity () 方法

public class AgeCheckUnit implements RuleUnit {

    ...

    @Override
    public Identity getUnitIdentity() {
        return new Identity(getClass(), minAge);
    }
}

使用这个覆盖,前面的规则单元执行示例会生成以下输出:

执行修改的规则单元的结果列表示例

[John>4, Sally>3, John>3]

现在,minAge 设置为 34 的规则单元被视为两个不同的规则单元,两者都被执行。

第 81 章 决策引擎中的 Phreak 规则算法

Red Hat Process Automation Manager 中的决策引擎使用 Phreak 算法进行规则评估。Phreak 从 Rete 算法发展,包括为面向对象的系统在以前的 Red Hat Process Automation Manager 版本中引入的增强 Rete 算法 ReteOO。总体而言,Phreak 比 Rete 和 ReteOO 更具扩展性,在大型系统中更快。

虽然 Rete 被视为 eager (即时规则评估)和数据面向数据,但 Phreak 被视为 lazy (延迟的规则评估)和目标导向。Rete 算法在插入、更新和删除操作过程中执行许多操作,以便查找所有规则的部分匹配。在规则匹配过程中,Rete 算法的强制性需要在最终执行规则前花费大量时间,特别是在大型系统中。使用 Phreak 时,规则的部分匹配会延迟,以便更有效地处理大量数据。

Phreak 算法在以前的 Rete 算法中添加以下一组改进:

  • 上下文内存的三个层:节点、网段和规则内存类型
  • 基于规则、基于段和基于节点的链接
  • lazy (延迟)规则评估
  • 带有暂停和恢复的基于堆栈的评估
  • 隔离规则评估
  • 面向集合的传播

81.1. Phreak 中的规则评估

当决定引擎启动时,所有规则都将被视为从可触发规则的模式匹配数据中 取消链接。在这个阶段,决策引擎中的 Phreak 算法不会评估规则。插入update 和删除操作已排队,Phreak 使用 heuristic (根据规则最可能导致执行)来计算并选择下一个评估规则。当为规则填充所有必需的输入值时,该规则将被视为与相关模式匹配数据的链接。然后,Phreak 创建一个代表此规则的目标,并将目标放置在按规则 salience 排序的优先级队列中。仅评估创建目标的规则,其他潜在的规则评估会延迟。在评估单个规则时,节点共享仍然通过分段的过程实现。

与面向元的 Rete 不同,Phreak 传播是面向集合的。对于正在评估的规则,决策引擎可以访问第一个节点,并处理所有排队的插入、更新和删除操作。结果添加到集合中,集合会传播到子节点。在子节点中,处理所有排队的插入、更新和删除操作,将结果添加到同一集合中。然后,该集合被传播到下一个子节点,并且同一进程会重复,直到它到达终端节点。此周期创建批处理进程效果,可为某些规则构造提供性能优势。

基于网络分段,通过分层位掩码系统进行链接和取消链接规则。构建规则网络时,会为由同一组规则共享的规则网络节点创建片段。规则由片段路径组成。如果规则没有与任何规则共享任何节点,则它将成为单个网段。

为片段中的每个节点分配一个位掩码偏移。根据以下要求,为规则路径中的每个片段分配另一个位掩码:

  • 如果节点至少有一个输入存在,则节点位被设置为 on 状态。
  • 如果片段中的每个节点将位设置为 on 状态,则片段位也会设置为 on 状态。
  • 如果任何节点位被设置为 off 状态,则片段也会设置为 off 状态。
  • 如果规则路径中的每个片段都设置为 on 状态,则该规则将被视为链接,并创建一个目标来调度规则进行评估。

相同的位掩码技术用于跟踪修改的节点、片段和规则。此跟踪功能可让已经链接的规则被修改自评估目标后取消调度。因此,任何规则无法评估部分匹配项。

在 Phreak 中,这种规则评估过程是可能的,因为与 Rete 中的单个内存相比,Phreak 具有三个有节点、片段和规则内存类型的上下文内存层。这种分层允许在规则评估过程中进行更多上下文了解。

图 81.1. Phreak 三层内存系统

LayeredMemory enterprise

以下示例演示了如何在这个三层内存系统中组织并评估规则。

示例 1: 单一规则(R1),它有三个模式:A、B 和 C。规则形成一个片段,位 1、2 和 4 用于节点。单个片段的偏移值为 1。

图 81.2. 示例 1:单一规则

segment1 enterprise

示例 2: 添加规则 R2 和共享模式 A。

图 81.3. 示例 2:两个带有模式共享的规则

segment2 enterprise

模式 A 放置在自己的片段中,为每个规则生成两个片段。这两个片段形成其各自规则的路径。第一个片段由两个路径共享。链接模式 A 时,片段将变为链接。然后,片段会迭代片段共享的每个路径,将位 1 设置为 on。如果稍后启用了模式 B 和 C,则路径 R1 的第二个片段链接,这会导致为 R1 打开位 2。为 R1 打开位 1 和位 2 后,该规则现已链接,并创建了目标来调度规则以便稍后评估和执行。

评估规则时,片段将启用共享匹配的结果。每个片段都有一个暂存内存来排队所有插入、更新和删除该片段。评估 R1 时,规则进程模式 A,这会导致一组元组。该算法检测到分段分割,为集合中的每个插入、更新和删除创建对等的元组,并将它们添加到 R2 暂存内存中。然后,这些元组将与任何现有的 stage 元组合并,并在最终评估 R2 时执行。

示例 3: 规则 R3 和 R4 被添加,共享模式 A 和 B。

图 81.4. 示例 3:带有模式共享的三三个规则

segment3 enterprise

规则 R3 和 R4 有三个片段,R1 有两个片段。模式 A 和 B 由 R1、R3 和 R4 共享,而模式 D 则由 R3 和 R4 共享。

示例 4: 单一规则(R1),它带有一个数字且没有模式共享。

图 81.5. 示例 4:单一规则,没有模式共享

segment4 enterprise

NotExistsAccumulate 节点包含多个元素时,将形成不同的活动。在本例中,元素 B not (C) 形成了数字。项 not (C) 是一个不需要归档的单个元素,因此在 Not node 内合并。数字使用专用片段。规则 R1 仍然有两个片段的路径,另一个内部路径。当关联被链接后,也会在外部段中链接。

示例 5: 规则 R1,其具有规则 R2 共享的数字。

图 81.6. 示例 5:两个规则,一个带有参与和模式共享

segment5 enterprise

规则中的电池节点可以由没有销售的规则共享。此共享会导致将网段分成两个片段。

受限 Not nodes 和 Accumulate 节点永远不会取消链接片段,并且始终被视为打开其位。

Phreak 评估算法基于堆栈,而不是基于方法的递归。当使用 StackEntry 来代表当前正在评估的节点时,可以随时暂停并恢复规则评估。

当规则评估达到一次时,会为外部路径片段和子组创建一个 StackEntry 对象。最后段首先被评估,当集合到达销售路径的末尾时,片段将合并到分段源到的外部节点的暂存列表中。然后,前面的 StackEntry 对象已被恢复,现在可以处理相关的结果。这个过程具有增加的好处,特别是对于 Accumulate 节点,所有工作都在批处理中完成,然后再传播到子节点。

相同的堆栈系统用于高效的后向链。当规则评估到达查询节点时,评估将暂停,并将查询添加到堆栈中。然后,查询会被评估来生成结果集,该集合保存在恢复的 StackEntry 对象的内存位置,以获取并传播到子节点。如果查询本身称为其他查询,该过程会重复,而当前查询已暂停,并为当前查询节点设置新的评估。

81.1.1. 使用正向和后链的规则评估

Red Hat Process Automation Manager 中的决策引擎是一个混合原因,它使用转发链和后链来评估规则。转发链规则系统是一种数据驱动的系统,它以决策引擎工作内存中的事实开始,并对这一事实做出更改。当对象插入到工作内存中时,因更改计划执行而满足的任何规则条件。

相反,反向链规则系统是一个目标驱动的系统,从决策引擎尝试满足的公式开始,通常使用递归。如果系统无法访问语音或目标,它会搜索子组,这是完成当前目标的一部分。系统会继续这个过程,直到满足初始目标或满足所有子状态为止。

下图演示了,决策引擎如何使用转发链和逻辑流中的向链段来评估规则:

图 81.7. 使用正向和后链的规则评估逻辑

RuleEvaluation Enterprise

81.2. 规则基础配置

Red Hat Process Automation Manager 包含一个 RuleBaseConfiguration.java 对象,可用于在决策引擎中配置异常处理程序设置、多线程执行和顺序模式。

对于规则基础配置选项,请从红帽客户门户网站下载 Red Hat Process Automation Manager 7.9.1 Source Distribution ZIP 文件,再进入到 ~/rhpam-7.9.1-sources/src/drools-$VERSION/drools-core/src/main/java/org/drools/core/RuleBaseConfiguration.javahttps://access.redhat.com/jbossnetwork/restricted/listSoftware.html

以下规则基本配置选项可用于决策引擎:

drools.consequenceExceptionHandler

配置后,此系统属性定义管理规则结果的异常的类。您可以使用此属性为决策引擎中的规则评估指定自定义异常处理程序。

默认值: org.drools.core.runtime.rule.impl.DefaultConsequenceExceptionHandler

您可以使用以下选项之一指定自定义异常处理程序:

  • 在系统属性中指定异常处理程序:

    drools.consequenceExceptionHandler=org.drools.core.runtime.rule.impl.MyCustomConsequenceExceptionHandler
  • 以编程方式创建 KIE 基础时指定异常处理程序:

    KieServices ks = KieServices.Factory.get();
    KieBaseConfiguration kieBaseConf = ks.newKieBaseConfiguration(); kieBaseConf.setOption(ConsequenceExceptionHandlerOption.get(MyCustomConsequenceExceptionHandler.class));
    KieBase kieBase = kieContainer.newKieBase(kieBaseConf);
drools.multithreadEvaluation

启用后,此系统属性可让决策引擎通过将 Phreak 规则网络划分为独立分区来并行评估规则。您可以使用此属性提高特定规则基础的规则评估速度。

默认值:false

您可以使用以下选项之一启用多线程评估:

  • 启用多线程评估系统属性:

    drools.multithreadEvaluation=true
  • 在以编程方式创建 KIE 基础时启用多线程评估:

    KieServices ks = KieServices.Factory.get();
    KieBaseConfiguration kieBaseConf = ks.newKieBaseConfiguration();
    kieBaseConf.setOption(MultithreadEvaluationOption.YES);
    KieBase kieBase = kieContainer.newKieBase(kieBaseConf);
警告

并行决策引擎目前不支持使用查询、风险或电缆组的规则。如果 KIE 基础中存在这些规则元素,编译器会发出警告并自动切回到单线程评估。然而,在某些情况下,决策引擎可能无法检测到不支持的规则元素和规则被错误地评估。例如,决策引擎可能无法检测规则何时依赖于 DRL 文件中的规则排序,从而导致因为不受支持的 salience 属性而产生错误的评估。

drools.sequential

启用后,这个系统属性会在决策引擎中启用后续模式。在后续模式中,决策引擎会按照决策引擎人员中列出的顺序来一次评估规则,而无需考虑工作内存中的更改。这意味着,决策引擎会忽略规则中的任何 插入修改 或更新 语句,并在单个序列中执行规则。因此,执行规则可能会更快,但重要的更新可能不适用于您的规则。如果您使用无状态 KIE 会话,并且您不希望执行规则来影响发票中的后续规则,您可以使用此属性。后续模式只适用于无状态 KIE 会话。

默认值:false

您可以使用以下选项之一启用后续模式:

  • 启用后续模式系统属性:

    drools.sequential=true
  • 在以编程方式创建 KIE 基础时启用后续模式:

    KieServices ks = KieServices.Factory.get();
    KieBaseConfiguration kieBaseConf = ks.newKieBaseConfiguration();
    kieBaseConf.setOption(SequentialOption.YES);
    KieBase kieBase = kieContainer.newKieBase(kieBaseConf);
  • 在 KIE 模块描述符文件(kmodule.xml)中为特定 Red Hat Process Automation Manager 项目启用后续模式:

    <kmodule>
      ...
      <kbase name="KBase2" default="false" sequential="true" packages="org.domain.pkg2, org.domain.pkg3" includes="KBase1">
        ...
      </kbase>
      ...
    </kmodule>

81.3. Phreak 中的顺序模式

连续模式是决策引擎中的高级规则基础配置,由 Phreak 支持,使决策引擎能够按照决策引擎人员中列出的顺序评估规则一次,而无需考虑工作内存中的更改。在后续模式中,决策引擎忽略规则中的任何 插入修改 或更新 语句,并在单个序列中执行规则。因此,执行规则可能会更快,但重要的更新可能不适用于您的规则。

后续模式只适用于无状态 KIE 会话,因为有状态 KIE 会话本质上使用之前调用的 KIE 会话中的数据。如果您使用无状态 KIE 会话,并且希望执行规则来影响电缆中的后续规则,请不要启用后续模式。在决策引擎中默认禁用后续模式。

要启用后续模式,请使用以下选项之一:

  • 将系统属性 drools.sequential 设置为 true
  • 在以编程方式创建 KIE 基础时启用后续模式:

    KieServices ks = KieServices.Factory.get();
    KieBaseConfiguration kieBaseConf = ks.newKieBaseConfiguration();
    kieBaseConf.setOption(SequentialOption.YES);
    KieBase kieBase = kieContainer.newKieBase(kieBaseConf);
  • 在 KIE 模块描述符文件(kmodule.xml)中为特定 Red Hat Process Automation Manager 项目启用后续模式:

    <kmodule>
      ...
      <kbase name="KBase2" default="false" sequential="true" packages="org.domain.pkg2, org.domain.pkg3" includes="KBase1">
        ...
      </kbase>
      ...
    </kmodule>

要将后续模式配置为使用动态电缆,请使用以下选项之一:

  • 将系统属性 drools.sequential.agenda 设置为 dynamic
  • 在以编程方式创建 KIE 基础时设置后续 products 选项:

    KieServices ks = KieServices.Factory.get();
    KieBaseConfiguration kieBaseConf = ks.newKieBaseConfiguration();
    kieBaseConf.setOption(SequentialAgendaOption.DYNAMIC);
    KieBase kieBase = kieContainer.newKieBase(kieBaseConf);

当您启用后续模式时,决策引擎会使用以下方法评估规则:

  1. 规则按照规则集中的 salience 和 location 进行排序。
  2. 每个可能的规则匹配都会创建一个元素。元素位置表示执行顺序。
  3. 节点内存被禁用,但正确的输入对象内存除外。
  4. left-input 适配器节点传播断开连接,并在 Command 对象中引用带有该节点的对象。Command 对象添加到工作内存中的列表中,以便稍后执行。
  5. 所有对象都被断言,然后检查并执行 Command 对象列表。
  6. 所有执行列表的结果都根据规则的序列号添加到元素中。
  7. 包含匹配项的元素按顺序执行。如果您设置了最大规则执行数,则决策引擎不会激活执行者中的规则数量。

在后续模式中,LeftInputAdapterNode 节点会创建一个 Command 对象,并将其添加到决策引擎工作内存中的列表。此命令对象包含对 LeftInputAdapterNode 节点和传播对象的引用。这些引用会在插入时停止任何输入输入传播,因此右侧输入不需要尝试加入左输入。引用也会避免对左输入内存的需求。

所有节点都关闭其内存,包括左输入的元组内存,但不包括正确的输入对象内存。完成所有断言并且填充所有对象的正确输入内存后,决策引擎会迭代 LeftInputAdatperNode Command 对象列表。对象传播网络,尝试加入右侧输入对象,但不会将它们保留在左面输入中。

具有调度元组的优先级队列的语音将被每个规则的元素替代。RuleTerminalNode 节点的序列号指示放置匹配项的元素。所有 Command 对象完成后,会检查元素并执行现有的匹配。为提高性能,保留元素中的第一个和最后一个填充的单元。

构建网络后,每个 RuleTerminalNode 节点都会根据其数量和添加到网络的顺序接收序列号。

右输入节点记住通常是用于快速删除对象的哈希映射。因为不支持删除对象,因此当对象值没有索引时,Phreak 使用对象列表。对于大量对象,索引的哈希映射可提供性能提高。如果对象只有几个实例,则 Phreak 使用对象列表而不是索引。

第 82 章 复杂的事件处理(CEP)

在 Red Hat Process Automation Manager 中,事件是应用程序域中重大更改状态的记录。根据域建模的方式,状态的更改可由单个事件、多个原子事件或关联事件的层次结构表示。从复杂的事件处理(CEP)的角度来看,事件是在特定时间发生的事实或对象类型,自定义规则是如何响应该事实或对象数据的定义。例如,在库存代理应用程序中,安全价格的变化、所有权从领导者更改为购买者,或者帐户拥有者平衡的变化都被视为事件,因为更改在给定时间发生在应用程序域状态。

Red Hat Process Automation Manager 中的决策引擎使用复杂的事件处理(CEP)来检测和处理事件集合中存在的多个事件,以及推断事件及其关系的新数据。

CEP 用例与业务规则用例共享一些要求和目标。

从业务的角度来看,业务规则定义通常根据事件触发的情况来定义。在以下示例中,事件形成了业务逻辑的基础:

  • 在算法的应用程序中,如果安全价格在日期打开价格之上增加 X 百分比时,规则会执行一个操作。价格增加由库存商业应用程序上的事件表示。
  • 在监控应用程序中,如果服务器空间中的温度在 Y 分钟内增加 X 等级,则一条规则会执行一个操作。传感器读取器由事件表示。

从技术角度来说,业务规则评估和 CEP 有以下关键技术:

  • 业务逻辑评估和 CEP 都需要与企业基础架构和应用程序无缝集成。这在生命周期管理、审计和安全性方面尤其重要。
  • 业务逻辑评估和 CEP 具有功能要求,如模式匹配,以及响应时间限制和查询规则解释等不工作要求。

CEP 场景有以下关键特征:

  • 场景通常是处理大量事件,但只有少量事件是相关的。
  • 事件通常不可变,代表状态为更改的记录。
  • 针对事件运行的规则和查询,且必须响应检测到的事件模式。
  • 相关事件通常具有强大的临时关系。
  • 单个事件不会被优先排序。CEP 系统优先选择相关事件的模式及其之间的关系。
  • 事件通常需要组成和聚合。

鉴于这些常见的 CEP 场景特性,Red Hat Process Automation Manager 中的 CEP 系统支持以下功能和功能来优化事件处理:

  • 带有正确语义的事件处理
  • 事件检测、关联、聚合和组成
  • 事件流处理
  • 临时限制来建模事件间的临时关系
  • 划分大量事件的窗口
  • 会话范围统一时钟
  • CEP 用例所需的事件卷
  • 重新主动规则
  • 在决策引擎(pipeline)中输入事件的适配器

82.1. 复杂事件处理中的事件

在 Red Hat Process Automation Manager 中,事件是应用程序域中重大更改状态的记录。根据域建模的方式,状态的更改可由单个事件、多个原子事件或关联事件的层次结构表示。从复杂的事件处理(CEP)的角度来看,事件是在特定时间发生的事实或对象类型,自定义规则是如何响应该事实或对象数据的定义。例如,在库存代理应用程序中,安全价格的变化、所有权从领导者更改为购买者,或者帐户拥有者平衡的变化都被视为事件,因为更改在给定时间发生在应用程序域状态。

事件有以下关键特征:

  • is immutable : 事件是过去发生且不更改的事件记录。

    注意

    决策引擎不会在代表事件的 Java 对象中强制实施不可变性。这个行为可使事件数据增强。您的应用程序应该能够填充未填充的事件属性,并且决策引擎将使用这些属性来增强事件利用推断的数据。但是,您不应该更改已填充的事件属性。

  • 具有强大的临时限制: 涉及事件的规则通常需要在相对于彼此的不同点的不同点上关联多个事件。
  • 已管理的生命周期: 因为事件不可变且具有临时限制,它们通常只在指定时间段内相关。这意味着决策引擎可以自动管理事件的生命周期。
  • 可以使用分片窗口: 您可以定义通过事件的时间或长度的分片窗口。分片时间窗是可以处理事件的指定时间段。分片长度窗口是可以处理的事件数量。

82.2. 将事实声明为事件

您可以将事实声明为 Java 类或 DRL 规则文件中的事件,以便决策引擎在复杂的事件处理过程中将事实处理为事件。您可以将事实声明为基于间隔的事件或时间点事件。基于间隔的事件具有持续时间,并在决策引擎的工作内存中保留,直到其持续时间被宽松为止。点事件没有持续时间,基本上是基于间隔的事件,持续时间为零。

�程

对于 Java 类或 DRL 规则文件中的相关事实类型,请输入 @role (event) metadata tag 和 parameter。@role metadata 标签接受以下两个值:

  • 事实 :(默认)宣布类型作为常规事实
  • Event: Declares 类型作为事件

例如,以下片段声明库存代理应用程序中的 StockPoint 事实类型必须作为事件处理:

将事实类型声明为事件

import some.package.StockPoint

declare StockPoint
  @role( event )
end

如果 StockPoint 是 DRL 规则文件中声明的事实类型,而不是在预先存在的类中声明事件,您可以在应用程序代码中声明事件:

在命令行中声明事实类型,并将其分配到事件角色

declare StockPoint
  @role( event )

  datetime : java.util.Date
  symbol : String
  price : double
end

82.3. 事件的元数据标签

决策引擎将以下元数据标签用于插入到决策引擎工作内存中的事件:您可以根据需要更改 Java 类或 DRL 规则文件中的默认元数据标签值。

注意

本节中的示例指向 VoiceCall 类,假设示例应用程序域模型包括以下类详情:

示例域模型中的 VoiceCall 事实类

public class VoiceCall {
  private String  originNumber;
  private String  destinationNumber;
  private Date    callDateTime;
  private long    callDuration;  // in milliseconds

  // Constructors, getters, and setters
}

@role

此标签决定了给定事实类型是否作为常规事实处理,还是在复杂的事件处理期间在决策引擎中处理事件。

默认参数: fact

支持的参数: factevent

@role( fact | event )

示例: Declare VoiceCall 作为事件类型

declare VoiceCall
  @role( event )
end

@timestamp

此标签会自动分配给决策引擎中的每个事件。默认情况下,时间由会话时钟提供,并在它插入到决策引擎的工作内存中时分配给事件。您可以指定自定义时间戳属性,而不是会话时钟添加的默认时间戳。

Default 参数:决策引擎会话时钟添加的时间

支持的参数: Session clock time 或自定义时间戳属性

@timestamp( <attributeName> )

示例: Declare VoiceCall timestamp 属性

declare VoiceCall
  @role( event )
  @timestamp( callDateTime )
end

@duration

此标签决定了决策引擎中事件的持续时间。事件可以是基于间隔的事件或时间事件。基于间隔的事件具有持续时间,并在决策引擎的工作内存中保留,直到其持续时间被宽松为止。点事件没有持续时间,基本上是基于间隔的事件,持续时间为零。默认情况下,决策引擎中的每个事件都为零。您可以指定自定义 duration 属性而不是默认值。

默认参数:Null (零)

支持的参数:自定义持续时间属性

@duration( <attributeName> )

示例: Declare VoiceCall duration 属性

declare VoiceCall
  @role( event )
  @timestamp( callDateTime )
  @duration( callDuration )
end

@expires

此标签决定事件在决策引擎工作内存中过期前的时长。默认情况下,当事件无法再匹配并激活任何当前规则时,事件会过期。您可以定义事件应过期的时间。此标签定义还覆盖由临时约束计算的隐式过期偏移,以及 KIE 基础中的分片窗口。只有在决策引擎以流模式运行时,此标签才可用。

默认参数:Null (事件后过期时间不再匹配并激活规则)

支持的参数: 自定义 timeOffset 属性,格式为 [IANAd][ theh][ them][114s][[ms]]

@expires( <timeOffset> )

示例:VoiceCall 事件的 Declare 过期偏移

declare VoiceCall
  @role( event )
  @timestamp( callDateTime )
  @duration( callDuration )
  @expires( 1h35m )
end

82.4. 决策引擎中的事件处理模式

决策引擎以云模式或流模式运行。在云模式中,决策引擎将事实处理为没有临时约束、独立于时间和无特定顺序的事实。在流模式中,决策引擎实时或接近实时将事实处理为具有强临时约束的事件。流模式使用同步在 Red Hat Process Automation Manager 中进行事件处理。

云模式

云模式是决策引擎的默认操作模式。在云模式中,决策引擎将事件视为一个未排序的云。事件仍具有时间戳,但在云模式下运行的决策引擎无法从时间戳中提取弹性,因为云模式会忽略当前时间。此模式使用规则约束来查找匹配的元组来激活和执行规则。

云模式不会在事实上强制实施任何类型的额外的要求。但是,由于此模式的决策引擎没有时间,所以无法使用临时功能,如分片窗口或自动生命周期管理。在云模式中,当不再需要事件时,必须明确重新遍历事件。

在云中不会应用以下要求:

  • 没有时钟同步,因为决策引擎没有时间的修改
  • 不排序事件,因为决策引擎将事件作为未排序的云处理,因此决策引擎与规则匹配

您可以通过在相关配置文件中设置系统属性或使用 Java 客户端 API 来指定云模式:

使用系统属性设置云模式

drools.eventProcessingMode=cloud

使用 Java 客户端 API 设置云模式

import org.kie.api.conf.EventProcessingOption;
import org.kie.api.KieBaseConfiguration;
import org.kie.api.KieServices.Factory;

KieBaseConfiguration config = KieServices.Factory.get().newKieBaseConfiguration();

config.setOption(EventProcessingOption.CLOUD);

您还可以使用特定 Red Hat Process Automation Manager 项目的 KIE 模块描述符文件(kmodule.xml)中的 eventProcessingMode="<mode>" KIE base 属性来指定云模式:

使用项目 kmodule.xml 文件设置云模式

<kmodule>
  ...
  <kbase name="KBase2" default="false" eventProcessingMode="cloud" packages="org.domain.pkg2, org.domain.pkg3" includes="KBase1">
    ...
  </kbase>
  ...
</kmodule>

流模式

流模式使决策引擎能够按时间处理事件,并在将事件插入到决策引擎中时实时处理事件。在流模式中,决策引擎同步事件流(因此不同流中的事件可以按按按按时间顺序处理),实施覆盖时间或长度的窗口,并启用自动生命周期管理。

以下要求适用于流模式:

  • 每个流中的事件必须按时间排序。
  • 必须存在会话时钟才能同步事件流。
注意

您的应用程序不需要在流间强制实施排序事件,但使用未同步的事件流可能会导致意外的结果。

您可以通过在相关配置文件中设置系统属性或使用 Java 客户端 API 来指定流模式:

使用系统属性设置流模式

drools.eventProcessingMode=stream

使用 Java 客户端 API 设置流模式

import org.kie.api.conf.EventProcessingOption;
import org.kie.api.KieBaseConfiguration;
import org.kie.api.KieServices.Factory;

KieBaseConfiguration config = KieServices.Factory.get().newKieBaseConfiguration();

config.setOption(EventProcessingOption.STREAM);

您还可以使用特定 Red Hat Process Automation Manager 项目的 KIE 模块描述符文件(kmodule.xml)中的 eventProcessingMode="<mode>" KIE base 属性来指定流模式:

使用项目 kmodule.xml 文件设置流模式

<kmodule>
  ...
  <kbase name="KBase2" default="false" eventProcessingMode="stream" packages="org.domain.pkg2, org.domain.pkg3" includes="KBase1">
    ...
  </kbase>
  ...
</kmodule>

82.4.1. 决策引擎流模式中的负模式

负模式是不符合的条件的模式。例如,如果检测到触发且没有激活 sprinkler,以下 DRL 规则会激活触发警告:

使用负模式触发警报规则

rule "Sound the alarm"
when
  $f : FireDetected()
  not(SprinklerActivated())
then
  // Sound the alarm.
end

在云模式中,决策引擎提前知道所有事实(相关事实和事件),并立即评估负模式。在流模式中,决策引擎可以在激活规则前支持事实上的临时限制,以等待集合时间。

流模式中的同一示例规则会激活触发警告,但会应用 10 秒的延迟。

触发具有负模式和时间延迟的警报规则(仅限流模式)

rule "Sound the alarm"
when
  $f : FireDetected()
  not(SprinklerActivated(this after[0s,10s] $f))
then
  // Sound the alarm.
end

以下修改后的触发警报规则要求每 10 秒发生一次 Heartbeat 事件。如果没有发生预期的事件,则执行该规则。此规则在第一个模式和负模式中使用同一类型的对象。负模式具有临时约束,在执行并排除绑定到 $hHeartbeat 事件前等待 0 到 10 秒,以便执行该规则。必须明确排除绑定事件 $h 才能执行规则,因为临时约束 [0s, …​] 不本质上排除该事件再次匹配。

触发警报规则排除在负模式中的绑定事件(仅限流模式)

rule "Sound the alarm"
when
  $h: Heartbeat() from entry-point "MonitoringStream"
  not(Heartbeat(this != $h, this after[0s,10s] $h) from entry-point "MonitoringStream")
then
  // Sound the alarm.
end

82.5. 事实类型的属性更改设置和监听程序

默认情况下,决策引擎不会在每次触发规则时重新评估事实类型的所有事实模式,而是只响应给定模式内受限制或绑定的修改属性。例如,如果规则调用 modify () 作为规则操作的一部分,但操作不会在 KIE 基础中生成新的数据,则决策引擎不会自动重新评估所有事实模式,因为没有修改任何数据。此属性重新活动行为可防止 KIE 基础中不需要的递归,并导致更有效的规则评估。这个行为还意味着,您不必使用 no-loop 规则属性来避免无限递归。

您可以使用以下 Knowledgebase BuilderConfiguration 选项修改或禁用此属性重新活动行为,然后根据需要使用 Java 类或 DRL 文件中的属性更改设置来微调属性:

  • ALWAYS: (默认)所有类型都是重新主动的属性,但您可以使用 @classReactive property-change 设置禁用特定类型的属性重新活动。
  • ALLOWED: 没有类型是属性重新主动,但您可以使用 @propertyReactive property-change 设置为特定类型启用属性重新活动。
  • DISABLED :无类型是属性重新主动。所有 property-change 侦听程序都会被忽略。

KnowledgeBuilderConfiguration 中的属性重新活动设置示例

KnowledgeBuilderConfiguration config = KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration();
config.setOption(PropertySpecificOption.ALLOWED);
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(config);

另外,您可以更新 Red Hat Process Automation Manager 发行版本的 standalone.xml 文件中的 drools.propertySpecific 系统属性:

系统属性中属性中的属性重新活动设置示例

<system-properties>
  ...
  <property name="drools.propertySpecific" value="ALLOWED"/>
  ...
</system-properties>

决策引擎支持以下 property-change 设置和监听程序作为事实类或声明的 DRL 事实类型:

@classReactive

如果在决策引擎中将属性重新活动设置为 ALWAYS (所有类型都是重新主动),则此标签将禁用特定 Java 类或声明的 DRL 事实类型的默认属性重新活动行为。如果您希望决策引擎在每次触发规则时重新评估指定事实类型的所有事实模式,而不是只响应给定模式内的修改属性,则可以使用此标签。

示例:在 DRL 类型声明中禁用默认属性重新活动

declare Person
  @classReactive
    firstName : String
    lastName : String
end

示例:在 Java 类中禁用默认属性重新活动

@classReactive
public static class Person {
    private String firstName;
    private String lastName;
}

@propertyReactive

如果在决策引擎中将属性 reactivity 设置为 ALLOWED (除非指定),则此标签将启用特定 Java 类或声明的 DRL 事实类型的属性重新活动。如果您希望决策引擎只响应指定事实类型的给定模式或绑定的修改属性,则可以使用此标签,而不是在每次触发规则时重新评估所有事实模式。

示例:启用 DRL 类型声明中的属性重新活动(当全局禁用重新活动时)

declare Person
  @propertyReactive
    firstName : String
    lastName : String
end

示例:在 Java 类中启用属性重新活动(当全局禁用重新活动时)

@propertyReactive
public static class Person {
    private String firstName;
    private String lastName;
}

@watch

此标签为您在 DRL 规则中的事实模式中指定的额外属性启用属性重新活动。只有在决策引擎中将属性 reactivity 设置为 ALWAYS,或者如果属性 reactivity 设为 ALLOWED 时,才会支持该标签,相关事实类型使用 @propertyReactive 标签。您可以在 DRL 规则中使用该标签,在事实属性重新活动逻辑中添加或排除特定属性。

默认参数: None

支持的参数:Property name, rhncfg (all), ! (not), ! the ! the no properties)

<factPattern> @watch ( <property> )

示例:在事实模式中启用或禁用属性重新活动

// Listens for changes in both `firstName` (inferred) and `lastName`:
Person(firstName == $expectedFirstName) @watch( lastName )

// Listens for changes in all properties of the `Person` fact:
Person(firstName == $expectedFirstName) @watch( * )

// Listens for changes in `lastName` and explicitly excludes changes in `firstName`:
Person(firstName == $expectedFirstName) @watch( lastName, !firstName )

// Listens for changes in all properties of the `Person` fact except `age`:
Person(firstName == $expectedFirstName) @watch( *, !age )

// Excludes changes in all properties of the `Person` fact (equivalent to using `@classReactivity` tag):
Person(firstName == $expectedFirstName) @watch( !* )

如果您在事实类型中使用 @watch 标签处理使用 @classReactive 标签(禁用属性重新活动),或者在决策引擎中将属性重新活动时,决策引擎会生成一个编译错误,相关事实类型不使用 @propertyReactive 标签。如果您在监听器注解中重复的属性(如 @watch (firstName, ! firstName) ),也会出现编译错误。

@propertyChangeSupport

对于实施对 TTY 规范中定义的属性更改的支持的事实,此标签可让决策引擎监控事实属性中的更改。https://download.oracle.com/otndocs/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/

示例:Aronlare 属性更改对 sVirt 对象的支持

declare Person
    @propertyChangeSupport
end

82.6. 事件的临时运算符

在流模式中,决策引擎支持以下临时运算符,用于插入到决策引擎工作内存中的事件。您可以使用这些运算符来定义您在 Java 类或 DRL 规则文件中声明的事件的临时原因行为。当决策引擎在云模式下运行时,不支持临时运算符。

  • after
  • 之前
  • coincides
  • during
  • includes
  • 完成
  • 完成完成
  • 先决条件
  • 满足
  • 重叠
  • 重叠:
  • 启动
  • 启动者

    after

    此 operator 指定当前事件是否在关联事件后发生。此 operator 也可以定义当前事件可以遵循关联的事件,或者限制当前事件可以遵循关联的事件的时间。

    例如,如果 $eventA 在 3 分钟到 30 秒和 $eventB 完成后 4 分钟之间启动,则以下模式匹配。如果 $eventA$eventB 完成后启动 3 分钟和 30 秒,或者在 $eventB 完成后再 4 分钟后启动,则模式匹配模式。

    $eventA : EventA(this after[3m30s, 4m] $eventB)

    您还可以使用以下方法表达此 Operator:

    3m30s <= $eventA.startTimestamp - $eventB.endTimeStamp <= 4m

    after 操作员支持最多两个参数值:

    • 如果定义了两个值,间隔从第一个值(示例中的 3 分钟和 30 秒)开始,并以第二个值结束(示例中 4 分钟)。
    • 如果只定义一个值,间隔从提供的值开始,并在没有结束时间的情况下运行。
    • 如果没有定义值,间隔以 1 毫秒开始,并在没有结束时间的情况下运行。

    之后的 operator 还支持负时间范围:

    $eventA : EventA(this after[-3m30s, -2m] $eventB)

    如果第一个值大于第二个值,则决策引擎会自动撤销它们。例如,以下两种模式由决策引擎解释,其方式相同:

    $eventA : EventA(this after[-3m30s, -2m] $eventB)
    $eventA : EventA(this after[-2m, -3m30s] $eventB)
    之前

    此 operator 指定当前事件是否在关联事件前发生。此操作员还可定义当前事件在关联事件之前可以处理的时间,或者定义当前事件可以在关联的事件之前的限制时间范围。

    例如,如果 $eventA 完成 3 分钟到 30 秒到 $eventB 启动前 4 分钟之间,则以下模式匹配。如果 $eventA 完成在 $eventB 启动之前的 3 分钟和 30 秒前,或者在 $eventB 启动前 4 分钟前,则模式匹配模式。

    $eventA : EventA(this before[3m30s, 4m] $eventB)

    您还可以使用以下方法表达此 Operator:

    3m30s <= $eventB.startTimestamp - $eventA.endTimeStamp <= 4m

    before 运算符最多支持两个参数值:

    • 如果定义了两个值,间隔从第一个值(示例中的 3 分钟和 30 秒)开始,并以第二个值结束(示例中 4 分钟)。
    • 如果只定义一个值,间隔从提供的值开始,并在没有结束时间的情况下运行。
    • 如果没有定义值,间隔以 1 毫秒开始,并在没有结束时间的情况下运行。

    before 运算符还支持负时间范围:

    $eventA : EventA(this before[-3m30s, -2m] $eventB)

    如果第一个值大于第二个值,则决策引擎会自动撤销它们。例如,以下两种模式由决策引擎解释,其方式相同:

    $eventA : EventA(this before[-3m30s, -2m] $eventB)
    $eventA : EventA(this before[-2m, -3m30s] $eventB)
    coincides

    此 operator 指定两个事件是否同时发生,其启动和结束时间相同。

    例如,如果 $eventA$eventB 的开始和结束时间戳都相同,则以下模式匹配:

    $eventA : EventA(this coincides $eventB)

    如果事件开始和结束时间之间的距离不相同,则 coincides 操作器支持最多两个参数值:

    • 如果只给出一个参数,则使用该参数为两个事件的开始和结束时间设置阈值。
    • 如果指定了两个参数,则第一个参数用作开始时间的阈值,第二个参数则用作结束时间的阈值。

    以下模式使用 start 和 end 时间阈值:

    $eventA : EventA(this coincides[15s, 10s] $eventB)

    如果满足以下条件,则模式匹配:

    abs($eventA.startTimestamp - $eventB.startTimestamp) <= 15s
    &&
    abs($eventA.endTimestamp - $eventB.endTimestamp) <= 10s
    警告

    决策引擎不支持 coincides operator 的负间隔。如果您使用负间隔,则决策引擎会生成一个错误。

    during

    此 operator 指定当前事件是否在关联的事件启动和结束时发生。当前事件必须在关联的事件启动后启动,且必须在关联事件结束前结束。(使用 coincides 操作符,开始和结束时间是相同的或几乎相同。)

    例如,如果 $eventA$eventB 启动后启动,并在 $eventB 结束前结束,则以下模式匹配:

    $eventA : EventA(this during $eventB)

    您还可以使用以下方法表达此 Operator:

    $eventB.startTimestamp < $eventA.startTimestamp <= $eventA.endTimestamp < $eventB.endTimestamp

    Operator 期间 支持其中一个、两个或四个可选参数:

    • 如果定义了一个值,则这个值是两个事件的开始时间和两个事件结束时间之间的最大距离。
    • 如果定义了两个值,则这些值是一个阈值,当前事件开始时间和结束时间必须与相关的事件开始和结束时间相关。

      例如,如果值为 5s10s,则当前事件必须在关联事件启动后 5 到 10 秒之间启动,且必须在关联事件结束 5 秒和 10 秒之间结束。

    • 如果定义了四个值,则第一个值和第二个值是事件开始时间之间的最小和最大距离,第三个值和第四个值是两个事件结束时间之间的最小和最大距离。
    includes

    此 operator 指定在当前事件发生时相关的事件是否发生。关联的事件必须在当前事件启动后启动,且必须在当前事件结束前结束。(此操作器的行为是运算符行为的相反。)

    例如,如果 $eventB$eventA start 后启动,并在 $eventA 结束前结束,则以下模式匹配:

    $eventA : EventA(this includes $eventB)

    您还可以使用以下方法表达此 Operator:

    $eventA.startTimestamp < $eventB.startTimestamp <= $eventB.endTimestamp < $eventA.endTimestamp

    includes 运算符支持 one、2 或四个可选参数:

    • 如果定义了一个值,则这个值是两个事件的开始时间和两个事件结束时间之间的最大距离。
    • 如果定义了两个值,则这些值是一个阈值,相关的事件开始时间和结束时间必须与当前事件启动和结束时间相关。

      例如,如果值为 5s10s,相关的事件必须在当前事件启动后 5 到 10 秒之间启动,且必须在当前事件结束 5 秒和 10 秒之间结束。

    • 如果定义了四个值,则第一个值和第二个值是事件开始时间之间的最小和最大距离,第三个值和第四个值是两个事件结束时间之间的最小和最大距离。
    完成

    此 operator 指定当前事件是否在关联的事件后启动,但两个事件同时终止。

    例如,如果 $eventA$eventB 启动后启动,并在 $eventB 结束时同时结束,则以下模式匹配:

    $eventA : EventA(this finishes $eventB)

    您还可以使用以下方法表达此 Operator:

    $eventB.startTimestamp < $eventA.startTimestamp
    &&
    $eventA.endTimestamp == $eventB.endTimestamp

    完成 运算符支持一个可选参数,用于设置两个事件结束时间之间允许的最大时间:

    $eventA : EventA(this finishes[5s] $eventB)

    如果满足以下条件,则此模式匹配:

    $eventB.startTimestamp < $eventA.startTimestamp
    &&
    abs($eventA.endTimestamp - $eventB.endTimestamp) <= 5s
    警告

    决策引擎不支持 完成 Operator 的负间隔。如果您使用负间隔,则决策引擎会生成一个错误。

    完成完成

    此 operator 指定关联的事件是否在当前事件后启动,但两个事件同时终止。(此操作器的行为与 完成 运算符行为相反。)

    例如,如果 $eventB$eventA 启动后启动,并在 $eventA 结束时同时结束,则以下模式匹配:

    $eventA : EventA(this finishedby $eventB)

    您还可以使用以下方法表达此 Operator:

    $eventA.startTimestamp < $eventB.startTimestamp
    &&
    $eventA.endTimestamp == $eventB.endTimestamp

    Operator 完成的 一个可选参数,它设定两个事件结束时间之间允许的最大时间:

    $eventA : EventA(this finishedby[5s] $eventB)

    如果满足以下条件,则此模式匹配:

    $eventA.startTimestamp < $eventB.startTimestamp
    &&
    abs($eventA.endTimestamp - $eventB.endTimestamp) <= 5s
    警告

    决策引擎不支持 Operator 完成 的负间隔。如果您使用负间隔,则决策引擎会生成一个错误。

    先决条件

    此 operator 指定当前事件在关联事件启动时是否同时结束。

    例如,如果 $eventA$eventB 启动时同时终止,则以下模式匹配:

    $eventA : EventA(this meets $eventB)

    您还可以使用以下方法表达此 Operator:

    abs($eventB.startTimestamp - $eventA.endTimestamp) == 0

    meets 操作符支持一个可选参数,该参数设定当前事件结束时间和关联事件的开始时间之间允许的最大时间:

    $eventA : EventA(this meets[5s] $eventB)

    如果满足以下条件,则此模式匹配:

    abs($eventB.startTimestamp - $eventA.endTimestamp) <= 5s
    警告

    决策引擎不支持 满足 Operator 的负间隔。如果您使用负间隔,则决策引擎会生成一个错误。

    满足

    此 operator 指定在当前事件启动时相关的事件是否同时结束。(此操作器的行为与 满足 运算符的行为相反。)

    例如,如果 $eventB$eventA 启动时同时终止,则以下模式匹配:

    $eventA : EventA(this metby $eventB)

    您还可以使用以下方法表达此 Operator:

    abs($eventA.startTimestamp - $eventB.endTimestamp) == 0

    Operator 满足 的一个可选参数,该参数在关联事件结束时间和当前事件的开始时间之间设置最大距离:

    $eventA : EventA(this metby[5s] $eventB)

    如果满足以下条件,则此模式匹配:

    abs($eventA.startTimestamp - $eventB.endTimestamp) <= 5s
    警告

    决策引擎不支持 Operator 满足 的负间隔。如果您使用负间隔,则决策引擎会生成一个错误。

    重叠

    此 operator 指定当前事件是否在关联事件启动前启动,并在相关的事件的时间范围内结束。当前事件必须在关联事件的开始和结束时间之间结束。

    例如,如果 $eventA $eventB 启动之前启动,然后在 $eventB 结束前结束,则以下模式匹配:

    $eventA : EventA(this overlaps $eventB)

    overlaps operator 支持最多两个参数:

    • 如果定义了一个参数,则该值是关联事件的开始时间和当前事件结束时间之间的最大距离。
    • 如果定义了两个参数,则值为关联事件开始时间和当前事件的结束时间之间的最小距离(第一个值)和当前事件的结束时间。
    重叠:

    此 operator 指定关联的事件是否在当前事件启动前启动,并在当前事件发生的时间范围内结束。关联的事件必须在当前事件的开始和结束时间之间结束。(此操作器的行为与重叠的运算符行为相反。)

    例如,如果 $eventB $eventA 启动之前启动,然后在 $eventA 结束前结束,则以下模式匹配:

    $eventA : EventA(this overlappedby $eventB)

    Operator 的重叠 支持最多两个参数:

    • 如果定义了一个参数,则该值是当前事件开始时间和关联事件结束时间之间的最大距离。
    • 如果定义了两个参数,则值是当前事件开始时间和关联事件结束时间之间的最小距离(第一个值)和最大距离(秒值)。
    启动

    此操作器指定两个事件是否同时启动,但当前事件在关联事件结束前结束。

    例如,如果 $eventA$eventB 同时启动,并且 $eventA 结束于 $eventB 结束,则以下模式匹配:

    $eventA : EventA(this starts $eventB)

    您还可以使用以下方法表达此 Operator:

    $eventA.startTimestamp == $eventB.startTimestamp
    &&
    $eventA.endTimestamp < $eventB.endTimestamp

    start 运算符支持一个可选参数,该参数在两个事件的开始时间之间设置最大距离:

    $eventA : EventA(this starts[5s] $eventB)

    如果满足以下条件,则此模式匹配:

    abs($eventA.startTimestamp - $eventB.startTimestamp) <= 5s
    &&
    $eventA.endTimestamp < $eventB.endTimestamp
    警告

    决策引擎不支持 start 运算符的负间隔。如果您使用负间隔,则决策引擎会生成一个错误。

    启动者

    此 operator 指定两个事件是否同时启动,但关联的事件在当前事件结束前结束。(此操作器的行为与 启动 操作器行为相反。)

    例如,如果 $eventA $eventB 同时启动,并且 $eventB 在 $eventA 结束之前,以下模式匹配:

    $eventA : EventA(this startedby $eventB)

    您还可以使用以下方法表达此 Operator:

    $eventA.startTimestamp == $eventB.startTimestamp
    &&
    $eventA.endTimestamp > $eventB.endTimestamp

    Operator 启动的 一个可选参数支持两个事件的开始时间之间设置最大距离:

    $eventA : EventA( this starts[5s] $eventB)

    如果满足以下条件,则此模式匹配:

    abs( $eventA.startTimestamp - $eventB.startTimestamp ) <= 5s
    &&
    $eventA.endTimestamp > $eventB.endTimestamp
    警告

    决策引擎不支持 Operator 启动 的负间隔。如果您使用负间隔,则决策引擎会生成一个错误。

82.7. 在决策引擎中实现会话时钟

在复杂的事件处理过程中,决策引擎中的事件可能具有临时限制,因此需要一个提供当前时间的会话时钟。例如,如果规则需要在最后 60 分钟内确定给定库存的平均价格,则决策引擎必须能够将库存价格事件时间戳与会话时钟中的当前时间进行比较。

决策引擎支持实时时钟和伪时钟。您可以根据场景使用一个或多个时钟类型:

  • 规则测试 :测试需要控制的环境,当测试包含具有临时约束的规则时,您必须能够控制输入规则和 事实以及时间流。
  • 常规执行: 决策引擎实时响应事件,因此需要实时时钟。
  • 特殊环境: 特定环境可能具有特定的时间控制要求。例如,集群环境可能需要时钟同步或 Java Enterprise Edition (JEE)环境,可能需要应用服务器提供的时钟。
  • 规则重播或模拟 : 为了重播或模拟场景,应用程序必须能够控制时间流。

当您决定在决策引擎中使用实时时钟还是伪时钟时,请考虑您的环境要求。

实时时钟

实时时钟是决策引擎中默认的时钟实施,使用系统时钟来确定时间戳的当前时间。要将决策引擎配置为使用实时时钟,请将 KIE 会话配置参数设置为 realtime

在 KIE 会话中配置实时时钟

import org.kie.api.KieServices.Factory;
import org.kie.api.runtime.conf.ClockTypeOption;
import org.kie.api.runtime.KieSessionConfiguration;

KieSessionConfiguration config = KieServices.Factory.get().newKieSessionConfiguration();

config.setOption(ClockTypeOption.get("realtime"));

伪时钟

决策引擎中的伪时钟实施有助于测试临时规则,并且可由应用程序控制。要将决策引擎配置为使用伪时钟,请将 KIE 会话配置参数设置为 pseudo

在 KIE 会话中配置伪时钟

import org.kie.api.runtime.conf.ClockTypeOption;
import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.api.KieServices.Factory;

KieSessionConfiguration config = KieServices.Factory.get().newKieSessionConfiguration();

config.setOption(ClockTypeOption.get("pseudo"));

您还可以使用额外的配置和事实处理程序来控制伪时钟:

控制 KIE 会话中的伪时钟行为

import java.util.concurrent.TimeUnit;

import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.api.KieServices.Factory;
import org.kie.api.runtime.KieSession;
import org.drools.core.time.SessionPseudoClock;
import org.kie.api.runtime.rule.FactHandle;
import org.kie.api.runtime.conf.ClockTypeOption;

KieSessionConfiguration conf = KieServices.Factory.get().newKieSessionConfiguration();

conf.setOption( ClockTypeOption.get("pseudo"));
KieSession session = kbase.newKieSession(conf, null);

SessionPseudoClock clock = session.getSessionClock();

// While inserting facts, advance the clock as necessary.
FactHandle handle1 = session.insert(tick1);
clock.advanceTime(10, TimeUnit.SECONDS);

FactHandle handle2 = session.insert(tick2);
clock.advanceTime(30, TimeUnit.SECONDS);

FactHandle handle3 = session.insert(tick3);

82.8. 事件流和入口点

决策引擎可以以事件流的形式处理大量事件。在 DRL 规则声明中,流也称为 入口点。当您在 DRL 规则或 Java 应用程序中声明入口点时,决策引擎会在编译时标识并创建正确的内部结构,以仅使用该入口点中的数据来评估该规则。

从一个入口点或流开始的事实,除了决策引擎的工作内存中外,还可以从任何其他入口点加入事实。事实始终与输入决策引擎的入口点保持关联。同一类型的事实可以通过多个入口点进入决策引擎,但通过入口点 A 输入决策引擎的事实永远不会从入口点 B 匹配。

事件流具有以下特征:

  • 流中的事件根据时间戳排序。时间戳对不同的流可能具有不同的语义,但它们始终在内部排序。
  • 事件流通常具有大量事件。
  • 流中的 Atomic 事件通常不单独使用,仅适用于流。
  • 事件流可以被同发布,包含单一类型的事件,或者异构事件,并包含不同类型的事件。

82.8.1. 声明规则数据的入口点

您可以为事件声明入口点(事件流),以便决策引擎仅使用该入口点中的数据来评估规则。您可以通过在 DRL 规则中或明确在 Java 应用程序中引用入口点来隐式声明入口点。

�程

使用以下方法之一声明入口点:

  • 在 DRL 规则文件中,为插入的事实指定 entry-point "<name>"

    使用 "ATM Stream" 入口点授权撤回规则

    rule "Authorize withdrawal"
    when
      WithdrawRequest($ai : accountId, $am : amount) from entry-point "ATM Stream"
      CheckingAccount(accountId == $ai, balance > $am)
    then
      // Authorize withdrawal.
    end

    使用 "Branch Stream" 入口点应用费用规则

    rule "Apply fee on withdraws on branches"
    when
      WithdrawRequest($ai : accountId, processed == true) from entry-point "Branch Stream"
      CheckingAccount(accountId == $ai)
    then
      // Apply a $2 fee on the account.
    end

    法国应用程序的 DRL 规则示例都使用 fact checking Account,但从不同的入口点插入事件 WithdrawalRequest。在运行时,决策引擎仅使用 "ATM Stream" 入口点中的数据来评估 Authorize 撤回 规则,并使用仅使用 "Branch Stream" 入口点中的数据来评估 应用费用 规则。插入到 "ATM Stream" 的任何事件都不能匹配 "Apply Cost"规则的模式,插入到 " Branch Stream" 的任何事件都永不与 "Authorize withdrawal rule" 的模式匹配。

  • 在 Java 应用程序代码中,使用 getEntryPoint () 方法指定并获取 EntryPoint 对象,并相应地将事实插入到该入口点中:

    带有 EntryPoint 对象的 Java 应用程序代码并插入的事实

    import org.kie.api.runtime.KieSession;
    import org.kie.api.runtime.rule.EntryPoint;
    
    // Create your KIE base and KIE session as usual.
    KieSession session = ...
    
    // Create a reference to the entry point.
    EntryPoint atmStream = session.getEntryPoint("ATM Stream");
    
    // Start inserting your facts into the entry point.
    atmStream.insert(aWithdrawRequest);

    然后,任何 从入口点"ATM Stream" 指定的 DRL 规则都会根据此入口点中的数据进行评估。

82.9. 划分时间或长度窗口

在流模式中,决策引擎可以从指定时间或长度窗口中处理事件。分片时间窗是可以处理事件的指定时间段。分片长度窗口是可以处理的事件数量。当您在 DRL 规则或 Java 应用程序中声明分片窗口时,决策引擎会在编译时标识并创建正确的内部结构,以仅使用该分片窗口中的数据来评估该规则。

例如,以下 DRL 规则片断指示决策引擎仅处理来自最后 2 分钟(由时间窗口)的库存点,或者只处理最后 10 个库存点(由长度窗口):

从最后 2 分钟开始的进程库存点(指定时间窗)

StockPoint() over window:time(2m)

处理最后 10 个库存点(过期长度窗口)

StockPoint() over window:length(10)

82.9.1. 为规则数据声明分片窗口

您可以为事件声明时间的分片窗口(时间流)或长度(发生时间数),以便决策引擎仅使用该窗口中的数据来评估规则。

�程

在 DRL 规则文件中,为插入事实指定 window:<time_or_length> (<value>)

例如,以下两个 DRL 规则根据平均温度激活触发警告。但是,第一个规则使用分片时间窗计算最后 10 分钟的平均时间窗,第二个规则使用分片长度窗口来计算上一个温度读取的平均窗口。

分片时间窗的平均温度

rule "Sound the alarm if temperature rises above threshold"
when
  TemperatureThreshold($max : max)
  Number(doubleValue > $max) from accumulate(
    SensorReading($temp : temperature) over window:time(10m),
    average($temp))
then
  // Sound the alarm.
end

分片长度窗口的平均温度

rule "Sound the alarm if temperature rises above threshold"
when
  TemperatureThreshold($max : max)
  Number(doubleValue > $max) from accumulate(
    SensorReading($temp : temperature) over window:length(100),
    average($temp))
then
  // Sound the alarm.
end

决策引擎丢弃任何超过 10 分钟或不是上一次读取的一部分的任何 SensorReading 事件,并继续实时重新计算平均或读取"slide"。

决策引擎不会自动从 KIE 会话中删除过时的事件,因为其他没有分片窗口声明的规则可能依赖于这些事件。决策引擎将事件存储在 KIE 会话中,直到事件由显式规则声明过期,或根据 KIE 基础中推断的数据在决策引擎中隐式原因。

82.10. 事件的内存管理

在流模式中,决策引擎使用自动内存管理来维护存储在 KIE 会话中的事件。决策引擎可以从 KIE 会话中重新遍历任何规则的事件,这些事件因为临时限制而不再匹配,并释放重新遍历事件保存的任何资源。

决策引擎使用显式或推断的过期事件来重新遍历过时的事件:

  • 显式过期 : 决策引擎移除在声明 @expires 标签的规则中明确设置的事件:

    带有显式过期的 DRL 规则片断

    declare StockPoint
      @expires( 30m )
    end

    这个示例规则将任何 StockPoint 事件设置为 30 分钟后过期,并在没有其他规则使用事件时从 KIE 会话中删除。

  • Inferred expiration: 决策引擎可以通过分析规则中的 temporal 约束来隐式计算给定事件的过期偏移:

    带有临时约束的 DRL 规则

    rule "Correlate orders"
    when
      $bo : BuyOrder($id : id)
      $ae : AckOrder(id == $id, this after[0,10s] $bo)
    then
      // Perform an action.
    end

    在本例中,决策引擎会自动计算每当出现 BuyOrder 事件时,决策引擎需要存储事件最多 10 秒并等待匹配的 AckOrder 事件。10 秒后,决策引擎会推断到期,并从 KIE 会话中删除事件。AckOrder 事件只能匹配现有的 BuyOrder 事件,因此如果没有匹配项并立即删除事件,则决策引擎会推断过期。

    决策引擎分析整个 KIE 基础,以查找每个事件类型的偏移,并确保没有其他规则使用正在等待移除的事件。每当带有显式过期值的隐式过期时,决策引擎会使用两个更大的时间帧来存储事件。

第 83 章 决策引擎查询和实时查询

您可以将查询与决策引擎搭配使用,根据规则中使用的事实模式检索事实集。模式也可以使用可选参数。

要将查询与决策引擎搭配使用,您可以在 DRL 文件中添加查询定义,然后在应用程序代码中获取匹配的结果。虽然查询迭代结果集合,但您可以使用绑定到查询的任何标识符访问对应的事实或事实字段,方法是使用绑定变量名称作为参数调用 get () 方法来访问对应的事实或事实字段。如果绑定引用事实对象,您可以通过调用 getFactHandle (),并将变量名称用作参数来检索事实处理。

DRL 文件中的查询定义示例

query "people under the age of 21"
    $person : Person( age < 21 )
end

获取和迭代查询结果的应用程序代码示例

QueryResults results = ksession.getQueryResults( "people under the age of 21" );
System.out.println( "we have " + results.size() + " people under the age of 21" );

System.out.println( "These people are under the age of 21:" );

for ( QueryResultsRow row : results ) {
    Person person = ( Person ) row.get( "person" );
    System.out.println( person.getName() + "\n" );
}

当您监控随着时间的变化时,通过迭代返回的集合调用查询和处理结果可能比较困难。为了降低持续查询的这一难度,Red Hat Process Automation Manager 提供了 实时查询,它使用附加的监听程序更改事件,而不是返回可迭代的结果集。通过为此视图的内容创建视图并发布更改事件,实时查询保持打开。

要激活实时查询,请使用参数启动查询,并在结果视图中监控更改。您可以使用 dispose () 方法终止查询并停用这种被动场景。

DRL 文件中的查询定义示例

query colors(String $color1, String $color2)
    TShirt(mainColor = $color1, secondColor = $color2, $price: manufactureCost)
end

带有事件监听器和实时查询的应用程序代码示例

final List updated = new ArrayList();
final List removed = new ArrayList();
final List added = new ArrayList();

ViewChangedEventListener listener = new ViewChangedEventListener() {
 public void rowUpdated(Row row) {
  updated.add( row.get( "$price" ) );
 }

 public void rowRemoved(Row row) {
  removed.add( row.get( "$price" ) );
 }

 public void rowAdded(Row row) {
  added.add( row.get( "$price" ) );
 }
};

// Open the live query:
LiveQuery query = ksession.openLiveQuery( "colors",
                                          new Object[] { "red", "blue" },
                                          listener );
...
...

// Terminate the live query:
query.dispose()

第 84 章 决策引擎事件监听程序和调试日志

在 Red Hat Process Automation Manager 中,您可以为决策引擎事件添加或删除监听程序,如事实插入和规则执行。借助决策引擎事件监听程序,您可以通知决策引擎活动,并将日志记录和审核与应用程序的核心工作分开。

决策引擎支持以下默认事件监听程序,用于电缆和工作内存:

  • AgendaEventListener
  • WorkingMemoryEventListener

对于每个事件监听程序,决策引擎还支持指定以下可监控的特定事件:

  • MatchCreatedEvent
  • MatchCancelledEvent
  • BeforeMatchFiredEvent
  • AfterMatchFiredEvent
  • AgendaGroupPushedEvent
  • AgendaGroupPoppedEvent
  • ObjectInsertEvent
  • ObjectDeletedEvent
  • ObjectUpdatedEvent
  • ProcessCompletedEvent
  • ProcessNodeLeftEvent
  • ProcessNodeTriggeredEvent
  • ProcessStartEvent

例如,以下代码使用附加到 KIE 会话的 DefaultAgendaEventListener 侦听器,并指定要监控的 AfterMatchFiredEvent 事件。执行规则后代码打印模式匹配(fired):

监控和打印电话中的 AfterMatchFiredEvent 事件的代码示例

ksession.addEventListener( new DefaultAgendaEventListener() {
   public void afterMatchFired(AfterMatchFiredEvent event) {
       super.afterMatchFired( event );
       System.out.println( event );
   }
});

决策引擎还支持以下电缆和工作内存事件监听程序进行调试日志:

  • DebugAgendaEventListener
  • DebugRuleRuntimeEventListener

这些事件监听程序实现相同的支持的 event-listener 方法,并默认包含一个 debug print 语句。您可以添加特定支持的事件来监控并记录,或监控所有销售或工作内存活动。

例如,以下代码使用 DebugRuleRuntimeEventListener 事件监听程序来监控和打印所有工作内存事件:

监控和打印所有工作内存事件的代码示例

ksession.addEventListener( new DebugRuleRuntimeEventListener() );

84.1. 在决策引擎中配置日志记录工具

决策引擎使用 Java 日志记录 API SLF4J 进行系统日志。您可以在决策引擎中使用以下日志实用程序之一来调查决策引擎活动,如进行故障排除或数据收集:

  • Logback
  • Apache Commons Logging
  • Apache Log4j
  • java.util.logging 软件包

�程

对于您要使用的日志记录工具,将相关依赖项添加到 Maven 项目,或者在 Red Hat Process Automation Manager 发行版本的 org.drools 软件包中保存相关的 XML 配置文件:

Logback 的 Maven 依赖项示例

<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>${logback.version}</version>
</dependency>

org.drools 软件包中的 logback.xml 配置文件示例

<configuration>
  <logger name="org.drools" level="debug"/>
  ...
<configuration>

org.drools 软件包中的 log4j.xml 配置文件示例

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
  <category name="org.drools">
    <priority value="debug" />
  </category>
  ...
</log4j:configuration>

注意

如果您要为巨型环境开发,请使用 slf4j-nopslf4j-simple logger。

第 85 章 用于 IDE 的 Red Hat Process Automation Manager 决策示例

Red Hat Process Automation Manager 提供了作为 Java 类分发的示例决策,您可以将其导入到集成开发环境(IDE)中。您可以使用这些示例来更好地了解决策引擎功能,或者将其用作您在您自己的 Red Hat Process Automation Manager 项目中定义的决策参考。

以下示例决定集是 Red Hat Process Automation Manager 中的一些示例:

  • hello World 示例 :演示基本规则执行和使用 debug 输出
  • State 示例 :通过规则 salience 和 sales 组来演示转发链和冲突解析
  • Fibonacci 示例 :通过规则 salience 来演示递归和冲突解析
  • 示例 :演示模式匹配、基本排序和计算
  • pet Store 示例 :演示规则关联组、全局变量、回调和 GUI 集成
  • Sudoku 示例 :演示复杂模式匹配、问题问题、回调和 GUI 集成
  • Doom 示例的托管 :演示后链和递归
注意

有关 Red Hat Business Optimizer 提供的优化示例,请参阅开始使用 Red Hat Business Optimizer

85.1. 在 IDE 中导入和执行 Red Hat Process Automation Manager 示例决策

您可以将 Red Hat Process Automation Manager 示例决策导入到集成开发环境(IDE)中,并执行它们来探索规则和代码功能的方式。您可以使用这些示例来更好地了解决策引擎功能,或者将其用作您在您自己的 Red Hat Process Automation Manager 项目中定义的决策参考。

先决�件

  • 安装了 Java 8 或更高版本。
  • 已安装 Maven 3.5.x 或更高版本。
  • 已安装 IDE,如 Red Hat CodeReady Studio。

流程

  1. 从红帽客户门户网站下载 并解压 Red Hat Process Automation Manager 7.9.1 源 分发到临时目录,如 /rhpam-7.9.1-sources
  2. 打开 IDE 并选择 FileImportMavenExisting Maven Projects,或者导入 Maven 项目的等效选项。
  3. Browse,导航到 ~/rhpam-7.9.1-sources/src/drools-$VERSION/drools-examples (或,对于生命周期的 Conway 的 Game,~/rhpam-7.9.1-sources/src/droolsjbpm-integration-$VERSION/droolsjbpm-integration-examples),并导入项目。
  4. 导航到您要运行的示例软件包,并使用 main 方法查找 Java 类。
  5. 右键点击 Java 类并选择 Run AsJava Application 来运行示例。

    要通过基本用户界面运行所有示例,请运行 org.drools . examples 主类中的 drorools App.java 类(例如,Brorools.examples 主类)。

    图 85.1. drools-examples (DroolsExamplesApp.java)中的所有示例的接口

    drool 示例运行所有

    图 85.2. droolsjbpm-integration-examples (DroolsJbpmIntegrationExamplesApp.java)中的所有示例的接口

    droolsjbpm 示例运行所有

85.2. hello World 示例决策(基本规则和调试)

Hello World 示例决策演示了如何将对象插入到决策引擎工作内存中,如何使用规则匹配对象,以及如何配置日志记录来跟踪决策引擎的内部活动。

以下是 Hello World 示例的概述:

  • 名称helloworld
  • 主类org.drools.examples.novncproxy.HelloWorldExample (在 src/main/java中)
  • 模块drools-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.novncproxy.HelloWorld.drl (在 src/main/resources中)
  • 目标 :演示基本规则执行和使用 debug 输出

在 Hello World 示例中,生成 KIE 会话来启用规则执行。所有规则都需要一个 KIE 会话才能执行。

用于规则执行的 KIE 会话

KieServices ks = KieServices.Factory.get(); 1
KieContainer kc = ks.getKieClasspathContainer(); 2
KieSession ksession = kc.newKieSession("HelloWorldKS"); 3

1
获取 KieServices 工厂。这是应用程序用来与决策引擎交互的主要接口。
2
从项目类路径创建一个 KieContainer。这会检测一个 /META-INF/kmodule.xml 文件,该文件使用 KieModule 配置并实例化 KieContainer
3
根据 /META-INF/kmodule.xml 文件中定义的 "HelloWorldKS" KIE 会话配置创建一个 KieSession
注意

有关 Red Hat Process Automation Manager 项目打包的更多信息,请参阅 打包和部署 Red Hat Process Automation Manager 项目

Red Hat Process Automation Manager 有一个事件模型,可公开内部引擎活动。两个默认调试监听程序 DebugAgendaEventListenerDebugRuleRuntimeEventListener,将调试事件信息输出到 System.err 输出中。KieRuntimeLogger 提供执行审核,您可以在图形查看的结果。

调试监听程序和审计日志记录程序

// Set up listeners.
ksession.addEventListener( new DebugAgendaEventListener() );
ksession.addEventListener( new DebugRuleRuntimeEventListener() );

// Set up a file-based audit logger.
KieRuntimeLogger logger = KieServices.get().getLoggers().newFileLogger( ksession, "./target/helloworld" );

// Set up a ThreadedFileLogger so that the audit view reflects events while debugging.
KieRuntimeLogger logger = ks.getLoggers().newThreadedFileLogger( ksession, "./target/helloworld", 1000 );

日志记录器是在 AgendaRuleRuntime 侦听程序基础上构建的专用实现。当决策引擎完成执行后,会调用 logger.close ()

该示例创建含有消息 "Hello World" 的单个 Message 对象,将状态 HELLO 插入到 KieSession 中,执行带有 fireAllRules () 的规则。

数据插入和执行

// Insert facts into the KIE session.
final Message message = new Message();
message.setMessage( "Hello World" );
message.setStatus( Message.HELLO );
ksession.insert( message );

// Fire the rules.
ksession.fireAllRules();

规则执行使用数据模型将数据作为输入并输出到 KieSession。本例中的数据模型有两个字段: 消息,即 String,可以是 HELLOGOODBYE

数据模型类

public static class Message {
    public static final int HELLO   = 0;
    public static final int GOODBYE = 1;

    private String          message;
    private int             status;
    ...
}

这两个规则位于 src/main/resources/org/drools/examples/HelloWorld.drl 文件中。

"Hello World" 规则的 when 条件指出每个 Message 对象的规则被激活到 KIE 会话中,其状态为 Message.HELLO。此外,还创建两个变量绑定:变量 消息 绑定到 message 属性,变量 m 绑定到匹配的 Message 对象本身。

规则的 then 操作指定将绑定变量 消息 的内容输出到 System.out,然后更改绑定到 mMessage 对象 的消息 和状态 属性。规则使用 modify 语句在一个语句中应用分配块,并在块末尾通知决策引擎更改。

"hello World" 规则

rule "Hello World"
  when
    m : Message( status == Message.HELLO, message : message )
  then
    System.out.println( message );
    modify ( m ) { message = "Goodbye cruel world",
                   status = Message.GOODBYE };
end

"Good Bye" 规则类似于 "Hello World" 规则,但它与状态为 Message.GOODBYE 的 Message 对象匹配。

"good Bye" 规则

rule "Good Bye"
  when
    Message( status == Message.GOODBYE, message : message )
  then
    System.out.println( message );
end

要执行示例,请在 IDE 中作为 Java 应用程序运行 org.drools.examples.helloworld.HelloWorldExample 类。规则写入 System.out,调试侦听器写入 System.err,审计日志记录器会在 target/ the.log 中创建一个日志文件

IDE 控制台中的 system.out 输出

Hello World
Goodbye cruel world

IDE 控制台中的 system.err 输出

==>[ActivationCreated(0): rule=Hello World;
                   tuple=[fid:1:1:org.drools.examples.helloworld.HelloWorldExample$Message@17cec96]]
[ObjectInserted: handle=[fid:1:1:org.drools.examples.helloworld.HelloWorldExample$Message@17cec96];
                 object=org.drools.examples.helloworld.HelloWorldExample$Message@17cec96]
[BeforeActivationFired: rule=Hello World;
                   tuple=[fid:1:1:org.drools.examples.helloworld.HelloWorldExample$Message@17cec96]]
==>[ActivationCreated(4): rule=Good Bye;
                   tuple=[fid:1:2:org.drools.examples.helloworld.HelloWorldExample$Message@17cec96]]
[ObjectUpdated: handle=[fid:1:2:org.drools.examples.helloworld.HelloWorldExample$Message@17cec96];
                old_object=org.drools.examples.helloworld.HelloWorldExample$Message@17cec96;
                new_object=org.drools.examples.helloworld.HelloWorldExample$Message@17cec96]
[AfterActivationFired(0): rule=Hello World]
[BeforeActivationFired: rule=Good Bye;
                   tuple=[fid:1:2:org.drools.examples.helloworld.HelloWorldExample$Message@17cec96]]
[AfterActivationFired(4): rule=Good Bye]

为更好地了解本例的执行流程,您可以将审计日志文件从 target/helloworld.log 加载到 IDE debug 视图或 审计 视图(例如,在一些 IDE 中的 WindowShow View 中)。

在本例中,审计视图显示 插入了对象,它为 "Hello World" 规则创建一个激活。然后执行激活,它会更新 Message 对象,并导致 "Good Bye" 规则激活。最后,执行 "Good Bye" 规则。当您在 Audit View 中选择一个事件时,原始事件(本例中为 "Activation created" 事件)以绿色形式突出显示。

图 85.3. hello World 示例审计视图

helloworld auditview1

85.3. 状态示例决策(转发链和冲突解析)

State 示例决定集演示了决策引擎如何使用 forward 链,以及对工作内存中事实的任何更改,以解决序列中的规则的执行冲突。该示例重点通过您可以在规则中定义的可变值或通过电缆组解决冲突。

以下是 State 示例的概述:

  • 名称状态
  • 主类org.drools.examples.state.StateExampleUsingSalience,org.drools.examples.state.StateExampleUsingAgendaGroup (in src/main/java)
  • 模块drools-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.state114.drl (在 src/main/resources中)
  • 目标 :通过规则 salience 和 sales 组来演示转发链和冲突解析

转发链规则系统是一种数据驱动的系统,它以决策引擎工作内存中的事实开始,并对这一事实做出更改。当对象插入到工作内存中时,因更改计划执行而满足的任何规则条件。

相反,反向链规则系统是一个目标驱动的系统,从决策引擎尝试满足的公式开始,通常使用递归。如果系统无法访问语音或目标,它会搜索子组,这是完成当前目标的一部分。系统会继续这个过程,直到满足初始目标或满足所有子状态为止。

Red Hat Process Automation Manager 中的决策引擎使用正向和后链来评估规则。

下图演示了,决策引擎如何使用转发链和逻辑流中的向链段来评估规则:

图 85.4. 使用正向和后链的规则评估逻辑

RuleEvaluation Enterprise

在 State 示例中,每个 State 类都有其名称及其当前状态字段(请参阅类 org.drools.examples.state.State)。以下状态是每个对象的两个可能的状态:

  • NOTRUN
  • 完æˆ�

状态类

public class State {
    public static final int NOTRUN   = 0;
    public static final int FINISHED = 1;

    private final PropertyChangeSupport changes =
        new PropertyChangeSupport( this );

    private String name;
    private int    state;

    ... setters and getters go here...
}

State 示例包含两个相同的示例版本,用于解决规则执行冲突:

  • StateExampleUsingSalience 版本,它通过使用规则 salience 解决冲突
  • StateExampleUsingAgendaGroups 版本,该版本使用规则购买组解决冲突

状态示例的两个版本都涉及四个状态对象: ABCD最初,其状态设置为 NOTRUN,这是示例使用的构造器的默认值。

使用 salience 的 state 示例

State 示例的 StateExampleUsingSalience 版本在规则中使用 salience 值来解决规则执行冲突。在激活队列中排序时,具有较高 salience 值的规则会被赋予更高的优先级。

示例将每个 State 实例插入到 KIE 会话中,然后调用 fireAllRules ()

Salience State 示例执行

final State a = new State( "A" );
final State b = new State( "B" );
final State c = new State( "C" );
final State d = new State( "D" );

ksession.insert( a );
ksession.insert( b );
ksession.insert( c );
ksession.insert( d );

ksession.fireAllRules();

// Dispose KIE session if stateful (not required if stateless).
ksession.dispose();

要执行示例,请在 IDE 中作为 Java 应用程序运行 org.drools.examples.state.StateExampleUsingSalience 类。

执行后,以下输出会出现在 IDE 控制台窗口中:

IDE 控制台中的 Salience State 示例输出

A finished
B finished
C finished
D finished

存在四个规则。

首先,"Bootstrap" 规则将触发,将 A 设置为状态 FINISHED,然后会导致 B 将其状态更改为 FINISHED。对象 CD 都依赖于 B,从而导致由 salience 值解析的冲突。

为更好地了解本例的执行流程,您可以将审计日志文件从 target/state.log 加载到 IDE debug 视图或 审计 视图(例如,在一些 IDE 中的 WindowShow View 中)。

在本例中,审计视图显示 对象 A 处于 NOTRUN 的断言激活 "Bootstrap" 规则,而其他对象的断言无效。

图 85.5. Salience State 示例审计视图

状态示例 audit1

salience State 示例中的规则"Bootstrap"

rule "Bootstrap"
  when
    a : State(name == "A", state == State.NOTRUN )
  then
    System.out.println(a.getName() + " finished" );
    a.setState( State.FINISHED );
end

"Bootstrap" 规则的执行会将 A 的状态更改为 FINISHED,这会激活规则 "A to B "。

在 salience State 示例中的规则 "A to B"

rule "A to B"
  when
    State(name == "A", state == State.FINISHED )
    b : State(name == "B", state == State.NOTRUN )
  then
    System.out.println(b.getName() + " finished" );
    b.setState( State.FINISHED );
end

规则 "A to B" 的执行会将 B 的状态更改为 FINISHED,这会激活规则 "B to C""B to D",将其激活放在决策引擎上。

在 salience State 示例中,规则 "B to C" 和 "B to D"

rule "B to C"
    salience 10
  when
    State(name == "B", state == State.FINISHED )
    c : State(name == "C", state == State.NOTRUN )
  then
    System.out.println(c.getName() + " finished" );
    c.setState( State.FINISHED );
end

rule "B to D"
  when
    State(name == "B", state == State.FINISHED )
    d : State(name == "D", state == State.NOTRUN )
  then
    System.out.println(d.getName() + " finished" );
    d.setState( State.FINISHED );
end

此时,这两个规则都可能会触发,因此规则都冲突。冲突解析策略使决策引擎能够决定要触发的规则。规则 "B to C" 具有更高的 salience 值(10 而不是默认的 salience 值 0),因此它会首先触发,将对象 C 修改为状态 FINISHED

IDE 中的 审计 视图显示规则 "A to B" 中的 State 对象的修改,这会导致两个激活冲突。

您还可以使用 IDE 中的 Agenda View 来调查决策引擎模拟的状态。在本例中,Agenda View 显示规则 "A to B" 中的断点,以及带有两个冲突规则的电缆状态。规则 "B to D" 最后触发,将对象 D 修改为状态 FINISHED

图 85.6. Salience State 示例 Agenda View

State example sales1

使用电缆组的状态示例

State 示例的 StateExampleUsingAgendaGroups 版本使用规则中的 sales 组来解决规则执行冲突。通过电缆组,您可以对决策引擎人员进行分区,以提供更多对规则组的执行控制。默认情况下,所有规则都位于 products 组 MAIN 中。您可以使用 sales -group 属性为规则指定不同的 sales 组。

最初,工作内存将其重点放在电缆组 MAIN 上。只有组收到重点时,才会触发电缆组中的规则。您可以使用 setFocus () 或 rule 属性 auto-focus 设置重点。auto-focus 属性可让规则在匹配并激活规则时自动为其电缆组赋予一个重点。

在本例中,auto-focus 属性使规则 "B 到 C"在" B 到 D" 之前触发。

模拟组状态示例中的规则"B 到 C"

rule "B to C"
    agenda-group "B to C"
    auto-focus true
  when
    State(name == "B", state == State.FINISHED )
    c : State(name == "C", state == State.NOTRUN )
  then
    System.out.println(c.getName() + " finished" );
    c.setState( State.FINISHED );
    kcontext.getKnowledgeRuntime().getAgenda().getAgendaGroup( "B to D" ).setFocus();
end

数字组 "B 到 D" 上的规则"B 到 C " 调用 setFocus (),启用它触发的活动规则,然后使规则 "B 到 D" 触发。

模拟组状态示例中的规则"B 到 D"

rule "B to D"
    agenda-group "B to D"
  when
    State(name == "B", state == State.FINISHED )
    d : State(name == "D", state == State.NOTRUN )
  then
    System.out.println(d.getName() + " finished" );
    d.setState( State.FINISHED );
end

要执行示例,请在 IDE 中作为 Java 应用程序运行 org.drools.examples.state.StateExampleUsingAgendaGroups 类。

执行后,以下输出会出现在 IDE 控制台窗口中(与 State 示例的 salience 版本相同):

IDE 控制台中的组状态示例输出

A finished
B finished
C finished
D finished

State 示例中的动态事实

此状态示例中的另一个显著概念是根据实施 PropertyChangeListener 对象的对象 使用动态事实。要让决策引擎查看并对事实属性更改的响应,应用程序必须通知发生了变化的决策引擎。您可以使用 modify 语句明确在规则中配置此通信,或者通过指定事实实现 PropertyChangeSupport 接口来隐式配置。

本例演示了如何使用 PropertyChangeSupport 接口来避免对规则中显式 修改 语句的需求。要使用这个接口,请确保您的事实以类 org.drools.example.State 实施它的方式实现 PropertyChangeSupport,然后使用 DRL 规则文件中的以下代码将决策引擎配置为侦听这些事实上的属性更改:

声明动态事实

declare type State
  @propertyChangeSupport
end

当使用 PropertyChangeListener 对象时,每个 setter 必须为通知实施额外的代码。例如,以下 state 设置器位于类 org.drools.examples 中:

带有 PropertyChangeSupport 的 setter 示例

public void setState(final int newState) {
    int oldState = this.state;
    this.state = newState;
    this.changes.firePropertyChange( "state",
                                     oldState,
                                     newState );
}

85.4. Fibonacci 示例决策(递归和冲突解析)

Fibonacci 示例决策集演示了决策引擎如何使用递归来解析序列中规则的执行冲突。该示例重点通过您可以在规则中定义的 salience 值解决冲突。

以下是 Fibonacci 示例的概述:

  • 名称 :fibonacci
  • 主类org.drools.examples.fibonacci.FibonacciExample ( src/main/java)
  • 模块drools-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.fibonacci.Fibonacci.drl (在 src/main/resources中)
  • 目标 :通过规则 salience 来演示递归和冲突解析

Fibonacci Numbers 形成以 0 和 1 开头的序列。下一个 Fibonacci 号通过添加前面的两个 Fibonacci 号: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946 等。

Fibonacci 示例使用带有以下两个字段的单事实类 Fibonacci

  • sequence
  • value

sequence 字段表示对象在 Fibonacci 数字序列中的位置。value 字段显示该序列位置的 Fibonacci 对象的值,其中 -1 表示仍需要计算的值。

Fibonacci 类

public static class Fibonacci {
    private int  sequence;
    private long value;

    public Fibonacci( final int sequence ) {
        this.sequence = sequence;
        this.value = -1;
    }

    ... setters and getters go here...
}

要执行示例,请在 IDE 中作为 Java 应用程序运行 org.drools.examples.fibonacci.FibonacciExample 类。

执行后,以下输出会出现在 IDE 控制台窗口中:

IDE 控制台中的 Fibonacci 示例输出

recurse for 50
recurse for 49
recurse for 48
recurse for 47
...
recurse for 5
recurse for 4
recurse for 3
recurse for 2
1 == 1
2 == 1
3 == 2
4 == 3
5 == 5
6 == 8
...
47 == 2971215073
48 == 4807526976
49 == 7778742049
50 == 12586269025

为了在 Java 中实现此行为,示例将插入单个 Fibonacci 对象,序列字段为 50。然后,示例使用递归规则插入其他 49 Fibonacci 对象。

这个示例使用 MVEL dialect modify 关键字启用块 setter 操作并通知决策引擎更改,而不是实施 PropertyChangeSupport 接口来使用动态事实。

Fibonacci 示例执行

ksession.insert( new Fibonacci( 50 ) );
ksession.fireAllRules();

这个示例使用以下三个规则:

  • "Recurse"
  • "Bootstrap"
  • "calculate"

规则 "Recurse" 匹配每个断言的 Fibonacci 对象,值为 -1,创建并模拟一个新的 Fibonacci 对象,序列小于当前匹配的对象。每次添加 Fibonacci 对象时,如果一个序列字段等于 1,则该规则会重新匹配并再次触发。当您在内存中所有 50 个 Fibonacci 对象后,in 条件元素用于停止规则匹配。规则也具有 salience 值,因为您需要在执行 "Bootstrap" 规则前,所有 50 个 Fibonacci 对象都变为serted。

规则"递归"

rule "Recurse"
    salience 10
  when
    f : Fibonacci ( value == -1 )
    not ( Fibonacci ( sequence == 1 ) )
  then
    insert( new Fibonacci( f.sequence - 1 ) );
    System.out.println( "recurse for " + f.sequence );
end

为更好地了解本例的执行流程,您可以将审计日志文件从 target/fibonacci.log 加载到 IDE debug 视图或 审计 视图(例如,在 WindowShow View 中)。

在本例中,审计视图显示 Fibonacci 对象的原始断言,序列 字段为 50,从 Java 代码完成。从那里,审计视图显示 规则的持续递归,其中每个断言 Fibonacci 对象会导致 "递归" 规则激活并再次触发。

图 85.7. 审计视图中的规则"递归"

fibonacci1

Fibonacci 对象带有 2 序列 字段被断言时,"Bootstrap" 规则会与 "递归"规则匹配 并激活。请注意,对于字段 序列 的限制,测试使用 12 的相等性:

规则"Bootstrap"

rule "Bootstrap"
  when
    f : Fibonacci( sequence == 1 || == 2, value == -1 ) // multi-restriction
  then
    modify ( f ){ value = 1 };
    System.out.println( f.sequence + " == " + f.value );
end

您还可以使用 IDE 中的 Agenda View 来调查决策引擎模拟的状态。"Bootstrap" 规则尚未触发,因为 "递归" 规则具有更高的 salience 值。

图 85.8. Agenda View 1 中的规则"递归"和"Bootstrap"

fibonacci technology1

当带有 1 序列Fibonacci 对象被断言时,"Bootstrap" 规则会再次匹配,从而导致该规则的两个激活。"递归" 规则不匹配并激活,因为当存在带有 1 序列Fibonacci 对象后,t 条件元素会立即停止匹配。

图 85.9. Agenda View 2 中的规则"递归"和"Bootstrap"

fibonacci agenda2

"Bootstrap" 规则将 序列12 的对象设置为值 1。现在,您有两个 Fibonacci 对象的值不等于 -1, "Calculate" 规则可以匹配。

此时,工作内存中几乎有 50 个 Fibonacci 对象。您需要选择合适的 triple 来依次计算每个值。如果您在没有字段限制的规则中使用三种 Fibonacci 模式来限制可能的跨产品,则结果将是 50x49x48 可能的组合,从而导致大约 125,000 个可能的规则触发,大多数规则都不正确。

"Calculate" 规则使用字段限制来以正确顺序评估三种 Fibonacci 模式。此技术称为 跨产品匹配

第一个模式找到任何值为 != -1Fibonacci 对象,并绑定模式和字段。第二个 Fibonacci 对象执行同样的操作,但添加额外的字段约束,以确保其序列大于绑定到 f1Fibonacci 对象。当此规则第一次触发时,您知道只有序列 12 具有 1 值,并且两个限制可确保 f1 引用序列 1,以及 f2 引用序列 2

最终模式找到 Fibonacci 对象,值设为 -1, 以及一个大于 f2 的序列。

此时,可从可用的跨产品正确选择三个 Fibonacci 对象,您可以计算绑定到 f3 的第三个 Fibonacci 对象的值。

规则"Calculate"

rule "Calculate"
  when
    // Bind f1 and s1.
    f1 : Fibonacci( s1 : sequence, value != -1 )
    // Bind f2 and v2, refer to bound variable s1.
    f2 : Fibonacci( sequence == (s1 + 1), v2 : value != -1 )
    // Bind f3 and s3, alternative reference of f2.sequence.
    f3 : Fibonacci( s3 : sequence == (f2.sequence + 1 ), value == -1 )
  then
    // Note the various referencing techniques.
    modify ( f3 ) { value = f1.value + v2 };
    System.out.println( s3 + " == " + f3.value );
end

modify 语句更新绑定到 f3Fibonacci 对象的值。这意味着您现在有一个没有等于 -1 的新 Fibonacci 对象,这允许 "Calculate" 规则重新匹配并计算下一个 Fibonacci 号。

IDE 的 debug 视图或 审计 视图显示触发最后一个 "Bootstrap" 规则如何修改 Fibonacci 对象,启用 "Calculate" 规则匹配,然后修改另一个 Fibonacci 对象,以便 "Calculate" 规则再次匹配。这个过程会继续,直到为所有 Fibonacci 对象设置值。

图 85.10. 审计视图中的规则

fibonacci4

85.5. 定价示例决策(精确表)

账单示例决策演示了如何使用电子表格决策表来计算以 tabular 格式而不是直接在 DRL 文件中计算过期策略的成本。

以下是隔离示例的概述:

  • 名称:Decisiontable
  • 主类org.drools.examples.decisiontable.PricingRuleDTExample (在 src/main/java中)
  • 模块drools-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.decisiontable.ExamplePolicyPricing.xls (在 src/main/resources中)
  • 目标 :演示使用电子表格决策表来定义规则

电子表格决策表是 XLS 或 XLSX 电子表,其中包含以表格格式定义的新规则。您可以使用独立 Red Hat Process Automation Manager 项目包含电子表格决策表,或者在 Business Central 中将它们上传到项目。决策表中的每一行都是一条规则,每个列都是一个条件、操作或其他规则属性。创建决策表并将其上传到 Red Hat Process Automation Manager 项目后,您定义的规则会编译成带有所有其他规则资产的 dols 规则。

定价示例的目的是提供一组新规则来计算基本价格,以及适用于特定类型的销售政策的库存驱动程序的货币。驱动程序的年龄和历史记录以及策略类型包括计算基本 Premium 贡献,其他规则会计算该驱动程序可能有资格的潜在承诺。

要执行示例,请在 IDE 中作为 Java 应用程序运行 org.drools.examples.decisiontable.PricingRuleDTExample 类。

执行后,以下输出会出现在 IDE 控制台窗口中:

Cheapest possible
BASE PRICE IS: 120
DISCOUNT IS: 20

执行示例的代码遵循典型的执行模式:规则已加载,插入事实,并且创建了无状态 KIE 会话。本例中的区别在于,规则在 ExamplePolicyPricing.xls 文件中定义,而不是 DRL 文件或其他源。电子表格文件使用模板和 DRL 规则加载到决策引擎中。

电子表格决策设置

ExamplePolicyPricing.xls 电子表在第一个标签页中包含两个决策表:

  • 基本定价规则
  • 促销活动规则

在示例电子表格演示时,您只能使用电子表的第一个标签页来创建路由表,但多个表可以在单个标签页内。决策表不一定遵循顶层逻辑,但更容易地捕获导致规则的数据。对规则的评估不一定是以给定顺序的评估,因为决策引擎的所有正常机制仍适用。这就是您可以在电子表的同一标签页中有多个决策表的原因。

决策表通过对应的规则模板文件 BasePricing.drtPromotionalPricing.drt 执行。这些模板文件通过其模板参数引用决策表,并直接引用决策表中的条件和操作的各种标头。

BasePricing.drt 规则模板文件

template header
age[]
profile
priorClaims
policyType
base
reason

package org.drools.examples.decisiontable;

template "Pricing bracket"
age
policyType
base

rule "Pricing bracket_@{row.rowNumber}"
  when
    Driver(age >= @{age0}, age <= @{age1}
        , priorClaims == "@{priorClaims}"
        , locationRiskProfile == "@{profile}"
    )
    policy: Policy(type == "@{policyType}")
  then
    policy.setBasePrice(@{base});
    System.out.println("@{reason}");
end
end template

PromotionalPricing.drt 规则模板文件

template header
age[]
priorClaims
policyType
discount

package org.drools.examples.decisiontable;

template "discounts"
age
priorClaims
policyType
discount

rule "Discounts_@{row.rowNumber}"
  when
    Driver(age >= @{age0}, age <= @{age1}, priorClaims == "@{priorClaims}")
    policy: Policy(type == "@{policyType}")
  then
    policy.applyDiscount(@{discount});
end
end template

规则通过 KIE Session DTableWithTemplateKBkmodule.xml 引用执行,这专门提到 ExamplePolicyPricing.xls 电子表,它是成功执行规则所必需的。此执行方法允许您将规则作为独立单元(如本例中)执行,或者在打包知识 JAR (KJAR)文件中包含规则,以便电子表格与要执行的规则一起打包。

执行规则和电子表格才能成功完成 kmodule.xml 文件的以下部分:

    <kbase name="DecisionTableKB" packages="org.drools.examples.decisiontable">
        <ksession name="DecisionTableKS" type="stateless"/>
    </kbase>

    <kbase name="DTableWithTemplateKB" packages="org.drools.examples.decisiontable-template">
        <ruleTemplate dtable="org/drools/examples/decisiontable-template/ExamplePolicyPricingTemplateData.xls"
                      template="org/drools/examples/decisiontable-template/BasePricing.drt"
                      row="3" col="3"/>
        <ruleTemplate dtable="org/drools/examples/decisiontable-template/ExamplePolicyPricingTemplateData.xls"
                      template="org/drools/examples/decisiontable-template/PromotionalPricing.drt"
                      row="18" col="3"/>
        <ksession name="DTableWithTemplateKS"/>
    </kbase>

作为使用规则模板文件执行决策表的替代选择,您可以使用 DecisionTableConfiguration 对象并将输入电子表指定为输入类型,如 DecisionTableInputType.xls

DecisionTableConfiguration dtableconfiguration =
    KnowledgeBuilderFactory.newDecisionTableConfiguration();
        dtableconfiguration.setInputType( DecisionTableInputType.XLS );

        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();

        Resource xlsRes = ResourceFactory.newClassPathResource( "ExamplePolicyPricing.xls",
                                                                getClass() );
        kbuilder.add( xlsRes,
                      ResourceType.DTABLE,
                      dtableconfiguration );

比较示例使用两种事实类型:

  • 驱动
  • 策略.

这个示例在对应的 Java 类 Driver.javaPolicy.java 中为事实设置默认值。驱动程序存在 30 年,没有之前的声明,目前具有风险配置文件 LOW驱动程序 所应用的策略是 COMPREHENSIVE

在任何决策表中,每行都被视为不同的规则,每个列都是一个条件或一个操作。每行在决策表中评估,除非在执行时清除了电缆。

决策表分布表(XLS 或 XLSX)需要两个关键区域来定义规则数据:

  • RuleSet 区域
  • RuleTable 区域

电子表格的 RuleSet 区域定义了您要全局应用到同一软件包中的所有规则的元素(不仅仅是电子表格),如规则集名称或通用规则属性。RuleTable 区域定义实际规则(箭头),以及组成指定规则集中的规则表的条件、操作和其他规则属性(columns)。决策表电子表格可以包含多个 RuleTable 区域,但只能包含一个 RuleSet 区域。

图 85.11. 决策表配置

DT Config

RuleTable 区域还定义规则属性应用到的对象,本例中为 DriverPolicy,以及对象的限制。例如,定义 Age Bracket 列的 Driver 对象约束是 age >= $1, age <= $2,其中以逗号分隔的范围在表列值中定义,如 18,24

基本定价规则

定价示例中的基本定价规则 决策表评估驱动程序的年龄、风险配置文件、声明数和策略类型,并根据这些条件生成策略的基本价格。

图 85.12. 基本价格计算

DT Table1

Driver 属性在下表中定义:

  • 年龄 Bracket :年龄括号包含条件 年龄 >=$1 的定义,年龄 <=$2,它定义了驱动程序期限的条件边界。此条件列突出显示 $1 和 $2 的使用,后者在电子表格中用逗号分开。您可以将这些值写入 18、2418,且两个格式都在执行自定义规则中工作。
  • 位置风险配置文件 : risk 配置集是一个字符串,示例程序始终以 LOW 的形式传递,但可以更改为反映 MEDHIGH
  • 之前的声明数量 :声明的数量定义为 condition 列必须完全等于触发该操作的整数。该值不是范围,仅完全匹配。

决策表的策略用于条件和规则操作,并在下表中定义属性:

  • 应用的策略类型 :策略类型是一个条件,它作为字符串传递,用于定义覆盖范围类型:COMPREHENSIVE、FIRE_THEFT、或 THIRD_PARTY
  • Base $ AUDbasePrice 定义为一个 ACTION,它根据与此值对应的电子表格单元,通过约束 policy.setBasePrice ($param) 设置价格。当您为此决策表执行对应的 DRL 规则时,该规则部分对与事实匹配的 true 条件执行这个 action 语句,并将基本价格设置为对应的值。
  • 记录原因 :当规则成功执行时,此操作会在 System.out 控制台中生成输出消息,反映触发的规则。之后会在应用程序中捕获并打印。

该示例也使用左侧的第一列对规则进行分类。此列仅用于注解,不会影响规则执行。

促销活动规则

计费示例中的促销活动规则 决策表评估了驱动程序的年龄、之前声明数量和策略类型,以根据销售政策价格产生潜在的参与。

图 85.13. 主要计算

DT Table2

此决策表包含该驱动程序可能有资格的条件。与基本价格计算类似,此表评估驱动程序的期限、之前声明的数量以及应用 Policy 类型 以确定要应用的 Discount % 速率。例如,如果驱动程序存在 30 年,没有之前的声明,并且针对 COMPREHENSIVE 策略应用,则驱动程序被指定为 20 百分比。

85.6. pet Store 示例决策(genda 组、全局变量、回调和 GUI 集成)

Pet Store 示例决定集演示了如何在规则中使用电缆组和全局变量,以及如何将 Red Hat Process Automation Manager 规则与图形用户界面(GUI)集成。在这种情况下,基于 Swing 的桌面应用程序。这个示例还演示了如何使用回调与正在运行的决策引擎交互,根据运行时工作内存的更改更新 GUI。

以下是 Pet Store 示例的概述:

  • 名称 :petstore
  • 主类org.drools.examples.petstore.PetStoreExample (在 src/main/java中)
  • 模块drools-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.petstore.PetStore.drl (在 src/main/resources中)
  • 目标 :演示规则关联组、全局变量、回调和 GUI 集成

在 Pet Store 示例中,P etStoreExample.java 类定义了以下主体类(除了处理 Swing 事件的多个类外):

  • Petstore 包含 main () 方法。
  • PetStoreUI 负责创建和显示基于 Swing 的 GUI。此类包含几个较小的类,主要用于响应各种 GUI 事件,如用户鼠标点击。
  • TableModel 包含表数据。此类基本上是一个 JavaBean,它扩展了 Swing 类 AbstractTableModel
  • 签出回调 可让 GUI 与规则交互。
  • Ordershow 保留您要购买的项目。
  • 购买 存储您购买的订购和产品的详细信息。
  • 产品 是一种 JavaBean,其中包含可用于购买的产品及其价格。

本例中的许多 Java 代码是基于普通 JavaBean 或 Swing 的普通代码。有关 Swing 组件的更多信息,请参阅有关 使用 JFC/Swing 创建 GUI 的 Java 指南。

Pet Store 示例中的规则执行行为

与其他示例决定,事实被立即触发,Petet Store 示例不会执行规则,直到基于用户交互收集更多事实。示例通过由构造器创建的 PetStoreUI 对象执行规则,该对象接受用于收集产品的 Vector 对象。然后,示例使用 CheckoutCallback 类的实例,其中包含之前载入的规则基础。

pet Store KIE 容器和事实执行设置

// KieServices is the factory for all KIE services.
KieServices ks = KieServices.Factory.get();

// Create a KIE container on the class path.
KieContainer kc = ks.getKieClasspathContainer();

// Create the stock.
Vector<Product> stock = new Vector<Product>();
stock.add( new Product( "Gold Fish", 5 ) );
stock.add( new Product( "Fish Tank", 25 ) );
stock.add( new Product( "Fish Food", 2 ) );

// A callback is responsible for populating the working memory and for firing all rules.
PetStoreUI ui = new PetStoreUI( stock,
                                new CheckoutCallback( kc ) );
ui.createAndShowGUI();

触发规则的 Java 代码位于 CheckoutCallBack.checkout () 方法中。当用户在 UI 中点 Checkout 时触发此方法。

从 CheckoutCallBack.checkout ()执行规则

public String checkout(JFrame frame, List<Product> items) {
    Order order = new Order();

    // Iterate through list and add to cart.
    for ( Product p: items ) {
        order.addItem( new Purchase( order, p ) );
    }

    // Add the JFrame to the ApplicationData to allow for user interaction.

    // From the KIE container, a KIE session is created based on
    // its definition and configuration in the META-INF/kmodule.xml file.
    KieSession ksession = kcontainer.newKieSession("PetStoreKS");

    ksession.setGlobal( "frame", frame );
    ksession.setGlobal( "textArea", this.output );

    ksession.insert( new Product( "Gold Fish", 5 ) );
    ksession.insert( new Product( "Fish Tank", 25 ) );
    ksession.insert( new Product( "Fish Food", 2 ) );

    ksession.insert( new Product( "Fish Food Sample", 0 ) );

    ksession.insert( order );

    // Execute rules.
    ksession.fireAllRules();

    // Return the state of the cart
    return order.toString();
}

示例代码将两个元素传递给 CheckoutCallBack.checkout () 方法。一个元素是 JFrame Swing 组件的处理,它包括输出文本帧,位于 GUI 的底部。第二个元素是订购项的列表,它来自 TableModel,它将信息从 GUI 右上角的 Table 区域存储。

for 循环将来自 GUI 的订购项列表转换为 Order JavaBean,也包含在 PetStoreExample.java 文件中。

在这种情况下,规则在无状态 KIE 会话中触发,因为所有数据都存储在 Swing 组件中,且不会执行,直到用户在 UI 中点 Checkout。每次点击 Checkout 时,列表的内容都会从 Swing TableModel 移到 KIE 会话工作内存中,然后使用 ksession.fireAllRules () 方法执行。

在此代码中,对 KieSession 有 9 个调用。首先从 KieContainer 创建一个新的 KieSession (此 KieContainer 中从 main () 方法中的 CheckoutCallBack 类传递的示例)。接下来的两个调用传递在规则中保存全局变量的两个对象:Swing 文本区域和用于编写消息的 Swing 帧。更多插入将产品的信息放在 KieSession 中,以及订购列表中。最后的调用是标准 fireAllRules ()

pet Store 规则文件导入、全局变量和 Java 功能

PetStore.drl 文件包含标准软件包和导入语句,供规则提供各种 Java 类。规则文件还包含 要在规则中使用的全局变量,定义为 和文本。全局变量包含对之前被名为 setGlobal () 方法的 Java 代码传递的 Swing 组件 JFrameJTextArea 组件的引用。与规则中的标准变量不同,当规则触发后马上过期,全局变量会在 KIE 会话生命周期中保留其值。这意味着这些全局变量的内容可用于评估所有后续规则。

Petstore.drl 软件包、导入和全局变量

package org.drools.examples;

import org.kie.api.runtime.KieRuntime;
import org.drools.examples.petstore.PetStoreExample.Order;
import org.drools.examples.petstore.PetStoreExample.Purchase;
import org.drools.examples.petstore.PetStoreExample.Product;
import java.util.ArrayList;
import javax.swing.JOptionPane;

import javax.swing.JFrame;

global JFrame frame
global javax.swing.JTextArea textArea

PetStore.drl 文件还包含文件中规则使用的两个功能:

PetStore.drl Java functions

function void doCheckout(JFrame frame, KieRuntime krt) {
        Object[] options = {"Yes",
                            "No"};

        int n = JOptionPane.showOptionDialog(frame,
                                             "Would you like to checkout?",
                                             "",
                                             JOptionPane.YES_NO_OPTION,
                                             JOptionPane.QUESTION_MESSAGE,
                                             null,
                                             options,
                                             options[0]);

       if (n == 0) {
            krt.getAgenda().getAgendaGroup( "checkout" ).setFocus();
       }
}

function boolean requireTank(JFrame frame, KieRuntime krt, Order order, Product fishTank, int total) {
        Object[] options = {"Yes",
                            "No"};

        int n = JOptionPane.showOptionDialog(frame,
                                             "Would you like to buy a tank for your " + total + " fish?",
                                             "Purchase Suggestion",
                                             JOptionPane.YES_NO_OPTION,
                                             JOptionPane.QUESTION_MESSAGE,
                                             null,
                                             options,
                                             options[0]);

       System.out.print( "SUGGESTION: Would you like to buy a tank for your "
                           + total + " fish? - " );

       if (n == 0) {
             Purchase purchase = new Purchase( order, fishTank );
             krt.insert( purchase );
             order.addItem( purchase );
             System.out.println( "Yes" );
       } else {
            System.out.println( "No" );
       }
       return true;
}

这两个功能执行以下操作:

  • doCheckout () 显示一个对话框,该对话框询问用户是否是她或他希望签出的。如果用户这样做,则重点设置为 checkout sales 组,使该组中的规则能够触发。
  • requireTank () 显示一个对话框,它要求用户在她或他希望购买 fish tank 时询问用户。如果用户这样做,会将一个新的 fish tank 产品 添加到工作内存的顺序列表中。
注意

在本例中,所有规则和功能都在同一个规则文件中有效。在生产环境中,您通常会在不同的文件中分隔规则和功能,或构建静态 Java 方法并使用导入功能导入文件,如 导入功能 my.package.name.hello

带有销售组的 pet 存储规则

Pet Store 示例中的大多数规则都使用电缆组来控制规则执行。通过电缆组,您可以对决策引擎人员进行分区,以提供更多对规则组的执行控制。默认情况下,所有规则都位于 products 组 MAIN 中。您可以使用 sales -group 属性为规则指定不同的 sales 组。

最初,工作内存将其重点放在电缆组 MAIN 上。只有组收到重点时,才会触发电缆组中的规则。您可以使用 setFocus () 或 rule 属性 auto-focus 设置重点。auto-focus 属性可让规则在匹配并激活规则时自动为其电缆组赋予一个重点。

Pet Store 示例对规则使用以下电缆组:

  • "init"
  • "evaluate"
  • "show items"
  • "checkout"

例如,示例规则 "Explode Cart" 使用 "init" cart 组来确保它有选择触发并插入 KIE 会话工作内存中:

规则"Explode Cart"

// Insert each item in the shopping cart into the working memory.
rule "Explode Cart"
    agenda-group "init"
    auto-focus true
    salience 10
  when
    $order : Order( grossTotal == -1 )
    $item : Purchase() from $order.items
  then
    insert( $item );
    kcontext.getKnowledgeRuntime().getAgenda().getAgendaGroup( "show items" ).setFocus();
    kcontext.getKnowledgeRuntime().getAgenda().getAgendaGroup( "evaluate" ).setFocus();
end

此规则与尚未计算其 grossTotal 的所有顺序匹配。每个购买项目的执行循环(按该顺序排列)。

规则使用与 leader 组相关的以下功能:

  • runlevel-group "init" 定义 products 组的名称。在这种情况下,只有一个规则位于组中。但是,Java 代码和规则结果都不适用于此组,因此它依赖于 auto-focus 属性来触发它。
  • auto-focus true 确保此规则虽然是 sales 组中的唯一规则,则在从 Java 代码调用 fireAllRules () 时获得触发的机会。
  • kcontext…​.setFocus () 将重点设置为 "显示项目 " 和"评估" 组,允许触发规则。在实践中,您将按顺序执行所有项目,将它们插入到内存中,然后在插入后触发其他规则。

"show items" products group 仅包含一条规则,"Show items"。对于 KIE 会话工作内存中当前顺序的每个购买,规则会根据规则文件中定义的 textArea 变量将详细信息记录到 GUI 底部的文本区域。

规则"Show items"

rule "Show Items"
    agenda-group "show items"
  when
    $order : Order()
    $p : Purchase( order == $order )
  then
   textArea.append( $p.product + "\n");
end

"评估" 公司组也从 "Explode Cart" 规则中获得了重点。此电话号码组包含两个规则 :"Free Fish Food Sample""Suggest Tank",它们按顺序执行。

规则 "Free Fish Food Sample"

// Free fish food sample when users buy a goldfish if they did not already buy
// fish food and do not already have a fish food sample.
rule "Free Fish Food Sample"
    agenda-group "evaluate" 1
  when
    $order : Order()
    not ( $p : Product( name == "Fish Food") && Purchase( product == $p ) ) 2
    not ( $p : Product( name == "Fish Food Sample") && Purchase( product == $p ) ) 3
    exists ( $p : Product( name == "Gold Fish") && Purchase( product == $p ) ) 4
    $fishFoodSample : Product( name == "Fish Food Sample" );
  then
    System.out.println( "Adding free Fish Food Sample to cart" );
    purchase = new Purchase($order, $fishFoodSample);
    insert( purchase );
    $order.addItem( purchase );
end

只有在满足以下条件时,规则 "Free Fish Food Sample" 才会触发:

1
在规则执行中,评估组 "evaluate" 组。
2
用户还没有 fish food。
3
用户还没有免费的 fish food 示例。
4
用户按顺序有一个黄金的fish。

如果顺序事实满足所有这些要求,则会创建一个新产品(Fish Food Sample),并添加到工作内存的顺序中。

规则"Suggest Tank"

// Suggest a fish tank if users buy more than five goldfish and
// do not already have a tank.
rule "Suggest Tank"
    agenda-group "evaluate"
  when
    $order : Order()
    not ( $p : Product( name == "Fish Tank") && Purchase( product == $p ) ) 1
    ArrayList( $total : size > 5 ) from collect( Purchase( product.name == "Gold Fish" ) ) 2
    $fishTank : Product( name == "Fish Tank" )
  then
    requireTank(frame, kcontext.getKieRuntime(), $order, $fishTank, $total);
end

只有在满足以下条件时,规则 "Suggest Tank" 才会触发:

1
用户的顺序没有 fish tank。
2
用户按顺序有超过五个 fish。

当规则触发时,它将调用规则文件中定义的 requireTank () 函数。此函数会显示一个对话框,它要求用户在她或他希望购买 fish tank 时询问用户。如果用户这样做,会将一个新的 fish tank 产品 添加到工作内存的顺序列表中。当规则调用 requireTank () 函数时,该规则会传递 全局变量,以便函数能够处理 Swing GUI。

Pet Store 示例中的 "do checkout" 规则没有 sales 组,且没有 when 条件,因此始终执行该规则并被视为默认 MAIN phone 组的一部分。

规则"do checkout"

rule "do checkout"
  when
  then
    doCheckout(frame, kcontext.getKieRuntime());
end

当规则触发时,它将调用规则文件中定义的 doCheckout () 函数。此函数会显示一个对话框,用于询问用户是否是她或他希望签出的对话框。如果用户这样做,则重点设置为 checkout sales 组,使该组中的规则能够触发。当规则调用 doCheckout () 函数时,该规则会传递 全局变量,以便函数能够处理 Swing GUI。

注意

本例还演示了一个故障排除技术,如果结果没有如您预期执行:您可以从规则的 when 语句中删除条件,并在 then 语句中测试操作以验证操作是否已正确执行。

"checkout" products 组包含三个规则,用于处理顺序签出并应用任何活动:" Gross Total", " Apply 5% Discount", 和 "Apply 10% Discount"

规则 "Gross Total", "Apply 5% Discount", 和 "Apply 10% Discount"

rule "Gross Total"
    agenda-group "checkout"
  when
    $order : Order( grossTotal == -1)
    Number( total : doubleValue ) from accumulate( Purchase( $price : product.price ),
                                                              sum( $price ) )
  then
    modify( $order ) { grossTotal = total }
    textArea.append( "\ngross total=" + total + "\n" );
end

rule "Apply 5% Discount"
    agenda-group "checkout"
  when
    $order : Order( grossTotal >= 10 && < 20 )
  then
    $order.discountedTotal = $order.grossTotal * 0.95;
    textArea.append( "discountedTotal total=" + $order.discountedTotal + "\n" );
end

rule "Apply 10% Discount"
    agenda-group "checkout"
  when
    $order : Order( grossTotal >= 20 )
  then
    $order.discountedTotal = $order.grossTotal * 0.90;
    textArea.append( "discountedTotal total=" + $order.discountedTotal + "\n" );
end

如果用户还没有计算 gross 总计,则 Gross Total 将产品价格聚合到总计,请将这个总数放在 KIE 会话中,并使用 textArea 全局变量通过 Swing JTextArea 显示它。

如果 gross 总数介于 1020 之间(策展单位),"Apply 5% Discount" 规则计算活动总数,将其添加到 KIE 会话中,并在文本区域中显示它。

如果 gross 总数不小于 20"Apply 10% Discount" 规则会计算参与总数,将其添加到 KIE 会话中,并在文本区域中显示它。

pet Store 示例执行

与其他 Red Hat Process Automation Manager 决策示例类似,您可以通过在 IDE 中作为 Java 应用程序运行 org.drools.examples.petstore.PetStoreExample 类来执行 Pet Store 示例。

当您执行 Pet Store 示例时,会出现 Pet Store Demo GUI 窗口。此窗口显示可用产品列表(左下),这是所选产品的空列表(右下)、checkout 和 Reset 按钮(中间)和空系统消息区域(bottom)。

图 85.14. 启动后,pet Store 示例 GUI

1 Petstore 开始屏幕

本例中发生以下事件来建立此执行行为:

  1. main () 方法已运行并加载规则基础,但还没有触发规则。目前,这是与已运行的规则连接的唯一代码。
  2. 创建了一个新的 PetStoreUI 对象,并授予规则基础的处理,以便稍后使用。
  3. 各种 Swing 组件已执行其功能,并显示初始 UI 屏幕并等待用户输入。

您可以点击列表中的各种产品来浏览 UI 设置:

图 85.15. 探索 Pet Store 示例 GUI

2 个库存添加到订购列表中

还没有触发规则代码。UI 使用 Swing 代码来检测用户鼠标点击,并将所选产品添加到 TableModel 对象中,以便在 UI 右上角显示。本例演示了 Model-View-Controller 设计模式。

当您点 Checkout 时,规则将以以下方式触发:

  1. 方法 CheckOutCallBack.checkout () 被 Swing 类调用(eventually),等待用户单击 Checkout。这会将来自 TableModel 对象(每个 UI 右上角)的数据插入到 KIE 会话工作内存中。然后,方法会触发规则。
  2. "Explode Cart" 规则是第一个触发,auto-focus 属性设置为 true。规则循环到 cart 中的所有产品,确保产品处于工作内存中,然后为 "显示项"和" 评估" 组提供触发的选项。这些组中的规则将 cart 的内容添加到文本区域( UI 不存在),评估您是否有资格免费 fish food,并决定是否希望购买 fish tank。

    图 85.16. fish tank mailbox

    3 购买建议
  3. "do checkout" 规则是触发的下一个规则,因为目前没有其他电缆组,因为它是默认的 MAIN farm 组的一部分。此规则始终调用 doCheckout () 函数,它要求您签出。
  4. doCheckout () 函数将重点设置为 "checkout" 电缆组,为该组中的规则提供要触发的选项。
  5. "checkout" 电缆组中的规则显示 cart 的内容,并应用适当的语音。
  6. 然后,Swing 会等待用户输入来选择更多产品(并导致规则再次触发)或关闭 UI。

    图 85.17. 所有规则触发后的 pet Store 示例 GUI

    4 Petstore 最终屏幕

您可以添加更多 System.out 调用来在 IDE 控制台中演示此事件流:

IDE 控制台中的 system.out 输出

Adding free Fish Food Sample to cart
SUGGESTION: Would you like to buy a tank for your 6 fish? - Yes

85.7. honest Politician 示例决策(非维护和风险)

Honest Politician 示例决定集演示了通过逻辑插入以及规则中的 salience 使用的真实维护的概念。

以下是 Honest Politician 示例的概述:

  • 名称:honestpolitician
  • 主类org.drools.examples.honestpolitician.HonestPoliticianExample (在 src/main/java中)
  • 模块drools-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.honestpolitician.HonestPolitician.drl (在 src/main/resources中)
  • 目标 :根据事实的逻辑插入和规则的使用,说明事实中的事实概念

Honest Politician 示例的基本内部是,只有语句为 true 时对象才能存在。规则结果可以在逻辑上插入带有 insertLogical () 方法的对象。这意味着,只要逻辑插入的规则保持在 KIE 会话工作内存中,对象仍保持在 KIE 会话工作内存中。当不再满足该规则时,对象会自动重新遍历。

在本例中,执行规则会导致一组 politicians 从 honest 变为 dishonest,从而导致一个被破坏的攻击。评估每个 politician 后,它们从设为 true 的 honesty 属性开始,但一条规则会触发使 politicians 不再休眠的规则。当它们的状态从 honest 切换到 dishonest 时,它们会被从工作内存中移除。规则 salience 通知决策引擎如何优先选择为它们定义了差异的任何规则,否则使用默认的 salience 值 0。在激活队列中排序时,具有较高 salience 值的规则会被赋予更高的优先级。

Politician 和 Hope 类

示例中的 Politician 示例是为 honest politician 配置的示例。Politician 类由 String 项 名称和 一个布尔值项组成:

Politician 类

public class Politician {
    private String name;
    private boolean honest;
    ...
}

Hope 类确定 Hope 对象是否存在。这类没有有意义的成员,但只要这个要求,就存在于工作内存中。

期望类

public class Hope {

    public Hope() {

    }
  }

politician honesty 的规则定义

在 Honest Politician 示例中,当工作内存中至少有一个 honest politician 时,"We 有一个 honest Politician" 规则逻辑插入一个新的 Hope 对象。当所有策略都变为 dishonest 后,H ope 对象会自动重新遍历。此规则具有值 10salience 属性,以确保它在任何其他规则之前触发,因为该阶段 "Hope 是 Dead" 规则为 true。

规则 "We 有一个 honest politician"

rule "We have an honest Politician"
    salience 10
  when
    exists( Politician( honest == true ) )
  then
    insertLogical( new Hope() );
end

一旦存在 Hope 对象,"Hope Lives" 规则会匹配并触发。此规则也具有 10salience 值,因此它优先于 "Conest" 规则。

规则"Hope Lives"

rule "Hope Lives"
    salience 10
  when
    exists( Hope() )
  then
    System.out.println("Hurrah!!! Democracy Lives");
end

最初,四个 honest politicians 存在,因此此规则有四个激活,它们都存在冲突。每个规则依次触发,破坏每个策略,使它们不再被休眠。当所有四个 politician 都损坏时,没有 politicians 属性 honest == true。规则 "We have a honest Politician" 不再为 true,其逻辑插入的对象(由于上次执行 新 Hope ())将自动重新遍历。

规则"Corrupt the Honest"

rule "Corrupt the Honest"
  when
    politician : Politician( honest == true )
    exists( Hope() )
  then
    System.out.println( "I'm an evil corporation and I have corrupted " + politician.getName() );
    modify ( politician ) { honest = false };
end

使用 Hope 对象会自动重新遍历事实维护系统,不适用于 Hope 的 condition 元素不再为 true,因此 "Hope 是 Dead" 规则匹配并触发。

规则"Hope 是 Dead"

rule "Hope is Dead"
  when
    not( Hope() )
  then
    System.out.println( "We are all Doomed!!! Democracy is Dead" );
end

执行和审核跟踪示例

HonestPoliticianExample.java 类中,会插入四个 politicians,并将 honest 状态设置为 true,以针对定义的自定义规则进行评估:

HonestPoliticianExample.java class execution

public static void execute( KieContainer kc ) {
        KieSession ksession = kc.newKieSession("HonestPoliticianKS");

        final Politician p1 = new Politician( "President of Umpa Lumpa", true );
        final Politician p2 = new Politician( "Prime Minster of Cheeseland", true );
        final Politician p3 = new Politician( "Tsar of Pringapopaloo", true );
        final Politician p4 = new Politician( "Omnipotence Om", true );

        ksession.insert( p1 );
        ksession.insert( p2 );
        ksession.insert( p3 );
        ksession.insert( p4 );

        ksession.fireAllRules();

        ksession.dispose();
    }

要执行示例,请在 IDE 中作为 Java 应用程序运行 org.drools.examples.honestpolitician.HonestPoliticianExample 类。

执行后,以下输出会出现在 IDE 控制台窗口中:

IDE 控制台中的执行输出

Hurrah!!! Democracy Lives
I'm an evil corporation and I have corrupted President of Umpa Lumpa
I'm an evil corporation and I have corrupted Prime Minster of Cheeseland
I'm an evil corporation and I have corrupted Tsar of Pringapopaloo
I'm an evil corporation and I have corrupted Omnipotence Om
We are all Doomed!!! Democracy is Dead

输出显示,尽管至少有一个 honest politician democracy lives。但是,由于每个 politician 都被一些公司损坏,所有策略都会变得不当,并且 democracy 都被死。

要更好地了解本例的执行流程,您可以修改 HonestPoliticianExample.java 类,使其包含 DebugRuleRuntimeEventListener 侦听器和一个审核日志记录器来查看执行详情:

带有审计日志记录器的 HonestPoliticianExample.java 类

package org.drools.examples.honestpolitician;

import org.kie.api.KieServices;
import org.kie.api.event.rule.DebugAgendaEventListener; 1
import org.kie.api.event.rule.DebugRuleRuntimeEventListener;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

public class HonestPoliticianExample {

    /**
     * @param args
     */
    public static void main(final String[] args) {
    	KieServices ks = KieServices.Factory.get(); 2
    	//ks = KieServices.Factory.get();
        KieContainer kc = KieServices.Factory.get().getKieClasspathContainer();
        System.out.println(kc.verify().getMessages().toString());
        //execute( kc );
        execute( ks, kc); 3
    }

    public static void execute( KieServices ks, KieContainer kc ) { 4
        KieSession ksession = kc.newKieSession("HonestPoliticianKS");

        final Politician p1 = new Politician( "President of Umpa Lumpa", true );
        final Politician p2 = new Politician( "Prime Minster of Cheeseland", true );
        final Politician p3 = new Politician( "Tsar of Pringapopaloo", true );
        final Politician p4 = new Politician( "Omnipotence Om", true );

        ksession.insert( p1 );
        ksession.insert( p2 );
        ksession.insert( p3 );
        ksession.insert( p4 );

        // The application can also setup listeners 5
        ksession.addEventListener( new DebugAgendaEventListener() );
        ksession.addEventListener( new DebugRuleRuntimeEventListener() );

        // Set up a file-based audit logger.
        ks.getLoggers().newFileLogger( ksession, "./target/honestpolitician" ); 6

        ksession.fireAllRules();

        ksession.dispose();
    }

}

1
在导入处理 DebugAgendaEventListenerDebugRuleRuntimeEventListener的软件包中添加
2
创建一个 KieServices Factoryks 元素来生成日志,因为此审计日志在 KieContainer 级别不可用
3
修改 execute 方法,以使用 KieServicesKieContainer
4
除了 KieContainer外,修改在 KieServices 中传递的 execute 方法
5
创建监听程序
6
构建在执行规则后可传递给 debug 视图或 审计 视图或 IDE 的日志

当您使用此修改后的日志记录功能运行 Honest Politician 时,您可以将 target/honestpolitician.log 中的审计日志文件加载到 IDE 调试视图或 审计 视图(例如,在一些 IDE 中显示 窗口Show View )。

在本例中,审计视图显示 执行流、插入和重新加载actions,如示例类和规则中定义的:

图 85.18. honest Politician 示例审计视图

honest politician 审计

插入第一个 politician 时,会发生两个激活。规则 "We 有一个 honest Politician" 首次插入的 politician 激活一次,因为它使用 exists 条件元素,它在插入至少一个 politician 时匹配。规则 "Hope is Dead" 也在这个阶段激活,因为 Hope 对象还没有插入。规则 "We 有一个 honest Politician" 触发,因为它具有高于规则 "Hope is Dead"salience 值,并插入 Hope 对象(以绿色表示)。Hope 对象的插入激活规则 "Hope Lives",并取消激活规则 "Hope is Dead "。插入还会激活每个插入的 honest politician 的规则 "Corrupt the Honest "。规则 "Hope Lives" 被执行并打印 "Hurrah!!!Democracy Lives"

接下来,对于每个策略,规则 "Corrupt the Honest" 触发,打印 "I'm a evil certification and I have damage X ",其中 X 是 politician 的名称,并将 politician honesty 值改为 false。当最后一个 honest politician 损坏时,H ope 会自动被事实维护系统(在蓝色中高)。绿色突出显示区域显示当前选定的蓝色突出显示区域的来源。重新遍历 Hope 事实后,规则 "Hope is dead" 会触发,打印 "We is all Doomed!!!!!!!Democracy 是 Dead"

85.8. Sudoku 示例决策(组合模式匹配、回调和 GUI 集成)

Sudoku 示例决定基于流行数量 puzzle Sudoku,演示了如何根据各种限制在 Red Hat Process Automation Manager 中使用规则来查找大型潜在解决方案空间的解决方案。本例还演示了如何将 Red Hat Process Automation Manager 规则集成到图形用户界面(GUI)中,在这种情况下,使用基于 Swing 的桌面应用程序,以及如何使用回调与正在运行的决策引擎交互,根据工作内存中的更改更新 GUI。

以下是 Sudoku 示例的概述:

  • 名称 :sudoku
  • 主类org.drools.examples.sudoku.SudokuExample (在 src/main/java中)
  • 模块drools-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.sudoku114.drl (在 src/main/resources中)
  • 目标 :演示复杂模式匹配、问题问题、回调和 GUI 集成

Sudoku 是一个基于逻辑的数字放置 puzzle。目标是填充 9x9 网格,以便每列、每行和每 9 个 3x3 区域都包含从 1 到 9 次的数字。puzzle setter 提供了部分完成的网格,puzzle solver 的任务是完成具有这些限制的网格。

解决问题的一般策略是确保在插入新数字时,必须在其特定的 3x3 区域、行和列中是唯一的。这个 Sudoku 示例决策使用 Red Hat Process Automation Manager 规则从各种困难级别解决 Sudoku puzzles,并尝试解决包含无效条目的缺陷。

Sudoku 示例执行和交互

与其他 Red Hat Process Automation Manager 决策示例类似,您可以通过在 IDE 中作为 Java 应用程序运行 org.drools.examples.sudoku.SudokuExample 类来执行 Sudoku 示例。

当您执行 Sudoku 示例时,会出现 droyku Example GUI 窗口。此窗口包含一个空的网格,但程序在内部存储各种您可以加载和解决。

FileSamplesSimple 加载其中一个示例。请注意,所有按钮都被禁用,直到网格加载为止。

图 85.19. 启动后,Sudoku 示例 GUI

sudoku1

当您加载 简单示例 时,网格会根据 puzzle 的初始状态填充。

图 85.20. 在载入简单示例后,Sudoku 示例 GUI

sudoku2

�以下选项中选择:

  • Solve 触发 Sudoku 示例中定义的规则,以填充剩余的值,并使按钮再次不活跃。

    图 85.21. 已解决简单示例

    sudoku3
  • Step 查看规则集找到的下一个数字。IDE 中的控制台窗口显示有关正在执行的规则的详细信息,以解决问题。

    IDE 控制台中的步骤执行输出

    single 8 at [0,1]
    column elimination due to [1,2]: remove 9 from [4,2]
    hidden single 9 at [1,2]
    row elimination due to [2,8]: remove 7 from [2,4]
    remove 6 from [3,8] due to naked pair at [3,2] and [3,7]
    hidden pair in row at [4,6] and [4,4]

  • 单击 Dump 以查看网格的状态,以及显示已建立的值或剩余值的单元格。

    在 IDE 控制台中转储执行输出

            Col: 0     Col: 1     Col: 2     Col: 3     Col: 4     Col: 5     Col: 6     Col: 7     Col: 8
    Row 0:  123456789  --- 5 ---  --- 6 ---  --- 8 ---  123456789  --- 1 ---  --- 9 ---  --- 4 ---  123456789
    Row 1:  --- 9 ---  123456789  123456789  --- 6 ---  123456789  --- 5 ---  123456789  123456789  --- 3 ---
    Row 2:  --- 7 ---  123456789  123456789  --- 4 ---  --- 9 ---  --- 3 ---  123456789  123456789  --- 8 ---
    Row 3:  --- 8 ---  --- 9 ---  --- 7 ---  123456789  --- 4 ---  123456789  --- 6 ---  --- 3 ---  --- 5 ---
    Row 4:  123456789  123456789  --- 3 ---  --- 9 ---  123456789  --- 6 ---  --- 8 ---  123456789  123456789
    Row 5:  --- 4 ---  --- 6 ---  --- 5 ---  123456789  --- 8 ---  123456789  --- 2 ---  --- 9 ---  --- 1 ---
    Row 6:  --- 5 ---  123456789  123456789  --- 2 ---  --- 6 ---  --- 9 ---  123456789  123456789  --- 7 ---
    Row 7:  --- 6 ---  123456789  123456789  --- 5 ---  123456789  --- 4 ---  123456789  123456789  --- 9 ---
    Row 8:  123456789  --- 4 ---  --- 9 ---  --- 7 ---  123456789  --- 8 ---  --- 3 ---  --- 5 ---  123456789

Sudoku 示例包含一个破坏的示例文件,在示例中定义的规则可以解析。

FileSamples!DELIBERATELY BROKEN! 加载有问题的示例。网格从某些问题开始,例如,第一行中的 5 值会出现两次,而这不允许使用。

图 85.22. broken Sudoku 示例初始状态

sudoku4

单击 Solve,以将过期规则应用到此无效的网格。Sudoku 示例中的关联规则会检测示例中的问题,并尝试尽可能解决 puzzle。这个过程没有完成,并保留一些单元为空。

过期规则活动显示在 IDE 控制台窗口中:

在有问题的示例中检测到问题

cell [0,8]: 5 has a duplicate in row 0
cell [0,0]: 5 has a duplicate in row 0
cell [6,0]: 8 has a duplicate in col 0
cell [4,0]: 8 has a duplicate in col 0
Validation complete.

图 85.23. 有问题的示例解决方案尝试

sudoku5

标记为 Hard 的 Sudoku 文件示例更为复杂,一般规则可能无法解决它们。IDE 控制台窗口中会显示失败的解决方案尝试:

未解析的硬链接

Validation complete.
...
Sorry - can't solve this grid.

解决损坏的样本的规则根据仍为单元候选者的值集合实施标准过期技术。例如,如果集合包含单个值,则这是单元的值。对于在 9 个单元组中出现一个值,规则会插入带有某些特定单元的解决方案值的类型 设置 事实。这将导致从单元所属的所有其他单元中分离这个值,并且该值会被重新遍历。

示例中的其他规则可减少某些单元的感知值。规则 "naked pair", "hidden pair in row", "hidden pair in column", and "hidden pair in physical" 会消除可能性,但不建立解决方案。规则 "X-wings in rows", "'X-wings in column"', "intersection removal row", 和 "intersection removal column" 会执行更复杂的背景。

Sudoku 示例类

软件包 org.drools.examples.sudoku.swing 包含以下核心类集合,该类实现了 Sudoku puzzles 的框架:

  • SudokuGridModel 类定义了一个接口,用来存储 Sudoku puzzle 作为 Cell 对象的 9x9 网格。
  • SudokuGridView 类是一个 Swing 组件,它可以视觉化 SudokuGridModel 类的任何实现。
  • SudokuGridEventSudokuGridListener 类在模型和视图之间进行通信状态更改。当单元值被解决或更改时,会触发事件。
  • SudokuGridSamples 类提供了部分填充 Sudoku puzzles 用于演示目的。
注意

这个软件包对 Red Hat Process Automation Manager 库没有任何依赖项。

软件包 org.drools.examples.sudoku 包含以下核心类集合,它们实现了元素 Cell 对象及其各种聚合:

  • CellFile 类,带有子类型 CellRowCellColCellSqr,它们都是 CellGroup 类的子类型。
  • SetOfNineCellCellGroup 子类,它提供了一个没有类型 Set & lt;Integer&gt; 的属性。对于 Cell 类,该集合代表单个候选集。对于 CellGroup 类,该集合是其单元的所有候选集合(仍需要分配的数字集)。

    在 Sudoku 示例中,有 81 Cell 和 27 CellGroup 对象,以及 Cell 属性 cellRowcellColcellSqr 以及 CellGroup 属性 单元 提供的链接。使用这些组件,您可以编写规则来检测特定情况,允许将值分配给单元,或从某些候选集中删除值。

  • Setting 类用于触发值分配附带的操作。所有规则中都会使用 设置 事实,以检测新情况以避免重新发生中间状态。
  • "Step" 不会定期终止时,在低优先级规则中使用 Stepping 类来执行紧急停止。这个行为表示程序无法解决模糊。
  • 主类 org.drools.examples.sudoku.SudokuExample 实施了组合了所有这些组件的 Java 应用程序。

Sudoku 验证规则(validate.drl)

Sudoku 示例中的 validate.drl 文件包含验证规则,用于检测单元组中重复数字。它们合并到一个 "validate" 站组中,允许用户在用户加载 puzzle 后明确激活该规则。

三种规则 "duplicate in cell …​" all 功能 的时间 条件如下:

  • 规则中的第一个条件会找到带有分配值的单元。
  • 规则中的第二个条件会拉取到该单元所属的三个单元组。
  • 根据规则,最终条件找到一个单元(除前一个除外),其值为第一个单元和同一行、列或方括号。

规则 "duplicate in cell …​"

rule "duplicate in cell row"
  when
    $c: Cell( $v: value != null )
    $cr: CellRow( cells contains $c )
    exists Cell( this != $c, value == $v, cellRow == $cr )
  then
    System.out.println( "cell " + $c.toString() + " has a duplicate in row " + $cr.getNumber() );
end

rule "duplicate in cell col"
  when
    $c: Cell( $v: value != null )
    $cc: CellCol( cells contains $c )
    exists Cell( this != $c, value == $v, cellCol == $cc )
  then
    System.out.println( "cell " + $c.toString() + " has a duplicate in col " + $cc.getNumber() );
end

rule "duplicate in cell sqr"
  when
    $c: Cell( $v: value != null )
    $cs: CellSqr( cells contains $c )
    exists Cell( this != $c, value == $v, cellSqr == $cs )
  then
    System.out.println( "cell " + $c.toString() + " has duplicate in its square of nine." );
end

规则 "terminate group" 是最后一个要触发的规则。此规则打印消息并停止序列。

规则 "terminate group"

rule "terminate group"
    salience -100
  when
  then
    System.out.println( "Validation complete." );
    drools.halt();
end

Sudokucertification rules (sudoku.drl)

Sudoku 示例中的 sudoku.drl 文件包含三种类型的规则:一个组处理到单元的数字分配,另一个组检测到可行的分配,第三个组从 candidate 集合中删除值。

规则 "set a value", "eliminate a value from Cell", 和 "retract setting" 取决于 Setting 对象的存在。第一个规则处理到单元的分配,以及从单元格的三个组 的空闲 集合中删除值的操作。这个组也会减少计数器,当零时,将控制返回到名为 fireUntilHalt () 的 Java 应用程序。

规则 "eliminate a value from Cell" 的目的是减少与新分配的单元相关的所有单元的候选列表。最后,当完成所有提升后,规则 " Retract 设置" 会重新遍历触发器 设置 事实。

规则 "set a value", "eliminate a value from a Cell", and "retract setting"

// A Setting object is inserted to define the value of a Cell.
// Rule for updating the cell and all cell groups that contain it
rule "set a value"
  when
    // A Setting with row and column number, and a value
    $s: Setting( $rn: rowNo, $cn: colNo, $v: value )

    // A matching Cell, with no value set
    $c: Cell( rowNo == $rn, colNo == $cn, value == null,
              $cr: cellRow, $cc: cellCol, $cs: cellSqr )

    // Count down
    $ctr: Counter( $count: count )
  then
    // Modify the Cell by setting its value.
    modify( $c ){ setValue( $v ) }
    // System.out.println( "set cell " + $c.toString() );
    modify( $cr ){ blockValue( $v ) }
    modify( $cc ){ blockValue( $v ) }
    modify( $cs ){ blockValue( $v ) }
    modify( $ctr ){ setCount( $count - 1 ) }
end

// Rule for removing a value from all cells that are siblings
// in one of the three cell groups
rule "eliminate a value from Cell"
  when
    // A Setting with row and column number, and a value
    $s: Setting( $rn: rowNo, $cn: colNo, $v: value )

    // The matching Cell, with the value already set
    Cell( rowNo == $rn, colNo == $cn, value == $v, $exCells: exCells )

    // For all Cells that are associated with the updated cell
    $c: Cell( free contains $v ) from $exCells
  then
    // System.out.println( "clear " + $v + " from cell " + $c.posAsString()  );
    // Modify a related Cell by blocking the assigned value.
    modify( $c ){ blockValue( $v ) }
end

// Rule for eliminating the Setting fact
rule "retract setting"
  when
    // A Setting with row and column number, and a value
    $s: Setting( $rn: rowNo, $cn: colNo, $v: value )

    // The matching Cell, with the value already set
    $c: Cell( rowNo == $rn, colNo == $cn, value == $v )

    // This is the negation of the last pattern in the previous rule.
    // Now the Setting fact can be safely retracted.
    not( $x: Cell( free contains $v )
         and
         Cell( this == $c, exCells contains $x ) )
  then
    // System.out.println( "done setting cell " + $c.toString() );
    // Discard the Setter fact.
    delete( $s );
    // Sudoku.sudoku.consistencyCheck();
end

双向规则会检测一个可能为单元分配数字的情况。规则 "single" 会为 Cell 触发一个包含单个数字的候选集。当单个候选不存在单元格时,规则 "hidden single" 会触发,但当单元存在包含候选者的单元格时,这个候选都不包括在单元格所属的三个组中。规则创建和插入 设置 事实。

规则"单一"和"隐藏单一"

// Detect a set of candidate values with cardinality 1 for some Cell.
// This is the value to be set.
rule "single"
  when
    // Currently no setting underway
    not Setting()

    // One element in the "free" set
    $c: Cell( $rn: rowNo, $cn: colNo, freeCount == 1 )
  then
    Integer i = $c.getFreeValue();
    if (explain) System.out.println( "single " + i + " at " + $c.posAsString() );
    // Insert another Setter fact.
    insert( new Setting( $rn, $cn, i ) );
end

// Detect a set of candidate values with a value that is the only one
// in one of its groups. This is the value to be set.
rule "hidden single"
  when
    // Currently no setting underway
    not Setting()
    not Cell( freeCount == 1 )

    // Some integer
    $i: Integer()

    // The "free" set contains this number
    $c: Cell( $rn: rowNo, $cn: colNo, freeCount > 1, free contains $i )

    // A cell group contains this cell $c.
    $cg: CellGroup( cells contains $c )
    // No other cell from that group contains $i.
    not ( Cell( this != $c, free contains $i ) from $cg.getCells() )
  then
    if (explain) System.out.println( "hidden single " + $i + " at " + $c.posAsString() );
    // Insert another Setter fact.
    insert( new Setting( $rn, $cn, $i ) );
end

来自最多组的规则,可以是独立或三组,可以手动实施用于手动的 Sudoku puzzles 的各种技术。

规则 "naked pair" 在组的两个单元中检测相同的大小为 2 的候选集合。这两个值可以从该组的所有其他候选集合中删除。

规则"naked pair"

// A "naked pair" is two cells in some cell group with their sets of
// permissible values being equal with cardinality 2. These two values
// can be removed from all other candidate lists in the group.
rule "naked pair"
  when
    // Currently no setting underway
    not Setting()
    not Cell( freeCount == 1 )

    // One cell with two candidates
    $c1: Cell( freeCount == 2, $f1: free, $r1: cellRow, $rn1: rowNo, $cn1: colNo, $b1: cellSqr )

    // The containing cell group
    $cg: CellGroup( freeCount > 2, cells contains $c1 )

    // Another cell with two candidates, not the one we already have
    $c2: Cell( this != $c1, free == $f1 /*** , rowNo >= $rn1, colNo >= $cn1 ***/ ) from $cg.cells

    // Get one of the "naked pair".
    Integer( $v: intValue ) from $c1.getFree()

    // Get some other cell with a candidate equal to one from the pair.
    $c3: Cell( this != $c1 && != $c2, freeCount > 1, free contains $v ) from $cg.cells
  then
    if (explain) System.out.println( "remove " + $v + " from " + $c3.posAsString() + " due to naked pair at " + $c1.posAsString() + " and " + $c2.posAsString() );
    // Remove the value.
    modify( $c3 ){ blockValue( $v ) }
end

三个规则 "hidden pair in …​" 函数类似于规则 "naked pair "。这些规则检测一个组的两个单元中有两个数字的子集,且在组的任何其他单元中不会发生值。这意味着,所有其他候选者可以从两个单元格中删除。

规则"hidden pair in …​"

// If two cells within the same cell group contain candidate sets with more than
// two values, with two values being in both of them but in none of the other
// cells, then we have a "hidden pair". We can remove all other candidates from
// these two cells.
rule "hidden pair in row"
  when
    // Currently no setting underway
    not Setting()
    not Cell( freeCount == 1 )

    // Establish a pair of Integer facts.
    $i1: Integer()
    $i2: Integer( this > $i1 )

    // Look for a Cell with these two among its candidates. (The upper bound on
    // the number of candidates avoids a lot of useless work during startup.)
    $c1: Cell( $rn1: rowNo, $cn1: colNo, freeCount > 2 && < 9, free contains $i1 && contains $i2, $cellRow: cellRow )

    // Get another one from the same row, with the same pair among its candidates.
    $c2: Cell( this != $c1, cellRow == $cellRow, freeCount > 2, free contains $i1 && contains $i2 )

    // Ascertain that no other cell in the group has one of these two values.
    not( Cell( this != $c1 && != $c2, free contains $i1 || contains $i2 ) from $cellRow.getCells() )
  then
    if( explain) System.out.println( "hidden pair in row at " + $c1.posAsString() + " and " + $c2.posAsString() );
    // Set the candidate lists of these two Cells to the "hidden pair".
    modify( $c1 ){ blockExcept( $i1, $i2 ) }
    modify( $c2 ){ blockExcept( $i1, $i2 ) }
end

rule "hidden pair in column"
  when
    not Setting()
    not Cell( freeCount == 1 )

    $i1: Integer()
    $i2: Integer( this > $i1 )
    $c1: Cell( $rn1: rowNo, $cn1: colNo, freeCount > 2 && < 9, free contains $i1 && contains $i2, $cellCol: cellCol )
    $c2: Cell( this != $c1, cellCol == $cellCol, freeCount > 2, free contains $i1 && contains $i2 )
    not( Cell( this != $c1 && != $c2, free contains $i1 || contains $i2 ) from $cellCol.getCells() )
  then
    if (explain) System.out.println( "hidden pair in column at " + $c1.posAsString() + " and " + $c2.posAsString() );
    modify( $c1 ){ blockExcept( $i1, $i2 ) }
    modify( $c2 ){ blockExcept( $i1, $i2 ) }
end

rule "hidden pair in square"
  when
    not Setting()
    not Cell( freeCount == 1 )

    $i1: Integer()
    $i2: Integer( this > $i1 )
    $c1: Cell( $rn1: rowNo, $cn1: colNo, freeCount > 2 && < 9, free contains $i1 && contains $i2,
               $cellSqr: cellSqr )
    $c2: Cell( this != $c1, cellSqr == $cellSqr, freeCount > 2, free contains $i1 && contains $i2 )
    not( Cell( this != $c1 && != $c2, free contains $i1 || contains $i2 ) from $cellSqr.getCells() )
  then
    if (explain) System.out.println( "hidden pair in square " + $c1.posAsString() + " and " + $c2.posAsString() );
    modify( $c1 ){ blockExcept( $i1, $i2 ) }
    modify( $c2 ){ blockExcept( $i1, $i2 ) }
end

两个规则处理行和 列中的"X-wings "。当两个不同的行(或列)中只有两个可能的值的单元,且这些候选者也位于同一列(或行),那么可以消除列(或行)中这个值的所有其他候选者。当您遵循其中一个规则中的模式序列时,请注意,如何按照单词(如 相同或 会导致带有适当约束或前缀的模式)表示的条件。

规则 "X-wings in …​"

rule "X-wings in rows"
  when
    not Setting()
    not Cell( freeCount == 1 )

    $i: Integer()
    $ca1: Cell( freeCount > 1, free contains $i,
                $ra: cellRow, $rano: rowNo,         $c1: cellCol,        $c1no: colNo )
    $cb1: Cell( freeCount > 1, free contains $i,
                $rb: cellRow, $rbno: rowNo > $rano,      cellCol == $c1 )
    not( Cell( this != $ca1 && != $cb1, free contains $i ) from $c1.getCells() )

    $ca2: Cell( freeCount > 1, free contains $i,
                cellRow == $ra, $c2: cellCol,       $c2no: colNo > $c1no )
    $cb2: Cell( freeCount > 1, free contains $i,
                cellRow == $rb,      cellCol == $c2 )
    not( Cell( this != $ca2 && != $cb2, free contains $i ) from $c2.getCells() )

    $cx: Cell( rowNo == $rano || == $rbno, colNo != $c1no && != $c2no,
               freeCount > 1, free contains $i )
  then
    if (explain) {
        System.out.println( "X-wing with " + $i + " in rows " +
            $ca1.posAsString() + " - " + $cb1.posAsString() +
            $ca2.posAsString() + " - " + $cb2.posAsString() + ", remove from " + $cx.posAsString() );
    }
    modify( $cx ){ blockValue( $i ) }
end

rule "X-wings in columns"
  when
    not Setting()
    not Cell( freeCount == 1 )

    $i: Integer()
    $ca1: Cell( freeCount > 1, free contains $i,
                $c1: cellCol, $c1no: colNo,         $ra: cellRow,        $rano: rowNo )
    $ca2: Cell( freeCount > 1, free contains $i,
                $c2: cellCol, $c2no: colNo > $c1no,      cellRow == $ra )
    not( Cell( this != $ca1 && != $ca2, free contains $i ) from $ra.getCells() )

    $cb1: Cell( freeCount > 1, free contains $i,
                cellCol == $c1, $rb: cellRow,  $rbno: rowNo > $rano )
    $cb2: Cell( freeCount > 1, free contains $i,
                cellCol == $c2,      cellRow == $rb )
    not( Cell( this != $cb1 && != $cb2, free contains $i ) from $rb.getCells() )

    $cx: Cell( colNo == $c1no || == $c2no, rowNo != $rano && != $rbno,
               freeCount > 1, free contains $i )
  then
    if (explain) {
        System.out.println( "X-wing with " + $i + " in columns " +
            $ca1.posAsString() + " - " + $ca2.posAsString() +
            $cb1.posAsString() + " - " + $cb2.posAsString() + ", remove from " + $cx.posAsString()  );
    }
    modify( $cx ){ blockValue( $i ) }
end

这两个规则 "intersection removal …​" 基于一个方括号中的某个数字的限制,可以在一行或单个列中出现。这意味着这个数字必须在行或列的两或三个单元之一,并且可以从组所有其他单元的候选集合中删除。模式建立受限发生,然后针对方括号和同一单元文件之外的每个单元触发。

规则 "intersection removal …​"

rule "intersection removal column"
  when
    not Setting()
    not Cell( freeCount == 1 )

    $i: Integer()
    // Occurs in a Cell
    $c: Cell( free contains $i, $cs: cellSqr, $cc: cellCol )
    // Does not occur in another cell of the same square and a different column
    not Cell( this != $c, free contains $i, cellSqr == $cs, cellCol != $cc )

    // A cell exists in the same column and another square containing this value.
    $cx: Cell( freeCount > 1, free contains $i, cellCol == $cc, cellSqr != $cs )
  then
    // Remove the value from that other cell.
    if (explain) {
        System.out.println( "column elimination due to " + $c.posAsString() +
                            ": remove " + $i + " from " + $cx.posAsString() );
    }
    modify( $cx ){ blockValue( $i ) }
end

rule "intersection removal row"
  when
    not Setting()
    not Cell( freeCount == 1 )

    $i: Integer()
    // Occurs in a Cell
    $c: Cell( free contains $i, $cs: cellSqr, $cr: cellRow )
    // Does not occur in another cell of the same square and a different row.
    not Cell( this != $c, free contains $i, cellSqr == $cs, cellRow != $cr )

    // A cell exists in the same row and another square containing this value.
    $cx: Cell( freeCount > 1, free contains $i, cellRow == $cr, cellSqr != $cs )
  then
    // Remove the value from that other cell.
    if (explain) {
        System.out.println( "row elimination due to " + $c.posAsString() +
                            ": remove " + $i + " from " + $cx.posAsString() );
    }
    modify( $cx ){ blockValue( $i ) }
end

这些规则对于许多但不是 Sudoku puzzles 而言已经足够了。为了解决非常困难,规则集需要更复杂的规则。(类似地,只有试用和错误才能解决一些模糊。)

85.9. 生命周期决策的整合方法(ruleflow 组和 GUI 集成)

Conway's Game of Life example 决策集基于 John Conway 的 famous cellular automaton,演示了如何在规则中使用 ruleflow 组来控制规则执行。这个示例还演示了如何将 Red Hat Process Automation Manager 规则与图形用户界面(GUI)集成,在本例中基于 Swing's Game of Life。

以下是 Conway's Game of Life (Conway)示例的概述:

  • Name:conway
  • 主类org.drools.examples.conway.ConwayRuleFlowGroupRun,org.drools.examples.conway.ConwayAgendaGroupRun (in src/main/java)
  • 模块droolsjbpm-integration-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.conway114.drl (在 src/main/resources中)
  • 目标 :演示 ruleflow 组和 GUI 集成
注意

The Conway's Game of Life example of the regularols jbpm-integration-examples in the Red Hat Process Automation Manager 7.9.1 source distribution from the Red Hat Customer Portal.

在 Conway's Game 的生命周期内,用户通过创建初始配置或具有定义属性的高级模式,然后观察初始状态的演进方式与游戏交互。游戏的目的是显示填充的开发,生成到生成。以上每个生成结果都基于所有单元的同时评估。

以下基本规则管理下一代内容,如下所示:

  • 如果实时单元少于两个实时邻居,它将划分掉 loneliness。
  • 如果实时单元有超过三个实时邻居,它将被过度分离。
  • 如果死单元具有三个实时邻居,则相当于生命周期。

任何不符合这些条件的单元都保留为在下一代位置中。

The Conway 的 Game of Life example 使用 Red Hat Process Automation Manager 规则和 ruleflow-group 属性来定义在游戏中实施的模式。该示例还包含一组决策集的版本,该版本通过电缆组实现相同的行为。通过电缆组,您可以对决策引擎人员进行分区,以提供对规则组的执行控制。默认情况下,所有规则都位于 products 组 MAIN 中。您可以使用 sales -group 属性为规则指定不同的 sales 组。

此概述不会探索使用电缆组的对比示例版本。有关销售组的更多信息,请参阅 Red Hat Process Automation Manager 决策集合,该设置专门解决电缆组。

执行和交互示例

与其他 Red Hat Process Automation Manager 决策示例类似,您可以通过在 IDE 中作为 Java 应用程序运行 org.drools.examples.conwayRuleFlowGroupRun 类来执行 Conway ruleflow 示例。

当您执行 Conway 示例时,会出现 Conway's Game of Life GUI 窗口。此窗口包含一个空的网格,或"arena",其中执行生命周期模拟。最初网格为空,因为系统上还没有实时单元。

图 85.24. 启动后的 GUI 示例

conway1

Pattern 下拉菜单中选择预定义的模式,然后单击 Next Generation 以点每个填充生成。每个单元都是 live 或 dead,其中实时单元包含一个绿色 ball。随着填充从初始模式增长时,根据游戏的规则,从初始模式增长或相对于邻居单元的单元格。

图 85.25. 一致性示例中的生成演进

conway2

邻居不仅包括左侧、右、顶部和底部连接的单元格,以及连接了 diagonly 的单元,因此每个单元格都有总计 8 个邻居。例外是角单元,其中只有三个邻居,以及四个边框的单元格,每个方都有五个邻居。

您可以通过单击单元来手动干预来创建或终止单元。

要从初始模式下运行,请单击 Start

使用带有 ruleflow 组的示例规则

ConwayRuleFlowGroupRun 示例中的规则使用 ruleflow 组来控制规则执行。ruleflow 组是由 rule flow-group rule 属性关联的一组规则。这些规则只能在组激活时触发。只有当 ruleflow 图的 Elaboration 到达代表组的节点时,组本身才能变为活动状态。

Conway 示例将以下 ruleflow 组用于规则:

  • "register neighbor"
  • "evaluate"
  • "calculate"
  • "reset calculate"
  • "birth"
  • "kill"
  • "kill all"

所有 Cell 对象都插入到 KIE 会话中,ruleflow 组 "register neighbor" 中的 "register …​" 规则可以被 ruleflow 进程执行。这个四个规则组会在某些单元格及其 northeastern、northern、northwestern 和 western neighbors 之间创建邻居关系。

这种关系是双向的,处理其他四个方向。边框单元不需要任何特殊处理。这些单元不会与没有邻居单元的邻居单元配对。

通过为这些规则触发所有激活的时间,所有单元都与所有邻居单元相关。

rules "register …​"

rule "register north east"
    ruleflow-group "register neighbor"
  when
    $cell: Cell( $row : row, $col : col )
    $northEast : Cell( row  == ($row - 1), col == ( $col + 1 ) )
  then
    insert( new Neighbor( $cell, $northEast ) );
    insert( new Neighbor( $northEast, $cell ) );
end

rule "register north"
    ruleflow-group "register neighbor"
  when
    $cell: Cell( $row : row, $col : col )
    $north : Cell( row  == ($row - 1), col == $col )
  then
    insert( new Neighbor( $cell, $north ) );
    insert( new Neighbor( $north, $cell ) );
end

rule "register north west"
    ruleflow-group "register neighbor"
  when
    $cell: Cell( $row : row, $col : col )
    $northWest : Cell( row  == ($row - 1), col == ( $col - 1 ) )
  then
    insert( new Neighbor( $cell, $northWest ) );
    insert( new Neighbor( $northWest, $cell ) );
end

rule "register west"
    ruleflow-group "register neighbor"
  when
    $cell: Cell( $row : row, $col : col )
    $west : Cell( row  == $row, col == ( $col - 1 ) )
  then
    insert( new Neighbor( $cell, $west ) );
    insert( new Neighbor( $west, $cell ) );
end

插入完所有单元后,一些 Java 代码会将模式应用到网格,将某些单元设置为 Live。然后,当用户单击 StartNext Generation 时,示例会执行 Generation ruleflow。此 ruleflow 管理每个生成周期中的单元的所有更改。

图 85.26. 生成 ruleflow

聚合规则流生成

ruleflow 进程输入 "evaluate" 规则流组,组中的任何活动规则都可以触发。这个组中的规则 "Kill the …​""Give Birth" 将游戏规则应用到 birth 或 kill 单元。这个示例使用 phase 属性根据特定规则组驱动 Cell 对象的原因。通常,阶段与 ruleflow 进程定义中的 ruleflow 组关联。

请注意,这个示例不会更改任何 Cell 对象的状态,因为它必须在应用更改前完成完整评估。示例将单元设置为 Phase.KILLPhase.114RTH阶段,稍后用于控制应用到 Cell 对象的操作。

规则 "Kill the …​" 和 "Give Birth"

rule "Kill The Lonely"
    ruleflow-group "evaluate"
    no-loop
  when
    // A live cell has fewer than 2 live neighbors.
    theCell: Cell( liveNeighbors < 2, cellState == CellState.LIVE,
                   phase == Phase.EVALUATE )
  then
    modify( theCell ){
        setPhase( Phase.KILL );
    }
end

rule "Kill The Overcrowded"
    ruleflow-group "evaluate"
    no-loop
  when
    // A live cell has more than 3 live neighbors.
    theCell: Cell( liveNeighbors > 3, cellState == CellState.LIVE,
                   phase == Phase.EVALUATE )
  then
    modify( theCell ){
        setPhase( Phase.KILL );
    }
end

rule "Give Birth"
    ruleflow-group "evaluate"
    no-loop
  when
    // A dead cell has 3 live neighbors.
    theCell: Cell( liveNeighbors == 3, cellState == CellState.DEAD,
                   phase == Phase.EVALUATE )
  then
    modify( theCell ){
        theCell.setPhase( Phase.BIRTH );
    }
end

评估网格中的所有 Cell 对象后,示例使用 "reset compute" 规则清除 " calculate" ruleflow 组中的任何激活。然后,在 ruleflow 中输入分割,如果 ruleflow 组被激活,使规则 "kill""birth" 触发。这些规则应用状态更改。

规则 "reset calculate", "kill", 和 "birth"

rule "reset calculate"
    ruleflow-group "reset calculate"
  when
  then
    WorkingMemory wm = drools.getWorkingMemory();
    wm.clearRuleFlowGroup( "calculate" );
end

rule "kill"
    ruleflow-group "kill"
    no-loop
  when
    theCell: Cell( phase == Phase.KILL )
  then
    modify( theCell ){
        setCellState( CellState.DEAD ),
        setPhase( Phase.DONE );
    }
end

rule "birth"
    ruleflow-group "birth"
    no-loop
  when
    theCell: Cell( phase == Phase.BIRTH )
  then
    modify( theCell ){
        setCellState( CellState.LIVE ),
        setPhase( Phase.DONE );
    }
end

在这个阶段,将几个 Cell 对象更改为 LIVEDEAD 状态。当单元格变为 live 或 dead 时,示例使用规则 "Calculate …​" 中的 邻居 关系来迭代所有周围的单元,增加或减少 liveNeighbor 数。更改了计数的任何单元都设置为 EVALUATE 阶段,以确保在 ruleflow 过程评估阶段将其包含在原因中。

在为所有单元决定和设置实时数后,ruleflow 进程将结束。如果用户最初点击 Start,则决策引擎会在此时重新启动 ruleflow。如果用户最初单击 Next Generation,用户可以请求另一个生成。

规则 "Calculate …​"

rule "Calculate Live"
    ruleflow-group "calculate"
    lock-on-active
  when
    theCell: Cell( cellState == CellState.LIVE )
    Neighbor( cell == theCell, $neighbor : neighbor )
  then
    modify( $neighbor ){
        setLiveNeighbors( $neighbor.getLiveNeighbors() + 1 ),
        setPhase( Phase.EVALUATE );
    }
end

rule "Calculate Dead"
    ruleflow-group "calculate"
    lock-on-active
  when
    theCell: Cell( cellState == CellState.DEAD )
    Neighbor( cell == theCell, $neighbor : neighbor )
  then
    modify( $neighbor ){
        setLiveNeighbors( $neighbor.getLiveNeighbors() - 1 ),
        setPhase( Phase.EVALUATE );
    }
end

85.10. 定制 Doom 示例决策(返回链和递归)

Doom 示例决策集的 House 演示了决策引擎如何使用向后兼容性和递归来访问分层系统中定义的目标或子组。

以下是 Doom 示例 House 的概述:

  • 名称后链
  • 主类org.drools.examples.backwardchaining.HouseOfDoomMain (在 src/main/java中)
  • 模块drools-examples
  • 类型 :Java 应用程序
  • 规则文件:org.drools.examples.backwardchaining.BC-Example.drl (在 src/main/resources中)
  • 目标 :演示后链和递归

后链规则系统是一个目标驱动的系统,从决策引擎尝试满足的目标驱动的系统开始,通常使用递归。如果系统无法访问语音或目标,它会搜索子组,这是完成当前目标的一部分。系统会继续这个过程,直到满足初始目标或满足所有子状态为止。

相反,转发链规则系统是一个数据驱动的系统,它以决策引擎的工作内存中的事实开始,并对这一事实的更改做出响应。当对象插入到工作内存中时,因更改计划执行而满足的任何规则条件。

Red Hat Process Automation Manager 中的决策引擎使用正向和后链来评估规则。

下图演示了,决策引擎如何使用转发链和逻辑流中的向链段来评估规则:

图 85.27. 使用正向和后链的规则评估逻辑

RuleEvaluation Enterprise

Doom 示例的 House 使用各种类型的查询的规则来查找托管中的房间和项目的位置。示例类 Location.java 包含示例中使用的 和位置 元素。示例类 HouseOfDoomMain.java 将项目或房间插入到其各自的位置,并执行规则。

HouseOfDoomMain.java 类的项目和位置

ksession.insert( new Location("Office", "House") );
ksession.insert( new Location("Kitchen", "House") );
ksession.insert( new Location("Knife", "Kitchen") );
ksession.insert( new Location("Cheese", "Kitchen") );
ksession.insert( new Location("Desk", "Office") );
ksession.insert( new Location("Chair", "Office") );
ksession.insert( new Location("Computer", "Desk") );
ksession.insert( new Location("Drawer", "Desk") );

示例规则依赖于向向链和递归来确定托管结构中的所有项目和房间的位置。

下图演示了 Doom 的 House 的结构,以及其中的项目和房间:

图 85.28. Doom 结构的托管

TransitiveReasoning Enterprise

要执行示例,请在 IDE 中作为 Java 应用程序运行 org.drools.examples.backwardchaining.HouseOfDoomMain 类。

执行后,以下输出会出现在 IDE 控制台窗口中:

IDE 控制台中的执行输出

go1
Office is in the House
---
go2
Drawer is in the House
---
go3
---
Key is in the Office
---
go4
Chair is in the Office
Desk is in the Office
Key is in the Office
Computer is in the Office
Drawer is in the Office
---
go5
Chair is in Office
Desk is in Office
Drawer is in Desk
Key is in Drawer
Kitchen is in House
Cheese is in Kitchen
Knife is in Kitchen
Computer is in Desk
Office is in House
Key is in Office
Drawer is in House
Computer is in House
Key is in House
Desk is in House
Chair is in House
Knife is in House
Cheese is in House
Computer is in Office
Drawer is in Office
Key is in Desk

示例中的所有规则都触发,以检测托管中的所有项目的位置,并在输出中打印各个项目的位置。

递归查询重复搜索数据结构的层次结构,以获取元素之间的关系。

在 Doom 示例中的 House 中,BC-Example.drl 文件包含一个 isContainedIn 查询,该查询中大多数规则都使用它递归评估插入到决策引擎中的数据的数据结构:

BC-Example.drl 中的递归查询

query isContainedIn( String x, String y )
  Location( x, y; )
  or
  ( Location( z, y; ) and isContainedIn( x, z; ) )
end

规则 "go" 会输出插入到系统中的每个字符串,以确定如何实施项目,规则 "go1" 调用查询 是ContainedIn

规则 "go" 和 "go1"

rule "go" salience 10
  when
    $s : String()
  then
    System.out.println( $s );
end

rule "go1"
  when
    String( this == "go1" )
    isContainedIn("Office", "House"; )
  then
    System.out.println( "Office is in the House" );
end

示例将 "go1" 字符串插入到决策引擎中,并激活 "go1" 规则来检测该项目 响应者 位于位置 House 中:

插入字符串和触发规则

ksession.insert( "go1" );
ksession.fireAllRules();

IDE 控制台中的规则 "go1" 输出

go1
Office is in the House

传输冲突规则

传输是父元素中包含的元素之间的关系,它在分级结构中有多个级别。

规则 "go2" 标识 DrawerHouse 的传输关系,即 Drawer 位于 House 内的 Desk 中。

rule "go2"
  when
    String( this == "go2" )
    isContainedIn("Drawer", "House"; )
  then
    System.out.println( "Drawer is in the House" );
end

示例将 "go2" 字符串插入到决策引擎中,并激活 "go2" 规则来检测该项目 Drawer 最终会在位置 House 中:

插入字符串和触发规则

ksession.insert( "go2" );
ksession.fireAllRules();

IDE 控制台中的规则"go2"输出

go2
Drawer is in the House

决策引擎根据以下逻辑决定此结果:

  1. 查询递归搜索存放中的多个级别,以检测 DrawerHouse 之间的传输冲突。
  2. 查询使用 Location (x, y;),而是使用 (z, y;),因为 Drawer 不直接在 House 中。
  3. z 参数当前未绑定,这意味着它没有值并返回参数中的所有内容。
  4. y 参数当前绑定到 House,因此 z 返回 OfficeKitchen
  5. 如果 Drawer 位于 响应者,查询会从印度收集信息并递归检查。为这些参数调用查询行 isContainedIn (x, z;)
  6. 印度没有直接存在 Drawer 实例,因此找不到任何匹配项。
  7. 使用 z unbound 时,查询会返回响应者中的数据,并确定 z == Desk

    isContainedIn(x==drawer, z==desk)
  8. isContainedIn 查询递归搜索三次,第三个时间则查询会检测 Desk 中的 Drawer 实例。

    Location(x==drawer, y==desk)
  9. 在第一个位置上匹配后,查询会递归搜索结构,以确定 Drawer 是否在 Desk 中,De sk 位于印度,且响应者位于 House 中。 因此,Drawer 位于 House 中,规则满足。

重新主动查询规则

被动查询搜索数据结构的层次结构,以获取元素之间的关系,并在修改结构中的元素时动态更新。

规则 "go3" 的功能作为一个重新主动查询,它通过传输冲突来检测响应中是否存在新项目密钥:该机构中的 Drawer 中的密钥

规则 "go3"

rule "go3"
  when
    String( this == "go3" )
    isContainedIn("Key", "Office"; )
  then
    System.out.println( "Key is in the Office" );
end

示例将 "go3" 字符串插入到决策引擎中,并激活 "go3" 规则。最初,此规则不满足,因为托管结构中没有项目密钥,因此规则不会生成任何输出。

插入字符串和触发规则

ksession.insert( "go3" );
ksession.fireAllRules();

IDE 控制台中的规则"go3"输出(不满意)

go3

然后,该示例在位置 Drawer 中插入一个新项目密钥,它位于 印度这个更改满足 "go3" 规则中的传输冲突,输出会相应地填充。

插入新项目位置和触发规则

ksession.insert( new Location("Key", "Drawer") );
ksession.fireAllRules();

IDE 控制台中的规则"go3"输出(满意)

Key is in the Office

此更改还在查询包含在后续递归搜索的结构中添加另一个级别。

在规则中使用未绑定参数的查询

具有一个或多个未绑定参数的查询会返回查询定义的(绑定)参数中的所有未定义(unbound)项目。如果查询中的所有参数都未绑定,则查询会返回查询范围内的所有项目。

规则 "go4" 使用 unbound 参数操作来搜索绑定参数 响应中的 所有项目,而不是使用 bound 参数搜索响应者中的特定项目:

规则"go4"

rule "go4"
  when
    String( this == "go4" )
    isContainedIn(thing, "Office"; )
  then
    System.out.println( thing + "is in the Office" );
end

示例将 "go4" 字符串插入到决策引擎中,并激活 "go4" 规则,以返回响应者中的所有项目:

插入字符串和触发规则

ksession.insert( "go4" );
ksession.fireAllRules();

IDE 控制台中的规则"go4"输出

go4
Chair is in the Office
Desk is in the Office
Key is in the Office
Computer is in the Office
Drawer is in the Office

规则 "go5" 使用 unbound 参数 和位置 在整个 House 数据结构中搜索所有项目及其位置:

规则 "go5"

rule "go5"
  when
    String( this == "go5" )
    isContainedIn(thing, location; )
  then
    System.out.println(thing + " is in " + location );
end

示例将 "go5" 字符串插入到决策引擎中,并激活 "go5" 规则来返回 House 数据结构中的所有项目及其位置:

插入字符串和触发规则

ksession.insert( "go5" );
ksession.fireAllRules();

IDE 控制台中的规则"go5"输出

go5
Chair is in Office
Desk is in Office
Drawer is in Desk
Key is in Drawer
Kitchen is in House
Cheese is in Kitchen
Knife is in Kitchen
Computer is in Desk
Office is in House
Key is in Office
Drawer is in House
Computer is in House
Key is in House
Desk is in House
Chair is in House
Knife is in House
Cheese is in House
Computer is in Office
Drawer is in Office
Key is in Desk

第 86 章 与决策引擎相关的性能调优注意事项

以下主要概念或推荐做法可帮助您优化决策引擎性能。本节中总结了这些概念,并在适用的情况下在跨引用文档中进行更详细的说明。本节将根据新版本的 Red Hat Process Automation Manager 根据需要扩展或更改。

对不需要重要的决策引擎更新的无状态 KIE 会话使用后续模式

连续模式是决策引擎中的高级规则基础配置,可让决策引擎按照决策引擎人员中列出的顺序评估规则一次,而无需考虑工作内存中的更改。因此,执行规则可能会更快,但重要的更新可能不适用于您的规则。后续模式只适用于无状态 KIE 会话。

要启用后续模式,请将系统属性 drools.sequential 设置为 true

有关启用它的连续模式或其他选项的详情请参考 第 81.3 节 “Phreak 中的顺序模式”

在事件监听器中使用简单的操作

限制事件监听程序的数量以及它们执行的操作类型。使用事件监听程序进行简单操作,如调试日志和设置属性。监听器中的复杂操作(如网络调用)可能会妨碍规则执行。完成 KIE 会话后,删除附加的事件监听程序,以便清理会话,如下例所示:

使用后删除的事件监听程序示例

Listener listener = ...;
StatelessKnowledgeSession ksession = createSession();
try {
    ksession.insert(fact);
    ksession.fireAllRules();
    ...
} finally {
    if (session != null) {
        ksession.detachListener(listener);
        ksession.dispose();
    }
}

有关决策引擎中内置事件监听程序和调试日志的详情,请参考 第 84 章 决策引擎事件监听程序和调试日志

为可执行模型构建配置 LambdaIntrospector 缓存大小
您可以配置 LambdaIntrospector.methodFingerprintsMap 缓存的大小,该缓存在可执行模型构建中使用。缓存的默认大小为 32。当您为缓存大小配置较小的值时,会减少内存用量。例如,您可以将系统属性 drools.lambda.introspector.cache.size 配置为 0, 以实现最小内存用量。请注意,较小的缓存大小也会减慢构建性能。
对可执行模型使用 lambda 外部化

启用 lambda 外部化,以便在运行时优化内存消耗。它重写了在可执行模型中生成和使用的 lambdas。这可让您多次为所有模式和相同的约束重复使用相同的 lambda。当对 Rete 或 phreak 进行实例化时,可执行模型将变为垃圾回收。

要为可执行模型启用 lambda 外部化,请包括以下属性:

-Ddrools.externaliseCanonicalModelLambda=true

第 87 章 其他资源

部分 X. 将机器学习与 Red Hat Process Automation Manager 集成

作为业务公司或业务逻辑开发人员,您可以使用带有决策模型和表示法(DMN)模型的 PMML 文件将机器学习与 Red Hat Process Automation Manager 集成。

第 88 章 原始 AI

当您考虑人工智能(AI)时,可能会考虑机器学习和大量数据。但是,机器学习只是图片的一部分。智能功能包括以下技术:

  • robotics:技术、科学和工程的集成,生成可执行由人执行的物理任务的机器
  • 机器学习:在向数据公开到数据时了解或改进算法的功能,而无需明确编程到数据
  • 自然语言处理:机器学习的一个子集,用于处理人为指纹
  • 数学优化:使用条件和约束来查找问题的最佳解决方案
  • 数字决定:使用定义的标准、条件以及一系列机器和人类任务做出决策

虽然科学人填写了什么称为人工常规智能(AGI),但其执行比人员更好,且无法与他们区分开,并在不人为干预或控制的情况下了解和演进,但 AGI 正在努力。同时,我们有多大的 AI,目前我们非常低,对我们来说更有用。Eagmatic AI 是 AI 技术的集合,在合并时为问题提供解决方案,如预测客户行为、提供自动化客户服务,有助于客户做出销售决策。

主要行业领导报告,以前机构已经与 AI 技术合作,因为它们认为是 AI 的潜在情况,而不是现在提供 AI 的可能性。AI 项目没有满意,因此减少了 AI 项目的 AI 缓慢和预算。使用 AI 进行这种差异通常被称为 AI winter。AI 有几个 AI winters 周期,后跟 AI spring,现在我们决定在 AI spring 中。机构认为 AI 可交付的实际情况。因为实际来说是可行的。AI 的方法认为现在可用的 AI 技术,在很有用的情况下将它们合并,并在创建实际问题的解决方案时添加人为干预。

原始 AI 解决方案示例

一个逻辑卷的 AI 应用程序是客户支持。客户文件有一个报告问题的支持问题单,例如登录错误。机器学习算法应用于票据,以将票据内容与现有解决方案匹配,具体取决于关键字或自然语言处理(NLP)。关键字可能会出现在许多解决方案中,有些相关和一些不相关。您可以使用数字决定来确定客户要呈现哪些解决方案。但是,有时,算法建议的任何解决方案都适合客户传播。这是因为,所有解决方案都有非常可靠的分数,或者多个解决方案具有非常强的分数。如果无法找到适当的解决方案,则数字决定涉及人工支持团队。要找到基于可用性和专家的最佳支持人员,数学优化通过考虑员工更严格的限制来选择支持票据的最佳分配者。

如本例所示,您可以组合机器学习,从数据分析和数字决定中提取信息,以建模人知识和体验。然后,您可以应用数学优化来调度人为帮助。这是一个适用于其他情况的模式,例如信用卡吞吐量和信用卡入侵检测。

这些技术使用四个行业标准:

  • 问题单管理模型和表示法(CMMN)

    CMMN 用于建模工作方法,其包括可能以无法预计的顺序执行的各种活动,具体取决于情况。CMMN 模型是事件中心。CMMN 克服了通过支持较少结构化工作任务和由人驱动的结构化工作任务和任务进行建模的限制。通过组合使用 IaaS 和 CMMN,您可以创建更强大的模型。

  • 商业流程模型和表示法(DSLN2)

    Tailoring2 规范是一种对象管理组(OMG)规范,用于定义以图形方式代表业务的标准,定义元素的执行语义,并以 XML 格式提供进程定义。Dan2 可以建模计算机和人类任务。

  • 决策模型和表示法(DMN)

    决策模型和表示法(DMN)是由 OMG 建立的标准,用于描述和建模操作决策。DMN 定义了一个 XML 模式,它允许在 DMN 兼容平台和机构间共享 DMN 模型,以便开发人员能够互动并实施 DMN 决策服务。DMN 标准与流程类似,并可与用于设计和建模的 Business Process Model 和 Notation (DSLN)标准一起使用。

  • 预测模型标记语言(PMML)

    PMML 是用于代表预测模型、数学模型使用统计技术在大量数据中取消或学习模式的语言。预测模型使用他们学习的模式来预测新数据中存在模式。使用 PMML 时,您可以在应用程序间共享预测模型。这些数据作为 PMML 文件导出,可由 DMN 模型使用。随着机器学习框架继续参与模型,更新的数据可以保存到现有的 PMML 文件中。这意味着,您可以使用任何应用程序创建的预测模型,这些模型可将模型保存为 PMML 文件。因此,DMN 和 PMML 集成良好。

全部放在一起

本图演示了预测决策自动化如何工作。

  1. 业务数据进入系统,例如来自 loan 应用程序的数据。
  2. 与预测模型集成的决策模型决定是否批准 loan 还是需要额外的任务。
  3. 例如,业务操作结果将发送给客户。

下一部分演示了预测决策自动化如何与 Red Hat Process Automation Manager 配合使用。

第 89 章 信用卡差异用例

行业使用原大 AI 在多个地区决定。一个区域是信用卡费用的吞吐量。当客户识别了信用卡的存在不正确或未识别的收费时,客户可能会给收费带来风险。在某些情况下需要信用卡入侵的人类干预,但大多数报告的信用卡 fraud 可以完全解决,或者部分通过原封 AI 解析。

此用例示例是一些不动的 Fortress 人员、企业客户 Joe 和商业流程管理(DSL)开发人员 Michelle。首先,我们将了解最初如何通过 Red Hat Process Automation Manager 数字决定使用 AI,然后我们将了解通过从机器学习创建的预测模型(PMML)模型来增强决策模型。

机器学习模型(如 Tensorflow™ 和 R™ )生成预测模型。您可以将这些预测模型保存为开放标准,如 PMML,以便您可以在 Red Hat Process Automation Manager 或其他支持 PMML 标准的产品中使用模型。

Red Hat Process Automation Manager 和 Red Hat OpenShift Container Platform

Fortress在 Red Hat OpenShift Container Platform 上使用 Red Hat Process Automation Manager 来开发和运行 Fortress 决策服务。Red Hat OpenShift Container Platform 是一个云平台,用于开发和运行容器化应用程序。它旨在启用支持它们的应用程序和数据中心,以便只从少量机器和应用程序扩展到为数百万客户端提供服务的数千台机器。Red Hat Process Automation Manager 是用于创建云原生自动化应用程序和微服务的红帽中间件。它使企业业务和 IT 用户能够记录、模拟、管理、自动化和监控业务流程和决策。Business Central 是 Red Hat Process Automation Manager 仪表板。

信用卡通过 Red Hat Process Automation Manager 数字决定

joe 是一个 Fortress Wright 客户。每个月都登录到 Fortress the website,在支付前查阅其所有责任。这个月,Joe 会看到一个被识别的事务,但数量不正确。供应商已收费了 $44.50 而不是 $4.50。joe 选择包含不正确项目的行,然后单击 Dispute

transaction history

此操作会启动一系列有关吞吐量的问题:

  1. 为什么您会观察这些事务?
  2. 您的卡是否是您的整个时间?
  3. 您想告诉我们什么其他问题吗?

在 Joe 回答问题后,网站为 Joe 提供了事件号 000004

Fortress the 现在必须决定是否在没有人工调查或手动调查声明的情况下重新模拟吞吐量。手动调查需要更多资源,以便在人类资源方面自动处理所消耗的大量成本。但是,如果公司自动接受所有对成本的吞吐量,因为支付了模糊的声明,因此成本最终将更大。某人或某项必须做出决定是否进行调查。

信用卡 Dispute 项目

为了帮助做出这一决策,Fortress 工作中心使用 Business Central 创建包含障碍的 fraudDispute Case 项目的 CreditCardDisputeCase 项目。

casefile

进程变量

当 Joe 报告吞吐量时,会使用 ID FR-00000004 创建 fraudDispute 进程的实例。Process Variables 选项卡包含多个特定于 Joe 帐户的变量和值,包括 CaseIDcaseFile_cardholderRIskRating (信用卡拥有者风险评级)和 caseFile_disputeRiskRating (这种差异的风险评级):

process variables 3

表也具有值为 truecasefile_automated 变量。这表示吞吐量满足自动处理的条件。

进程图

Diagram 选项卡包含 slirp 图,它显示了在决定是否自动或手动处理吞吐量时使用的决策路径:

bpmn

Decision Task 任务包含基于 caseFile_cardholderRiskRiskRat ing 变量的值是否自动收费到 Joe 的帐户(Milestone 1)的规则,或者是否需要更多的调查(Milestone 2),它基于 caseFile_cardholderRisk RiskRiskRating 变量的值。如果 Joe 的 Dispute 与自动批准标准匹配,则遵循 Milestone 1,并且会收费给其帐户。这个子进程非常强大且效率更高。如果 Joe 的吞吐量需要手动评估,则启动 Milestone 2 中的子进程,这需要一些人类执行者,并将需要更多资源进行处理。

在这种情况下,决策任务任务决定处理 Joe 的吞吐量,因此它遵循 Milestone 1: Automatic the

DMN 模型

以下简化的 DMN 模型显示作为 fraudDispute Decision 任务 一部分的决策过程:

simple dmn

输入变量为 Age (cardholder age), Incident Count (this cardholder), Cardholder Status (standard, silver, gold, platinum)和 Fraud Amount

Red Hat Process Automation Manager 使用决策表中的输入变量来支持数字决策。决策表由人工业务创建。该人员创建了经过草案的业务需求分析文档,或电子表格以供利益相关者审查和批准。然后,项目设计器使用 Business Central DMN 编辑器将分析文档中的数据传送到 DMN 模型。Fortress 信用卡 Dispute 进程有两个决策表,即 Cardholder Risk Rating table 和 Dispute Risk Rating 表。Cardholder Risk Rating 表包含三个输入变量: Incident CountCardholder Status、和 AgeDispute Risk Rating 表包含 Cardholder Status 输入变量。它根据 cardholder 状态以及吞吐量的数量计算 dispute 的风险。

riskrating

  • Cardholder risk Rating

    joe 是位于 25 年龄的 Silver 卡拥有者。以前,他存在两个以上的吞吐量,因此自己的风险评级为 2。如果 Joe 没有以前的吞吐量,则他的风险评级为 0。

  • 风险评级

    因为 Joe 是一个 Silver 卡拥有者,因此没有吞吐量的数量为 $40,Joe 在 Dispute Risk Rating 表中有一个 1 个评级。如果未吞吐量的数量为 $140,Joe 的风险评级为 2。

以下公式是作为 DMN 模型中 流程自动 最终决策的一部分实施的,使用两个决策表中的分数来确定是否自动收费的吞吐量数(Milestone 1),还是是否需要更多的调查(Milestone 2)

(Cardholder Risk Rating + Dispute Risk Rating) < 5

如果 Joe 的整体风险分数小于 5,则会自动收费出电量(最小1)。如果总体分数为 5 或更高,则手动处理其吞吐量(等级2)。

在 Red Hat Process Automation Manager 数字决定中添加机器学习

由于 Fortress 对其客户具有历史数据,包括以前的事务和历史记录,因此企业可以将这些数据与机器学习一起使用,以创建可在 DMN 模型决策任务中使用的预测模型。与业务专家创建的路由表相比,这可以更加准确地评估风险。

Fortress the 有两个 PMML 文件集合,其中包含模型,它们更准确地评估风险预测。一个集合基于线性回归算法,另一个基于随机林算法。

pmml models

线性回归是在统计数据和机器学习中最常用的算法之一。它使用一个线性仲裁,它组合了一组数字输入和输出值。随机林使用许多决策树作为输入来创建预测模型。

添加 PMML 文件

Michelle 将 dispute_risk_linear_regression PMML 文件导入到她的项目。她将 Cardholder risk Model Business model 添加到 DMN 模型中,并将 dispute_risk_linear_regression PMML 文件与节点相关联。Red Hat Process Automation Manager 分析 PMML 文件,并为节点添加输入参数。Michelle 将 Cardholder risk Model 节点与 Dispute Risk Rating 相关联。

然后 Michelle 将 credit_card_holder_risk_linear_regression PMML 模型添加到项目中,创建 Dispute risk Model 模式 DMN 文件,创建并将 credit_card_holder_risk_linear_regression PMML 文件与节点相关联。Red Hat Process Automation Manager 分析 PMML 文件,并为节点添加输入参数。

下图是 Michelle 的 DMN 模型,它使用 PMML 文件中的预测模型替换分析决策表:

DMN PMML 2

Michelle 现在返回到 fraudDispute ö 模型,并使用她添加的 PMML 文件更新模型。然后,她重新部署项目。

增加分数精度

在这个新场景中,Michelle 重新部署了带有 PMML 模型的 Fortress mailbox 项目,我们会看到 Joe 日志到其 Fortress 账户并报告与不正确的事务相同的情况。在 Business Central 中,Michelle 会导航到 Process Instances 窗口,她会看到 Joe 的新吞吐量实例。在 Process Variables 选项卡中,Michelle 检查 cardHolderRiskRatingdisputeRiskRating 的值。它们已更改,因为模型现在使用 PMML 文件。这通过使用基于历史数据的机器学习模型,从而更加精确地预测风险。同时,公司的策略仍由 DMN 决策模型强制执行:风险预测低于指定阈值,从而可以自动处理此吞吐量。

process variables pmml

监�

最后,Fortress Wright 使用 Prometheus 收集有关信用卡吞吐量和 Grafana 的指标,以实时视觉化这些指标。监视器的上限显示业务指标键性能指示器(KPI),而下部分则显示操作指标 KPI。

grafana

89.1. 使用带有 DMN 模型的 PMML 模型来解决信用卡事务吞吐量

本例演示了如何使用 Red Hat Process Automation Manager 创建使用 PMML 模型来解决信用卡事务吞吐量的 DMN 模型。当客户服务信用卡交易时,系统决定是否自动处理事务。

先决�件

  • Red Hat Process Automation Manager 可用,并在 Red Hat Process Automation Manager 安装中的 ~/kie-server.war/WEB-INF/lib~/business-central.war/WEB-INF/lib 目录中添加了以下 JAR 文件:

    • kie-dmn-jpmml-7.44.0.Final-redhat-00006.jar

      此文件包括在红帽客户门户网站的软件 下载页面中 的 Red Hat Decision Manager 7.9 Maven 存储库分发中(需要登录)。此文件的组 ID、工件 ID 和版本(GAV)标识符为 org.kie:kie-dmn-jpmml:7.44.0.Final-redhat-00006。如需更多信息,请参阅 Business Central 的 DMN 文件中的"Including PMML 模型"部分 使用 DMN 模型设计决策服务

    • JPMML Evaluator 1.5.1 JAR 文件
    • JPMML Evaluator Extensions 1.5.1 JAR 文件

      这些文件需要在 KIE 服务器和 Business Central 中启用 JPMML 评估。

      重要

      红帽支持与 PMML (JPMML)的 Java Evaluator API 集成,用于 Red Hat Process Automation Manager 中的 PMML 执行。但是,红帽不支持 JPMML 库。如果您在 Red Hat Process Automation Manager 发行版中包含 JPMML 库,请参阅 JPMML 的 Openscoring.io 许可证条款。

�程

  1. 使用 第 89.2 节 “信用卡交易处理 PMML 文件” 中的 XML 示例的内容创建 dtree_risk_predictor.pmml 文件。
  2. 在 Business Central 中,创建 Credit Card Dispute 项目:

    1. 导航到 Menu → Design → Projects
    2. 单击 Add Project
    3. Name 框中,输入 Credit Card Dispute 并点 Add
  3. Credit Card Dispute 项目的 Assets 窗口中,将 dtree_risk_predictor.pmml 文件导入到 com 软件包中:

    import pmml

    1. Import Asset
    2. Create new Import Asset 对话框中,在 Name 框中输入 dtree_risk_predictor,从 Package 菜单中选择 com,选择 dtree_risk_predictor.pmml 文件,然后点 OK

      dtree_risk_predictor.pmml 文件的内容会出现在 Overview 窗口中。

  4. com 软件包中创建 Dispute Transaction Check DMN 模型:

    dmn asset

    1. 要返回项目窗口,请单击面栏中的 Credit Card Dispute
    2. Add Asset
    3. 在资产库中点 DMN
    4. Create new DMN 对话框中,在 Name 框中输入 Dispute Transaction Check,从 Package 菜单中选择 com,然后单击 OK

      DMN 编辑器会打开 Dispute Transaction Check DMN 模型。

  5. 创建 tTransaction 自定义数据类型:

    ttransactions

    1. Data Types 选项卡。
    2. Add a custom Data Type
    3. Name 框中,输入 tTransaction
    4. Type 菜单中选择 Structure
    5. 要创建数据类型,请点击检查标记。

      tTransaction 自定义数据类型会出现一个变量行。

    6. 在变量行的 Name 字段中输入 transaction_amount,从 Type 菜单中选择 Number,然后点检查标记。
    7. 若要添加新变量行,请单击 transaction_amount 行上的加号符号。此时会出现一个新行。
    8. Name 字段中输入 cardholder_identifier,从 Type 菜单中选择 Number,然后点检查标记。
  6. 添加 风险 Predictor dtree_risk_predictor.pmml 模型:

    include model

    1. 在 DMN 编辑器的 Included Models 窗口中,单击 Include Model
    2. Include Model 对话框中,从 Models 菜单中选择 dtree_risk_predictor.pmml
    3. Provides a unique name 框中输入 risk Predictor,然后单击 OK
  7. 使用 风险预测器和 DecisionTreeClassifier 模型创建 风险预测 商业知识库(BKM)节点:

    risk predictor function

    1. 在 DMN 编辑器的 Model 窗口中,将 BKM 节点拖到 DMN 编辑器 palette 中。

      bkm

    2. 重命名节点 风险优先级
    3. 点节点左侧的回收站图标下的编辑图标。

      risk predictor node

    4. Risk Predictor 框中点 F,然后从 Select Function Kind 菜单中选择 PMMLFP 的更改。
    5. 双击 First select PMML 文档 框,然后选择 risk Predictor
    6. 双击 Second select PMML model 框,然后选择 DecisionTreeClassifier
    7. 要返回 DMN 编辑器面板,请单击 Back to Dispute Transaction Check
  8. 使用数据类型 t Transaction 创建事务输入数据节点:

    risk transaction

    1. 在 DMN 编辑器的 Model 窗口中,将输入数据节点拖到 DMN 编辑器 palette 中。

      input node

    2. 重命名节点 事务
    3. 选择节点,然后单击窗口右上角的属性铅笔图标。
    4. Properties 面板中,选择 Information Item → Data type → tTransaction,然后关闭面板。
  9. 创建 Transaction Dispute risk 决策节点,并为功能添加 Transaction 节点进行 数据输入和风险 Predictor 节点:

    model3

    1. 在 DMN 编辑器的 Model 窗口中,将决策数据节点拖到 DMN 编辑器 palette 中。

      decision node

    2. 重命名节点 交易 Dispute risk
    3. 选择 风险预测 节点,并将箭头从节点右上角拖到事务性风险 节点。
    4. 选择 Transaction 节点,并将箭头从节点右下角拖到事务性风险 节点。
  10. Transaction Dispute risk 节点中,创建 风险预测 器调用功能:

    transaction dispute risk

    1. 选择 Transaction Dispute Risk 节点,然后点击节点左侧的编辑图标。
    2. Select expression,然后从菜单中选择 Invocation
    3. Enter function 框中输入 risk Predictor。
    4. 单击 P1
    5. Edit Parameter 对话框中,在 Name 框中输入 amount,从 Data Type 菜单中选择 number,然后按 Enter 键。
    6. Select expression然后从菜单中选择 Literal 表达式
    7. 在量旁边的框中输入 Transaction.transaction_ amount
    8. 右键点击 1,并选择位于以下 。这会打开 Edit Parameter 对话框。
    9. Name 框中输入 holder_index,从 Data Type 菜单中选择 number,然后按 Enter 键。
    10. 点行 2 上的 Select expression,然后从菜单中选择 Literal 表达式
    11. 大小 旁边的框中输入 Transaction.cardholder_identifier
  11. 使用数据类型 号创建 风险 阈值输入数据节点

    model4

    1. 在 DMN 编辑器的 Model 窗口中,将输入数据节点拖到 DMN 编辑器 palette 中。
    2. 重命名节点 风险阈值
    3. 选择节点,然后单击窗口右上角的属性铅笔图标。
    4. Properties 面板中,选择 Information Item → Data type → number,然后关闭面板。
  12. 创建 可以自动处理? 决策节点作为输入交易的 Dispute 风险 和风险 阈值 节点:

    model5

    1. 将决策节点拖到 DMN 编辑器面板,并重命名 它可以被自动处理?
    2. 选择节点,然后单击节点左上角的编辑图标。
    3. Select expression,然后从菜单中选择 Literal 表达式
    4. 在框中输入 Transaction Dispute Risk.predicted_dispute_risk < Risk Threshold
    5. 选择 Transaction Dispute risk 节点,并将节点左上角的箭头拖到 可以自动处理的节点?
    6. 选择 risk Threshold 节点,并将节点左下角的箭头拖到 可以自动处理的节点?
  13. 保存模型并构建项目:

    1. 在 DMN 编辑器中,单击 Save
    2. 如有必要,更正出现的任何错误。
    3. 要返回项目窗口,请单击面栏中的 Credit Card Dispute
    4. 单击 Build。该项目应该成功构建。
  14. 添加并运行测试场景: AIScenarioSimulations

    1. Add Asset
    2. 选择 Test Scenario
    3. Create new Test Scenario 对话框中,输入名称 Test Dispute Transaction Check,从 Package 菜单中选择 com,然后选择 DMN
    4. Choose a DMN asset 菜单中选择 Dispute Transaction Check.dmn,然后点 OK。测试模板构建。
    5. 输入以下值并点 Save

      注意

      不要向 Transaction Dispute Risk 列中添加一个值。这个值由测试场景决定。

      表 89.1. 测试场景参数

      æ��è¿°风险阈值cardholder_identifiertransaction_amount可以自动处理?

      风险阈值 5 自动处理

      5

      1234

      1000

      true

      风险阈值 4,number = 1000,未处理

      4

      1234

      1000

      false

      风险阈值 4,number = 180,自动处理

      4

      1234

      180

      true

      风险阈值 1, amount = 1, 未处理

      1

      1234

      1

      false

    6. 要运行测试,请单击 Validate 右侧的 Play 按钮。结果会出现在屏幕右侧的 Test Report 面板中。

89.2. 信用卡交易处理 PMML 文件

使用以下 XML 内容在 第 89.1 节 “使用带有 DMN 模型的 PMML 模型来解决信用卡事务吞吐量” 命名空间中创建 dtree_risk_predictor.pmml 文件。

<?xml version="1.0" encoding="UTF-8"?>
<PMML xmlns="http://www.dmg.org/PMML-4_2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="4.2" xsi:schemaLocation="http://www.dmg.org/PMML-4_2 http://www.dmg.org/v4-2-1/pmml-4-2.xsd">
  <Header copyright="Copyright (c) 2018 Software AG" description="Default Description">
    <Application name="Nyoka" version="4.3.0" />
    <Timestamp>2020-10-09 14:27:26.622723</Timestamp>
  </Header>
  <DataDictionary numberOfFields="3">
    <DataField name="amount" optype="continuous" dataType="double" />
    <DataField name="holder_index" optype="continuous" dataType="double" />
    <DataField name="dispute_risk" optype="categorical" dataType="integer">
      <Value value="1" />
      <Value value="2" />
      <Value value="3" />
      <Value value="4" />
      <Value value="5" />
    </DataField>
  </DataDictionary>
  <TreeModel modelName="DecisionTreeClassifier" functionName="classification" missingValuePenalty="1.0">
    <MiningSchema>
      <MiningField name="amount" usageType="active" optype="continuous" />
      <MiningField name="holder_index" usageType="active" optype="continuous" />
      <MiningField name="dispute_risk" usageType="target" optype="categorical" />
    </MiningSchema>
    <Output>
      <OutputField name="probability_1" optype="continuous" dataType="double" feature="probability" value="1" />
      <OutputField name="probability_2" optype="continuous" dataType="double" feature="probability" value="2" />
      <OutputField name="probability_3" optype="continuous" dataType="double" feature="probability" value="3" />
      <OutputField name="probability_4" optype="continuous" dataType="double" feature="probability" value="4" />
      <OutputField name="probability_5" optype="continuous" dataType="double" feature="probability" value="5" />
      <OutputField name="predicted_dispute_risk" optype="categorical" dataType="integer" feature="predictedValue" />
    </Output>
    <Node id="0" recordCount="600.0">
      <True />
      <Node id="1" recordCount="200.0">
        <SimplePredicate field="amount" operator="lessOrEqual" value="99.94000244140625" />
        <Node id="2" score="2" recordCount="55.0">
          <SimplePredicate field="holder_index" operator="lessOrEqual" value="0.5" />
          <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
          <ScoreDistribution value="2" recordCount="55.0" confidence="1.0" />
          <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
          <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
          <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
        </Node>
        <Node id="3" score="1" recordCount="145.0">
          <SimplePredicate field="holder_index" operator="greaterThan" value="0.5" />
          <ScoreDistribution value="1" recordCount="145.0" confidence="1.0" />
          <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
          <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
          <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
          <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
        </Node>
      </Node>
      <Node id="4" recordCount="400.0">
        <SimplePredicate field="amount" operator="greaterThan" value="99.94000244140625" />
        <Node id="5" recordCount="105.0">
          <SimplePredicate field="holder_index" operator="lessOrEqual" value="0.5" />
          <Node id="6" score="3" recordCount="54.0">
            <SimplePredicate field="amount" operator="lessOrEqual" value="150.4550018310547" />
            <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
            <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
            <ScoreDistribution value="3" recordCount="54.0" confidence="1.0" />
            <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
            <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
          </Node>
          <Node id="7" recordCount="51.0">
            <SimplePredicate field="amount" operator="greaterThan" value="150.4550018310547" />
            <Node id="8" recordCount="40.0">
              <SimplePredicate field="amount" operator="lessOrEqual" value="200.00499725341797" />
              <Node id="9" recordCount="36.0">
                <SimplePredicate field="amount" operator="lessOrEqual" value="195.4949951171875" />
                <Node id="10" recordCount="2.0">
                  <SimplePredicate field="amount" operator="lessOrEqual" value="152.2050018310547" />
                  <Node id="11" score="4" recordCount="1.0">
                    <SimplePredicate field="amount" operator="lessOrEqual" value="151.31500244140625" />
                    <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                    <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                    <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
                    <ScoreDistribution value="4" recordCount="1.0" confidence="1.0" />
                    <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                  </Node>
                  <Node id="12" score="3" recordCount="1.0">
                    <SimplePredicate field="amount" operator="greaterThan" value="151.31500244140625" />
                    <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                    <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                    <ScoreDistribution value="3" recordCount="1.0" confidence="1.0" />
                    <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                    <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                  </Node>
                </Node>
                <Node id="13" recordCount="34.0">
                  <SimplePredicate field="amount" operator="greaterThan" value="152.2050018310547" />
                  <Node id="14" recordCount="20.0">
                    <SimplePredicate field="amount" operator="lessOrEqual" value="176.5050048828125" />
                    <Node id="15" recordCount="19.0">
                      <SimplePredicate field="amount" operator="lessOrEqual" value="176.06500244140625" />
                      <Node id="16" score="4" recordCount="9.0">
                        <SimplePredicate field="amount" operator="lessOrEqual" value="166.6449966430664" />
                        <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                        <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                        <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
                        <ScoreDistribution value="4" recordCount="9.0" confidence="1.0" />
                        <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                      </Node>
                      <Node id="17" recordCount="10.0">
                        <SimplePredicate field="amount" operator="greaterThan" value="166.6449966430664" />
                        <Node id="18" score="3" recordCount="1.0">
                          <SimplePredicate field="amount" operator="lessOrEqual" value="167.97999572753906" />
                          <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                          <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                          <ScoreDistribution value="3" recordCount="1.0" confidence="1.0" />
                          <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                          <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                        </Node>
                        <Node id="19" score="4" recordCount="9.0">
                          <SimplePredicate field="amount" operator="greaterThan" value="167.97999572753906" />
                          <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                          <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                          <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
                          <ScoreDistribution value="4" recordCount="9.0" confidence="1.0" />
                          <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                        </Node>
                      </Node>
                    </Node>
                    <Node id="20" score="3" recordCount="1.0">
                      <SimplePredicate field="amount" operator="greaterThan" value="176.06500244140625" />
                      <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                      <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                      <ScoreDistribution value="3" recordCount="1.0" confidence="1.0" />
                      <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                      <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                    </Node>
                  </Node>
                  <Node id="21" score="4" recordCount="14.0">
                    <SimplePredicate field="amount" operator="greaterThan" value="176.5050048828125" />
                    <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                    <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                    <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
                    <ScoreDistribution value="4" recordCount="14.0" confidence="1.0" />
                    <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                  </Node>
                </Node>
              </Node>
              <Node id="22" recordCount="4.0">
                <SimplePredicate field="amount" operator="greaterThan" value="195.4949951171875" />
                <Node id="23" score="3" recordCount="1.0">
                  <SimplePredicate field="amount" operator="lessOrEqual" value="195.76499938964844" />
                  <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                  <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                  <ScoreDistribution value="3" recordCount="1.0" confidence="1.0" />
                  <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                  <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                </Node>
                <Node id="24" recordCount="3.0">
                  <SimplePredicate field="amount" operator="greaterThan" value="195.76499938964844" />
                  <Node id="25" score="4" recordCount="1.0">
                    <SimplePredicate field="amount" operator="lessOrEqual" value="196.74500274658203" />
                    <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                    <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                    <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
                    <ScoreDistribution value="4" recordCount="1.0" confidence="1.0" />
                    <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                  </Node>
                  <Node id="26" recordCount="2.0">
                    <SimplePredicate field="amount" operator="greaterThan" value="196.74500274658203" />
                    <Node id="27" score="3" recordCount="1.0">
                      <SimplePredicate field="amount" operator="lessOrEqual" value="197.5800018310547" />
                      <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                      <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                      <ScoreDistribution value="3" recordCount="1.0" confidence="1.0" />
                      <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                      <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                    </Node>
                    <Node id="28" score="4" recordCount="1.0">
                      <SimplePredicate field="amount" operator="greaterThan" value="197.5800018310547" />
                      <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                      <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                      <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
                      <ScoreDistribution value="4" recordCount="1.0" confidence="1.0" />
                      <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                    </Node>
                  </Node>
                </Node>
              </Node>
            </Node>
            <Node id="29" score="5" recordCount="11.0">
              <SimplePredicate field="amount" operator="greaterThan" value="200.00499725341797" />
              <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
              <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
              <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
              <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
              <ScoreDistribution value="5" recordCount="11.0" confidence="1.0" />
            </Node>
          </Node>
        </Node>
        <Node id="30" recordCount="295.0">
          <SimplePredicate field="holder_index" operator="greaterThan" value="0.5" />
          <Node id="31" score="2" recordCount="170.0">
            <SimplePredicate field="amount" operator="lessOrEqual" value="150.93499755859375" />
            <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
            <ScoreDistribution value="2" recordCount="170.0" confidence="1.0" />
            <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
            <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
            <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
          </Node>
          <Node id="32" recordCount="125.0">
            <SimplePredicate field="amount" operator="greaterThan" value="150.93499755859375" />
            <Node id="33" recordCount="80.0">
              <SimplePredicate field="holder_index" operator="lessOrEqual" value="2.5" />
              <Node id="34" recordCount="66.0">
                <SimplePredicate field="amount" operator="lessOrEqual" value="199.13500213623047" />
                <Node id="35" score="3" recordCount="10.0">
                  <SimplePredicate field="amount" operator="lessOrEqual" value="155.56999969482422" />
                  <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                  <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                  <ScoreDistribution value="3" recordCount="10.0" confidence="1.0" />
                  <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                  <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                </Node>
                <Node id="36" recordCount="56.0">
                  <SimplePredicate field="amount" operator="greaterThan" value="155.56999969482422" />
                  <Node id="37" score="2" recordCount="1.0">
                    <SimplePredicate field="amount" operator="lessOrEqual" value="155.9000015258789" />
                    <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                    <ScoreDistribution value="2" recordCount="1.0" confidence="1.0" />
                    <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
                    <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                    <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                  </Node>
                  <Node id="38" recordCount="55.0">
                    <SimplePredicate field="amount" operator="greaterThan" value="155.9000015258789" />
                    <Node id="39" recordCount="31.0">
                      <SimplePredicate field="amount" operator="lessOrEqual" value="176.3699951171875" />
                      <Node id="40" recordCount="30.0">
                        <SimplePredicate field="amount" operator="lessOrEqual" value="175.72000122070312" />
                        <Node id="41" recordCount="19.0">
                          <SimplePredicate field="amount" operator="lessOrEqual" value="168.06999969482422" />
                          <Node id="42" recordCount="6.0">
                            <SimplePredicate field="amount" operator="lessOrEqual" value="158.125" />
                            <Node id="43" score="3" recordCount="5.0">
                              <SimplePredicate field="amount" operator="lessOrEqual" value="157.85499572753906" />
                              <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                              <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                              <ScoreDistribution value="3" recordCount="5.0" confidence="1.0" />
                              <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                              <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                            </Node>
                            <Node id="44" score="2" recordCount="1.0">
                              <SimplePredicate field="amount" operator="greaterThan" value="157.85499572753906" />
                              <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                              <ScoreDistribution value="2" recordCount="1.0" confidence="1.0" />
                              <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
                              <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                              <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                            </Node>
                          </Node>
                          <Node id="45" score="3" recordCount="13.0">
                            <SimplePredicate field="amount" operator="greaterThan" value="158.125" />
                            <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                            <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                            <ScoreDistribution value="3" recordCount="13.0" confidence="1.0" />
                            <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                            <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                          </Node>
                        </Node>
                        <Node id="46" recordCount="11.0">
                          <SimplePredicate field="amount" operator="greaterThan" value="168.06999969482422" />
                          <Node id="47" score="2" recordCount="1.0">
                            <SimplePredicate field="amount" operator="lessOrEqual" value="168.69499969482422" />
                            <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                            <ScoreDistribution value="2" recordCount="1.0" confidence="1.0" />
                            <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
                            <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                            <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                          </Node>
                          <Node id="48" recordCount="10.0">
                            <SimplePredicate field="amount" operator="greaterThan" value="168.69499969482422" />
                            <Node id="49" recordCount="4.0">
                              <SimplePredicate field="holder_index" operator="lessOrEqual" value="1.5" />
                              <Node id="50" score="2" recordCount="1.0">
                                <SimplePredicate field="amount" operator="lessOrEqual" value="172.0250015258789" />
                                <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                                <ScoreDistribution value="2" recordCount="1.0" confidence="1.0" />
                                <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
                                <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                                <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                              </Node>
                              <Node id="51" score="3" recordCount="3.0">
                                <SimplePredicate field="amount" operator="greaterThan" value="172.0250015258789" />
                                <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                                <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                                <ScoreDistribution value="3" recordCount="3.0" confidence="1.0" />
                                <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                                <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                              </Node>
                            </Node>
                            <Node id="52" score="3" recordCount="6.0">
                              <SimplePredicate field="holder_index" operator="greaterThan" value="1.5" />
                              <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                              <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                              <ScoreDistribution value="3" recordCount="6.0" confidence="1.0" />
                              <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                              <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                            </Node>
                          </Node>
                        </Node>
                      </Node>
                      <Node id="53" score="2" recordCount="1.0">
                        <SimplePredicate field="amount" operator="greaterThan" value="175.72000122070312" />
                        <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                        <ScoreDistribution value="2" recordCount="1.0" confidence="1.0" />
                        <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
                        <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                        <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                      </Node>
                    </Node>
                    <Node id="54" recordCount="24.0">
                      <SimplePredicate field="amount" operator="greaterThan" value="176.3699951171875" />
                      <Node id="55" score="3" recordCount="16.0">
                        <SimplePredicate field="amount" operator="lessOrEqual" value="192.0999984741211" />
                        <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                        <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                        <ScoreDistribution value="3" recordCount="16.0" confidence="1.0" />
                        <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                        <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                      </Node>
                      <Node id="56" recordCount="8.0">
                        <SimplePredicate field="amount" operator="greaterThan" value="192.0999984741211" />
                        <Node id="57" score="2" recordCount="1.0">
                          <SimplePredicate field="amount" operator="lessOrEqual" value="192.75499725341797" />
                          <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                          <ScoreDistribution value="2" recordCount="1.0" confidence="1.0" />
                          <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
                          <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                          <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                        </Node>
                        <Node id="58" score="3" recordCount="7.0">
                          <SimplePredicate field="amount" operator="greaterThan" value="192.75499725341797" />
                          <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                          <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                          <ScoreDistribution value="3" recordCount="7.0" confidence="1.0" />
                          <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                          <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                        </Node>
                      </Node>
                    </Node>
                  </Node>
                </Node>
              </Node>
              <Node id="59" recordCount="14.0">
                <SimplePredicate field="amount" operator="greaterThan" value="199.13500213623047" />
                <Node id="60" score="5" recordCount="10.0">
                  <SimplePredicate field="holder_index" operator="lessOrEqual" value="1.5" />
                  <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                  <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                  <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
                  <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                  <ScoreDistribution value="5" recordCount="10.0" confidence="1.0" />
                </Node>
                <Node id="61" score="4" recordCount="4.0">
                  <SimplePredicate field="holder_index" operator="greaterThan" value="1.5" />
                  <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                  <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                  <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
                  <ScoreDistribution value="4" recordCount="4.0" confidence="1.0" />
                  <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
                </Node>
              </Node>
            </Node>
            <Node id="62" recordCount="45.0">
              <SimplePredicate field="holder_index" operator="greaterThan" value="2.5" />
              <Node id="63" score="2" recordCount="37.0">
                <SimplePredicate field="amount" operator="lessOrEqual" value="199.13999938964844" />
                <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                <ScoreDistribution value="2" recordCount="37.0" confidence="1.0" />
                <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
                <ScoreDistribution value="4" recordCount="0.0" confidence="0.0" />
                <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
              </Node>
              <Node id="64" score="4" recordCount="8.0">
                <SimplePredicate field="amount" operator="greaterThan" value="199.13999938964844" />
                <ScoreDistribution value="1" recordCount="0.0" confidence="0.0" />
                <ScoreDistribution value="2" recordCount="0.0" confidence="0.0" />
                <ScoreDistribution value="3" recordCount="0.0" confidence="0.0" />
                <ScoreDistribution value="4" recordCount="8.0" confidence="1.0" />
                <ScoreDistribution value="5" recordCount="0.0" confidence="0.0" />
              </Node>
            </Node>
          </Node>
        </Node>
      </Node>
    </Node>
  </TreeModel>
</PMML>

第 90 章 å…¶ä»–资æº�

附录 A. 版本信息

文档最后在 2022 年 3 月 8 日更新。

附录 B. 联系信息

Red Hat Process Automation Manager 文档团队: brms-docs@redhat.com

法律通告

Copyright © 2023 Red Hat, Inc.
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, the Red Hat logo, JBoss, OpenShift, Fedora, the Infinity logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.
Linux® is the registered trademark of Linus Torvalds in the United States and other countries.
Java® is a registered trademark of Oracle and/or its affiliates.
XFS® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States and/or other countries.
MySQL® is a registered trademark of MySQL AB in the United States, the European Union and other countries.
Node.js® is an official trademark of Joyent. Red Hat is not formally related to or endorsed by the official Joyent Node.js open source or commercial project.
The OpenStack® Word Mark and OpenStack logo are either registered trademarks/service marks or trademarks/service marks of the OpenStack Foundation, in the United States and other countries and are used with the OpenStack Foundation's permission. We are not affiliated with, endorsed or sponsored by the OpenStack Foundation, or the OpenStack community.
All other trademarks are the property of their respective owners.