19.3. loan 应用程序项目示例
在以下部分中,loan 应用程序项目被用作将 DRL 项目迁移到红帽构建 Kogito 部署的例子。loan 应用程序项目的域模型由两个类组成,即 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中的规则从类路径中的其他模块获取。使用此方法,您可以重复使用相同的KieContainer来处理与FindApprovedLoansEndpoint端点相关的后续调用,而无需重新编译规则。注意在将规则单元迁移到使用传统 API 的 Kogito 微服务的红帽构建过程中,这两个模块将合并。如需更多信息,请参阅 使用旧 API 将 DRL 规则单元迁移到红帽构建的 Kogito 微服务。
当调用
FindApprovedLoansEndpoint端点时,会从KieContainer创建新的KieSession。KieSession将填充LoanAppDto中由 JSON 请求未组合生成的对象。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,并根据输入数据评估业务逻辑。在业务逻辑评估后,最后一个规则收集列表中所有批准的应用程序,并返回与输出相同的列表。- 启动红帽构建的 Quarkus 应用程序。
使用包含要检查的 loan 应用程序的 JSON 请求调用
FindApprovedLoansEndpoint端点。规则中使用
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是由替换KieContainer的kogito-legacy-api模块提供的接口。使用KieRuntimeBuilder,您可以像在KieContainer中创建的方式创建KieBases和KieSessions。Red Hat build of Kogito 在编译时自动生成KieRuntimeBuilder接口的实现,并将KieRuntimeBuilder集成到一个类中,它实现了FindApprovedLoansEndpointREST 端点。以开发模式启动您的红帽构建的 Quarkus 应用程序。
您还可以使用热重新加载来对应用到正在运行的应用的规则文件进行更改。另外,您可以创建基于规则的应用程序的原生镜像。
19.3.3. 实施规则单元和自动 REST 端点生成 复制链接链接已复制到粘贴板!
将规则单元迁移到 Kogito 微服务的红帽构建后,您可以实施规则单元和 REST 端点的自动生成。
在红帽构建的 Kogito 中,规则单元包含一组规则和事实,规则与规则匹配。红帽构建的 Kogito 中的规则单位也附带数据源。规则单元数据源是给定规则单元处理的数据源,代表用于评估规则单元的入口点。规则单元使用两种类型的数据源:
-
datastream:这是仅附加数据源。在DataStream中,订阅者收到新的和过去的信息,流可以在被动流中是热或冷的信息。另外,添加到DataStream中的事实无法更新或删除。 -
Datastore:此数据源用于可修改的数据。您可以使用将对象添加到DataStore时返回的FactHandle更新或删除对象。
总体而言,规则单元包含两个部分:要评估的事实的定义,以及评估事实的规则集合。
流程
使用 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; } }在上例中,不使用
LoanAppDtotheLoanUnit类直接绑定。LoanAppDto用于 marshall 或 unmarshall JSON 请求。另外,前面的示例实现了org.kie.kogito.rules.RuleUnitData接口,并使用DataStore包含要批准的 loan 应用程序。org.kie.kogito.rules.RuleUnitData是一个标记接口,用于通知决策引擎LoanUnit类是规则单元定义的一部分。此外,DataStore负责允许通过触发新规则并触发其他规则来响应更改。另外,规则会修改上例中的
批准属性。在 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, deposit >= 1000, amount DAEMON maxAmount ]或者,您可以使用标准 DRL 语法,您可以在其中将数据源名称指定为入口点。但是,您需要再次指定匹配对象的类型,如下例所示,即使决策引擎可以从数据源中推断类型:
$L: LoanApplication (applicant.age >= 20, deposit >= 1000, amount FULL 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 端点示例,它将规则单元作为输入,并将输入传递给查询 executor 以返回输出:
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 端点。