搜索

13.2. 直接嵌入 Java 应用程序中的 PMML 传统调用

download PDF

当知识资产直接嵌入到调用程序中,或者被实际拉取为 KJAR 的 Maven 依赖关系时,KIE 容器是本地的。如果代码版本和 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.67.0.Final-redhat-00024)。

    注意

    考虑将 Red Hat Business Automation 材料清单(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.13.5.redhat-00002</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>

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

    重要

    要使用传统实施,请确保将 kie-pmml-ement ation 系统属性设置为 legacy

  2. 类路径ReleaseId 创建 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 方法外,M 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 对象添加到这些会话,然后基于 RuleUnit 来执行规则,后者作为参数传递到 run() 方法。calculatePossiblePackageNamesgetStartingRuleUnit 方法决定了传递给 run() 方法的 RuleUnit 类的完全限定名称。

为方便您的 PMML 模型执行,您还可以使用 Red Hat Process Automation Manager 支持的 PMML4ExecutionHelper 类。有关 PMML 帮助程序类的更多信息,请参阅 第 13.2.1 节 “PMML 执行帮助程序类”

13.2.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 时,您不需要像典型的 PMML 模型执行一样指定可能的软件包名称或 RuleUnit 类。

要构建 PMML4ExecutionHelper 类,请使用 PMML4ExecutionHelper class 确定如何检索 PMML4ExecutionHelper 的实例。

以下是构建 PMML4ExecutionHelper 类类方法的 PMML4ExecutionHelper 类方法:

pmML4ExecutionHelperFactory 方法,用于 KIE 基础中的 PMML 资产

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

public static PMML4ExecutionHelper getExecutionHelper(String modelName, KieBase kbase)

public static PMML4ExecutionHelper getExecutionHelper(String modelName, KieBase kbase, boolean includeMiningDataSources)
pmML4ExecutionHelperFactory 方法用于项目类路径上的 PMML 资产

当 PMML 资产位于项目类路径上时,请使用以下方法。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)
资源中的 PMML4ExecutionHelper factory 方法,用于资源中的 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、byte 数组和资源 PMML4ExecutionHelperFactory 方法为生成的规则和 Java 类创建 KIE 容器。容器用作 RuleUnitExecutor 使用的 KIE 基础的源。容器没有保留。在 KIE 基本中已有 PMML4ExecutionHelperFactory 方法的 PMML4ExecutionHelperFactory 方法不会以这种方式创建 KIE 容器。

Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

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

让开源更具包容性

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

關於紅帽

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

© 2024 Red Hat, Inc.