19.3. loan application project 示例
在以下小节中,metering 应用程序项目作为一个示例用于将 DRL 项目迁移到 Red Hat build of Kogito 部署。loan Application 项目的域模型由两个类组成,即 LoanApplication
类和 Applicant
类:
LoanApplication
类示例
public class LoanApplication { private String id; private Applicant applicant; private int amount; private int deposit; private boolean approved = false; public LoanApplication(String id, Applicant applicant, int amount, int deposit) { this.id = id; this.applicant = applicant; this.amount = amount; this.deposit = deposit; } }
Applicant
类示例
public class Applicant { private String name; private int age; public Applicant(String name, int age) { this.name = name; this.age = age; } }
规则集是利用业务决策创建来批准或拒绝应用程序,以及收集列表中所有已批准的应用程序的最后一个规则。
在 loan 应用程序中设置的规则示例
global Integer maxAmount; global java.util.List approvedApplications; rule LargeDepositApprove when $l: LoanApplication( applicant.age >= 20, deposit >= 1000, amount <= maxAmount ) then modify($l) { setApproved(true) }; // loan is approved end rule LargeDepositReject when $l: LoanApplication( applicant.age >= 20, deposit >= 1000, amount > maxAmount ) then modify($l) { setApproved(false) }; // loan is rejected end // ... more loans approval/rejections business rules ... rule CollectApprovedApplication when $l: LoanApplication( approved ) then approvedApplications.add($l); // collect all approved loan applications end
19.3.1. 使用红帽构建的 Quarkus 公开使用 REST 端点的规则评估
您可以使用红帽构建的 Quarkus 公开在 Business Central 中通过 REST 端点开发的规则评估。
流程
根据包含规则和 Quarkus 库的模块创建新模块,提供 REST 支持:
创建新模块的依赖项示例
<dependencies> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy-jackson</artifactId> </dependency> <dependency> <groupId>org.example</groupId> <artifactId>drools-project</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependencies>
创建 REST 端点。
以下是创建 REST 端点的示例设置:
FindApprovedLoansEndpoint
端点设置示例@Path("/find-approved") public class FindApprovedLoansEndpoint { private static final KieContainer kContainer = KieServices.Factory.get().newKieClasspathContainer(); @POST() @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public List<LoanApplication> executeQuery(LoanAppDto loanAppDto) { KieSession session = kContainer.newKieSession(); List<LoanApplication> approvedApplications = new ArrayList<>(); session.setGlobal("approvedApplications", approvedApplications); session.setGlobal("maxAmount", loanAppDto.getMaxAmount()); loanAppDto.getLoanApplications().forEach(session::insert); session.fireAllRules(); session.dispose(); return approvedApplications; } }
在上例中,将创建包含规则的
KieContainer
并添加到 static 字段中。KieContainer
中的规则是从类路径中的其他模块获得的。使用此方法,您可以重复使用与FindApprovedLoansEndpoint
端点相关的后续调用的KieContainer
,而无需重新编译规则。注意两个模块将在下一流程中使用旧 API 将规则单元迁移到红帽构建 Kogito 微服务。如需更多信息,请参阅使用旧 API 将 DRL 规则单元迁移到红帽构建 Kogito 微服务。
调用
FindApprovedLoansEndpoint
端点时,会从KieContainer
创建新的KieSession
。KieSession
填充了来自LoanAppDto
的对象,从 JSON 请求的 unmarshalling 中生成。LoanAppDto
类示例public class LoanAppDto { private int maxAmount; private List<LoanApplication> loanApplications; public int getMaxAmount() { return maxAmount; } public void setMaxAmount(int maxAmount) { this.maxAmount = maxAmount; } public List<LoanApplication> getLoanApplications() { return loanApplications; } public void setLoanApplications(List<LoanApplication> loanApplications) { this.loanApplications = loanApplications; } }
调用
fireAllRules()
方法时,会触发KieSession
d,并针对输入数据评估业务逻辑。在业务逻辑评估后,最后一条规则会在列表中收集所有已批准的应用程序,并且返回相同的列表作为输出。- 启动 Quarkus 应用程序的红帽构建。
使用 JSON 请求调用
FindApprovedLoansEndpoint
端点,该端点包含要检查的 loan 应用程序。maxAmount
的值在规则中使用,如下例所示:curl 请求示例
curl -X POST -H 'Accept: application/json' -H 'Content-Type: application/json' -d '{"maxAmount":5000, "loanApplications":[ {"id":"ABC10001","amount":2000,"deposit":1000,"applicant":{"age":45,"name":"John"}}, {"id":"ABC10002","amount":5000,"deposit":100,"applicant":{"age":25,"name":"Paul"}}, {"id":"ABC10015","amount":1000,"deposit":100,"applicant":{"age":12,"name":"George"}} ]}' http://localhost:8080/find-approved
JSON 响应示例
[ { "id": "ABC10001", "applicant": { "name": "John", "age": 45 }, "amount": 2000, "deposit": 1000, "approved": true } ]
使用此方法时,您无法使用热重新加载功能,且无法创建项目的原生镜像。在接下来的步骤中,缺少的 Quarkus 功能由 Kogito 扩展提供,以便 Quarkus 了解 DRL 文件,并以类似的方式实现热重新加载功能。
19.3.2. 将规则评估迁移到使用旧 API 的红帽 Kogito 微服务构建
使用 REST 端点公开规则评估后,您可以使用传统 API 将规则评估迁移到红帽构建 Kogito 微服务。
流程
在项目
pom.xml
文件中添加以下依赖项,以启用红帽构建的 Quarkus 和旧 API:使用 Quarkus 和旧 API 的依赖项示例
<dependencies> <dependency> <groupId>org.kie.kogito</groupId> <artifactId>kogito-quarkus-rules</artifactId> </dependency> <dependency> <groupId>org.kie.kogito</groupId> <artifactId>kogito-legacy-api</artifactId> </dependency> </dependencies>
重写 REST 端点实现:
REST 端点实现示例
@Path("/find-approved") public class FindApprovedLoansEndpoint { @Inject KieRuntimeBuilder kieRuntimeBuilder; @POST() @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public List<LoanApplication> executeQuery(LoanAppDto loanAppDto) { KieSession session = kieRuntimeBuilder.newKieSession(); List<LoanApplication> approvedApplications = new ArrayList<>(); session.setGlobal("approvedApplications", approvedApplications); session.setGlobal("maxAmount", loanAppDto.getMaxAmount()); loanAppDto.getLoanApplications().forEach(session::insert); session.fireAllRules(); session.dispose(); return approvedApplications; } }
在重写的 REST 端点实施中,而不是从
KieContainer
创建KieSession
,而是使用集成的KieRuntimeBuilder
自动创建KieSession
。KieRuntimeBuilder
是一个由kogito-legacy-api
模块提供的接口,它取代了KieContainer
。使用KieRuntimeBuilder
,您可以以类似您在KieContainer
中创建的方式创建KieBases
和KieSessions
。Red Hat build of Kogito 在编译时自动生成KieRuntimeBuilder
接口的实施,并将KieRuntimeBuilder
整合到类中,该函数实施FindApprovedLoansEndpoint
REST 端点。以开发模式启动您的 Red Hat build of Quarkus 应用程序。
您还可以使用热重新加载对应用到正在运行的应用程序的规则文件进行更改。另外,您可以创建基于规则的应用程序的原生镜像。
19.3.3. 实施规则单元和自动 REST 端点生成
将规则单元迁移到 Red Hat build of Kogito microservice 后,您可以实施规则单元和 REST 端点的自动生成。
在 Red Hat build of Kogito 中,规则单元包含一组规则和事实,与规则匹配。Red Hat build of Kogito 中的规则单元也附带数据源。规则单元数据源是由给定规则单元处理的数据源,代表入口点,用于评估规则单元。规则单元使用两种类型的数据源:
-
data
stream:这是仅附加数据源。在DataStream
中,订阅者接收新的和过去的信息,流可以是热或冷的。另外,添加到DataStream
中的事实无法更新或删除。 -
Datastore
:此数据源用于可修改的数据。您可以使用对象添加到DataStore
中时返回的事实来更新或删除对象。
总体而言,规则单元包含两个部分:评估的事实的定义以及评估事实的一组规则。
流程
使用 POJO 实施事实定义:
使用 POJO 实施事实定义示例
package org.kie.kogito.queries; import org.kie.kogito.rules.DataSource; import org.kie.kogito.rules.DataStore; import org.kie.kogito.rules.RuleUnitData; public class LoanUnit implements RuleUnitData { private int maxAmount; private DataStore<LoanApplication> loanApplications; public LoanUnit() { this(DataSource.createStore(), 0); } public LoanUnit(DataStore<LoanApplication> loanApplications, int maxAmount) { this.loanApplications = loanApplications; this.maxAmount = maxAmount; } public DataStore<LoanApplication> getLoanApplications() { return loanApplications; } public void setLoanApplications(DataStore<LoanApplication> loanApplications) { this.loanApplications = loanApplications; } public int getMaxAmount() { return maxAmount; } public void setMaxAmount(int maxAmount) { this.maxAmount = maxAmount; } }
在上例中,而不是使用
LoanAppD 到
LoanUnit
类被直接绑定。LoanAppDto
用于 marshall 或 unmarshall JSON 请求。另外,上例实施了org.kie.kogito.rules.RuleUnitData
接口,并使用DataStore
包含要批准的 loan 应用程序。org.kie.kogito.rules.RuleUnitData
是一个标记接口,用于通知决定引擎LoanUnit
类是规则单元定义的一部分。另外,DataStore
负责通过触发新规则并触发其他规则来响应更改。另外,规则的结果会修改上例中的
approved
属性。在 contrary 中,maxAmount
值被视为规则单元的配置参数,不会修改。maxAmount
会在规则评估过程中自动处理,并从 JSON 请求中传递的值自动设置。实施 DRL 文件:
DRL 文件的实现示例
package org.kie.kogito.queries; unit LoanUnit; // no need to using globals, all variables and facts are stored in the rule unit rule LargeDepositApprove when $l: /loanApplications[ applicant.age >= 20, deposit >= 1000, amount <= maxAmount ] // oopath style then modify($l) { setApproved(true) }; end rule LargeDepositReject when $l: /loanApplications[ applicant.age >= 20, deposit >= 1000, amount > maxAmount ] then modify($l) { setApproved(false) }; end // ... more loans approval/rejections business rules ... // approved loan applications are now retrieved through a query query FindApproved $l: /loanApplications[ approved ] end
您创建的 DRL 文件必须声明与事实定义实施相同的软件包,以及一个具有相同 Java 类名称的单元。Java 类将
RuleUnitData
接口实施为接口属于同一规则单元的状态。另外,上例中的 DRL 文件会使用 OOPath 表达式重写。在 DRL 文件中,数据源充当入口点,OOPath 表达式包含数据源名称作为 root。但是,限制在方括号中添加,如下所示:
$L: /loanApplications[ applicant.age >= 20, stored >= 1000, amount maxAmount ]
或者,您可以使用标准 DRL 语法,在其中指定数据源名称作为入口点。但是,您需要再次指定匹配对象的类型,如下例所示,即使决策引擎能够推断数据源的类型:
$L: LoanApplication(applicant.age >= 20, stored >= 1000, amount gap maxAmount)from entry-point loanApplications
在前面的示例中,收集所有批准的 loan 应用的最后一个规则将被替换为检索列表的查询。规则单元定义要在输入中用于评估规则的事实,而查询则定义了规则评估中预期的输出。使用这个方法,红帽构建的 Kogito 可以自动生成一个执行查询的类,并如下例所示:
LoanUnitQueryFindApproved
类示例public class LoanUnitQueryFindApproved implements org.kie.kogito.rules.RuleUnitQuery<List<org.kie.kogito.queries.LoanApplication>> { private final RuleUnitInstance<org.kie.kogito.queries.LoanUnit> instance; public LoanUnitQueryFindApproved(RuleUnitInstance<org.kie.kogito.queries.LoanUnit> instance) { this.instance = instance; } @Override public List<org.kie.kogito.queries.LoanApplication> execute() { return instance.executeQuery("FindApproved").stream().map(this::toResult).collect(toList()); } private org.kie.kogito.queries.LoanApplication toResult(Map<String, Object> tuple) { return (org.kie.kogito.queries.LoanApplication) tuple.get("$l"); } }
以下是一个 REST 端点示例,它使用规则单元作为输入并将输入传递给查询执行器返回输出:
LoanUnitQueryFindApprovedEndpoint
端点示例@Path("/find-approved") public class LoanUnitQueryFindApprovedEndpoint { @javax.inject.Inject RuleUnit<org.kie.kogito.queries.LoanUnit> ruleUnit; public LoanUnitQueryFindApprovedEndpoint() { } public LoanUnitQueryFindApprovedEndpoint(RuleUnit<org.kie.kogito.queries.LoanUnit> ruleUnit) { this.ruleUnit = ruleUnit; } @POST() @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public List<org.kie.kogito.queries.LoanApplication> executeQuery(org.kie.kogito.queries.LoanUnit unit) { RuleUnitInstance<org.kie.kogito.queries.LoanUnit> instance = ruleUnit.createInstance(unit); return instance.executeQuery(LoanUnitQueryFindApproved.class); } }
注意您还可以添加多个查询和每个查询,并生成不同的 REST 端点。例如,为 find-approved 生成
FindApproved
REST 端点。