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()方法时,会触发KieSessiond,并针对输入数据评估业务逻辑。在业务逻辑评估后,最后一条规则会在列表中收集所有已批准的应用程序,并且返回相同的列表作为输出。- 启动 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-approvedJSON 响应示例
[ { "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整合到类中,该函数实施FindApprovedLoansEndpointREST 端点。以开发模式启动您的 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 中的规则单元也附带数据源。规则单元数据源是由给定规则单元处理的数据源,代表入口点,用于评估规则单元。规则单元使用两种类型的数据源:
-
datastream:这是仅附加数据源。在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 生成
FindApprovedREST 端点。