搜索

19.3. loan application project 示例

download PDF

在以下小节中,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 端点开发的规则评估。

流程

  1. 根据包含规则和 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>

  2. 创建 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 创建新的 KieSessionKieSession 填充了来自 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,并针对输入数据评估业务逻辑。在业务逻辑评估后,最后一条规则会在列表中收集所有已批准的应用程序,并且返回相同的列表作为输出。

  3. 启动 Quarkus 应用程序的红帽构建。
  4. 使用 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 微服务。

流程

  1. 在项目 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>

  2. 重写 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 中创建的方式创建 KieBasesKieSessions。Red Hat build of Kogito 在编译时自动生成 KieRuntimeBuilder 接口的实施,并将 KieRuntimeBuilder 整合到类中,该函数实施 FindApprovedLoansEndpoint REST 端点。

  3. 以开发模式启动您的 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 中时返回的事实来更新或删除对象。

总体而言,规则单元包含两个部分:评估的事实的定义以及评估事实的一组规则。

流程

  1. 使用 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 请求中传递的值自动设置。

  2. 实施 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 端点。

Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.