Red Hat Process Automation Manager でのデシジョンサービスの開発

Red Hat Process Automation Manager 7.10

概要

本ガイドでは、DMN (Decision Model and Notation) モデル、Droools ルール言語 (DRL) ファイル、ガイド付きデシジョンテーブルなどのデシジョンオーサリングアセットを使用して、Red Hat Process Automation Manager でデシジョンサービスを開発する方法を説明します。

前書き

ビジネスデシジョンの開発者は、Red Hat Process Automation Manager で DMN (Decision Model and Notation) モデル、Drools ルール言語 (DRL) ルール、ガイド付きデシジョンテーブルなどのルールオーサリングアセットを使用してデシジョンサービスを開発できます。

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。まずは、マスター (master)、スレーブ (slave)、ブラックリスト (blacklist)、ホワイトリスト (whitelist) の 4 つの用語の置き換えから始めます。この取り組みは膨大な作業を要するため、今後の複数のリリースで段階的に用語の置き換えを実施して参ります。詳細は、弊社の CTO である Chris Wright のメッセージ を参照してください。

パート I. DMN モデルを使用したデシジョンサービスの作成

ビジネスアナリストやルール作成者は、DMN (Decision Model and Notation) を使用して、デシジョンサービスを視覚的にモデル化できます。DMN デシジョンモデルの意思決定要件は、1 つ以上の意思決定要件ダイアグラム (DRD) で記述された意思決定要件グラフ (DRG) により決まります。DMN モデルでは、DRD は DRG 全体の一部またはすべてを表します。DRD は、デシジョンテーブルなど、DMN ボックス式で定義されたロジックを使用した各デシジョンノードで、開始から終了までビジネスデシジョンを追跡します。

Red Hat Process Automation Manager は、適合レベル 3 で DMN 1.2 モデルの設計およびランタイムをサポートし、適合レベル 3 で DMN 1.1 および 1.3 モデルはランタイムのみサポートします。DMN モデルは、Business Central で直接作成するか、VSCode の Red Hat Process Automation Manager DMN モデラーを使用して作成するか、既存の DMN モデルを Red Hat Process Automation Manager プロジェクトにインポートしてデプロイおよび実行することができます。Business Central にインポートした DMN 1.1 および 1.3 モデル (DMN 1.3 機能は含まれません) は、DMN デザイナーで開き、保存時に DMN 1.2 モデルに変換されます。

DMN に関する詳細は、Object Management Group (OMG) の「Decision Model and Notation specification」を参照してください。

DMN デシジョンサービスの例を使用した段階的なチュートリアルは、『デシジョンサービスのスタートガイド』を参照してください。

第1章 Red Hat Process Automation Manager におけるデシジョン作成アセット

Red Hat Process Automation Manager は、デシジョンサービスにビジネスデシジョンを定義するのに使用可能なアセットを複数サポートします。デシジョン作成アセットはそれぞれ長所が異なるため、目的やニーズに合わせて、アセットを 1 つ、または複数を組み合わせて使用できます。

以下の表では、デシジョンサービスでデシジョンを定義する最適な方法を選択できるように、Red Hat Process Automation Manager プロジェクトでサポートされている主要なデシジョン作成アセットを紹介します。

表1.1 Red Hat Process Automation Manager でサポートされるデシジョン作成アセット

アセット主な特徴オーサリングツールドキュメント

DMN (Decision Model and Notation) モデル

  • Object Management Group (OMG) が定義する標準記法をもとにしたデシジョンモデルである
  • 一部またはすべての意思決定要件グラフ (DRG: Decision Requirements Graph) を表すグラフィカルな意思決定要件ダイアグラム (DRD: Decision Requirements Diagram) を使用してビジネスデシジョンのフローを追跡する
  • DMN モデルが DMN 準拠プラットフォーム間で共有できるようにする XML スキーマを使用する
  • DMN デシジョンテーブルおよび他の DMN ボックス式表現 (Boxed Expression) でデシジョンロジックを定義する Friendly Enough Expression Language (FEEL) をサポートする
  • Business Process Model and Notation (BPMN) プロセスモデルと効率的に統合できる
  • 包括性、具体性、および安定性のある意思決定フローの作成に最適である

Business Central または DMN 準拠のエディター

『DMN モデルを使用したデシジョンサービスの作成』

ガイド付きデシジョンテーブル

  • Business Central の UI ベースのテーブルデザイナーで作成するルールのテーブルである
  • デシジョンテーブルにスプレッドシートで対応する代わりにウィザードで対応する
  • 条件を満たした入力に、フィールドとオプションを提供する
  • ルールテンプレートを作成するテンプレートキーと値をサポートする
  • その他のアセットではサポートされていないヒットポリシー、リアルタイム検証などの追加機能をサポートする
  • コンパイルエラーを最小限に抑えるため、制限されているテーブル形式でルールを作成するのに最適である

Business Central

「ガイド付きデシジョンテーブルを使用したデシジョンサービスの作成」

スプレッドシートのデシジョンテーブル

  • Business Central にアップロード可能な XLS または XLSX スプレッドシート形式のデシジョンテーブルである
  • ルールテンプレートを作成するテンプレートキーと値をサポートする
  • Business Central 外で管理しているデシジョンテーブルでルールを作成するのに最適である
  • アップロード時に適切にルールをコンパイルするために厳密な構文要件がある

スプレッドシートエディター

「スプレッドシート形式のデシジョンテーブルを使用したデシジョンサービスの作成」

ガイド付きルール

  • Business Central の UI ベースのルールデザイナーで作成する個々のルールである
  • 条件を満たした入力に、フィールドとオプションを提供する
  • コンパイルエラーを最小限に抑えるため、制御されている形式で単独のルールを作成するのに最適である

Business Central

「ガイド付きルールを使用したデシジョンサービスの作成」

ガイド付きルールテンプレート

  • Business Central の UI ベースのテンプレートデザイナーで作成する再利用可能なルール構造である
  • 条件を満たした入力に、フィールドとオプションを提供する
  • (このアセットの目的の基本となる) ルールテンプレートを作成するテンプレートのキーと値をサポートする
  • ルール構造が同じで、定義したフィールド値が異なるルールを多数作成するのに最適である

Business Central

「ガイド付きルールテンプレートを使用したデシジョンサービスの作成」

DRL ルール

  • .drl テキストファイルに直接定義する個々のルールである
  • 最も柔軟性が高く、ルールと、ルール動作に関するその他の技術を定義できる
  • スタンドアロン環境で作成し、Red Hat Process Automation Manager に統合可能
  • 詳細な DRL オプションを必要とするルールを作成するのに最適である
  • ルールを適切にコンパイルするための厳密な構文要件がある

Business Central または統合開発環境 (IDE)

「DRL ルールを使用したデシジョンサービスの作成」

予測モデルマークアップ言語 (PMML: Predictive Model Markup Language) モデル

  • Data Mining Group (DMG) が定義する標準記法に基づく予測データ分析モデルである
  • PMML モデルを PMML 準拠プラットフォーム間で共有できるようにする XML スキーマを使用する
  • 回帰、スコアカード、ツリー、マイニングなどのモデルタイプをサポートする
  • スタンドアロンの Red Hat Process Automation Manager プロジェクトに追加したり、Business Central のプロジェクトにインポートしたりできる
  • Red Hat Process Automation Manager のデシジョンサービスに予測データを統合するのに最適である

PMML または XML エディター

『PMML モデルでのデシジョンサービスの作成』

第2章 Red Hat Process Automation Manager の BPMN モデラ―および DMN モデラー

Red Hat Process Automation Manager は、グラフィカルモデラーを使用して Business Process Model and Notation (BPMN) プロセスモデルと、Decision Model and Notation (DMN) デシジョンモデルを設計するのに使用できる次の拡張機能またはアプリケーションを提供します。

  • Business Central: 関連する埋め込みデザイナーで、BPMN モデル、DMN モデル、およびテストシナリオファイルを表示および設計できます。

    Business Central を使用するには、Business Central を含む開発環境を設定してビジネスルールおよびプロセスを作成し、KIE Server を作成して、作成したビジネスルールとプロセスを実行およびテストします。

  • Red Hat Process Automation Manager VSCode 拡張: Visual Studio Code (VSCode) で BPMN モデル、DMN モデル、およびテストシナリオファイルを表示して、作成できるようにします。VSCode 拡張機能には VSCode 1.46.0 以降が必要です。

    Red Hat Process Automation Manager VSCode 拡張機能をインストールするには、VSCode で Extensions メニューオプションを選択して、Red Hat Business Automation Bundle 拡張を検索し、インストールします。

  • スタンドアロン BPMN および DMN エディター: Web アプリケーションに組み込まれた BPMN モデルおよび DMN モデルを表示して、作成できます。必要なファイルをダウンロードするには、NPM レジストリー から NPM アーティファクトを使用するか、https://<YOUR_PAGE>/dmn/index.js (DMN スタンドアロンのエディターライブラリーの場合)、または https://<YOUR_PAGE>/bpmn/index.js (BPMN スタンドアロンエディターライブラリーの場合) で JavaScript ファイルを直接ダウンロードします。

2.1. Red Hat Process Automation Manager VSCode 拡張機能バンドルのインストール

Red Hat Process Automation Manager は、Red Hat Business Automation Bundle VSCode 拡張機能を提供します。これにより、Decision Model and Notation (DMN) デシジョンモデル、Business Process Model and Notation (BPMN) 2.0 ビジネスプロセス、およびテストシナリオを VSCode で直接作成できます。VSCode は、新しいビジネスアプリケーションを開発するために推奨される統合開発環境 (IDE) です。Red Hat Process Automation Manager は、必要に応じて DMN サポートまたは BPMN サポートに VSCode 拡張機能である DMN Editor および BPMN Editor をそれぞれ提供します。

重要

VSCode のエディターは、Business Central のエディターと部分的に互換性があり、VSCode では複数の Business Central 機能がサポートされていません。

前提条件

  • VSCode の最新の安定版がインストールされている。

手順

  1. VSCode IDE で Extensions メニューオプションを選択し、DMN、BPMN、およびテストシナリオファイルのサポートに対して Red Hat Business Automation Bundle を検索します。

    DMN ファイルまたは BPMN ファイルだけをサポートする場合は、DMN Editor または BPMN Editor 拡張機能をそれぞれ検索することもできます。

  2. Red Hat Business Automation Bundle 拡張機能が VSCode に表示されたら、これを選択して Install をクリックします。
  3. VSCode エディターの動作を最適化するには、拡張機能のインストールが完了した後、VSCode のインスタンスを再度読み込み、または閉じてから再起動します。

VSCode 拡張バンドルをインストールした後、VSCode で開くか作成するすべての .dmn ファイル、.bpmn ファイル、または .bpmn2 ファイルがグラフィカルモデルとして自動的に表示されます。さらに、開くまたは作成する .scesim ファイルは、ビジネスデシジョンの機能をテストするテーブルテストシナリオモデルとして自動的に表示されます。

DMN、BPMN、またはテストシナリオモデラーが DMN、BPMN、またはテストシナリオファイルの XML ソースのみを開き、エラーメッセージが表示される場合は、報告されたエラーおよびモデルファイルを確認して、すべての要素が正しく定義されていることを確認します。

注記

新しい DMN モデルまたは BPMN モデルの場合は、Web ブラウザーで dmn.new または bpmn.new を入力して、オンラインモデラーで DMN モデルまたは BPMN モデルを設計することもできます。モデルの作成が終了したら、オンラインモデラーページで Download をクリックして、DMN ファイルまたは BPMN ファイルを VSCode の Red Hat Process Automation Manager プロジェクトにインポートできます。

2.2. Red Hat Process Automation Manager スタンドアロンのエディターの設定

Red Hat Process Automation Manager は、自己完結型のライブラリーに分散されたスタンドアロンのエディターを提供し、エディターごとにオールインワンの JavaScript ファイルを提供します。JavaScript ファイルは、包括的な API を使用してエディターを設定および制御します。

スタンドアロンのエディターは、以下の 3 つの方法でインストールできます。

  • 各 JavaScript ファイルを手動でダウンロード
  • NPM パッケージの使用

手順

  1. 以下の方法のいずれかを使用して、スタンドアロンのエディターをインストールします。

    各 JavaScript ファイルを手動でダウンロード: この方法の場合は、以下の手順に従います。

    1. JavaScript ファイルをダウンロードします。
    2. ダウンロードした Javascript ファイルをホスト型アプリケーションに追加します。
    3. 以下の <script> タグを HTML ページに追加します。

      DMN エディターの HTML ページのスクリプトタグ

      <script src="https://<YOUR_PAGE>/dmn/index.js"></script>

      BPMN エディターの HTML ページのスクリプトタグ

      <script src="https://<YOUR_PAGE>/bpmn/index.js"></script>

    NPM パッケージの使用: この方法の場合は、以下の手順に従います。

    1. NPM パッケージを package.json ファイルに追加します。

      NPM パッケージの追加

      npm install @redhat/kogito-tooling-kie-editors-standalone

    2. 各エディターライブラリーを TypeScript ファイルにインポートします。

      各エディターのインポート

      import * as DmnEditor from "@redhat/kogito-tooling-kie-editors-standalone/dist/dmn"
      import * as BpmnEditor from "@redhat/kogito-tooling-kie-editors-standalone/dist/bpmn"

  2. スタンドアロンのエディターをインストールしたら、以下の例のように提供されたエディター API を使用して必要なエディターを開き、DMN エディターを開きます。API はエディターごとに同じです。

    DMN スタンドアロンのエディターを開く

    const editor = DmnEditor.open({
      container: document.getElementById("dmn-editor-container"),
      initialContent: Promise.resolve(""),
      readOnly: false,
      origin: "",
      resources: new Map([
        [
          "MyIncludedModel.dmn",
          {
            contentType: "text",
            content: Promise.resolve("")
          }
        ]
      ])
    });

    エディター API で以下のパラメーターを使用します。

    表2.1 パラメーターの例

    パラメーター説明

    container

    エディターが追加される HTML 要素。

    initialContent

    DMN モデルのコンテンツへの Pomise。以下の例のように、このパラメーターは空にすることができます。

    • Promise.resolve("")
    • Promise.resolve("<DIAGRAM_CONTENT_DIRECTLY_HERE>")
    • fetch("MyDmnModel.dmn").then(content ⇒ content.text())

    readonly (任意)

    エディターでの変更を許可します。コンテンツの編集を許可する場合は false (デフォルト)、エディターで読み取り専用モードの場合は true に設定します。

    注記

    現在、DMN エディターだけが読み取り専用モードをサポートしています。

    origin (任意)

    リポジトリーの起点。デフォルト値は window.location.origin です。

    resources (任意)

    エディターのリソースのマッピング。たとえば、このパラメーターを使用して、BPMN エディターの DMN エディターまたは作業アイテム定義に含まれるモデルを提供します。マップの各エントリーには、リソース名と、content-type (text または binary) および content (initialContent パラメーターと同様) で構成されるオブジェクトが含まれています。

    返されるオブジェクトには、エディターの操作に必要なメソッドが含まれます。

    表2.2 返されたオブジェクトメソッド

    メソッド説明

    getContent(): Promise<string>

    エディターのコンテンツを含む promise を返します。

    setContent(content: string): void

    エディターの内容を設定します。

    getPreview(): Promise<string>

    現在のダイアグラムの SVG 文字列が含まれる promise を返します。

    subscribeToContentChanges(callback: (isDirty: boolean) ⇒ void): (isDirty: boolean) ⇒ void

    エディターでコンテンツを変更し、サブスクライブ解除に使用されるのと同じコールバックを返す際に呼び出されるコールバックを設定します。

    unsubscribeToContentChanges(callback: (isDirty: boolean) ⇒ void): void

    エディターでコンテンツが変更される際に渡されたコールバックのサブスクライブを解除します。

    markAsSaved(): void

    エディターの内容が保存されることを示すエディターの状態をリセットします。また、コンテンツの変更に関連するサブスクライブされたコールバックをアクティベートします。

    undo(): void

    エディターの最後の変更を元に戻します。また、コンテンツの変更に関連するサブスクライブされたコールバックをアクティベートします。

    redo(): void

    エディターで、最後に元に戻した変更をやり直します。また、コンテンツの変更に関連するサブスクライブされたコールバックをアクティベートします。

    close(): void

    エディターを終了します。

    getElementPosition(selector: string): Promise<Rect>

    要素をキャンバスまたはビデオコンポーネント内に置いた場合に、標準のクエリーセレクターを拡張する方法を提供します。selector パラメーターは、Canvas:::MySquareVideo:::PresenterHand などの <PROVIDER>:::<SELECT> 形式に従う必要があります。このメソッドは、要素の位置を表す Rect を返します。

    envelopeApi: MessageBusClientApi<KogitoEditorEnvelopeApi>

    これは高度なエディター API です。高度なエディター API の詳細は、MessageBusClientApi および KogitoEditorEnvelopeApi を参照してください。

第3章 Maven を使用した DMN モデルおよび BPMN モデルの作成および実行

Maven アーキタイプを使用して、Business Central ではなく Red Hat Process Automation Manager VSCode 拡張機能を使用して、VSCode で DMN モデルおよび BPMN モデルを開発できます。その後、必要に応じて、Business Central で、アーキタイプを Red Hat Process Automation Manager のデシジョンサービスおよびプロセスサービスに統合できます。DMN モデルおよび BPMN モデルを開発する方法は、Red Hat Process Automation Manager VSCode 拡張機能を使用して新規ビジネスアプリケーションを構築する場合に便利です。

手順

  1. コマンドターミナルで、新しい Red Hat Process Automation Manager プロジェクトを保存するローカルディレクトリーに移動します。
  2. 以下のコマンドを入力して、以下の Maven アーキタイプを使用して、定義したディレクトリーにプロジェクトを生成します。

    Maven アーキタイプを使用したプロジェクトの生成

    mvn archetype:generate \
        -DarchetypeGroupId=org.kie \
        -DarchetypeArtifactId=kie-kjar-archetype \
        -DarchetypeVersion=7.48.0.Final-redhat-00004

    このコマンドにより、必要な依存関係で Maven プロジェクトが生成され、ビジネスアプリケーションを構築するのに必要なディレクトリーとファイルが生成されます。プロジェクト開発時に Git バージョン制御システム (推奨) を設定して使用できます。

    同じディレクトリーに複数のプロジェクトを生成する場合は、直前のコマンドに -DgroupId=<groupid> -DartifactId=<artifactId> を追加して、生成されたビジネスアプリケーションの artifactId および groupId を指定できます。

  3. VSCode IDE で File をクリックし、Open Folder を選択し、直前のコマンドを使用して生成されたディレクトリーに移動します。
  4. 最初のアセットを作成する前に、ビジネスアプリケーションのパッケージ (例: org.kie.businessapp) を設定し、以下のパスにそれぞれのディレクトリーを作成します。

    • PROJECT_HOME/src/main/java
    • PROJECT_HOME/src/main/resources
    • PROJECT_HOME/src/test/resources

    たとえば、org.kie.businessapp パッケージの PROJECT_HOME/src/main/java/org/kie/businessapp を作成できます。

  5. VSCode を使用して、ビジネスアプリケーションにアセットを作成します。以下の方法で、Red Hat Process Automation Manager VSCode 拡張機能がサポートするアセットを作成できます。

    • ビジネスプロセスを作成するには、PROJECT_HOME/src/main/java/org/kie/businessapp ディレクトリーに、.bpmn または .bpmn2 の新規ファイルを作成します (例: Process.bpmn)。
    • DMN モデルを作成するには、PROJECT_HOME/src/main/java/org/kie/businessapp ディレクトリーに、.dmn の新規ファイルを作成します (例: AgeDecision.dmn)。
    • テストシナリオシミュレーションモデルを作成するには、PROJECT_HOME/src/main/java/org/kie/businessapp ディレクトリーに、.scesim の新規ファイルを作成します (例: TestAgeScenario.scesim)。
  6. Maven アーキタイプでアセットを作成したら、コマンドラインで (pom.xml がある) プロジェクトのルートディレクトリーに移動し、以下のコマンドを実行してプロジェクトのナレッジ JAR (KJAR) を構築します。

    mvn clean install

    ビルドに失敗したら、コマンドラインのエラーメッセージに記載されている問題に対応し、ビルドに成功するまでプロジェクトの妥当性確認を行います。ただし、ビルドに成功すると、PROJECT_HOME/target ディレクトリーでビジネスアプリケーションのアーティファクトを確認できます。

    注記

    mvn clean install コマンドを使用して、開発中の主要な変更ごとにプロジェクトを検証します。

REST API を使用して実行中の KIE Server に、ビジネスアプリケーションの生成されたナレッジ JAR (KJAR) をデプロイできます。プロセスの REST API の使用方法は、「KIE API を使用した Red Hat Process Automation Manager との対話」を参照してください。

第4章 DMN (Decision Model and Notation)

DMN (Decision Model and Notation) は、業務的意思決定を説明してモデル化するために、OMG (Object Management Group) が確立している規格です。DMN は XML スキーマを定義して、DMN モデルを DMN 準拠のプラットフォーム間や組織間で共有し、ビジネスアナリストやビジネスルール開発者が DMN デシジョンサービスの設計と実装で協力できるようにするものです。DMN 規格は、ビジネスプロセスを開発してモデル化する BPMN (Business Process Model and Notation) 規格と類似しており、一緒に使用できます。

DMN の背景およびアプリケーションの詳細は、OMG の「Decision Model and Notation specification」を参照してください。

4.1. DMN 適合レベル

DMN 仕様は、ソフトウェア実装における増分の適合レベルを 3 つ定義します。特定のレベルの準拠を主張する製品は、その前の適合レベルにも準拠する必要があります。たとえば、適合レベル 3 を実装するには、適合レベル 1 および 2 でサポートされるコンポーネントにも対応する必要があります。各適合レベルの公式な定義は OMG の 「Decision Model and Notation specification」を参照してください。

以下の一覧では、3 つの DMN 適合レベルをまとめています。

適合レベル 1
DMN 適合レベル 1 の実装は、意思決定要件ダイアグラム (DRD)、デシジョンロジック、デシジョンテーブルをサポートしますが、デシジョンモデルは実行可能ではありません。式の定義には、自然言語、非体系化言語を含むすべての言語を使用できます。
適合レベル 2
DMN 適合レベル 2 の実装には、適合レベル 1 の要件のほかに、S-FEEL (Simplified Friendly Enough Expression Language) 式と、完全に実行可能なデシジョンモデルをサポートします。
適合レベル 3
DMN 適合レベル 3 の実装には、適合レベル 1 および 2 の要件のほかに、FEEL (Friendly Enough Expression Language) 式、ボックス式の完全セット、完全に実行可能なデシジョンモデルをサポートします。

Red Hat Process Automation Manager は、適合レベル 3 で DMN 1.2 モデルの設計およびランタイムをサポートし、適合レベル 3 で DMN 1.1 および 1.3 モデルはランタイムのみサポートします。DMN モデルは、Business Central で直接作成するか、VSCode の Red Hat Process Automation Manager DMN モデラーを使用して作成するか、既存の DMN モデルを Red Hat Process Automation Manager プロジェクトにインポートしてデプロイおよび実行することができます。Business Central にインポートした DMN 1.1 および 1.3 モデル (DMN 1.3 機能は含まれません) は、DMN デザイナーで開き、保存時に DMN 1.2 モデルに変換されます。

4.2. DMN 意思決定要件ダイアグラム (DRD) のコンポーネント

デシジョン要件ダイアグラム (DRD) は、DMN モデルを視覚的にしたものです。DMN モデルでは、DRD は意思決定要件グラフ (DRG) 全体の一部またはすべてを表します。DRD は、デシジョンノード、ビジネスナレッジモデル、ビジネスナレッジのソース、入力データ、およびデシジョンサービスを使用して、ビジネスデシジョンを追跡します。

以下の表では、DRD のコンポーネントについてまとめています。

表4.1 DRD コンポーネント

コンポーネント説明表記

要素

デシジョン

1 つ以上の要素が定義したデシジョンロジックをもとに出力を決定するノード。

dmn decision node

ビジネスナレッジモデル

1 つまたは複数のデシジョン要素が含まれる再利用可能な関数。同じロジックですが、サブの入力または決定が異なるため、ビジネスナレッジモデルを使用してどの手順に従うかを決定します。

dmn bkm node

ナレッジソース

デシジョンまたはビジネスナレッジモデルを規定する外部の機関、ドキュメント、委員会またはポリシー。ナレッジソースは、実行可能なビジネスルールではなく、実際の要因への参照となります。

dmn knowledge source node

入力データ

デシジョンノードまたはビジネスナレッジモデルで使用する情報。入力データには通常、融資戦略で使用するローン申請データなど、ビジネスに関連するビジネスレベルのコンセプトまたはオブジェクトが含まれます。

dmn input data node

デシジョンサービス

呼び出しのサービスとして公開される、再利用可能なデシジョンセットを含むトップレベルのデシジョン。デシジョンサービスは、外部アプリケーションまたは BPMN ビジネスプロセスから呼び出し可能です。

dmn decision service node

要件コネクター

情報要件

情報を必要とする別のデシジョンノードへの入力データノードまたはデシジョンノードからの接続

dmn info connector

ナレッジ要件

デシジョンロジックを呼び出す別のビジネスナレッジモデルまたはデシジョンノードへのビジネスナレッジモデルからの接続

dmn knowledge connector

認証局の要件

入力データノードまたはデシジョンノードから従属するナレッジソース、またはナレッジソースからデシジョンノード、ビジネスナレッジモデル、または別のナレッジソースへの接続

dmn authority connector

アーティファクト

テキストのアノテーション

入力データノード、デシジョンノード、ビジネスナレッジモデル、またはナレッジソースに関連する注釈

dmn annotation node

関連付け

入力データノード、デシジョンノード、ビジネスナレッジモデル、またはナレッジソースからテキストアノテーションへの接続

dmn association connector

以下の表では、DRD 要素間で使用可能なコネクターについてまとめています。

表4.2 DRD コネクタールール

接続元接続先接続の種類

デシジョン

デシジョン

情報要件

dmn decision to decision

ビジネスナレッジモデル

デシジョン

ナレッジ要件

dmn bkm to decision

ビジネスナレッジモデル

dmn bkm to bkm

デシジョンサービス

デシジョン

ナレッジ要件

dmn decision service to decision

ビジネスナレッジモデル

dmn decision service to bkm

入力データ

デシジョン

情報要件

dmn input to decision

ナレッジソース

認証局の要件

dmn input to knowledge source

ナレッジソース

デシジョン

認証局の要件

dmn knowledge source to decision

ビジネスナレッジモデル

dmn knowledge source to bkm

ナレッジソース

dmn knowledge source to knowledge source

デシジョン

テキストのアノテーション

関連付け

dmn decision to annotation

ビジネスナレッジモデル

dmn bkm to annotation

ナレッジソース

dmn knowledge source to annotation

入力データ

dmn input to annotation

以下の DRD は、これらの DMN コンポーネントの実際の使用例です。

図4.1 DRD 例: ローンの事前審査

dmn example drd

以下の DRD は、再利用可能なデシジョンサービスの一部となる DMN コンポーネントについて例示しています。

図4.2 DRD 例: デシジョンサービスとしての電話の対応

dmn example drd3

DMN デシジョンサービスノードでは、一番下のセグメントデシジョンノードはデシジョンサービス外からの入力データを組み込んで、デシジョンサービスノードにある一番上のセグメントの最終地点に行き着きます。デシジョンサービスから返される上位のデシジョンは、後続のデシジョンまたは DMN モデルのビジネスナレッジ要件に実装されます。他の DMN モデル内の DMN デシジョンサービスを再利用し、異なる入力データや外向け接続で、同じデシジョンロジックを適用します。

4.3. FEEL を使用したルール表現

FEEL (Friendly Enough Expression Language) は、オブジェクトマネージメントグループ (OMG: Object Management Group) の DMN 仕様が定義する式言語です。FEEL 式は DMN モデルを使用して、意思決定のロジックを定義します。FEEL は、デシジョンモデル構成概念にセマンティクスを割り当てて、意思決定のモデル化および実行を容易にすることを目的としています。意思決定要件ダイアグラム (DRD) の FEEL 式は、デシジョンノードおよびビジネスナレッジモデルのボックス式のテーブルセルで使用されます。

DMN における FEEL の詳細は、OMG の「Decision Model and Notation specification」を参照してください。

4.3.1. FEEL のデータ型

FEEL (Friendly Enough Expression Language) では、以下のデータ型がサポートされます。

  • 数値
  • 文字列
  • ブール値
  • 日付
  • 時間
  • 日時
  • 日時で指定する期間
  • 年および月で指定する期間
  • 関数
  • コンテキスト
  • 範囲 (または間隔)
  • リスト
注記

DMN 仕様で変数を functioncontextrange、または list として宣言する明示的な方法はありませんが、Red Hat Process Automation Manager では、これらの種類の変数をサポートするように DMN 組み込み型が拡張されています。

次の一覧では、各データ型を説明します。

数値

数値は、FEEL では IEEE 754-2008 の「10 進法の 128 形式 (34 桁)」に基づいています。内部的には、数値は Java の MathContext DECIMAL128 を持つ BigDecimals として表されます。FEEL でサポートされる数値データ型は 1 つしかないため、整数と浮動小数点には同じ型が使用されます。

FEEL では、小数点の記号にドット (.) が使用されます。-INF+INF、または NaN はサポートされません。FEEL では、null を使用して、無効な数字を表します。

Red Hat Process Automation Manager では、DMN 仕様が拡張され、以下の数値表記法もサポートされます。

  • 科学的記数法: サフィックス e<exp> または E<exp> を付けて、科学的記数法を使用できます。たとえば、1.2e31.2*10**3 と表記するのと同じですが、式ではなくリテラルを使用しています。
  • 16 進数: プリフィックス 0x を付けて、16 進数を使用できます。たとえば、0xff は、10 進数の 255 と同じです。大文字および小文字いずれもサポートされます。たとえば、0XFF0xff と同じです。
  • 型のサフィックス: 型のサフィックスとして fFdDlL を使用できます。このサフィックスは無視されます。
文字列

FEEL では、二重引用符で区切った文字が文字列として解釈されます。

"John Doe"

ブール値
FEEL は、3 値ブール論理を使用するため、ブール論理式には truefalse、または null を使用できます。
日付

FEEL では日付リテラルがサポートされていませんが、組み込みの date() 関数を使用して日付の値を構築できます。時間文字列は、FEEL では「XML Schema Part 2: Datatypes」ドキュメントに定義されている形式に準拠します。形式は、"YYYY-MM-DD" で、YYYY は 4 桁の年数、MM は 2 桁の月数、DD は日数に置き換えます。

例:

date( "2017-06-23" )

日付オブジェクトには、真夜中を表す "00:00:00" と同一の時間があります。日付には、タイムゾーンがなく、ローカルであると見なされます。

時間

FEEL では時間リテラルがサポートされていませんが、組み込みの time() 関数を使用して時間の値を構築できます。時間文字列は、FEEL では「XML Schema Part 2: Datatypes」ドキュメントで定義されている形式に準拠します。形式は "hh:mm:ss[.uuu][(+-)hh:mm]" です。ここで、hh は時間 (00 から 23)、mm は分、ss は秒です。任意で、ミリ秒 (uuu) を定義でき、UTC 時間の正 (+) または負 (-) のオフセットを追加してタイムゾーンを定義できます。オフセットを使用する代わりに、z 文字を使用して UTC 時間を表すことができますが、これは -00:00 のオフセットと同じです。オフセットが定義されていない場合には、時間はローカルとみなされます。

例:

time( "04:25:12" )
time( "14:10:00+02:00" )
time( "22:35:40.345-05:00" )
time( "15:00:30z" )

オフセットまたはタイムゾーンを定義する時間値は、オフセットまたはタイムゾーンを定義しないローカル時間と比較できません。

日時

FEEL では日時リテラルがサポートされていませんが、組み込みの date and time() 関数を使用して値を構築できます。日時文字列は、FEEL では「XML Schema Part 2: Datatypes」ドキュメントに定義された形式に準拠します。形式は "<date>T<time>" です。<date> および <time> は規定の XML スキーマ形式に準拠し、T で結合されます。

例:

date and time( "2017-10-22T23:59:00" )
date and time( "2017-06-13T14:10:00+02:00" )
date and time( "2017-02-05T22:35:40.345-05:00" )
date and time( "2017-06-13T15:00:30z" )

オフセットまたはタイムゾーンを定義する日時の値と、オフセットまたはタイムゾーンを定義しないローカルの日時の値を比較することはできません。

重要

DMN 仕様の実装が、XML スキーマでスペースをサポートしない場合は、キーワード dateTimedate and time の同義語として使用してください。

日時で指定する期間

FEEL では日と時間で指定する期間を表すリテラルがサポートされていませんが、組み込みの duration() 関数を使用して値を構築できます。FEEL では、「XML Schema Part 2: Datatypes」ドキュメントに定義されている形式に準拠しますが、日、時間、分、および秒にしか適用されません。月および年はサポートされません。

例:

duration( "P1DT23H12M30S" )
duration( "P23D" )
duration( "PT12H" )
duration( "PT35M" )
重要

DMN 仕様の実装が、XML スキーマでスペースをサポートしない場合は、キーワード dayTimeDurationdays and time duration の同義語として使用してください。

年および月で指定する期間

FEEL では年と月で指定する期間リテラルがサポートされていませんが、組み込みの duration() 関数を使用して値を構築できます。FEEL では XML Schema Part 2: Datatypes ドキュメントに定義されている形式に準拠しますが、年と月にしか適用されません。日、時間、分、または秒はサポートされません。

例:

duration( "P3Y5M" )
duration( "P2Y" )
duration( "P10M" )
duration( "P25M" )
重要

DMN 仕様の実装が、XML スキーマでスペースをサポートしない場合は、キーワード yearMonthDurationyears and months duration の同義語として使用してください。

関数

FEEL には、関数を作成するのに使用する function リテラル (または無名関数) があります。DMN 仕様で変数を function として宣言する明示的な方法が提供されていませんが、Red Hat Process Automation Manager では、関数の変数をサポートするように DMN 型が拡張されています。

例:

function(a, b) a + b

この例では、FEEL 式は、パラメーター a および b を追加して結果を返す関数を作成します。

コンテキスト

FEEL には、コンテキストを作成するのに使用する context リテラルがあります。context は、FEEL ではキーと値のペアのリストとなり、Java などの言語におけるマッピングに似ています。DMN 仕様で変数を context として宣言する明示的な方法が提供されていませんが、Red Hat Process Automation Manager では、コンテキストの変数をサポートするようにビルドイン DMN 型が拡張されています。

例:

{ x : 5, y : 3 }

この式では、チャート内の等位を示す 2 つのエントリー (x および y) を持つコンテキストが作成されます。

DMN 1.2 では、コンテキスト作成に、キーの一覧を属性として含めてアイテム定義を作成し、そのアイテム定義型を含めて変数を宣言する方法も使用できます。

Red Hat Process Automation Manager の DMN API では、DMNContext の DMN ItemDefinition 構造様式として、次の 2 つがサポートされます。

  • ユーザー定義の Java タイプ: DMN の ItemDefinition で各コンポーネントのプロパティーとゲッターを定義する有効な JavaBeans オブジェクト。必要に応じて、無効な Java 識別子になるコンポーネント名を示すゲッターに対して @FEELProperty アノテーションを使用することもできます。
  • java.util.Map インターフェース: DMN の ItemDefinition でコンポーネント名に対応するキーで、適切なエンティティーを定義する必要があります。
範囲 (または間隔)

FEEL には、範囲または間隔を作成するのに使用する range リテラルがあります。FEEL の range は、下方境界および上方境界を定義する値で、開区間または閉区間のいずれかにできます。DMN 仕様には、変数を range と宣言する明示的な方法はありませんが、Red Hat Process Automation Manager では、範囲をサポートするようにビルドイン DMN 型が拡張されています。

範囲の構文は以下の形式で定義されます。

range          := interval_start endpoint '..' endpoint interval_end
interval_start := open_start | closed_start
open_start     := '(' | ']'
closed_start   := '['
interval_end   := open_end | closed_end
open_end       := ')' | '['
closed_end     := ']'
endpoint       := expression

エンドポイントの式は比較可能な値を返す必要があり、下方エンドポイントは上方エンドポイントよりも低くなる必要があります。

たとえば、以下のリテラル式は、1 から 10 まで (いずれも閉区間) の間隔を定義します。

[ 1 .. 10 ]

以下のリテラル式は 1 時間から 12 時間までの間隔を定義します。下方境界は含まれます (閉区間) が、上方境界は含まれません (開区間)。

[ duration("PT1H") .. duration("PT12H") )

デシジョンテーブルの範囲を使用して値の範囲をテストしたり、単純なリテラル式で範囲を使用したりできます。たとえば、以下のリテラル式は、変数 x0 から 100 の間にある場合は true を返します。

x in [ 1 .. 100 ]
リスト

FEEL には、アイテムの一覧を作成するのに使用する list リテラルがあります。FEEL の list は、値のコンマ区切りの一覧を角カッコで囲んで表現できます。DMN 仕様には (別の式で使用する以外に) 変数を list と宣言する明示的な方法はありませんが、Red Hat Process Automation Manager では、リスト型の変数をサポートするようにビルドイン DMN 型が拡張されています。

例:

[ 2, 3, 4, 5 ]

FEEL のリストはすべて同じ型の要素を含み、変更できません。リストの要素はインデックスでアクセスでき、最初の要素が 1 になります。負のインデックスは、リストの末尾から数えた要素を表します。たとえば、-1 は最後の要素にアクセスできることを示します。

たとえば、以下の式は、リスト x の 2 番目の要素を返します。

x[2]

以下の式は、リスト x の、最後から 2 番目の要素を返します。

x[-2]

一覧の要素は、count の関数でカウントすることもでき、この関数は、要素の一覧をパラメーターとして使用します。

たとえば、以下の式では 4 を返します。

count([ 2, 3, 4, 5 ])

4.3.2. FEEL の組み込み関数

他のプラットフォームやシステムとの相互運用性を促進するために、FEEL (Friendly Enough Expression Language) には組み込み関数のライブラリーが含まれています。組み込みの FEEL 機能は、DMN デシジョンサービスで関数を使用できるように、Drools の Decision Model and Notation (DMN) エンジンで実装されています。

以下のセクションでは、NAME( PARAMETERS ) の形式で記載されている、FEEL の組み込み関数ごとに説明します。DMN における FEEL の詳細は、OMG の「Decision Model and Notation specification」 を参照してください。

4.3.2.1. 変換関数

以下の関数は、異なるタイプの値同士での変換をサポートします。以下の例のように、これらの関数の一部は、特定の文字列形式を使用します。

  • date string: 2020-06-01 など、「XML Schema Part 2: Datatypes」ドキュメントで定義されている形式に準拠します。
  • time string: 以下のいずれかの形式に従います。

    • 23:59:00z など、「XML Schema Part 2: Datatypes」ドキュメントに定義されている形式
    • 00:01:00@Etc/UTC など、ISO 8601 で定義したローカルの時間の後に @ および IANA タイムゾーンを続けた形式
  • date time string: 2012-12-25T11:00:00Z のように、date string の後に Ttime string 列が続く形式に従います。
  • duration string: P1Y2M などの 「XQuery 1.0 and XPath 2.0 Data Model」に定義されている days and time duration および years and months duration の形式に従います
date( from ) - date の使用

fromdate 値に変換します。

表4.3 パラメーター

パラメータータイプ形式

from

string

date string

date( "2012-12-25" ) - date( "2012-12-24" ) = duration( "P1D" )

date( from ) - date and time の使用

値を from から date に変換し、時間のコンポーネントを null に設定します。

表4.4 パラメーター

パラメータータイプ

from

date and time

date(date and time( "2012-12-25T11:00:00Z" )) = date( "2012-12-25" )

date( year, month, day )

指定の year、month、および day の値から date を生成します。

表4.5 パラメーター

パラメータータイプ

year

number

month

number

day

number

date( 2012, 12, 25 ) = date( "2012-12-25" )

date and time( date, time )

指定した日付から date and time を生成して、時間のコンポーネントと指定の時間を無視します。

表4.6 パラメーター

パラメータータイプ

date

date または date and time

time

time

date and time ( "2012-12-24T23:59:00" ) = date and time(date( "2012-12-24" ), time( "23:59:00" ))

date and time( from )

指定の文字列から date and time を生成します。

表4.7 パラメーター

パラメータータイプ形式

from

string

date time string

date and time( "2012-12-24T23:59:00" ) + duration( "PT1M" ) = date and time( "2012-12-25T00:00:00" )

time( from )

指定の文字列から time を生成します。

表4.8 パラメーター

パラメータータイプ形式

from

string

time string

time( "23:59:00z" ) + duration( "PT2M" ) = time( "00:01:00@Etc/UTC" )

time( from )

指定のパラメーターから time を生成し、日付コンポーネントを無視します。

表4.9 パラメーター

パラメータータイプ

from

time または date and time

time(date and time( "2012-12-25T11:00:00Z" )) = time( "11:00:00Z" )

time( hour, minute, second, offset? )

指定した hour、minute、および second のコンポーネント値から time を生成します。

表4.10 パラメーター

パラメータータイプ

hour

number

minute

number

second

number

offset (任意)

days and time duration または null

time( "23:59:00z" ) = time(23, 59, 0, duration( "PT0H" ))

number( from, grouping separator, decimal separator )

指定の区切り文字を使用して fromnumber に変換します。

表4.11 パラメーター

パラメータータイプ

from

有効な数字を表す string

grouping separator

スペース ( )、コンマ (,)、ピリオド (.)、または null

decimal separator

grouping separator と同じタイプですが、同じ値は使用できません。

number( "1 000,0", " ", "," ) = number( "1,000.0", ",", "." )

string( from )

指定のパラメーターを文字列表現にします。

表4.12 パラメーター

パラメータータイプ

from

null 値以外の値

string( 1.1 ) = "1.1"
string( null ) = null

duration( from )

fromdays and time duration、または years and months duration に変換します。

表4.13 パラメーター

パラメータータイプ形式

from

string

duration string

date and time( "2012-12-24T23:59:00" ) - date and time( "2012-12-22T03:45:00" ) = duration( "P2DT20H14M" )
duration( "P2Y2M" ) = duration( "P26M" )

years and months duration( from, to )

指定した 2 つのパラメーター間の years and months duration を計算します。

表4.14 パラメーター

パラメータータイプ

from

date または date and time

to

date または date and time

years and months duration( date( "2011-12-22" ), date( "2013-08-24" ) ) = duration( "P1Y8M" )

4.3.2.2. ブール値関数

以下の関数は、ブール値の操作をサポートします。

not( negand )

negand オペランドの論理否定を実行します。

表4.15 パラメーター

パラメータータイプ

negand

boolean

not( true ) = false
not( null ) = null

4.3.2.3. 文字列関数

以下の関数は、文字列の操作をサポートします。

注記

FEEL では、Unicode 文字はコードポイントを基にカウントされます。

substring( string, start position, length? )

指定の長さの開始地点からサブ文字列を返します。最初の文字の位置値は 1 です。

表4.16 パラメーター

パラメータータイプ

string

string

start position

number

length (任意)

number

substring( "testing",3 ) = "sting"
substring( "testing",3,3 ) = "sti"
substring( "testing", -2, 1 ) = "n"
substring( "\U01F40Eab", 2 ) = "ab"

注記

FEEL では、文字リテラルの "\U01F40Eab"🐎ab 文字列 (馬の記号の後に ab) となります。

string length( string )

指定の文字列の長さを計算します。

表4.17 パラメーター

パラメータータイプ

string

string

string length( "tes" ) = 3
string length( "\U01F40Eab" ) = 3

upper case( string )

指定の文字列の大文字バージョンを生成します。

表4.18 パラメーター

パラメータータイプ

string

string

upper case( "aBc4" ) = "ABC4"

lower case( string )

指定の文字列の小文字バージョンを生成します。

表4.19 パラメーター

パラメータータイプ

string

string

lower case( "aBc4" ) = "abc4"

substring before( string, match )

一致した値の前にあるサブ文字列を計算します。

表4.20 パラメーター

パラメータータイプ

string

string

match

string

substring before( "testing", "ing" ) = "test"
substring before( "testing", "xyz" ) = ""

substring after( string, match )

一致した値の後にあるサブ文字列を計算します。

表4.21 パラメーター

パラメータータイプ

string

string

match

string

substring after( "testing", "test" ) = "ing"
substring after( "", "a" ) = ""

replace( input, pattern, replacement, flags? )

正規表現の置換を計算します。

表4.22 パラメーター

パラメータータイプ

input

string

pattern

string

replacement

string

flags (任意)

string

注記

この関数は、「XQuery 1.0 and XPath 2.0 Functions and Operators」で定義されている正規表現パラメーターを使用します。

replace( "abcd", "(ab)|(a)", "[1=$1][2=$2]" ) = "[1=ab][2=]cd"

contains( string, match )

文字列に一致部分が含まれる場合に true を返します。

表4.23 パラメーター

パラメータータイプ

string

string

match

string

contains( "testing", "to" ) = false

starts with( string, match )

指定の値と一致する文字列で開始する場合に、true を返します。

表4.24 パラメーター

パラメータータイプ

string

string

match

string

starts with( "testing", "te" ) = true

ends with( string, match )

指定の値と一致する文字列で終了する場合に、true を返します。

表4.25 パラメーター

パラメータータイプ

string

string

match

string

ends with( "testing", "g" ) = true

matches( input, pattern, flags? )

入力が正規表現と一致する場合に true を返します。

表4.26 パラメーター

パラメータータイプ

input

string

pattern

string

flags (任意)

string

注記

この関数は、「XQuery 1.0 and XPath 2.0 Functions and Operators」で定義されている正規表現パラメーターを使用します。

matches( "teeesting", "^te*sting" ) = true

split( string, delimiter )

元の文字列のリストを返し、区切り文字の正規表現パターンで分割します。

表4.27 パラメーター

パラメータータイプ

string

string

delimiter

正規表現パターンの string

注記

この関数は、「XQuery 1.0 and XPath 2.0 Functions and Operators」で定義されている正規表現パラメーターを使用します。

split( "John Doe", "\\s" ) = ["John", "Doe"]
split( "a;b;c;;", ";" ) = ["a","b","c","",""]

4.3.2.4. リスト関数

以下の関数は、リストの操作をサポートします。

注記

FEEL では、リストに含まれる最初の要素のインデックスは 1 となります。リストに含まれる最後の要素のインデックスは -1 として特定できます。

list contains( list, element )

リストに対象の要素が含まれる場合には true を返します。

表4.28 パラメーター

パラメータータイプ

list

list

element

null を含むすべてのタイプ

list contains( [1,2,3], 2 ) = true

count( list )

リスト内の要素をカウントします。

表4.29 パラメーター

パラメータータイプ

list

list

count( [1,2,3] ) = 3
count( [] ) = 0
count( [1,[2,3]] ) = 2

min( list )

一覧の値と同じ最小の要素を返します。

表4.30 パラメーター

パラメータータイプ

list

list

別の署名

min( e1, e2, ..., eN )

min( [1,2,3] ) = 1
min( 1 ) = 1
min( [1] ) = 1

max( list )

一覧の値と同じ最大の要素を返します。

表4.31 パラメーター

パラメータータイプ

list

list

別の署名

max( e1, e2, ..., eN )

max( 1,2,3 ) = 3
max( [] ) = null

sum( list )

リスト内の数字の合計を返します。

表4.32 パラメーター

パラメータータイプ

list

number 要素の list

別の署名

sum( n1, n2, ..., nN )

sum( [1,2,3] ) = 6
sum( 1,2,3 ) = 6
sum( 1 ) = 1
sum( [] ) = null

mean( list )

リスト内の要素の平均 (計算平均) を計算します。

表4.33 パラメーター

パラメータータイプ

list

number 要素の list

別の署名

mean( n1, n2, ..., nN )

mean( [1,2,3] ) = 2
mean( 1,2,3 ) = 2
mean( 1 ) = 1
mean( [] ) = null

all( list )

リスト内の全要素が true の場合は true を返します。

表4.34 パラメーター

パラメータータイプ

list

boolean 要素の list

別の署名

all( b1, b2, ..., bN )

all( [false,null,true] ) = false
all( true ) = true
all( [true] ) = true
all( [] ) = true
all( 0 ) = null

any( list )

リスト内の要素が true の場合は true を返します。

表4.35 パラメーター

パラメータータイプ

list

boolean 要素の list

別の署名

any( b1, b2, ..., bN )

any( [false,null,true] ) = true
any( false ) = false
any( [] ) = false
any( 0 ) = null

sublist( list, start position, length? )

開始位置からサブリストを返します。ただし、length 要素に限定されます。

表4.36 パラメーター

パラメータータイプ

list

list

start position

number

length (任意)

number

sublist( [4,5,6], 1, 2 ) = [4,5]

append( list, item )

アイテムに追加されるリストを作成します。

表4.37 パラメーター

パラメータータイプ

list

list

item

任意のタイプ

append( [1], 2, 3 ) = [1,2,3]

concatenate( list )

連結された一覧の結果で一覧を作成します。

表4.38 パラメーター

パラメータータイプ

list

list

concatenate( [1,2],[3] ) = [1,2,3]

insert before( list, position, newItem )

指定の位置に挿入された newItem でリストを作成します。

表4.39 パラメーター

パラメータータイプ

list

list

position

number

newItem

任意のタイプ

insert before( [1,3],1,2 ) = [2,1,3]

remove( list, position )

指定の位置から除外された要素を削除して一覧を作成します。

表4.40 パラメーター

パラメータータイプ

list

list

position

number

remove( [1,2,3], 2 ) = [1,3]

reverse( list )

逆リストを返します。

表4.41 パラメーター

パラメータータイプ

list

list

reverse( [1,2,3] ) = [3,2,1]

index of( list, match )

要素に一致するインデックスを返します。

パラメーター

  • list タイプの list
  • 任意のタイプの match

表4.42 パラメーター

パラメータータイプ

list

list

match

任意のタイプ

index of( [1,2,3,2],2 ) = [2,4]

union( list )

複数のリストから全要素の一覧を返し、重複を除外します。

表4.43 パラメーター

パラメータータイプ

list

list

union( [1,2],[2,3] ) = [1,2,3]

distinct values( list )

単一リストから要素の一覧を返し、重複を除外します。

表4.44 パラメーター

パラメータータイプ

list

list

distinct values( [1,2,3,2,1] ) = [1,2,3]

flatten( list )

フラット化されたリストを返します。

表4.45 パラメーター

パラメータータイプ

list

list

flatten( [[1,2],[[3]], 4] ) = [1,2,3,4]

product( list )

リスト内の数字の積を返します。

表4.46 パラメーター

パラメータータイプ

list

number 要素の list

別の署名

product( n1, n2, ..., nN )

product( [2, 3, 4] ) = 24
product( 2, 3, 4 ) = 24

median( list )

リストの数字の中央値を返します。要素の数が奇数の場合、結果は中央の要素になります。要素の数が偶数の場合、結果は中央にある 2 つの要素の平均になります。

表4.47 パラメーター

パラメータータイプ

list

number 要素の list

別の署名

median( n1, n2, ..., nN )

median( 8, 2, 5, 3, 4 ) = 4
median( [6, 1, 2, 3] ) = 2.5
median( [ ] ) = null

stddev( list )

リストの数値の標準偏差を返します。

表4.48 パラメーター

パラメータータイプ

list

number 要素の list

別の署名

stddev( n1, n2, ..., nN )

stddev( 2, 4, 7, 5 ) = 2.081665999466132735282297706979931
stddev( [47] ) = null
stddev( 47 ) = null
stddev( [ ] ) = null

mode( list )

リスト内の数字の最頻値を返します。複数の要素が返される場合、番号は昇順でソートされます。

表4.49 パラメーター

パラメータータイプ

list

number 要素の list

別の署名

mode( n1, n2, ..., nN )

mode( 6, 3, 9, 6, 6 ) = [6]
mode( [6, 1, 9, 6, 1] ) = [1, 6]
mode( [ ] ) = [ ]

4.3.2.5. 数値関数

以下の関数は、数値演算をサポートしています。

decimal( n, scale )

指定されたスケールの数値を返します。

表4.50 パラメーター

パラメータータイプ

n

number

scale

範囲の [−6111..6176]number

decimal( 1/3, 2 ) = .33
decimal( 1.5, 0 ) = 2
decimal( 2.5, 0 ) = 2

floor( n )

指定された数値以下の最大の整数を返します。

表4.51 パラメーター

パラメータータイプ

n

number

floor( 1.5 ) = 1
floor( -1.5 ) = -2

ceiling( n )

指定された数値以上の最小の整数を返します。

表4.52 パラメーター

パラメータータイプ

n

number

ceiling( 1.5 ) = 2
ceiling( -1.5 ) = -1

abs( n )

絶対値を返します。

表4.53 パラメーター

パラメータータイプ

n

numberdays and time duration、または years and months duration

abs( 10 ) = 10
abs( -10 ) = 10
abs( @"PT5H" ) = @"PT5H"
abs( @"-PT5H" ) = @"PT5H"

modulo( dividend, divisor )

除数による被除数の除算の余りを返します。被除数または除数のいずれかが負の場合、結果は除数と同じ符号になります。

注記

この関数は、modulo(dividend, divisor) = dividend - divisor*floor(dividen d/divisor) としても表されます。

表4.54 パラメーター

パラメータータイプ

dividend

number

divisor

number

modulo( 12, 5 ) = 2
modulo( -12,5 )= 3
modulo( 12,-5 )= -3
modulo( -12,-5 )= -2
modulo( 10.1, 4.5 )= 1.1
modulo( -10.1, 4.5 )= 3.4
modulo( 10.1, -4.5 )= -3.4
modulo( -10.1, -4.5 )= -1.1

sqrt( number )

指定された数値の平方根を返します。

表4.55 パラメーター

パラメータータイプ

n

number

sqrt( 16 ) = 4

log( number )

指定された数値の対数を返します。

表4.56 パラメーター

パラメータータイプ

n

number

decimal( log( 10 ), 2 ) = 2.30

exp( number )

オイラーの数値 e を、指定された数の累乗で返します。

表4.57 パラメーター

パラメータータイプ

n

number

decimal( exp( 5 ), 2 ) = 148.41

odd( number )

指定された数が奇数の場合は true を返します。

表4.58 パラメーター

パラメータータイプ

n

number

odd( 5 ) = true
odd( 2 ) = false

even( number )

指定された数が偶数の場合は true を返します。

表4.59 パラメーター

パラメータータイプ

n

number

even( 5 ) = false
even ( 2 ) = true

4.3.2.6. 日付および時刻の関数

以下の関数は、日付および時刻の演算をサポートしています。

is( value1, value2 )

両方の値が FEEL セマンティックドメインの同じ要素である場合は、true を返します。

表4.60 パラメーター

パラメータータイプ

value1

任意のタイプ

value2

任意のタイプ

is( date( "2012-12-25" ), time( "23:00:50" ) ) = false
is( date( "2012-12-25" ), date( "2012-12-25" ) ) = true
is( time( "23:00:50z" ), time( "23:00:50" ) ) = false

4.3.2.7. リスト関数

次の関数は、単一のスカラー値とそのような値の範囲の間の関係を確立するための時間的順序付け操作をサポートします。これらの関数は、Health Level Seven (HL7) International の「Clinical Quality Language (CQL) 1.4 syntax」のコンポーネントに似ています。

before( )

要素 A が要素 B の前にあり、評価が true になるための関連要件も満たされた場合は true を返します。

署名

  1. before( point1 point2 )
  2. before( point range )
  3. before( range point )
  4. before( range1,range2 )

true に評価するための要件

  1. point1 < point2
  2. point < range.start or ( point = range.start and not(range.start included) )
  3. range.end < point or ( range.end = point and not(range.end included) )
  4. range1.end < range2.start or (( not(range1.end included) or not(range2.start included) ) and range1.end = range2.start )

before( 1, 10 ) = true
before( 10, 1 ) = false
before( 1, [1..10] ) = false
before( 1, (1..10] ) = true
before( 1, [5..10] ) = true
before( [1..10], 10 ) = false
before( [1..10), 10 ) = true
before( [1..10], 15 ) = true
before( [1..10], [15..20] ) = true
before( [1..10], [10..20] ) = false
before( [1..10), [10..20] ) = true
before( [1..10], (10..20] ) = true

after( )

要素 A が要素 B の後にあり、評価が true になるための関連要件も満たされた場合は true を返します。

署名

  1. after( point1 point2 )
  2. after( point range )
  3. after( range, point )
  4. after( range1 range2 )

true に評価するための要件

  1. point1 > point2
  2. point > range.end or ( point = range.end and not(range.end included) )
  3. range.start > point or ( range.start = point and not(range.start included) )
  4. range1.start > range2.end or (( not(range1.start included) or not(range2.end included) ) and range1.start = range2.end )

after( 10, 5 ) = true
after( 5, 10 ) = false
after( 12, [1..10] ) = true
after( 10, [1..10) ) = true
after( 10, [1..10] ) = false
after( [11..20], 12 ) = false
after( [11..20], 10 ) = true
after( (11..20], 11 ) = true
after( [11..20], 11 ) = false
after( [11..20], [1..10] ) = true
after( [1..10], [11..20] ) = false
after( [11..20], [1..11) ) = true
after( (11..20], [1..11] ) = true

meets( )

要素 A が要素 B を満たし、true に評価されるための関連要件も満たされた場合は true を返します。

署名

  1. meets( range1, range2 )

true に評価するための要件

  1. range1.end included and range2.start included and range1.end = range2.start

meets( [1..5], [5..10] ) = true
meets( [1..5), [5..10] ) = false
meets( [1..5], (5..10] ) = false
meets( [1..5], [6..10] ) = false

met by( )

要素 A が要素 B によって満たされ、評価が true になるための関連要件も満たされた場合は true を返します。

署名

  1. met by( range1, range2 )

true に評価するための要件

  1. range1.start included and range2.end included and range1.start = range2.end

met by( [5..10], [1..5] ) = true
met by( [5..10], [1..5) ) = false
met by( (5..10], [1..5] ) = false
met by( [6..10], [1..5] ) = false

overlaps( )

要素 A が要素 B とオーバーラップし、評価が true になるための関連要件も満たされた場合は true を返します。

署名

  1. overlaps( range1, range2 )

true に評価するための要件

  1. ( range1.end > range2.start or (range1.end = range2.start and (range1.end included or range2.end included)) ) and ( range1.start < range2.end or (range1.start = range2.end and range1.start included and range2.end included) )

overlaps( [1..5], [3..8] ) = true
overlaps( [3..8], [1..5] ) = true
overlaps( [1..8], [3..5] ) = true
overlaps( [3..5], [1..8] ) = true
overlaps( [1..5], [6..8] ) = false
overlaps( [6..8], [1..5] ) = false
overlaps( [1..5], [5..8] ) = true
overlaps( [1..5], (5..8] ) = false
overlaps( [1..5), [5..8] ) = false
overlaps( [1..5), (5..8] ) = false
overlaps( [5..8], [1..5] ) = true
overlaps( (5..8], [1..5] ) = false
overlaps( [5..8], [1..5) ) = false
overlaps( (5..8], [1..5) ) = false

overlaps before( )

要素 A が要素 B の前にオーバーラップし、評価が true になるための関連要件も満たされた場合は true を返します。

署名

  1. overlaps before( range1 range2 )

true に評価するための要件

  1. ( range1.start < range2.start or (range1.start = range2.start and range1.start included and range2.start included) ) and ( range1.end > range2.start or (range1.end = range2.start and range1.end included and range2.start included) ) and ( range1.end < range2.end or (range1.end = range2.end and (not(range1.end included) or range2.end included )) )

overlaps before( [1..5], [3..8] ) = true
overlaps before( [1..5], [6..8] ) = false
overlaps before( [1..5], [5..8] ) = true
overlaps before( [1..5], (5..8] ) = false
overlaps before( [1..5), [5..8] ) = false
overlaps before( [1..5), (1..5] ) = true
overlaps before( [1..5], (1..5] ) = true
overlaps before( [1..5), [1..5] ) = false
overlaps before( [1..5], [1..5] ) = false

overlaps after( )

要素 A が要素 B の後にオーバーラップする場合に、評価が true になるための関連要件も満たされた場合は true を返します。

署名

  1. overlaps after( range1 range2 )

true に評価するための要件

  1. ( range2.start < range1.start or (range2.start = range1.start and range2.start included and not( range1.start included)) ) and ( range2.end > range1.start or (range2.end = range1.start and range2.end included and range1.start included) ) and ( range2.end < range1.end or (range2.end = range1.end and (not(range2.end included) or range1.end included)) )

overlaps after( [3..8], [1..5] )= true
overlaps after( [6..8], [1..5] )= false
overlaps after( [5..8], [1..5] )= true
overlaps after( (5..8], [1..5] )= false
overlaps after( [5..8], [1..5) )= false
overlaps after( (1..5], [1..5) )= true
overlaps after( (1..5], [1..5] )= true
overlaps after( [1..5], [1..5) )= false
overlaps after( [1..5], [1..5] )= false
overlaps after( (1..5), [1..5] )= false
overlaps after( (1..5], [1..6] )= false
overlaps after( (1..5], (1..5] )= false
overlaps after( (1..5], [2..5] )= false

finishes( )

要素 A が要素 B を終了し、評価が true になるための関連要件も満たされた場合は true を返します。

署名

  1. finishes( point, range )
  2. finishes( range1, range2 )

true に評価するための要件

  1. range.end included and range.end = point
  2. range1.end included = range2.end included and range1.end = range2.end and ( range1.start > range2.start or (range1.start = range2.start and (not(range1.start included) or range2.start included)) )

finishes( 10, [1..10] ) = true
finishes( 10, [1..10) ) = false
finishes( [5..10], [1..10] ) = true
finishes( [5..10), [1..10] ) = false
finishes( [5..10), [1..10) ) = true
finishes( [1..10], [1..10] ) = true
finishes( (1..10], [1..10] ) = true

finished by( )

要素 A が要素 B によって終了し、評価が true になるための関連要件も満たされた場合は true を返します。

署名

  1. finished by( range, point )
  2. finished by( range1 range2 )

true に評価するための要件

  1. range.end included and range.end = point
  2. range1.end included = range2.end included and range1.end = range2.end and ( range1.start < range2.start or (range1.start = range2.start and (range1.start included or not(range2.start included))) )

finished by( [1..10], 10 ) = true
finished by( [1..10), 10 ) = false
finished by( [1..10], [5..10] ) = true
finished by( [1..10], [5..10) ) = false
finished by( [1..10), [5..10) ) = true
finished by( [1..10], [1..10] ) = true
finished by( [1..10], (1..10] ) = true

includes( )

要素 A が要素 B を含み、評価が true になるための関連要件も満たされた場合は true を返します。

署名

  1. includes( range, point )
  2. includes( range1, range2 )

true に評価するための要件

  1. (range.start < point and range.end > point) or (range.start = point and range.start included) or (range.end = point and range.end included)
  2. ( range1.start < range2.start or (range1.start = range2.start and (range1.start included or not(range2.start included))) ) and ( range1.end > range2.end or (range1.end = range2.end and (range1.end included or not(range2.end included))) )

includes( [1..10], 5 ) = true
includes( [1..10], 12 ) = false
includes( [1..10], 1 ) = true
includes( [1..10], 10 ) = true
includes( (1..10], 1 ) = false
includes( [1..10), 10 ) = false
includes( [1..10], [4..6] ) = true
includes( [1..10], [1..5] ) = true
includes( (1..10], (1..5] ) = true
includes( [1..10], (1..10) ) = true
includes( [1..10), [5..10) ) = true
includes( [1..10], [1..10) ) = true
includes( [1..10], (1..10] ) = true
includes( [1..10], [1..10] ) = true

during( )

要素 A が要素 B の間にあり、 true に評価するための関連要件も満たされた場合は true を返します。

署名

  1. during( point, range )
  2. during( range1 range2 )

true に評価するための要件

  1. (range.start < point and range.end > point) or (range.start = point and range.start included) or (range.end = point and range.end included)
  2. ( range2.start < range1.start or (range2.start = range1.start and (range2.start included or not(range1.start included))) ) and ( range2.end > range1.end or (range2.end = range1.end and (range2.end included or not(range1.end included))) )

during( 5, [1..10] ) = true
during( 12, [1..10] ) = false
during( 1, [1..10] ) = true
during( 10, [1..10] ) = true
during( 1, (1..10] ) = false
during( 10, [1..10) ) = false
during( [4..6], [1..10] ) = true
during( [1..5], [1..10] ) = true
during( (1..5], (1..10] ) = true
during( (1..10), [1..10] ) = true
during( [5..10), [1..10) ) = true
during( [1..10), [1..10] ) = true
during( (1..10], [1..10] ) = true
during( [1..10], [1..10] ) = true

starts( )

要素 A が要素 B を開始し、評価が true になるための関連要件も満たされた場合は true を返します。

署名

  1. starts( point, range )
  2. starts( range1, range2 )

true に評価するための要件

  1. range.start = point and range.start included
  2. range1.start = range2.start and range1.start included = range2.start included and ( range1.end < range2.end or (range1.end = range2.end and (not(range1.end included) or range2.end included)) )

starts( 1, [1..10] ) = true
starts( 1, (1..10] ) = false
starts( 2, [1..10] ) = false
starts( [1..5], [1..10] ) = true
starts( (1..5], (1..10] ) = true
starts( (1..5], [1..10] ) = false
starts( [1..5], (1..10] ) = false
starts( [1..10], [1..10] ) = true
starts( [1..10), [1..10] ) = true
starts( (1..10), (1..10) ) = true

started by( )

要素 A が要素 B によって開始し、評価が true になるための関連要件も満たされた場合は true を返します。

署名

  1. started by( range, point )
  2. started by( range1, range2 )

true に評価するための要件

  1. range.start = point and range.start included
  2. range1.start = range2.start and range1.start included = range2.start included and ( range2.end < range1.end or (range2.end = range1.end and (not(range2.end included) or range1.end included)) )

started by( [1..10], 1 ) = true
started by( (1..10], 1 ) = false
started by( [1..10], 2 ) = false
started by( [1..10], [1..5] ) = true
started by( (1..10], (1..5] ) = true
started by( [1..10], (1..5] ) = false
started by( (1..10], [1..5] ) = false
started by( [1..10], [1..10] ) = true
started by( [1..10], [1..10) ) = true
started by( (1..10), (1..10) ) = true

coincides( )

要素 A が要素 B に一致し、評価が true になるための関連要件も満たされた場合は true を返します。

署名

  1. coincides( point1, point2 )
  2. coincides( range1, range2 )

true に評価するための要件

  1. point1 = point2
  2. range1.start = range2.start and range1.start included = range2.start included and range1.end = range2.end and range1.end included = range2.end included

coincides( 5, 5 ) = true
coincides( 3, 4 ) = false
coincides( [1..5], [1..5] ) = true
coincides( (1..5), [1..5] ) = false
coincides( [1..5], [2..6] ) = false

4.3.2.8. 時間関数

以下の関数は、一般的な時間演算をサポートしています。

day of year( date )

その年のその日のグレゴリオ暦の数値を返します。

表4.61 パラメーター

パラメータータイプ

date

date または date and time

day of year( date(2019, 9, 17) ) = 260

day of week( date )

グレゴリオ暦の曜日 ("Monday""Tuesday""Wednesday""Thursday""Friday""Saturday"、または "Sunday") を返します。

表4.62 パラメーター

パラメータータイプ

date

date または date and time

day of week( date(2019, 9, 17) ) = "Tuesday"

month of year( date )

グレゴリオ暦の月 ("January""February""March""April""May""June""July""August""September""October""November"、または "December") を返します。

表4.63 パラメーター

パラメータータイプ

date

date または date and time

month of year( date(2019, 9, 17) ) = "September"

month of year( date )

ISO 8601 で定義されているグレゴリオ暦の週を返します。

表4.64 パラメーター

パラメータータイプ

date

date または date and time

week of year( date(2019, 9, 17) ) = 38
week of year( date(2003, 12, 29) ) = 1
week of year( date(2004, 1, 4) ) = 1
week of year( date(2005, 1, 1) ) = 53
week of year( date(2005, 1, 3) ) = 1
week of year( date(2005, 1, 9) ) = 1

4.3.2.9. ソート関数

次の関数は、並べ替え操作をサポートしています。

sort( list, precedes )

同じ要素のリストを返しますが、ソート関数に従って順序付けされます。

表4.65 パラメーター

パラメータータイプ

list

list

precedes

function

sort( list: [3,1,4,5,2], precedes: function(x,y) x < y ) = [1,2,3,4,5]

4.3.2.10. コンテキスト関数

以下の関数は、コンテキスト操作をサポートします。

get value( m, key )

指定のエントリーキーのコンテキストから値を返します。

表4.66 パラメーター

パラメータータイプ

m

context

key

string

get value( {key1 : "value1"}, "key1" ) = "value1"
get value( {key1 : "value1"}, "unexistent-key" ) = null

get entries( m )

指定されたコンテキストのキーと値のペアの一覧を返します。

表4.67 パラメーター

パラメータータイプ

m

context

get entries( {key1 : "value1", key2 : "value2"} ) = [ { key : "key1", value : "value1" }, {key : "key2", value : "value2"} ]

4.3.3. FEEL の変数および関数名

従来の多くの式言語と異なり、FEEL (Friendly Enough Expression Language) は、変数および関数名でスペースと少数の特殊文字をサポートします。FEEL 名は 文字?、または _ の要素で始める必要があります。ユニコード文字も使用できます。変数名は、言語キーワード (andtrueevery など) で開始することはできません。先頭以外には (複数桁の) 数値、空白文字、特殊文字 (+-/*'. など) を使用できます。

たとえば、以下の名前はすべて有効な FEEL 名です。

  • Age
  • Birth Date
  • Flight 234 pre-check procedure

FEEL の変数名および関数名には、いくつかの制約が適用されます。

曖昧性 (多義性)
名前の一部に、スペース、キーワード、およびその他の特殊文字を使用して FEEL に多義性を持たせることができます。この多義性は、式のコンテキストで左から右に名前を一致させて解決されます。パーサーは、変数名を、その範囲に一致する中で一番長い名前に解決します。必要に応じて、( ) を使用して名前の多義性を排除できます。
名前で使用されるスペース

DMN 仕様では、FEEL 名におけるスペース使用を制限します。DMN 仕様によると、名前には複数のスペースを使用できますが、連続して使用することはできません。

言語を使いやすく、スペース使用に関するよくある誤りを回避するために、Red Hat Process Automation Manager では、スペースを連続して使用する制限が取り除かれています。Red Hat Process Automation Manager では、スペースを連続して使用する変数名がサポートされますが、スペースを連続して使用してもスペースの数は 1 つに正規化されます。Red Hat Process Automation Manager の変数参照では、First Name (スペース 1 つ) および First Name (スペース 2 つ) の両方が使用できます。

また、Red Hat Process Automation Manager では、Web ページ、タブ、改行でよく見られる分割できない空白文字などの使用を正規化します。Red Hat Process Automation Manager の FEEL エンジンの観点では、このような文字はすべて、処理される前に 1 つの空白文字に正規化されます。

キーワードの in
キーワードの in は、この言語の中で、唯一変数名に使用できないキーワードです。仕様では、変数名にキーワードを使用できますが、変数名に in を使用すると、foreverysome の各表現概念と矛盾します。

4.4. ボックス式の DMN デシジョンロジック

DMN のボックス式は、意思決定要件ダイアグラム (DRD) でデシジョンノードおよびビジネスナレッジモデルの基盤ロジックを定義するのに使用するテーブルです。ボックス式には他のボックス式が含まれる場合がありますが、トップレベルのボックス式は単一の DRD アーティファクトのデシジョンロジックに対応します。DRD は DMN デシジョンモデルのフローを表現し、ボックス式は個別ノードの実際のデシジョンロジックを定義します。DRD とボックス式は、完全で機能的な DMN デシジョンモデルを形成します。

以下は、DMN のボックス式の種類です。

  • デシジョンテーブル
  • リテラル式
  • コンテキスト
  • 関係
  • 関数
  • 呼び出し
  • リスト
注記

Red Hat Process Automation Manager では、Business Central にボックスリスト式が含まれていませんが、FEEL list のデータ型が含まれているためボックスリテラル式で使用できます。Red Hat Process Automation Manager に含まれる list のデータ型およびその他の FEEL データ型については、「FEEL のデータ型」 を参照してください。

ボックス式で使用する Friendly Enough Expression Language (FEEL) 式はすべて、OMG の「Decision Model and Notation specification」に記載されている FEEL 構文の要件に準拠する必要があります。

4.4.1. DMN デシジョンテーブル

DMN のデシジョンテーブルは、1 つ以上のビジネスルールをテーブル形式で視覚的に表します。デシジョンテーブルを使用して、デシジョンモデルの特定の地点でこれらのルールを適用するデシジョンノードのルールを定義します。テーブルの各行はルール 1 つで構成されており、その特定行に対する条件 (入力) と結果 (出力) を定義する列が含まれます。各行の定義は、条件の値を使用して結果を取得できるほど正確です。入力と出力の値には、FEEL 式または定義済みのデータ型の値を指定できます。

たとえば、以下のデシジョンテーブルでは、ローン申請者のクレジットスコアの定義範囲に基づき、クレジットスコアを評価します。

図4.3 クレジットスコア評価のデシジョンテーブル

dmn decision table example

以下のデシジョンテーブルでは、申請者の借り入れ資格や Berueu Call Type に従い、申請者の融資戦略における次のステップを決定します。

図4.4 融資戦略のデシジョンテーブル

dmn decision table example2

以下のデシジョンテーブルでは、ローン事前審査のデシジョンモデルで終端デシジョンノードとして、申請者のローン適正を決定します。

図4.5 ローン事前審査のデシジョンテーブル

dmn decision table example3

デシジョンテーブルは、ルールとデシジョンロジックのモデル化の方法として一般的で、多くの方法論 (DMN など) や実装フレームワーク (Drools など) で使用されます。

重要

Red Hat Process Automation Manager は DMN デシジョンテーブルおよび Drools ネイティブのデシジョンテーブルの両方をサポートしますが、アセットのタイプが異なると構文の要件も異なり、それぞれを置き換えて使用できません。Red Hat Process Automation Manager の Drools ネイティブのデシジョンテーブルに関する情報は、「スプレッドシートのデシジョンテーブルを使用したデシジョンサービスの作成」を参照してください。

4.4.1.1. DMN デシジョンテーブルのヒットポリシー

ヒットポリシーは、デシジョンテーブルにある複数のルールが指定の入力値と一致する場合に、どのように結果に到達するかを決定します。たとえば、デシジョンテーブルの中の 1 つのルールでは、軍人に価格の割引を適用し、別のルールでは学生に割引を適用する場合に、学生であり軍人である顧客には、デシジョンテーブルのヒットポリシーに割引を 1 つだけ適用するのか (UniqueFirst) または両方の割引を適用するのか (Collect Sum) 指定しておく必要があります。ヒットポリシーの 1 文字 (UFC+) をデシジョンテーブルの左上隅に指定します。

DMN では、以下のデシジョンテーブルのヒットポリシーがサポートされます。

  • Unique (U): 一致するルールを 1 つだけ許可します。重複はエラーとなります。
  • Any (A): 複数のルールが一致するのを許可しますが、出力は同じである必要があります。一致している複数のルールで出力が同じでないと、エラーが発生します。
  • Priority (P): 複数のルールが一致し、結果が異なるのを許可します。出力値リストで最初に出力されるものが選択されます。
  • First (F): ルールの順番に従い、最初に一致するのを使用します。
  • Collect (C+、C>、C<、C#): 集約関数に基づいて、複数のルールから出力を集めます。

    • Collect ( C ): 任意のリストで値を集めます。
    • Collect Sum (C+): 集計したすべての値の合計を出力します。値は数値でなければなりません。
    • Collect Min (C<): 一致する中で最小の値を出力します。結果の値は、数値、日付、またはテキスト (辞書的順序) など、比較可能な値である必要があります。
    • Collect Max (C>): 一致する中で最高の値を出力します。結果の値は、数値、日付、またはテキスト (辞書的順序) など、比較可能な値である必要があります。
    • Collect Count (C#): 一致するルールの数を出力します。

4.4.2. ボックスリテラル式

DMN のボックスリテラル式は、テーブルのセル内のテキストとして使用するリテラル FEEL 式で、通常ラベル付きの列およびデータタイプが割り当てられています。ボックスリテラル式を使用して、デシジョンの特定のノードに対して FEEL で直接、単純または複雑なノードロジックまたはデシジョンデータを定義できます。リテラル FEEL 式は OMG の 「Decision Model and Notation specification」の FEEL 構文要件に準拠する必要があります。

たとえば、以下のボックスリテラル式では、融資のデシジョンにおいて最低限許容できる PITI 計算 (元金 (Principal)、利子 (Interest)、税金(Tax)、保険(Insurance)) を定義します。ここでの acceptable rate は、DMN モデルで定義した変数です。

図4.6 PITI の最小値のボックスリテラル式

dmn literal expression example2

以下のボックスリテラル式は、年齢、場所、趣味などの基準のスコアをもとに、オンラインの出会い系アプリでデート相手の候補 (ソウルメイト) 一覧をソートします。

図4.7 オンラインでデート相手の候補者をマッチングするボックスリテラル式

dmn literal expression example3b

4.4.3. ボックスコンテキスト式

DMN のボックスコンテキスト式は、結果の値が含まれる、値と変数名のセットです。名前と値のペアはそれぞれ、コンテキストエントリーとなっています。コンテキスト式を使用して、デシジョンロジックでデータの定義を表現し、DMN デシジョンモデル内で任意のデシジョン要素の値を設定します。ボックスコンテキスト式の値は、データ型の値または FEEL 式を指定でき、デシジョンテーブル、リテラル式、または別のコンテキスト式など、どの型でもサブ式をネスト化させることができます。

たとえば、以下のボックスコンテキスト式では、定義したデータ型 (tPassengerTable, tFlightNumberList) をもとに、飛行機の再予約を行うデシジョンモデルで遅延客をソートする要素を定義します。

図4.8 航空機利用客のウェイティングリストのボックスコンテキスト式

dmn context expression example

以下のボックスコンテキスト式では、サブコンテキスト式が含まれるフロントエンドの割合計算として表現されている PITI (元金 (Principal)、利子 (Interest)、税金(Tax)、保険(Insurance)) をもとに、ローンの申請者が最小限必要とされるローンの支払いをしているかを決定する要素を定義します。

図4.9 フロントエンドクライアント PITI 割合のボックスコンテキスト式

dmn context expression example2

4.4.4. ボックスリレーション式

DMN のボックスリレーション式は、指定のエンティティーに関する情報 (行として記載) が含まれる従来のデータテーブルです。ボックスリレーションテーブルを使用して、特定のノードでのデシジョンで関連するエンティティーのデシジョンデータを定義します。ボックスリレーション式は、変数名と値を設定する点ではコンテキスト式に似ていますが、リレーション式には結果の値が含まれておらず、定義した変数を 1 つをもとに全変数値を列ごとにリストします。

たとえば、以下のボックスリレーション式は、従業員の勤務表デシジョンで従業員に関する情報を提供します。

図4.10 従業員の情報を含むボックスリレーション式

dmn relation expression example

4.4.5. ボックス関数式

DMN のボックス関数式は、リテラル FEEL 式、外部の JAVA または PMML 関数のネスト化されたコンテキスト式、あらゆる型のネスト化されたボックス式を含む、パラメーターを使用するボックス式です。デフォルトでは、全ビジネスナレッジモデルは、ボックス関数式として定義されます。ボックス関数式を使用して、デシジョンロジックで関数を呼び出し、全ビジネスナレッジモデルを定義します。

たとえば、以下のボックス関数式では、フライトの予約変更デシジョンモデルで、航空機の定員を決定します。

図4.11 フライトの定員に使用するボックス関数式

dmn function expression example

以下のボックス関数式には、デシジョンモデルの計算で絶対値を判断するコンテキスト式として使用する基本的な Java 関数が含まれています。

図4.12 絶対値のボックス関数式

dmn function expression example2

以下のボックス関数式では、ネスト化されたコンテキスト式として定義された関数値を使用し、融資のデシジョンのビジネスナレッジモデルとして、住宅ローンの月額を決定します。

図4.13 ビジネスナレッジモデルのローン計算で使用するボックス関数式

dmn function expression example3

以下のボックス関数式は、DMN ファイルに含まれる PMML モデルを使用して、融資の意思決定において、最低許容可能な PITI (元金、利息、税金、保険) の計算を定義します。

図4.14 ビジネスナレッジモデルに PMML モデルが含まれるボックス関数式

dmn function expression example5

4.4.6. ボックス呼び出し式

DMN のボックス呼び出し式は、ビジネスナレッジモデルを呼び出すボックス式です。ボックス呼び出し式には、呼び出すビジネスナレッジモデルの名前と、パラメーターバインディングのリストが含まれています。各バインディングは、1 行に 2 つのボックス式を入れることで表現します。左のボックスにはパラメーターの名前、右のボックスには呼び出したビジネスナレッジモデルを評価するパラメーターに割り当てられる値のバインディング式が含まれます。ボックス式を使用して、デシジョンモデルで定義されているビジネスナレッジモデルを特定のデシジョンノードで呼び出します。

たとえば、以下のボックス呼び出し式では、フライト予約変更のデシジョンモデルで終端デシジョンノードとして Reassign Next Passenger ビジネスナレッジモデルを呼び出します。

図4.15 フライトの乗客を再割り当てするボックス呼び出し式

dmn invocation example

以下のボックス呼び出し式では、InstallmentCalculation ビジネスナレッジモデルを呼び出し、ローンを負担できるかどうか決定する前に、ローンの月額を計算します。

図4.16 必要な月額を判断するボックス呼び出し式

dmn invocation example2

4.4.7. ボックスリスト式

DMN のボックスリスト式は、アイテムの FEEL 一覧を表します。ボックスリストを使用して、デシジョン内にある特定のノードの関連アイテムをリストで定義します。セル内のリストアイテムにリテラル FEEL 式を使用して、より複雑なリストを作成することもできます。

たとえば、次のボックスリスト式では、ローン申請のデシジョンサービスで、承認されたクレジットスコア機関を特定します。

図4.17 承認されたクレジットスコア機関のボックスリスト式

dmn list expression example

以下のボックスリスト式では、承認されたクレジットスコア機関も特定しますが、FEEL ロジックを使用して、DMN 入力ノードを基に機関のステータス (Inc.、LLC、SA、GA) を定義します。

図4.18 承認されたクレジットスコア機関のステータスに FEEL ロジックを使用したボックスリスト式

dmn list expression example2
dmn list expression example2a

4.5. DMN モデルの例

以下は、入力データ、状況、企業のガイドラインをもとに、デシジョンモデルをどのように使用して決断に至るかを判断する実際の DMN モデル例です。以下のシナリオでは、サンディエゴからニューヨークへのフライトがキャンセルされ、欠航となってしまったフライトの航空会社は、このフライトの乗客に対して、別のフライトを手配する必要があります。

まずは、乗客を目的地に運ぶ最適な方法を決めるのに必要な情報を集めます。

入力データ
  • フライトリスト
  • 乗客リスト
決定
  • 新しいフライトで席を確保する乗客の優先順位をつける
  • 乗客に提示するフライトを決定する
ビジネスナレッジモデル
  • 乗客の優先順位を決定する企業のプロセス
  • 席に余裕があるフライト
  • フライトをキャンセルされた乗客を再割り当てするのに最適な方法を決定する会社のルール

次に、航空会社は、DMN 仕様を使用して、以下の意思決定要件ダイアグラム (DRD) でそのデシジョンプロセスをモデル化し、予約変更の最適解を決める以下のダイアグラムを作成します。

図4.19 フライト予約変更の DRD

dmn passenger rebooking drd

DRD では、フローチャートのように、プロセスの各要素に異なる形状を使用します。楕円形には必要な入力データが 2 つ、長方形にはモデルでのデシジョンポイントを含み、端が欠けた長方形 (ビジネスナレッジモデル) には、繰り返し呼び出せる再利用可能なロジックが含まれます。

DRD は、FEEL 式またはデータ型の値を使用して変数定義を提供するボックス式から各要素のロジックを引き出します。

ウィティングリストの優先順位を確立する以下のデシジョンなど、ボックス式には基本的なものもあります。

図4.20 ウェイティングリストの優先順位に関するボックスコンテキスト式のサンプル

dmn context expression example

ボックス式には、次の遅延客を再割り当てするための以下のビジネスナレッジモデルなど、詳細にわたる情報や計算が含まれ、さらに複雑なものもあります。

図4.21 乗客再割り当てのボックス関数式

dmn reassign passenger

以下は、このデシジョンモデルの DMN ソースファイルです。

<dmn:definitions xmlns="https://www.drools.org/kie-dmn/Flight-rebooking" xmlns:dmn="http://www.omg.org/spec/DMN/20151101/dmn.xsd" xmlns:feel="http://www.omg.org/spec/FEEL/20140401" id="_0019_flight_rebooking" name="0019-flight-rebooking" namespace="https://www.drools.org/kie-dmn/Flight-rebooking">
  <dmn:itemDefinition id="_tFlight" name="tFlight">
    <dmn:itemComponent id="_tFlight_Flight" name="Flight Number">
      <dmn:typeRef>feel:string</dmn:typeRef>
    </dmn:itemComponent>
    <dmn:itemComponent id="_tFlight_From" name="From">
      <dmn:typeRef>feel:string</dmn:typeRef>
    </dmn:itemComponent>
    <dmn:itemComponent id="_tFlight_To" name="To">
      <dmn:typeRef>feel:string</dmn:typeRef>
    </dmn:itemComponent>
    <dmn:itemComponent id="_tFlight_Dep" name="Departure">
      <dmn:typeRef>feel:dateTime</dmn:typeRef>
    </dmn:itemComponent>
    <dmn:itemComponent id="_tFlight_Arr" name="Arrival">
      <dmn:typeRef>feel:dateTime</dmn:typeRef>
    </dmn:itemComponent>
    <dmn:itemComponent id="_tFlight_Capacity" name="Capacity">
      <dmn:typeRef>feel:number</dmn:typeRef>
    </dmn:itemComponent>
    <dmn:itemComponent id="_tFlight_Status" name="Status">
      <dmn:typeRef>feel:string</dmn:typeRef>
    </dmn:itemComponent>
  </dmn:itemDefinition>
  <dmn:itemDefinition id="_tFlightTable" isCollection="true" name="tFlightTable">
    <dmn:typeRef>tFlight</dmn:typeRef>
  </dmn:itemDefinition>
  <dmn:itemDefinition id="_tPassenger" name="tPassenger">
    <dmn:itemComponent id="_tPassenger_Name" name="Name">
      <dmn:typeRef>feel:string</dmn:typeRef>
    </dmn:itemComponent>
    <dmn:itemComponent id="_tPassenger_Status" name="Status">
      <dmn:typeRef>feel:string</dmn:typeRef>
    </dmn:itemComponent>
    <dmn:itemComponent id="_tPassenger_Miles" name="Miles">
      <dmn:typeRef>feel:number</dmn:typeRef>
    </dmn:itemComponent>
    <dmn:itemComponent id="_tPassenger_Flight" name="Flight Number">
      <dmn:typeRef>feel:string</dmn:typeRef>
    </dmn:itemComponent>
  </dmn:itemDefinition>
  <dmn:itemDefinition id="_tPassengerTable" isCollection="true" name="tPassengerTable">
    <dmn:typeRef>tPassenger</dmn:typeRef>
  </dmn:itemDefinition>
  <dmn:itemDefinition id="_tFlightNumberList" isCollection="true" name="tFlightNumberList">
    <dmn:typeRef>feel:string</dmn:typeRef>
  </dmn:itemDefinition>
  <dmn:inputData id="i_Flight_List" name="Flight List">
    <dmn:variable name="Flight List" typeRef="tFlightTable"/>
  </dmn:inputData>
  <dmn:inputData id="i_Passenger_List" name="Passenger List">
    <dmn:variable name="Passenger List" typeRef="tPassengerTable"/>
  </dmn:inputData>
  <dmn:decision name="Prioritized Waiting List" id="d_PrioritizedWaitingList">
    <dmn:variable name="Prioritized Waiting List" typeRef="tPassengerTable"/>
    <dmn:informationRequirement>
      <dmn:requiredInput href="#i_Passenger_List"/>
    </dmn:informationRequirement>
    <dmn:informationRequirement>
      <dmn:requiredInput href="#i_Flight_List"/>
    </dmn:informationRequirement>
    <dmn:knowledgeRequirement>
      <dmn:requiredKnowledge href="#b_PassengerPriority"/>
    </dmn:knowledgeRequirement>
    <dmn:context>
      <dmn:contextEntry>
        <dmn:variable name="Cancelled Flights" typeRef="tFlightNumberList"/>
        <dmn:literalExpression>
          <dmn:text>Flight List[ Status = "cancelled" ].Flight Number</dmn:text>
        </dmn:literalExpression>
      </dmn:contextEntry>
      <dmn:contextEntry>
        <dmn:variable name="Waiting List" typeRef="tPassengerTable"/>
        <dmn:literalExpression>
          <dmn:text>Passenger List[ list contains( Cancelled Flights, Flight Number ) ]</dmn:text>
        </dmn:literalExpression>
      </dmn:contextEntry>
      <dmn:contextEntry>
        <dmn:literalExpression>
          <dmn:text>sort( Waiting List, passenger priority )</dmn:text>
        </dmn:literalExpression>
      </dmn:contextEntry>
    </dmn:context>
  </dmn:decision>
  <dmn:decision name="Rebooked Passengers" id="d_RebookedPassengers">
    <dmn:variable name="Rebooked Passengers" typeRef="tPassengerTable"/>
    <dmn:informationRequirement>
      <dmn:requiredDecision href="#d_PrioritizedWaitingList"/>
    </dmn:informationRequirement>
    <dmn:informationRequirement>
      <dmn:requiredInput href="#i_Flight_List"/>
    </dmn:informationRequirement>
    <dmn:knowledgeRequirement>
      <dmn:requiredKnowledge href="#b_ReassignNextPassenger"/>
    </dmn:knowledgeRequirement>
    <dmn:invocation>
      <dmn:literalExpression>
        <dmn:text>reassign next passenger</dmn:text>
      </dmn:literalExpression>
      <dmn:binding>
        <dmn:parameter name="Waiting List"/>
        <dmn:literalExpression>
          <dmn:text>Prioritized Waiting List</dmn:text>
        </dmn:literalExpression>
      </dmn:binding>
      <dmn:binding>
        <dmn:parameter name="Reassigned Passengers List"/>
        <dmn:literalExpression>
          <dmn:text>[]</dmn:text>
        </dmn:literalExpression>
      </dmn:binding>
      <dmn:binding>
        <dmn:parameter name="Flights"/>
        <dmn:literalExpression>
          <dmn:text>Flight List</dmn:text>
        </dmn:literalExpression>
      </dmn:binding>
    </dmn:invocation>
  </dmn:decision>
  <dmn:businessKnowledgeModel id="b_PassengerPriority" name="passenger priority">
    <dmn:encapsulatedLogic>
      <dmn:formalParameter name="Passenger1" typeRef="tPassenger"/>
      <dmn:formalParameter name="Passenger2" typeRef="tPassenger"/>
      <dmn:decisionTable hitPolicy="UNIQUE">
        <dmn:input id="b_Passenger_Priority_dt_i_P1_Status" label="Passenger1.Status">
          <dmn:inputExpression typeRef="feel:string">
            <dmn:text>Passenger1.Status</dmn:text>
          </dmn:inputExpression>
          <dmn:inputValues>
            <dmn:text>"gold", "silver", "bronze"</dmn:text>
          </dmn:inputValues>
        </dmn:input>
        <dmn:input id="b_Passenger_Priority_dt_i_P2_Status" label="Passenger2.Status">
          <dmn:inputExpression typeRef="feel:string">
            <dmn:text>Passenger2.Status</dmn:text>
          </dmn:inputExpression>
          <dmn:inputValues>
            <dmn:text>"gold", "silver", "bronze"</dmn:text>
          </dmn:inputValues>
        </dmn:input>
        <dmn:input id="b_Passenger_Priority_dt_i_P1_Miles" label="Passenger1.Miles">
          <dmn:inputExpression typeRef="feel:string">
            <dmn:text>Passenger1.Miles</dmn:text>
          </dmn:inputExpression>
        </dmn:input>
        <dmn:output id="b_Status_Priority_dt_o" label="Passenger1 has priority">
          <dmn:outputValues>
            <dmn:text>true, false</dmn:text>
          </dmn:outputValues>
          <dmn:defaultOutputEntry>
            <dmn:text>false</dmn:text>
          </dmn:defaultOutputEntry>
        </dmn:output>
        <dmn:rule id="b_Passenger_Priority_dt_r1">
          <dmn:inputEntry id="b_Passenger_Priority_dt_r1_i1">
            <dmn:text>"gold"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r1_i2">
            <dmn:text>"gold"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r1_i3">
            <dmn:text>>= Passenger2.Miles</dmn:text>
          </dmn:inputEntry>
          <dmn:outputEntry id="b_Passenger_Priority_dt_r1_o1">
            <dmn:text>true</dmn:text>
          </dmn:outputEntry>
        </dmn:rule>
        <dmn:rule id="b_Passenger_Priority_dt_r2">
          <dmn:inputEntry id="b_Passenger_Priority_dt_r2_i1">
            <dmn:text>"gold"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r2_i2">
            <dmn:text>"silver","bronze"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r2_i3">
            <dmn:text>-</dmn:text>
          </dmn:inputEntry>
          <dmn:outputEntry id="b_Passenger_Priority_dt_r2_o1">
            <dmn:text>true</dmn:text>
          </dmn:outputEntry>
        </dmn:rule>
        <dmn:rule id="b_Passenger_Priority_dt_r3">
          <dmn:inputEntry id="b_Passenger_Priority_dt_r3_i1">
            <dmn:text>"silver"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r3_i2">
            <dmn:text>"silver"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r3_i3">
            <dmn:text>>= Passenger2.Miles</dmn:text>
          </dmn:inputEntry>
          <dmn:outputEntry id="b_Passenger_Priority_dt_r3_o1">
            <dmn:text>true</dmn:text>
          </dmn:outputEntry>
        </dmn:rule>
        <dmn:rule id="b_Passenger_Priority_dt_r4">
          <dmn:inputEntry id="b_Passenger_Priority_dt_r4_i1">
            <dmn:text>"silver"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r4_i2">
            <dmn:text>"bronze"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r4_i3">
            <dmn:text>-</dmn:text>
          </dmn:inputEntry>
          <dmn:outputEntry id="b_Passenger_Priority_dt_r4_o1">
            <dmn:text>true</dmn:text>
          </dmn:outputEntry>
        </dmn:rule>
        <dmn:rule id="b_Passenger_Priority_dt_r5">
          <dmn:inputEntry id="b_Passenger_Priority_dt_r5_i1">
            <dmn:text>"bronze"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r5_i2">
            <dmn:text>"bronze"</dmn:text>
          </dmn:inputEntry>
          <dmn:inputEntry id="b_Passenger_Priority_dt_r5_i3">
            <dmn:text>>= Passenger2.Miles</dmn:text>
          </dmn:inputEntry>
          <dmn:outputEntry id="b_Passenger_Priority_dt_r5_o1">
            <dmn:text>true</dmn:text>
          </dmn:outputEntry>
        </dmn:rule>
      </dmn:decisionTable>
    </dmn:encapsulatedLogic>
    <dmn:variable name="passenger priority" typeRef="feel:boolean"/>
  </dmn:businessKnowledgeModel>
  <dmn:businessKnowledgeModel id="b_ReassignNextPassenger" name="reassign next passenger">
    <dmn:encapsulatedLogic>
      <dmn:formalParameter name="Waiting List" typeRef="tPassengerTable"/>
      <dmn:formalParameter name="Reassigned Passengers List" typeRef="tPassengerTable"/>
      <dmn:formalParameter name="Flights" typeRef="tFlightTable"/>
      <dmn:context>
        <dmn:contextEntry>
          <dmn:variable name="Next Passenger" typeRef="tPassenger"/>
          <dmn:literalExpression>
            <dmn:text>Waiting List[1]</dmn:text>
          </dmn:literalExpression>
        </dmn:contextEntry>
        <dmn:contextEntry>
          <dmn:variable name="Original Flight" typeRef="tFlight"/>
          <dmn:literalExpression>
            <dmn:text>Flights[ Flight Number = Next Passenger.Flight Number ][1]</dmn:text>
          </dmn:literalExpression>
        </dmn:contextEntry>
        <dmn:contextEntry>
          <dmn:variable name="Best Alternate Flight" typeRef="tFlight"/>
          <dmn:literalExpression>
            <dmn:text>Flights[ From = Original Flight.From and To = Original Flight.To and Departure > Original Flight.Departure and Status = "scheduled" and has capacity( item, Reassigned Passengers List ) ][1]</dmn:text>
          </dmn:literalExpression>
        </dmn:contextEntry>
        <dmn:contextEntry>
          <dmn:variable name="Reassigned Passenger" typeRef="tPassenger"/>
          <dmn:context>
            <dmn:contextEntry>
              <dmn:variable name="Name" typeRef="feel:string"/>
              <dmn:literalExpression>
                <dmn:text>Next Passenger.Name</dmn:text>
              </dmn:literalExpression>
            </dmn:contextEntry>
            <dmn:contextEntry>
              <dmn:variable name="Status" typeRef="feel:string"/>
              <dmn:literalExpression>
                <dmn:text>Next Passenger.Status</dmn:text>
              </dmn:literalExpression>
            </dmn:contextEntry>
            <dmn:contextEntry>
              <dmn:variable name="Miles" typeRef="feel:number"/>
              <dmn:literalExpression>
                <dmn:text>Next Passenger.Miles</dmn:text>
              </dmn:literalExpression>
            </dmn:contextEntry>
            <dmn:contextEntry>
              <dmn:variable name="Flight Number" typeRef="feel:string"/>
              <dmn:literalExpression>
                <dmn:text>Best Alternate Flight.Flight Number</dmn:text>
              </dmn:literalExpression>
            </dmn:contextEntry>
          </dmn:context>
        </dmn:contextEntry>
        <dmn:contextEntry>
          <dmn:variable name="Remaining Waiting List" typeRef="tPassengerTable"/>
          <dmn:literalExpression>
            <dmn:text>remove( Waiting List, 1 )</dmn:text>
          </dmn:literalExpression>
        </dmn:contextEntry>
        <dmn:contextEntry>
          <dmn:variable name="Updated Reassigned Passengers List" typeRef="tPassengerTable"/>
          <dmn:literalExpression>
            <dmn:text>append( Reassigned Passengers List, Reassigned Passenger )</dmn:text>
          </dmn:literalExpression>
        </dmn:contextEntry>
        <dmn:contextEntry>
          <dmn:literalExpression>
            <dmn:text>if count( Remaining Waiting List ) > 0 then reassign next passenger( Remaining Waiting List, Updated Reassigned Passengers List, Flights ) else Updated Reassigned Passengers List</dmn:text>
          </dmn:literalExpression>
        </dmn:contextEntry>
      </dmn:context>
    </dmn:encapsulatedLogic>
    <dmn:variable name="reassign next passenger" typeRef="tPassengerTable"/>
    <dmn:knowledgeRequirement>
      <dmn:requiredKnowledge href="#b_HasCapacity"/>
    </dmn:knowledgeRequirement>
  </dmn:businessKnowledgeModel>
  <dmn:businessKnowledgeModel id="b_HasCapacity" name="has capacity">
    <dmn:encapsulatedLogic>
      <dmn:formalParameter name="flight" typeRef="tFlight"/>
      <dmn:formalParameter name="rebooked list" typeRef="tPassengerTable"/>
      <dmn:literalExpression>
        <dmn:text>flight.Capacity > count( rebooked list[ Flight Number = flight.Flight Number ] )</dmn:text>
      </dmn:literalExpression>
    </dmn:encapsulatedLogic>
    <dmn:variable name="has capacity" typeRef="feel:boolean"/>
  </dmn:businessKnowledgeModel>
</dmn:definitions>

第5章 Red Hat Process Automation Manager における DMN サポート

Red Hat Process Automation Manager は、適合レベル 3 で DMN 1.2 モデルの設計およびランタイムをサポートし、適合レベル 3 で DMN 1.1 および 1.3 モデルはランタイムのみサポートします。DMN モデルは、お使いの Red Hat Process Automation Manager デシジョンサービスと複数の方法で統合できます。

  • DMN デザイナーを使用して Business Central で直接 DMN モデルを設計します。
  • Business Central で プロジェクトに DMN ファイルをインポートします (Menu → Design → Projects → Import Asset)。Business Central にインポートした DMN 1.1 および 1.3 モデル (DMN 1.3 機能は含まれません) は、DMN デザイナーで開き、保存時に DMN 1.2 モデルに変換されます。
  • Business Central を使用せずにプロジェクトのナレッジ JAR (KJAR) ファイルの一部として DMN ファイルをパッケージ化します。

次の表は、Red Hat Process Automation Manager の各 DMN バージョンの設計とランタイムサポートをまとめたものです。

表5.1 Red Hat Process Automation Manager における DMN サポート

DMN バージョン

DMN エンジンのサポート

DMN モデラーのサポート

実行

開く

保存

DMN 1.1

grn check

grn check

bk x

DMN 1.2

grn check

grn check

grn check

DMN 1.3

grn check

grn check

bk x

全 DMN 適合レベル 3 の要件に加え、Red Hat Process Automation Manager には FEEL および DMN モデルコンポーネントに機能拡張および修正が含まれており、Red Hat Process Automation Manager での DMN デシジョンサービスの実装体験を最適化します。DMN モデルは、プラットフォームの観点からすると、Red Hat Process Automation Manager プロジェクトに追加したり、DMN デシジョンサービスを起動するために KIE Server にデプロイしたりできるため、DRL ファイルやスプレッドシートのデシジョンテーブルなど、Red Hat Process Automation Manager の他のビジネスアセットとよく似ています。

Red Hat Process Automation Manager プロジェクトのパッケージ化およびデプロイメント方法を使用して外部の DMN ファイルを追加する方法は、「Red Hat Process Automation Manager プロジェクトのパッケージ化およびデプロイ」を参照してください。

5.1. Red Hat Process Automation Manager における設定可能な DMN プロパティー

Red Hat Process Automation Manager には、クライアントアプリケーションの KIE Server で DMN モデルを実行する時に設定できる以下の DMN プロパティーが含まれます。これらのプロパティーは、KIE Server にプロジェクトをデプロイする際に、Red Hat Process Automation Manager プロジェクトの kmodule.xml ファイルを使用して設定できます。

org.kie.dmn.strictConformance

このプロパティーを有効にすると、一部の helper 関数や、DMN 1.1 にバックポートされた DMN 1.2 の機能強化など、DMN 規定以外に提供された拡張機能やプロファイルをデフォルトで無効にします。このプロパティーを使用して、DMN Technology Compatibility Kit (TCK) を実行するなど、純粋な DMN 機能だけをサポートするデシジョンエンジンを設定できます。

デフォルト値は false です。

-Dorg.kie.dmn.strictConformance=true
org.kie.dmn.runtime.typecheck

このプロパティーを有効にすると、DRD 要素の入力または出力として、DMN モデルに宣言した型に従う実際の値を検証できるようになります。このプロパティーを使用して、DMN モデルに提供されたデータ、または DMN モデルが生成したデータが、モデルに指定したものに準拠するかどうかを検証できます。

デフォルト値は false です。

-Dorg.kie.dmn.runtime.typecheck=true
org.kie.dmn.decisionservice.coercesingleton

このプロパティーは、デフォルトで、1 つの出力デシジョンを定義するデシジョンサービスの結果を、1 つの出力デシジョン値にします。このプロパティーを無効にすると、出力されたデシジョンを定義するデシジョンサービスの結果を、その意思決定のエントリーを 1 つ持つ context にします。このプロパティーを使用して、プロジェクト要件に従ってデシジョンサービスを調整できます。

デフォルト値は true です。

-Dorg.kie.dmn.decisionservice.coercesingleton=false
org.kie.dmn.profiles.$PROFILE_NAME

このプロパティーは、Java の完全修飾名で設定された場合に、起動時にデシジョンエンジンに DMN プロファイルを読み込みます。このプロパティーを使用して、DMN 規定とは異なるサポート機能、またはそれ以外のサポート機能を使用する事前定義した DMN プロファイルを実装できます。Signavio DMN モデラーを使用して DMN モデルを作成する場合は、このプロパティーを使用して Signavio DMN プロファイルからお使いの DMN デシジョンサービスに機能を実装します。

-Dorg.kie.dmn.profiles.signavio=org.kie.dmn.signavio.KieDMNSignavioProfile
org.kie.dmn.runtime.listeners.$LISTENER_NAME

Java の完全修飾名で値を指定すると、このプロパティーは起動時に DMN Runtime Listener をデシジョンエンジンに読み込み、登録します。DMN モデルの評価時に複数のイベントを通知するには、このプロパティーを使用して DMN リスナーを登録してください。

KIE Server にプロジェクトをデプロイする際にこのプロパティーを設定するには、プロジェクトの kmodule.xml ファイルでこのプロパティーを変更します。このアプローチは、リスナーがプロジェクトに固有であり、KIE Server でデプロイされたプロジェクトにのみその構成を適用する必要がある場合に役立ちます。

<kmodule xmlns="http://www.drools.org/xsd/kmodule">
  <configuration>
    <property key="org.kie.dmn.runtime.listeners.mylistener" value="org.acme.MyDMNListener"/>
  </configuration>
</kmodule>

Red Hat Process Automation Manager 環境に対してこのプロパティーをグローバルに設定するには、コマンドターミナルまたはその他のグローバルアプリケーション設定メカニズムを使用してこのプロパティーを変更します。このアプローチは、デシジョンエンジンが Java アプリケーションの一部として埋め込まれた場合に便利です。

-Dorg.kie.dmn.runtime.listeners.mylistener=org.acme.MyDMNListener
org.kie.dmn.compiler.execmodel

このプロパティーが有効な場合には、ランタイムに実行可能なルールモデルに DMN デシジョンテーブルロジックをコンパイルできます。このプロパティーを使用して、DMN デシジョンテーブルのロジックをより効率的に評価できます。このプロパティーは、実行可能なモデルのコンパイルがプロジェクトのコンパイル時に実行されなかった場合に有用です。このプロパティーを有効にすると、デシジョンエンジンにより最初の評価時のコンパイル時間が増加してしまいますが、その後のコンパイルがより効率的になります。

デフォルト値は false です。

-Dorg.kie.dmn.compiler.execmodel=true

5.2. Red Hat Process AutomationManager で構成可能な DMN 検証

デフォルトでは、Red Hat Process Automation Manager プロジェクトの pom.xml ファイルの kie-maven-plugin コンポーネントは、以下の <validateDMN> 設定を使用して DMN モデルアセットの事前コンパイル検証を実行し、DMN デシジョンテーブルの静的分析を実行します。

  • VALIDATE_SCHEMA: DMN モデルファイルは DMN 仕様の XSD スキーマに対して検証され、ファイルが有効な XML であり、この仕様に準拠することを確認します。
  • VALIDATE_MODEL: DMN モデルに対して事前コンパイル分析が実行され、基本的なセマンティックが DMN 仕様と合致するようにします。
  • ANALYZE_DECISION_TABLE: DMN デシジョンテーブルは、ギャップまたは重複に対して静的に分析され、デシジョンテーブルのセマンティックがベストプラクティスに従います。

以下の例のように、デフォルトの DMN 検証および DMN デシジョンテーブル分析動作を変更して、プロジェクトビルドで指定された検証のみを実行するか、以下の例に示すように、このデフォルト動作を完全に無効にできます。

DMN 検証およびデシジョンテーブル分析のデフォルト設定

<plugin>
  <groupId>org.kie</groupId>
  <artifactId>kie-maven-plugin</artifactId>
  <extensions>true</extensions>
  <configuration>
    <validateDMN>VALIDATE_SCHEMA,VALIDATE_MODEL,ANALYZE_DECISION_TABLE</validateDMN>
  </configuration>
</plugin>

DMN デシジョンテーブルの静的分析のみを実行する設定

<plugin>
  <groupId>org.kie</groupId>
  <artifactId>kie-maven-plugin</artifactId>
  <extensions>true</extensions>
  <configuration>
    <validateDMN>ANALYZE_DECISION_TABLE</validateDMN>
  </configuration>
</plugin>

XSD スキーマ検証のみを実行する設定

<plugin>
  <groupId>org.kie</groupId>
  <artifactId>kie-maven-plugin</artifactId>
  <extensions>true</extensions>
  <configuration>
    <validateDMN>VALIDATE_SCHEMA</validateDMN>
  </configuration>
</plugin>

DMN モデルの検証のみを実行する設定

<plugin>
  <groupId>org.kie</groupId>
  <artifactId>kie-maven-plugin</artifactId>
  <extensions>true</extensions>
  <configuration>
    <validateDMN>VALIDATE_MODEL</validateDMN>
  </configuration>
</plugin>

すべての DMN 検証を無効化する設定

<plugin>
  <groupId>org.kie</groupId>
  <artifactId>kie-maven-plugin</artifactId>
  <extensions>true</extensions>
  <configuration>
    <validateDMN>disable</validateDMN>
  </configuration>
</plugin>

注記

認識されない <validateDMN> 設定フラグを入力すると、すべての事前コンパイル検証は無効になり、Maven プラグインが関連するログメッセージを生成します。

第6章 Business Central での DMN モデルの作成および編集

Business Central の DMN デザイナーを使用すると、DMN 意思決定要件ダイアグラム (DRD) を設計し、完全で機能的な DMN 意思決定モデルの意思決定論理を定義できます。Red Hat Process Automation Manager は、適合レベル 3 の DMN 1.2 モデルに対する設計とランタイムの両方のサポートを提供し、FEEL と DMN モデルコンポーネントの機能拡張と修正が含まれており、Red Hat Process Automation Manager での DMN デシジョンサービスの実装が最適化されます。Red Hat Process Automation Manager では、適合レベル 3 の DMN 1.1 および 1.3 に対してランタイムのみをサポートしますが、Business Central にインポートした DMN 1.1 および 1.3 (DMN 1.3 機能は含まない) はすべて、DMN デザイナーで開かれ、保存時に DMN 1.2 モデルに変換されます。

手順

  1. Business Central で、MenuDesignProjects に移動して、プロジェクト名をクリックします。
  2. Business Central プロジェクトで DMN ファイルを作成するか、インポートします。

    DMN ファイルを作成するには、Add AssetDMN をクリックし、わかりやすい DMN モデル名を入力して、適切な Package を選択してから、Ok をクリックします。

    既存の DMN ファイルをインポートするには、Import Asset をクリックし、DMN モデル名を入力して、適切な Package を選択し、アップロードする DMN ファイルを選択してから Ok をクリックします。

    新しい DMN ファイルが Project ExplorerDMN パネルに表示され、DMN 意思決定要件ダイアグラム (DRD) のキャンバスが表示されます。

    注記

    レイアウトの情報が含まれていない DMN ファイルをインポートした場合は、インポートした意思決定要件ダイアグラム (DRD) は DMN デザイナーで自動的にフォーマットされます。DMN デザイナーで Save をクリックして、DRD レイアウトを保存します。

    インポートした DRD が自動的にフォーマットされていない場合、DMN デザイナーの右上のツールバーにある Perform automatic layout アイコンを選択して DRD をフォーマットしてください。

  3. 左側のツールバーから DMN ノードの 1 つをクリックしてドラッグし、新規またはインポートした DMN 意思決定要件ダイアグラム (DRD) にコンポーネントを追加しはじめてください。

    図6.1 DRD コンポーネントの追加

    dmn drag decision node

    以下の DRD コンポーネントを利用できます。

    • デシジョン: DMN ディジョンにこのノードを使用します。1 つ以上の要素が定義したデシジョンロジックをもとに出力を決定するノード。
    • ビジネスナレッジモデル: 1 つまたは複数のデシジョン要素が含まれる再利用可能な関数には、このノードを使用します。同じロジックですが、サブの入力または決定が異なるため、ビジネスナレッジモデルを使用してどの手順に従うかを決定します。
    • ナレッジソース: デシジョンまたはビジネスナレッジモデルを規定する外部の機関、ドキュメント、委員会またはポリシーにはこのノードを使用します。ナレッジソースは、実行可能なビジネスルールではなく、実際の要因への参照となります。
    • 入力データ: デシジョンノードまたはビジネスナレッジモデルで使用する情報にはこのノードを使用します。入力データには通常、融資戦略で使用するローン申請データなど、ビジネスに関連するビジネスレベルのコンセプトまたはオブジェクトが含まれます。
    • テキストの注釈: 入力データノード、デシジョンノード、ビジネスナレッジモデル、またはナレッジソースに関連する注釈にはこのノードを使用します。
    • デシジョンサービス: 呼び出し用にデシジョンサービスとして実装される再利用可能なデシジョンセットを含めるにはこのノードを使用します。デシジョンサービスは、他の DMN モデルで使用し、外部アプリケーションまたは BPMN ビジネスプロセスから呼び出しできます。
  4. DMN デザイナーキャバスで、新規の DRD ノードをダブルクリックして情報ノード名を入力します。
  5. ノードがデシジョンまたはビジネスナレッジモデルの場合は、ノードオプションを表示するノードを選択して Edit アイコンをクリックし、DMN ボックス式を開き、ノードのデシジョンロジックを定義します。

    図6.2 新規デシジョンノードのボックス式の表示

    dmn decision edit

    図6.3 新規ビジネスナレッジモデルのボックス式の表示

    dmn bkm edit

    デフォルトでは、ビジネスナレッジモデルはすべて、リテラル FEEL 式、外部の JAVA または PMML 関数のネスト化されたコンテキスト式、またはあらゆる型のネスト化されたボックス式を含む、ボックス関数式として定義されます。

    デシジョンノードの場合は、定義されていないテーブルをクリックし、ボックスリテラル式、ボックスコンテキスト式、デシジョンテーブル、またはその他の DMN ボックスコンテキスト式など、使用するボックス式のタイプを選択します。

    図6.4 デシジョンノードの論理タイプの選択

    dmn decision boxed expression options

    ビジネスナレッジモデルの場合は、左上の関数セルをクリックして関数型を選択するか、関数値のセルを右クリックし、Clear を選択して、別の型のボックス式を選択します。

    図6.5 ビジネスナレッジモデルの機能または他のロジックタイプの選択

    dmn bkm define
  6. デザインノード (任意の式タイプ) またはビジネスナレッジモデル (関数式) のいずれかに対して選択したボックス式デザイナーで、該当するテーブルセルをクリックして、デシジョンロジックに含めるテーブル名、変数データ型、変数名、値、関数パラメーター、バインディング、FEEL 式を定義します。

    セルを右クリックして、テーブルの行および列の挿入または削除、テーブルのコンテンツの消去など、随時、追加のアクションを実行します。

    以下は、ローン申請者のクレジットスコアの定義範囲をもとに、クレジットスコアの評価を決定するデシジョンノードのデシジョンテーブルの一例です。

    図6.6 クレジットスコア評価のデシジョンノードのデシジョンテーブル

    dmn decision table example1a

    以下は、元金、利子、税金、保険 (PITI) をもとに、リテラル式として住宅ローンの支払額を計算するビジネスナレッジモデルのボックス関数式の一例です。

    図6.7 PITI 計算のビジネスナレッジモデルの関数

    dmn function expression example4
  7. 選択したノードのデシジョンロジックを定義した後に、Back to "<MODEL_NAME>" をクリックして DRD ビューに戻ります。
  8. 選択した DRD ノードについては、利用可能な接続オプションを使用して、DRD の次のノードを作成して接続するか、左のツールバーから DRD キャンバスに新規ノードをクリックしてドラッグします。

    ノードタイプで、どの接続オプションがサポートされているかが決まります。たとえば、入力データ ノードは、アプリケーションの接続タイプを使用してデシジョンオード、ナレッジソース、またはテキストの注釈を接続できますが、ナレッジソース ノードは、どの DRD 要素にでも接続できます。デシジョン ノードは、別のデシジョンまたはテキスト注釈にだけ接続できます。

    以下の接続タイプは、ノードの種類に応じて利用できます。

    • 情報要件: 入力データノードまたはデシジョンノードから、情報を必要とする別のデシジョンノードに移動するにはこの接続を使用します。
    • ナレッジ要件: ビジネスナレッジモデルからデシジョンロジックを呼び出す別のビジネスナレッジモデルまたはデシジョンノードに移動するにはこの接続を使用します。
    • 認証局の要件: 入力データノードまたはデシジョンノードから従属するナレッジソース、またはナレッジソースからデシジョンノード、ビジネスナレッジモデルまたは別のナレッジソースに移動するにはこの接続を使用します。
    • 関連付け: 入力データノード、デシジョンノード、ビジネスナレッジモデル、またはナレッジソースからテキストアノテーションに移動するにはこの接続を使用します。

    図6.8 クレジットスコアの入力からクレジットスコア評価のデシジョンへの接続

    dmn input connection example
    dmn input connection example2
  9. 継続して、デシジョンモデルの残りの DRD コンポーネントを追加し、定義します。DMN デザイナーで定期的に Save をクリックして作業を保存します。

    注記

    DRD を定期的に保存すると、DMN デザイナーは DMN モデルを静的に検証し、モデルが完全に定義されるまでエラーメッセージを送出する可能性があります。DMN モデルをすべて定義し終えてもエラーが発生する場合は、特定の問題を随時トラブルシューティングしてください。

  10. DRD の全コンポーネントを追加して定義した後に、Save をクリックし、完了した DRD を保存して検証します。

    DRD レイアウトを調節するには、DMN デザイナーの右上のツールバーにある Perform automatic layout アイコンを選択してください。

    以下は、ローンの事前審査デシジョンモデルの DRD の一例です。

    図6.9 ローンの事前審査の完全な DRD

    dmn example drd

    以下は、再利用可能なデシジョンサービスを使用した電話対応デシジョンモデルの DRD 例です。

    図6.10 デシジョンサービスを使用した電話対応の完全な DRD

    dmn example drd3

    DMN デシジョンサービスノードでは、一番下のセグメントデシジョンノードはデシジョンサービス外からの入力データを組み込んで、デシジョンサービスノードにある一番上のセグメントの最終地点に行き着きます。デシジョンサービスから返される上位のデシジョンは、後続のデシジョンまたは DMN モデルのビジネスナレッジ要件に実装されます。他の DMN モデル内の DMN デシジョンサービスを再利用し、異なる入力データや外向け接続で、同じデシジョンロジックを適用します。

6.1. Business Central でボックス式を使用した DMN デシジョンロジックの定義

DMN のボックス式は、意思決定要件ダイアグラム (DRD) でデシジョンノードおよびビジネスナレッジモデルの基盤ロジックを定義するのに使用するテーブルです。ボックス式には他のボックス式が含まれる場合がありますが、トップレベルのボックス式は単一の DRD アーティファクトのデシジョンロジックに対応します。DRD は DMN デシジョンモデルのフローを表現し、ボックス式は個別ノードの実際のデシジョンロジックを定義します。DRD とボックス式は、完全で機能的な DMN デシジョンモデルを形成します。

Business Central で DMN デザイナーを使用して、同梱のボックス式で DRD コンポーネントのデシジョンロジックを定義できます。

前提条件

  • Business Central で DMN ファイルを作成しているか、インポートしている。

手順

  1. Business Central で MenuDesignProjects に移動して、プロジェクト名をクリックし、変更する DMN ファイルを選択します。
  2. DMN デザイナーのキャンバスで、定義するデシジョンノードまたはビジネスナレッジモデルノードを選択し、Edit アイコンをクリックして DMN ボックス式デザイナーを開きます。

    図6.11 新規デシジョンノードのボックス式の表示

    dmn decision edit

    図6.12 新規ビジネスナレッジモデルのボックス式の表示

    dmn bkm edit

    デフォルトでは、ビジネスナレッジモデルはすべて、リテラル FEEL 式、外部の JAVA または PMML 関数のネスト化されたコンテキスト式、またはあらゆる型のネスト化されたボックス式を含む、ボックス関数式として定義されます。

    デシジョンノードの場合は、定義されていないテーブルをクリックし、ボックスリテラル式、ボックスコンテキスト式、デシジョンテーブル、またはその他の DMN ボックスコンテキスト式など、使用するボックス式のタイプを選択します。

    図6.13 デシジョンノードの論理タイプの選択

    dmn decision boxed expression options

    ビジネスナレッジモデルノードの場合は、左上の関数セルをクリックして関数型を選択するか、関数値のセルを右クリックし、Clear を選択して、別の型のボックス式を選択します。

    図6.14 ビジネスナレッジモデルの機能または他のロジックタイプの選択

    dmn bkm define
  3. この例では、デシジョンノードを使用して、ボックス式タイプとして デシジョンテーブル を使用します。

    DMN のデシジョンテーブルは、1 つ以上のルールをテーブル形式で視覚的に表します。テーブルの各行はルール 1 つで構成されており、その特定行に対する条件 (入力) と結果 (出力) を定義する列が含まれます。

  4. 入力列のヘッダーをクリックして、入力条件の名前とデータ型を定義します。たとえば、入力列に Credit Score.FICO という名前で、number のデータ型を指定します。この列は、数字のクレジットスコア値または、各種ローン申請者を指定します。
  5. 出力列ヘッダーをクリックして、出力値の名前とデータ型を定義します。たとえば、出力列に Credit Score Rating という名前を指定して、Data Type オプションの横で Manage をクリックし、Data Types ページに移動して、スコア評価を制約として、カスタムのデータ型を作成します。

    図6.15 列のヘッダー値のデータ型管理

    dmn manage data types
  6. Data Types ページで、New Data Type をクリックして新規データ型を追加するか、Import Data Object をクリックして、使用するプロジェクトから既存のデータオブジェクトを DMN データ型としてインポートします。

    プロジェクトから DMN データ型としてデータオブジェクトをインポートしてから、そのオブジェクトを更新した場合は、DMN データ型としてデータオブジェクトを再インポートして DMN モデルに変更を適用する必要があります。

    この例では、New Data Type をクリックし、Credit_Score_Rating のデータ型を string で作成します。

    図6.16 新しいデータ型の追加

    dmn custom data type add
  7. Add Constraints をクリックして、ドロップダウンオプションから Enumeration を選択し、以下の制約を追加します。

    • "Excellent"
    • "Good"
    • "Fair"
    • "Poor"
    • "Bad"

    図6.17 新しいデータ型への制約の追加

    dmn custom data type constraints

    データ型の制約の順序を変更するには、必要に応じて、制約の行の左端をクリックしてその行をドラッグします。

    図6.18 制約をドラッグして制約順序を変更

    dmn custom data type constraints drag

    指定のデータ型の制約タイプと構文要件に関する情報は、「Decision Model and Notation specification」を参照してください。

  8. OK をクリックして制約を保存し、データ型の右側のチェックマークをクリックしてデータ型を保存します。
  9. Credit Score Rating デシジョンテーブルに戻り、Credit Score Rating 列ヘッダーをクリックして、保存したデータ型をこの新規カスタムデータ型に設定します。
  10. Credit Score.FICO の入力列を使用して、クレジットスコアの値またはクレジットの範囲を定義し、Credit Score Rating 列を使用して、Credit_Score_Rating のデータ型で定義した対応する評価の 1 つを指定します。

    値のセルを右クリックして、行 (ルール) および列 (句) を挿入または削除します。

    図6.19 クレジットスコア評価のデシジョンノードのデシジョンテーブル

    dmn decision table example1a
  11. 全ルールを定義した後に、デシジョンテーブルの左上隅をクリックして、ヒットポリシー組み込みアグリゲーター (COLLECT ヒットポリシーのみ) のルールを定義します。

    ヒットポリシーは、デシジョンテーブルにある複数のルールが指定の入力値とマッチした場合にどのように結果に到達するのかを決定します。組み込みアグリゲーターは、COLLECT ヒットポリシーを使用する場合にどのようにルール値を累積するかを決定します。

    図6.20 デシジョンテーブルヒットポリシーの定義

    dmn hit policies

    以下のデシジョンテーブルは、より複雑なデシジョンテーブルで、ローン事前審査のデシジョンモデルで終端デシジョンノードとして、申請者のローン適正を決定します。

    図6.21 ローン事前審査のデシジョンテーブル

    dmn decision table example3

デシジョンテーブル以外のボックス式タイプの場合は、ボックス式のテーブルを移動して、デシジョンロジックの変数とパラメーターを定義するのと同様にこれらのガイドラインに従いますが、ボックス式のタイプの要件に従うようにしてください。ボックスリテラル式など、ボックス式の一部では列が 1 つのテーブルの場合や、関数、テキスト、呼び出し式などのボックス式は、他のタイプのボックス式がネスト化された、列が複数あるテーブルの場合もあります。

たとえば、以下のボックスコンテキスト式では、サブコンテキスト式が含まれるフロントエンドの割合計算として表現されている PITI (元金 (Principal)、利子 (Interest)、税金(Tax)、保険(Insurance)) をもとに、ローンの申請者が最小限必要とされるローンの支払いをしているかを決定するパラメーターを定義します。

図6.22 フロントエンドクライアント PITI 割合のボックスコンテキスト式

dmn context expression example2

以下のボックス関数式では、ネスト化されたコンテキスト式として定義された関数値を使用し、融資のデシジョンのビジネスナレッジモデルとして、住宅ローンの月額を決定します。

図6.23 ビジネスナレッジモデルのローン計算で使用するボックス関数式

dmn function expression example3

各ボックス式のタイプの例および詳細は、「ボックス式の DMN デシジョンロジック」を参照してください。

6.2. Business Central での DMN ボックス式のカスタムデータ型の作成

Business Central の DMN のボックス式では、データ型により、ボックス式の関連のテーブル、列、またはフィールド内で使用するデータの構造を決定します。デフォルトの DMN データ型 (文字列、数字、ブール値など) を使用するか、独自のデータ型を作成して、ボックス式の値に実装する新たなフィールドや制限を指定することもできます。

ボックス式のカスタムのデータ型として、単純なデータ型または構造化されたデータ型のいずれかを作成できます。

  • 単純な データ型では、名前とタイプの割当のみを指定できます。例: Age (number)
  • 構造化された データ型には、親データ型に関連する複数のフィールドが含まれます。例: Name (string)Age (number)Email (string) のフィールドが含まれる単一の型 Person

前提条件

  • Business Central で DMN ファイルを作成しているか、インポートしている。

手順

  1. Business Central で MenuDesignProjects に移動して、プロジェクト名をクリックし、変更する DMN ファイルを選択します。
  2. DMN デザイナーのキャンバスで、データ型を定義するデシジョンノードまたはビジネスナレッジモデルを選択し、Edit アイコンをクリックして DMN ボックス式デザイナーを開きます。
  3. ボックス式が定義されていないデシジョンノードの場合は、定義されていないテーブルをクリックし、ボックスリテラル式、ボックスコンテキスト式、デシジョンテーブル、またはその他の DMN ボックスコンテキスト式など、使用するボックス式のタイプを選択します。

    図6.24 デシジョンノードの論理タイプの選択

    dmn decision boxed expression options
  4. テーブルヘッダのセルまたは、(ボックス式のタイプに合わせて) データ型を定義するパラメーターフィールドをクリックし、Manage をクリックして、カスタムのデータ型を作成する Data Types ページに移動します。

    図6.25 列のヘッダー値のデータ型管理

    dmn manage data types

    DMN デザイナーの右上隅の Properties アイコンを選択して、指定のデシジョンノードまたはビジネスナレッジモデルノードのカスタムデータ型を設定して管理することも可能です。

    図6.26 意思決定要件 (DRD) プロパティーでのデータ型の管理

    dmn manage data types1a

    ボックス式で指定のセルに定義するデータ型により、ボックス式の関連のテーブル、列、フィールド内で使用するデータの構造を決定します。

    この例では、DMN デシジョンテーブルの出力列 クレジットスコア評価 は、申請者のクレジットスコアをもとにカスタムのクレジットスコア評価を定義します。

  5. Data Types ページで、New Data Type をクリックして新規データ型を追加するか、Import Data Object をクリックして、使用するプロジェクトから既存のデータオブジェクトを DMN データ型としてインポートします。

    プロジェクトから DMN データ型としてデータオブジェクトをインポートしてから、そのオブジェクトを更新した場合は、DMN データ型としてデータオブジェクトを再インポートして DMN モデルに変更を適用する必要があります。

    この例では、New Data Type をクリックし、Credit_Score_Rating のデータ型を string で作成します。

    図6.27 新しいデータ型の追加

    dmn custom data type add

    データ型がアイテムの一覧を必要とする場合は、List 設定を有効にします。

  6. Add Constraints をクリックして、ドロップダウンオプションから Enumeration を選択し、以下の制約を追加します。

    • "Excellent"
    • "Good"
    • "Fair"
    • "Poor"
    • "Bad"

    図6.28 新しいデータ型への制約の追加

    dmn custom data type constraints

    データ型の制約の順序を変更するには、必要に応じて、制約の行の左端をクリックしてその行をドラッグします。

    図6.29 制約をドラッグして制約順序を変更

    dmn custom data type constraints drag

    指定のデータ型の制約タイプと構文要件に関する情報は、「Decision Model and Notation specification」を参照してください。

  7. OK をクリックして制約を保存し、データ型の右側のチェックマークをクリックしてデータ型を保存します。
  8. Credit Score Rating デシジョンテーブルに戻り、Credit Score Rating 列ヘッダーをクリックして、保存したデータ型をこの新規カスタムデータ型に設定し、指定した評価制約で、対象の列のルール値を定義します。

    図6.30 クレジットスコア評価のデシジョンテーブル

    dmn decision table example1a

    シナリオの DMN デシジョンモデルで、Credit Score Rating デシジョンが、以下の Loan Prequalification デシジョンに流れ、このデシジョンではカスタムのデータ型が必要です。

    図6.31 ローン事前審査のデシジョンテーブル

    dmn manage data types blank
  9. この例をそのまま使用し、Data Types ウィンドウに戻り、New Data Type をクリックして、Loan_Qualification データ型を制約なしの Structure として作成します。

    新しい構造化データ型を保存すると、最初のサブフィールドが表示され、この親データ型で、ネスト化されたデータフィールドの定義を開始できます。デシジョンテーブル内にネスト化された列ヘッダー、コンテキストまたは関数式でネスト化されたパラメーターなど、ボックス式の構造化された親データ型と関連するこれらのサブフィールドを使用できます。

    追加のサブフィールドについては Loan_Qualification のデータ型の横にある追加のアイコンをクリックします。

    図6.32 新しい構造化データ型へのネスト化フィールドの追加

    dmn manage data types structured
  10. この例では、構造化された Loan_Qualification データ型に、"Qualified""Not Qualified" の列挙制約がある Qualification フィールドと、制約のない Reason フィールドを追加します。また、"Sufficient""Insufficient" の列挙制約がある、単純なデータ型 Back_End_RatioFront_End_Ratio を追加します。

    作成する各データ型の右側にあるチェックマークをクリックして変更を保存します。

    図6.33 ネスト化されたデータ型への制約の追加

    dmn manage data types structured2

    データ型の順序やネスト化を変更するには、必要に応じて、データ型の行の左端をクリックしてその行をドラッグします。

    図6.34 データ型をドラッグしてデータ型の順番やネスト化を変更

    dmn manage data types structured2 drag
  11. デシジョンテーブルに戻り、列ごとに、列ヘッダーセルをクリックし、対応する新規のカスタムデータ型に、このデータ型を設定して、(該当する場合には) 指定した制約で必要に応じて列のルール値を定義します。

    図6.35 ローン事前審査のデシジョンテーブル

    dmn decision table example3

デシジョンテーブル以外のボックス式タイプの場合は、ボックス式のテーブルを移動して、必要に応じてカスタムのデータ型を定義するのと同様に、これらのガイドラインに従うようにしてください。

たとえば、以下のボックス関数式はカスタムの tCandidatetProfile の構造化データ型を使用して、データを関連付けてオンライン出会い系でのデート相手としての適合性を判断します。

図6.36 オンライン出会い系でデート相手としての適合性に使用するボックス関数式

dmn manage data types structured3

図6.37 オンライン出会い系でデート相手としての適合性に使用するカスタムデータ型の定義

dmn manage data types structured3a

図6.38 オンライン出会い系でデート相手としての適合性に使用するカスタムデータ型を含むパラメーター定義

dmn manage data types structured3b

6.3. Business Central の DMN ファイルに含まれるモデル

Business Central の DMN デザイナーで Included Models タブを使用して、指定の DMN ファイルに、お使いのプロジェクトの他の DMN モデルや、Predictive Model Markup Language (PMML) モデルを使用できます。別の DMN ファイルに DMN モデルを追加すると、同じ意思決定要件ダイアグラム (DRD) にある両方のモデルのノードやロジックをすべて使用できます。DMN ファイルに PMML モデルを追加すると、その PMML モデルを DMN デシジョンノードまたはビジネスナレッジモデルノードのボックス関数式として呼び出すことができます。

Business Central では、他のプロジェクトの DMN または PMML モデルは追加できません。

6.3.1. Business Central の DMN ファイルへの他の DMN モデルの追加

Business Central では、指定の DMN ファイルに、プロジェクトの他の DMN モデルを追加できます。別の DMN ファイルに DMN モデルを追加すると、同じ意思決定要件ダイアグラム (DRD) にある両方のモデルのノードやロジックをすべて使用できますが、追加したモデルのノードは編集できません。追加したモデルのノードを編集するには、直接追加したモデルのソースファイルを更新する必要があります。追加した DMN モデルのソースファイルを更新した場合は、DMN モデルが追加されている DMN ファイルを表示して (または一旦閉じて、開き直して)、変更を確認してください。

Business Central では、他のプロジェクトの DMN モデルは追加できません。

前提条件

  • Business Central で (.dmn ファイルとして) 同じプロジェクトに DMN モデルが作成されているか、インポートされている。

手順

  1. Business Central で MenuDesignProjects に移動して、プロジェクト名をクリックし、変更する DMN ファイルを選択します。
  2. DMN デザイナーで、Included Models タブをクリックします。
  3. Include Model をクリックして、Models リストのプロジェクトから DMN モデルを選択し、追加するモデルの一意名を入力して、Include をクリックします。

    図6.39 DMN モデルの追加

    dmn include model

    この DMN ファイルに、DMN ファイルが追加され、追加したモデルからの DRD ノードがすべて Decision Navigator ビューの Decision Components に表示されます。

    図6.40 追加した DMN モデルのデシジョンコンポーネントを含む DMN ファイル

    dmn include model list

    追加したモデルからの全データ型が DMN ファイルの Data Types タブにも、読み取り専用モードで表示されます。

    図6.41 追加した DMN モデルのデータ型を含む DMN ファイル

    dmn include model data types
  4. DMN デザイナーの Model タブで、追加した DRD コンポーネントをクリックしてキャンバスにドラッグし、DRD での実装を開始します。

    図6.42 追加した DMN モデルの DRD コンポーネントの追加

    dmn include model drd

    追加したモデルの DRD ノードまたはデータタイプを編集するには、追加したモデルのソースファイルを直接更新する必要があります。追加した DMN モデルのソースファイルを更新した場合は、DMN モデルが追加されている DMN ファイルを表示して (または一旦閉じて、開き直して)、変更を確認してください。

    追加したモデル名を編集するか、追加したモデルを DMN ファイルから削除するには、DMN デザイナーの Included Models タブを使用します。

    重要

    追加したモデルを削除すると、DRD で現在使用している追加モデルのノードもすべて削除されます。

6.3.2. Business Central の DMN ファイルへの PMML モデルの追加

Business Central では、指定した DMN ファイルに、プロジェクトの Predictive Model Markup Language (PMML) を追加できます。DMN ファイルに PMML モデルを追加すると、その PMML モデルを DMN デシジョンノードまたはビジネスナレッジモデルノードのボックス関数式として呼び出すことができます。追加した PMML モデルのソースファイルを更新した場合は、DMN ファイルの PMML モデルを削除して追加し直し、ソースの変更を適用する必要があります。

Business Central では、他のプロジェクトからの PMML モデルを追加できません。

前提条件

  • Business Central で (.pmml ファイルとして) 同じプロジェクトに PMML モデルがインポートされている。

手順

  1. DMN プロジェクトで、プロジェクトの pom.xml ファイルに以下の依存関係を追加して、PMML 評価を有効にします。

    <!-- Required for the PMML compiler -->
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>kie-pmml</artifactId>
      <version>${rhpam.version}</version>
      <scope>provided</scope>
    </dependency>
    
    <!-- Alternative dependencies for JPMML Evaluator, override `kie-pmml` dependency -->
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-dmn-jpmml</artifactId>
      <version>${rhpam.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.jpmml</groupId>
      <artifactId>pmml-evaluator</artifactId>
      <version>1.5.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.jpmml</groupId>
      <artifactId>pmml-evaluator-extension</artifactId>
      <version>1.5.1</version>
      <scope>provided</scope>
    </dependency>

    Business Central でプロジェクト pom.xml にアクセスするには、プロジェクトで既存のアセットを選択し、画面左側の Project Explorer メニューで Customize View ギアアイコンをクリックし、Repository Viewpom.xml を選択します。

    Java Evaluator API for PMML (JPMML) と完全な PMML 仕様の実装を使用する場合は、DMN プロジェクトで代わりとなる JPMML の依存関係を使用してください。JPMML の依存関係と標準の kie-pmml の依存関係が両方ある場合は、kie-pmml の依存関係が無効になります。JPMML のライセンス条件に関する情報は、Openscoring.io を参照してください。

    重要

    従来の kie-pmml 依存関係は、Red Hat Process Automation Manager 7.10.0 で非推奨になり、将来の Red Hat Process Automation Manager リリースで kie-pmml-trusty 依存関係に置き換えられる予定です。

    注記

    個別の依存関係に対して Red Hat Process Automation Manager <version> を指定するのではなく、Red Hat Business Automation BOM (bill of materials) の依存関係をプロジェクトの pom.xml ファイルに追加することを検討してください。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.10.0.redhat-00004</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>

    Red Hat Business Automation BOM (Bill of Materials) についての詳細情報は、「What is the mapping between RHPAM product and maven library version?」 を参照してください。

  2. DMN プロジェクトに JPMML 依存関係を追加して JPMML Evaluator を使用する場合は、以下の JAR ファイルをダウンロードし、Red Hat Process Automation Manager ディストリビューションの ~/kie-server.war/WEB-INF/lib~/business-central.war/WEB-INF/lib のディレクトリーに追加します。

    • Red Hat カスタマーポータル から取得した Red Hat Process Automation Manager 7.10.0 Maven Repository ディストリビューションの JAR ファイル kie-dmn-jpmml (rhpam-7.10.0-maven-repository/maven-repository/org/kie/kie-dmn-jpmml/7.48.0.Final-redhat-00004/kie-dmn-jpmml-7.48.0.Final-redhat-00004.jar)
    • オンラインの Maven リポジトリーから取得した JPMML Evaluator 1.5.1 JAR ファイル
    • オンラインの Maven リポジトリーから取得した JPMML Evaluator Extensions 1.5.1 JAR ファイル

    これらのアーティファクトは、KIE Server と Business Central で JPMML 評価を有効化するのに必要です。

    重要

    Red Hat は、Red Hat Process Automation Manager で PMML を実行するため、Java Evaluator API for PMML (JPMML) との統合をサポートしています。しかし、Red Hat は JPMML ライブラリーを直接サポートしません。Red Hat Process Automation Manager ディストリビューションに JPMML ライブラリーを含む場合は、JPMML の Openscoring.io ライセンス条件を確認してください。

  3. Business Central で MenuDesignProjects に移動して、プロジェクト名をクリックし、変更する DMN ファイルを選択します。
  4. DMN デザイナーで、Included Models タブをクリックします。
  5. Include Model をクリックして、Models リストのプロジェクトから PMML モデルを選択し、追加するモデルの一意名を入力して、Include をクリックします。

    図6.43 PMML モデルの追加

    dmn include model pmml

    PMML モデルは、この DMN ファイルに追加されます。

    図6.44 PMML モデルを含む DMN ファイル

    dmn include model list pmml
  6. DMN デザイナーの Model タブで、PMML モデルを呼び出すデシジョンノードまたはビジネスナレッジモデルノードを選択または作成して、Edit アイコンをクリックし、DMN ボックス式デザイナーを開きます。

    図6.45 新規デシジョンノードのボックス式の表示

    dmn decision edit

    図6.46 新規ビジネスナレッジモデルのボックス式の表示

    dmn bkm edit
  7. 式タイプを Function (ビジネスナレッジモデルノードのデフォルト) に設定し、左上の機能セルをクリックして PMML を選択します。
  8. テーブルの documentmodel の行で、未定義のセルをダブルクリックして、PMML ドキュメント、およびそのドキュメント内の関連する PMML モデルを指定します。

    図6.47 DMN ビジネスナレッジモデルへの PMML モデルの追加

    dmn include model expression pmml

    図6.48 DMN ビジネスナレッジモデルでの PMML 定義の例

    dmn function expression example5

    追加した PMML モデルのソースファイルを更新した場合は、DMN ファイルの PMML モデルを削除して追加し直し、ソースの変更を適用する必要があります。

    追加したモデル名を編集するか、追加したモデルを DMN ファイルから削除するには、DMN デザイナーの Included Models タブを使用します。

6.4. Business Central の複数の図を含む DMN モデルの作成

複雑な DMN モデルには、Business Central で DMN デザイナーを使用して、DMN デシジョンモデルに関する全体的な意識決定要件グラフ (DRG) の一部を表す複数の DMN の意思決定要件ダイアグラムを設計できます。単純な場合は、単一の DRD を使用して、デシジョンモデルに対して全体的な DRG をすべて表すことができますが、複雑な場合は、1 つの DRD のサイズが大きくなり、追跡が困難になる可能性があります。そのため、多くの意思決定要件で DMN の意思決定モデルをより適切に整理するために、このモデルを、DRG 全体の集中型 DRD を大きく構成する小規模のネストされた DRD に分割することができます。

前提条件

手順

  1. Business Central で DMN プロジェクトに移動し、プロジェクトに DMN ファイルを作成またはインポートします。
  2. 新規またはインポートされた DMN ファイルを開いて DMN デザイナーで DRD を表示し、左側のツールバーの DMN ノードを使用して DRD の設計または変更を開始します。
  3. 別のネストされた DRD で定義する DMN ノードについては、ノードを選択し、DRD Actions アイコンをクリックし、利用可能なオプションから選択します。

    図6.49 DRD を細分化する DRD アクションアイコン

    dmn drd actions

    以下のオプションが利用できます。

    • Create: このオプションを使用してネストされた DRD を作成します。この DRD は、選択したノードの DMN コンポーネントおよび図を個別に定義できます。
    • Add to: ネストされた DRD がすでに作成されている場合は、このオプションを使用して選択したノードを既存の DRD に追加します。
    • Remove: 選択したノードがネストされた DRD 内にある場合は、このオプションを使用して、ネストされた DRD からノードを削除します。

    DMN のデシジョンモデル内にネストされた DRD を作成すると、新しい DRD は別の DRD キャンバスで開き、利用可能な DRD とコンポーネントが Decision Navigator の左側のメニューに表示されます。Decision Navigator メニューを使用して、ネストされた DRD を名前変更または削除できます。

    図6.50 Decision Navigator メニューで新しいネストされた DRD の名前を変更

    dmn drd actions rename
  4. 新しいネストされた DRD の別のキャンバスで、DMN モデルのこの部分で必要なすべてのコンポーネントのフローと論理を設計します。
  5. そのために、デシジョンモデルに他のネストされた DRD を追加および定義し、完了した DMN ファイルを保存します。

    たとえば、ローン事前審査デシジョンモデルの次の DRD には、ネストされた DRD がないモデルのすべての DMN コンポーネントが含まれています。この例では、すべてのコンポーネントおよびロジックの単一の DRD に依存しているため、図は大きくて複雑になります。

    図6.51 ローンの事前審査のための単一の DRD

    dmn example drd

    または、この手順に従って、この例の DRD を複数のネストされた DRD に分割し、以下の例のように意思決定要件をより適切に整理できます。

    図6.52 ローンの事前審査のための複数のネストされた DRD

    dmn drd multiple

    図6.53 フロントエンド比率 DRD の概要

    dmn drd multiple front end

    図6.54 フロントエンド比率の DRD

    dmn drd multiple front end details

    図6.55 クレジットカード評価 DRD の概要

    dmn drd multiple credit score

    図6.56 クレジットカード評価の DRD

    dmn drd multiple credit score details

    図6.57 バックエンド比率 DRD の概要

    dmn drd multiple back end

    図6.58 バックエンド比率の DRD

    dmn drd multiple back end details

6.5. Business Central の DMN モデルドキュメント

Business Central の DMN デザイナーで、Documentation タブを使用して、オフラインで使用できるように HTML ファイルとして出力またはダウンロード可能な、DMN モデルのレポートを生成します。DMN モデルのレポートには、DMN モデルの全意思決定要件ダイアグラム (DRD)、データタイプ、およびボックス式が含まれます。このレポートを使用して、DMN モデルの詳細を共有したり、社内のレポートワークフローの一部として共有できます。

図6.59 DMN モデルレポートの例

dmn documentation

6.6. Business Central での DMN ナビゲーションとプロパティー

Business Central の DMN デザイナーには、以下の追加機能が含まれており、意思決定要件ダイアグラム (DRD) のコンポーネントやプロパティーの移動を容易にします。

DMN ファイルとダイアグラムのビュー

DMN デザイナーの左上隅で、Project Explorer ビューを選択して、全 DMN と他のファイルを移動するか、Decision Navigator ビューを選択して、選択した DRD のデシジョンコンポーネント、グラフ、ボックス式の間を移動します。

図6.60 Project Explorer のビュー

dmn designer project view

図6.61 Decision Navigator のビュー

dmn designer nav view
dmn designer nav view2
注記

DMN ファイルに含まれる DMN モデルからの DRD コンポーネント (Included Models タブ) は、DMN ファイルの Decision Components パネルにも表示されます。

DMN デザイナーの右上隅で、Explore diagram アイコンを選択して、選択した DRD で俯瞰プレビューを表示して、選択した DRD のノード間を移動します。

図6.62 Exploer Diagram ビュー

dmn designer preview
DRD プロパティーと設計

DMN デザイナーの右上隅で、Properties アイコンを選択して、情報、データ型、選択した DRD、DRD ノード、またはボックス式セルの外観を変更できます。

図6.63 DRD ノードのプロパティー

dmn designer properties

全 DRD のプロパティーを表示するには、特定のノードではなく、DRD キャンバスの背景をクリックします。

DRD 検索

DMN デザイナーの右上隅にある検索バーを使用して、DRD に表示されるテキストを検索します。検索機能は、特にノードが多数指定された複雑な DRD に有用です。

図6.64 DRD 検索

dmn designer search
DMN デシジョンサービスの詳細

DMN デザイナーで意思決定サービスノードを選択して、Properties パネルの Input DataEncapsulated DecisionsOutput Decisions などの追加のプロパティーを表示します。

図6.65 デシジョンサービスの詳細

DMN デシジョンサービスの詳細

第7章 DMN モデルの実行

Business Central を使用して Red Hat Process Automation Manager のプロジェクトに DMN ファイルをインポートまたは作成するか、Business Central を使用しないプロジェクトのナレッジ JAR (KJAR) ファイルの一部として DMN ファイルをパッケージ化できます。Red Hat Process Automation Manager プロジェクトに DMN ファイルを実装した後に、KIE Server にこのファイルを含む KIE コンテナーをデプロイしてリモートアクセスするか、呼び出すアプリケーションの依存関係として KIE コンテナーを直接操作することで、DMN デシジョンサービスを実行できます。DMN ナレッジパッケージを作成しデプロイするその他のオプションも利用できますが、そのほとんどはナレッジアセットの全タイプ (DRL ファイルやプロセス定義など) と類似しています。

プロジェクトのパッケージングおよびデプロイメントの方法に外部 DMN アセットを含める方法は、『Red Hat Process Automation Manager プロジェクトのパッケージ化およびデプロイ』を参照してください。

7.1. DMN コールの Java アプリケーションへの直接組み込み

KIE コンテナーは、呼び出しプログラムにナレッジアセットを直接組み込む場合や、KJAR 用 Maven 依存関係を使用して物理的にプルする場合は、ローカルとみなされます。コードのバージョンと、DML 定義のバージョンとの間に密接な関係がある場合は、通常、ナレッジアセットをプロジェクトに直接組み込みます。意思決定への変更は、アプリケーションをアップデートして再デプロイしないと有効になりません。このアプローチに対する利点は、適切なオペレーションがランタイムへの外部の依存関係に依存していないことですが、ロックされた環境の場合は制限になる可能性があります。

Maven の依存関係を使用すると、システムプロパティーを使用して、アップデートを定期的にスキャンして自動的にアップデートするなど、特定バージョンの意思決定が動的に変更するため、柔軟性が高まります。これにより、外部の依存関係がサービスのデプロイ時間に影響を及ぼしますが、意思決定はローカルで実行されるため、ランタイム時に利用可能な外部サービスに対する信頼が低くなります。

前提条件

  • KJAR アーティファクトとして DMN プロジェクトをビルドして Maven リポジトリーにデプロイするか、プロジェクトクラスパスの一部として DMN アセットを追加している。理想的には、より効率的な実行ができるように、実行可能なモデルとして DMN プロジェクトをビルドしておいてください。

    mvn clean install -DgenerateDMNModel=yes

    プロジェクトのパッケージ化およびデプロイメント、および実行可能モデルに関する詳細は、『Red Hat Process Automation Manager プロジェクトのパッケージ化およびデプロイ』を参照してください。

手順

  1. クライアントアプリケーションで、Java プロジェクトの関連クラスパスに以下の依存関係を追加します。

    <!-- Required for the DMN runtime API -->
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-dmn-core</artifactId>
      <version>${rhpam.version}</version>
    </dependency>
    
    <!-- Required if not using classpath KIE container -->
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-ci</artifactId>
      <version>${rhpam.version}</version>
    </dependency>

    <version> は、プロジェクトで現在使用している Red Hat Process Automation Manager の Maven アーティファクトバージョンです (例: 7.48.0.Final-redhat-00004)。

    注記

    個別の依存関係に対して Red Hat Process Automation Manager <version> を指定するのではなく、Red Hat Business Automation BOM (bill of materials) の依存関係をプロジェクトの pom.xml ファイルに追加することを検討してください。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.10.0.redhat-00004</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>

    Red Hat Business Automation BOM (Bill of Materials) についての詳細情報は、「What is the mapping between RHPAM product and maven library version?」 を参照してください。

  2. classpath または 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. namespace モデルおよび modelName モデルを使用して、KIE コンテナーの DMNRuntime と、評価する DMN モデルへの参照を取得します。

    DMNRuntime dmnRuntime = KieRuntimeFactory.of(kieContainer.getKieBase()).get(DMNRuntime.class);
    
    String namespace = "http://www.redhat.com/_c7328033-c355-43cd-b616-0aceef80e52a";
    String modelName = "dmn-movieticket-ageclassification";
    
    DMNModel dmnModel = dmnRuntime.getModel(namespace, modelName);
  4. 希望するモデルに対してデシジョンサービスを実行します。

    DMNContext dmnContext = dmnRuntime.newContext();  1
    
    for (Integer age : Arrays.asList(1,12,13,64,65,66)) {
        dmnContext.set("Age", age);  2
        DMNResult dmnResult =
            dmnRuntime.evaluateAll(dmnModel, dmnContext);  3
    
        for (DMNDecisionResult dr : dmnResult.getDecisionResults()) {  4
            log.info("Age: " + age + ", " +
                     "Decision: '" + dr.getDecisionName() + "', " +
                     "Result: " + dr.getResult());
      }
    }
    1
    モデル評価に対する入力として使用する、新しい DMN コンテキストをインスタンス化します。この例では、Age Classification の意思決定を複数回ループさせています。
    2
    入力の DMN コンテキストに入力変数を割り当てます。
    3
    DMN モデルに定義した DMN デシジョンをすべて評価します。
    4
    1 回の評価で結果が 1 つ以上になることがあり、ループを作成します。

    この例では、以下の結果を出力します。

    Age 1 Decision 'AgeClassification' : Child
    Age 12 Decision 'AgeClassification' : Child
    Age 13 Decision 'AgeClassification' : Adult
    Age 64 Decision 'AgeClassification' : Adult
    Age 65 Decision 'AgeClassification' : Senior
    Age 66 Decision 'AgeClassification' : Senior

    DMN モデルがより効率性の高い実行を行えるように、実行可能なモデルとしてこれまでにコンパイルされていない場合は、DMN モデルの実行時に、以下のプロパティーを有効化してください。

    -Dorg.kie.dmn.compiler.execmodel=true

7.2. KIE Server Java クライアント API を使った DMN サービスの実行

KIE Server Java クライアント API は、KIE Server の REST または JMS インターフェースを通してリモートの DMN サービスを呼び出す軽量なアプローチを提供します。これにより、KIE ベースと相互に作用するのに必要なランタイムの依存関係の数が減ります。これを有効にして適切なペースで個別に相互作用するようにし、意思決定の定義から呼び出しコードを切り離すと、柔軟性が上がります。

KIE Server Java クライアント API の詳細は、「KIE API を使用した Red Hat Process Automation Manager の操作」を参照してください。

前提条件

  • KIE Server がインストールされ、設定されている (kie-server ロールが割り当てられているユーザーの既知のユーザー名と認証情報を含む)。インストールオプションは、『Red Hat Process Automation Manager インストールの計画』を参照してください。
  • KJAR アーティファクトとして DMN プロジェクトをビルドして、KIE Server にデプロイしておく。理想的には、より効率的な実行ができるように、実行可能なモデルとして DMN プロジェクトをビルドしておいてください。

    mvn clean install -DgenerateDMNModel=yes

    プロジェクトのパッケージ化およびデプロイメント、および実行可能モデルに関する詳細は、『Red Hat Process Automation Manager プロジェクトのパッケージ化およびデプロイ』を参照してください。

  • KIE コンテナーの ID にDMN モデルを含んでいる。1 つ以上のモデルが存在する場合は、そのモデルの名前空間およびモデル名が必要です。

手順

  1. クライアントアプリケーションで、Java プロジェクトの関連クラスパスに以下の依存関係を追加します。

    <!-- Required for the KIE Server Java client API -->
    <dependency>
      <groupId>org.kie.server</groupId>
      <artifactId>kie-server-client</artifactId>
      <version>${rhpam.version}</version>
    </dependency>

    <version> は、プロジェクトで現在使用している Red Hat Process Automation Manager の Maven アーティファクトバージョンです (例: 7.48.0.Final-redhat-00004)。

    注記

    個別の依存関係に対して Red Hat Process Automation Manager <version> を指定するのではなく、Red Hat Business Automation BOM (bill of materials) の依存関係をプロジェクトの pom.xml ファイルに追加することを検討してください。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.10.0.redhat-00004</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>

    Red Hat Business Automation BOM (Bill of Materials) についての詳細情報は、「What is the mapping between RHPAM product and maven library version?」 を参照してください。

  2. 適切な接続情報で KieServicesClient をインスタンス化します。

    例:

    KieServicesConfiguration conf =
        KieServicesFactory.newRestConfiguration(URL, USER, PASSWORD); 1
    
    conf.setMarshallingFormat(MarshallingFormat.JSON);  2
    
    KieServicesClient kieServicesClient = KieServicesFactory.newKieServicesClient(conf);
    1
    接続情報:
    • サンプル URL: http://localhost:8080/kie-server/services/rest/server
    • この認証情報は、kie-server ロールを持つユーザーを参照します。
    2
    マーシャリングの形式は、org.kie.server.api.marshalling.MarshallingFormat のインスタンスです。これは、メッセージが JSON であるか XML であるかを制御します。マーシャリング形式のオプションは、JSON、JAXB、 XSTREAM です。
  3. KIE サーバーの Java クライアントインスタンスで getServicesClient() メソッドを呼び出すことで、関連する KIE Server に接続した KIE サーバーの Java クライアントから DMNServicesClient を取得します。

    DMNServicesClient dmnClient = kieServicesClient.getServicesClient(DMNServicesClient.class );

    これで、dmnClient が、KIE Server でデシジョンサービスを実行できるようになりました。

  4. 希望するモデルに対してデシジョンサービスを実行します。

    例:

    for (Integer age : Arrays.asList(1,12,13,64,65,66)) {
        DMNContext dmnContext = dmnClient.newContext(); 1
        dmnContext.set("Age", age);  2
        ServiceResponse<DMNResult> serverResp =   3
            dmnClient.evaluateAll($kieContainerId,
                                  $modelNamespace,
                                  $modelName,
                                  dmnContext);
    
        DMNResult dmnResult = serverResp.getResult();  4
        for (DMNDecisionResult dr : dmnResult.getDecisionResults()) {
            log.info("Age: " + age + ", " +
                     "Decision: '" + dr.getDecisionName() + "', " +
                     "Result: " + dr.getResult());
        }
    }
    1
    モデル評価に対する入力として使用する、新しい DMN コンテキストをインスタンス化します。この例では、Age Classification の意思決定を複数回ループさせています。
    2
    入力 DMN コンテキストに入力変数を割り当てます。
    3
    DMN モデルに定義したすべての DMN の意思決定を評価します。
    • $kieContainerId は、DMN モデルを含む KJAR がデプロイされているコンテナーの ID です。
    • $modelNamespace は、モデルの名前空間です。
    • $modelName は、モデルの名前です。
    4
    DMN の結果オブジェクトは、サーバーの応答から利用できます。

    この時点では、dmnResult には、評価した DMN モデルから得た意思決定の結果がすべて含まれます。

    DMNServicesClient で利用可能なメソッドを使用して、モデルで特定の DMN 意思決定だけを実行することもできます。

    注記

    KIE コンテナーに DMN モデルが 1 つだけ含まれる場合は、KIE Server API によってデフォルトで選択されるため、$modelNamespace$modelName を除外できます。

7.3. KIE Server REST API を使った DMN サービスの実行

KIE Server の REST エンドポイントで直接対話することで、呼び出しコードと、意思決定ロジックの定義の分離が最大になります。呼び出しコードに直接の依存関係がないため、Node.js.NET など、完全に異なる開発プラットフォームに実装できます。このセクションの例では、Nix スタイルの curl コマンドを示しますが、REST クライアントに適用するための関連情報を提供します。

KIE Server REST API の詳細は、「KIE API を使用した Red Hat Process Automation Manager の操作」を参照してください。

前提条件

  • KIE Server がインストールされ、設定されている (kie-server ロールが割り当てられているユーザーの既知のユーザー名と認証情報を含む)。インストールオプションは、『Red Hat Process Automation Manager インストールの計画』を参照してください。
  • KJAR アーティファクトとして DMN プロジェクトをビルドして、KIE Server にデプロイしておく。理想的には、より効率的な実行ができるように、実行可能なモデルとして DMN プロジェクトをビルドしておいてください。

    mvn clean install -DgenerateDMNModel=yes

    プロジェクトのパッケージ化およびデプロイメント、および実行可能モデルに関する詳細は、『Red Hat Process Automation Manager プロジェクトのパッケージ化およびデプロイ』を参照してください。

  • KIE コンテナーの ID にDMN モデルを含んでいる。1 つ以上のモデルが存在する場合は、そのモデルの名前空間およびモデル名が必要です。

手順

  1. KIE Server REST API エンドポイントにアクセスするためのベース URL を決定します。これには、以下の値が必要です (例ではローカルデプロイメントのデフォルト値を使用しています)。

    • ホスト (localhost)
    • ポート (8080)
    • ルートコンテキスト (kie-server)
    • ベース REST パス (services/rest/)

    ローカルデプロイメントにおけるベース URL の例:

    http://localhost:8080/kie-server/services/rest/

  2. ユーザー認証要件を決定します。

    ユーザーを KIE Server 設定に直接定義すると、ユーザー名およびパスワードを要求する HTTP Basic 認証が使用されます。要求を成功させるには、ユーザーに kie-server ルールが必要です。

    以下の例は、curl 要求に認証情報を追加する方法を示します。

    curl -u username:password <request>

    Red Hat Single Sign-On を使用して KIE Server を設定している場合は、要求にベアラートークンが必要です。

    curl -H "Authorization: bearer $TOKEN" <request>
  3. 要求と応答の形式を指定します。REST API エンドポイントには JSON と XML の両方の書式が利用でき、要求ヘッダーを使用して設定されます。

    JSON

    curl -H "accept: application/json" -H "content-type: application/json"

    XML

    curl -H "accept: application/xml" -H "content-type: application/xml"

  4. 必要に応じて、デプロイしたデシジョンモデルのリストに対するコンテナーのクエリーです。

    [GET] server/containers/{containerId}/dmn

    curl 要求例:

    curl -u krisv:krisv -H "accept: application/xml" -X GET "http://localhost:8080/kie-server/services/rest/server/containers/MovieDMNContainer/dmn"

    サンプルの XML 出力:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <response type="SUCCESS" msg="OK models successfully retrieved from container 'MovieDMNContainer'">
        <dmn-model-info-list>
            <model>
                <model-namespace>http://www.redhat.com/_c7328033-c355-43cd-b616-0aceef80e52a</model-namespace>
                <model-name>dmn-movieticket-ageclassification</model-name>
                <model-id>_99</model-id>
                <decisions>
                    <dmn-decision-info>
                        <decision-id>_3</decision-id>
                        <decision-name>AgeClassification</decision-name>
                    </dmn-decision-info>
                </decisions>
            </model>
        </dmn-model-info-list>
    </response>

    サンプルの JSON 出力:

    {
      "type" : "SUCCESS",
      "msg" : "OK models successfully retrieved from container 'MovieDMNContainer'",
      "result" : {
        "dmn-model-info-list" : {
          "models" : [ {
            "model-namespace" : "http://www.redhat.com/_c7328033-c355-43cd-b616-0aceef80e52a",
            "model-name" : "dmn-movieticket-ageclassification",
            "model-id" : "_99",
            "decisions" : [ {
              "decision-id" : "_3",
              "decision-name" : "AgeClassification"
            } ]
          } ]
        }
      }
    }
  5. モデルを実行します。

    [POST] server/containers/{containerId}/dmn

    curl 要求例:

    curl -u krisv:krisv -H "accept: application/json" -H "content-type: application/json" -X POST "http://localhost:8080/kie-server/services/rest/server/containers/MovieDMNContainer/dmn" -d "{ \"model-namespace\" : \"http://www.redhat.com/_c7328033-c355-43cd-b616-0aceef80e52a\", \"model-name\" : \"dmn-movieticket-ageclassification\", \"decision-name\" : [ ], \"decision-id\" : [ ], \"dmn-context\" : {\"Age\" : 66}}"

    JSON 要求例:

    {
      "model-namespace" : "http://www.redhat.com/_c7328033-c355-43cd-b616-0aceef80e52a",
      "model-name" : "dmn-movieticket-ageclassification",
      "decision-name" : [ ],
      "decision-id" : [ ],
      "dmn-context" : {"Age" : 66}
    }

    XML 要求例 (JAXB 形式):

    <?xml version="1.0" encoding="UTF-8"?>
    <dmn-evaluation-context>
        <model-namespace>http://www.redhat.com/_c7328033-c355-43cd-b616-0aceef80e52a</model-namespace>
        <model-name>dmn-movieticket-ageclassification</model-name>
        <dmn-context xsi:type="jaxbListWrapper" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <type>MAP</type>
            <element xsi:type="jaxbStringObjectPair" key="Age">
                <value xsi:type="xs:int" xmlns:xs="http://www.w3.org/2001/XMLSchema">66</value>
            </element>
        </dmn-context>
    </dmn-evaluation-context>
    注記

    要求には、その形式にかかわらず、以下の要素が必要です。

    • モデルの名前空間
    • モデル名
    • 入力値を含むコンテキストオブジェクト

    JSON 応答例:

    {
      "type" : "SUCCESS",
      "msg" : "OK from container 'MovieDMNContainer'",
      "result" : {
        "dmn-evaluation-result" : {
          "messages" : [ ],
          "model-namespace" : "http://www.redhat.com/_c7328033-c355-43cd-b616-0aceef80e52a",
          "model-name" : "dmn-movieticket-ageclassification",
          "decision-name" : [ ],
          "dmn-context" : {
            "Age" : 66,
            "AgeClassification" : "Senior"
          },
          "decision-results" : {
            "_3" : {
              "messages" : [ ],
              "decision-id" : "_3",
              "decision-name" : "AgeClassification",
              "result" : "Senior",
              "status" : "SUCCEEDED"
            }
          }
        }
      }
    }

    XML (JAXB 形式) 応答例:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <response type="SUCCESS" msg="OK from container 'MovieDMNContainer'">
          <dmn-evaluation-result>
                <model-namespace>http://www.redhat.com/_c7328033-c355-43cd-b616-0aceef80e52a</model-namespace>
                <model-name>dmn-movieticket-ageclassification</model-name>
                <dmn-context xsi:type="jaxbListWrapper" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                      <type>MAP</type>
                      <element xsi:type="jaxbStringObjectPair" key="Age">
                            <value xsi:type="xs:int" xmlns:xs="http://www.w3.org/2001/XMLSchema">66</value>
                      </element>
                      <element xsi:type="jaxbStringObjectPair" key="AgeClassification">
                            <value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">Senior</value>
                      </element>
                </dmn-context>
                <messages/>
                <decisionResults>
                      <entry>
                            <key>_3</key>
                            <value>
                                  <decision-id>_3</decision-id>
                                  <decision-name>AgeClassification</decision-name>
                                  <result xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Senior</result>
                                  <messages/>
                                  <status>SUCCEEDED</status>
                            </value>
                      </entry>
                </decisionResults>
          </dmn-evaluation-result>
    </response>

第8章 関連資料

パート II. PMML モデルでのデシジョンサービスの作成

ビジネスルール開発者は、Predictive Model Markup Language (PMML) を使用して統計またはデータマイニングモデルを定義し、Red Hat Process Automation Manager のデシジョンサービスと統合できます。Red Hat Process Automation Manager には、回帰、スコアカード、ツリー、マイニングモデル向けの PMML 4.2.1 のコンシューマー適合サポートが含まれます。Red Hat Process Automation Manager には、PMML モデルエディターが同梱されていませんが、XML または PMML 固有のオーサリングツールを使用して、PMML モデルを作成してから Red Hat Process Automation Manager プロジェクトに統合できます。

PMML に関する詳細は、DMG の「PMML 仕様」を参照してください。

注記

Decision Model and Notation (DMN) モデルを使用して独自のデシジョンサービスを設計し、DMN サービスの一部として PMML モデルを追加することもできます。Red Hat Process Automation Manager 7.10 の DMN サポートに関する詳細は、以下の資料を参照してください。

第9章 Red Hat Process Automation Manager におけるデシジョン作成アセット

Red Hat Process Automation Manager は、デシジョンサービスにビジネスデシジョンを定義するのに使用可能なアセットを複数サポートします。デシジョン作成アセットはそれぞれ長所が異なるため、目的やニーズに合わせて、アセットを 1 つ、または複数を組み合わせて使用できます。

以下の表では、デシジョンサービスでデシジョンを定義する最適な方法を選択できるように、Red Hat Process Automation Manager プロジェクトでサポートされている主要なデシジョン作成アセットを紹介します。

表9.1 Red Hat Process Automation Manager でサポートされるデシジョン作成アセット

アセット主な特徴オーサリングツールドキュメント

DMN (Decision Model and Notation) モデル

  • Object Management Group (OMG) が定義する標準記法をもとにしたデシジョンモデルである
  • 一部またはすべての意思決定要件グラフ (DRG: Decision Requirements Graph) を表すグラフィカルな意思決定要件ダイアグラム (DRD: Decision Requirements Diagram) を使用してビジネスデシジョンのフローを追跡する
  • DMN モデルが DMN 準拠プラットフォーム間で共有できるようにする XML スキーマを使用する
  • DMN デシジョンテーブルおよび他の DMN ボックス式表現 (Boxed Expression) でデシジョンロジックを定義する Friendly Enough Expression Language (FEEL) をサポートする
  • Business Process Model and Notation (BPMN) プロセスモデルと効率的に統合できる
  • 包括性、具体性、および安定性のある意思決定フローの作成に最適である

Business Central または DMN 準拠のエディター

『DMN モデルを使用したデシジョンサービスの作成』

ガイド付きデシジョンテーブル

  • Business Central の UI ベースのテーブルデザイナーで作成するルールのテーブルである
  • デシジョンテーブルにスプレッドシートで対応する代わりにウィザードで対応する
  • 条件を満たした入力に、フィールドとオプションを提供する
  • ルールテンプレートを作成するテンプレートキーと値をサポートする
  • その他のアセットではサポートされていないヒットポリシー、リアルタイム検証などの追加機能をサポートする
  • コンパイルエラーを最小限に抑えるため、制限されているテーブル形式でルールを作成するのに最適である

Business Central

「ガイド付きデシジョンテーブルを使用したデシジョンサービスの作成」

スプレッドシートのデシジョンテーブル

  • Business Central にアップロード可能な XLS または XLSX スプレッドシート形式のデシジョンテーブルである
  • ルールテンプレートを作成するテンプレートキーと値をサポートする
  • Business Central 外で管理しているデシジョンテーブルでルールを作成するのに最適である
  • アップロード時に適切にルールをコンパイルするために厳密な構文要件がある

スプレッドシートエディター

「スプレッドシート形式のデシジョンテーブルを使用したデシジョンサービスの作成」

ガイド付きルール

  • Business Central の UI ベースのルールデザイナーで作成する個々のルールである
  • 条件を満たした入力に、フィールドとオプションを提供する
  • コンパイルエラーを最小限に抑えるため、制御されている形式で単独のルールを作成するのに最適である

Business Central

「ガイド付きルールを使用したデシジョンサービスの作成」

ガイド付きルールテンプレート

  • Business Central の UI ベースのテンプレートデザイナーで作成する再利用可能なルール構造である
  • 条件を満たした入力に、フィールドとオプションを提供する
  • (このアセットの目的の基本となる) ルールテンプレートを作成するテンプレートのキーと値をサポートする
  • ルール構造が同じで、定義したフィールド値が異なるルールを多数作成するのに最適である

Business Central

「ガイド付きルールテンプレートを使用したデシジョンサービスの作成」

DRL ルール

  • .drl テキストファイルに直接定義する個々のルールである
  • 最も柔軟性が高く、ルールと、ルール動作に関するその他の技術を定義できる
  • スタンドアロン環境で作成し、Red Hat Process Automation Manager に統合可能
  • 詳細な DRL オプションを必要とするルールを作成するのに最適である
  • ルールを適切にコンパイルするための厳密な構文要件がある

Business Central または統合開発環境 (IDE)

「DRL ルールを使用したデシジョンサービスの作成」

予測モデルマークアップ言語 (PMML: Predictive Model Markup Language) モデル

  • Data Mining Group (DMG) が定義する標準記法に基づく予測データ分析モデルである
  • PMML モデルを PMML 準拠プラットフォーム間で共有できるようにする XML スキーマを使用する
  • 回帰、スコアカード、ツリー、マイニングなどのモデルタイプをサポートする
  • スタンドアロンの Red Hat Process Automation Manager プロジェクトに追加したり、Business Central のプロジェクトにインポートしたりできる
  • Red Hat Process Automation Manager のデシジョンサービスに予測データを統合するのに最適である

PMML または XML エディター

『PMML モデルでのデシジョンサービスの作成』

第10章 Predictive Model Markup Language (PMML)

Predictive Model Markup Language (PMML) は、統計およびデータマイニングモデルの定義用に、Data Miningu Group (DMG) が確立した XML ベースの標準です。PMML モデルは、ビジネスアナリストや開発者が一元的に PMML ベースのアセットやサービスを設計、分析、実装するために、PMML 準拠のプラットフォーム間や組織全体で共有することができます。

PMML の背景およびアプリケーションに関する詳細は、DMG の「PMML 仕様」を参照してください。

10.1. PMML 適合レベル

PMML 仕様は、PMML モデルが確実に作成および統合されるように、ソフトウェア実装におけるプロデューサーおよびコンシューマーの適合レベルを定義します。各適合レベルの正式な定義については、DMG の PMML 適合 のページを参照してください。

以下の一覧では、PMML 適合レベルをまとめています。

プロデューサーの適合
ツールまたはアプリケーションは、少なくとも 1 種類のモデルに対して有効な PMML ドキュメントが生成されている場合に、プロデューサーの適合があるとされます。PMML のプロデューサー適合要件を満たすことで、モデル定義のドキュメントが構文的に正しく、このドキュメントで定義したモデルインスタンスが、モデル仕様に定義されている意味論の基準と整合性を保てるようにします。
コンシューマーの適合
ツールまたはアプリケーションは、少なくとも 1 種類のモデルに対して有効な PMML ドキュメントが生成されている場合に、コンシューマーの適合があるとされます。コンシューマー適合要件を満たすことで、プロデューサー適合にあわせて作成された PMML モデルが定義どおりに統合され、使用できるようにします。たとえば、アプリケーションが回帰モデルタイプに適合しているコンシューマーである場合は、有効な PMML ドキュメントで、別の適合プロデューサーにより作成されたこのタイプのモデルを定義していれば、アプリケーション内でどちらでも使用できます。

Red Hat Process Automation Manager には、以下の PMML 4.2.1 モデルタイプに対するコンシューマー適合サポートが含まれます。

Red Hat Process Automation Manager でサポートされていないモデルを含め、すべての PMML モデルタイプの一覧は、DMG の PMML specification を参照してください。

第11章 PMML モデルの例

PMML は、XML スキーマ を定義しており、このスキーマを使用することで、PMML モデルが異なる PMML 準拠のプラットフォーム間で使用できるようになります。PMML 仕様では、プロデューサーとコンシューマー適合を満たしていることが前提で、複数のソフトウェアプラットフォームが同じファイルを使用してオーサリング、テスト、および実稼働環境での実行を可能にします。

以下は、PMM の回帰、スコアカード、ツリー、マイニングモデルの例です。これらの例では、Red Hat Process Automation Manager のデシジョンサービスと統合可能なモデルでサポートされているタイプを紹介します。

PMML の詳細例は、DMG の「PMML Sample Files」ページを参照してください。

PMML 回帰モデルの例

<PMML version="4.2" xsi:schemaLocation="http://www.dmg.org/PMML-4_2 http://www.dmg.org/v4-2-1/pmml-4-2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.dmg.org/PMML-4_2">
  <Header copyright="JBoss"/>
  <DataDictionary numberOfFields="5">
    <DataField dataType="double" name="fld1" optype="continuous"/>
    <DataField dataType="double" name="fld2" optype="continuous"/>
    <DataField dataType="string" name="fld3" optype="categorical">
      <Value value="x"/>
      <Value value="y"/>
    </DataField>
    <DataField dataType="double" name="fld4" optype="continuous"/>
    <DataField dataType="double" name="fld5" optype="continuous"/>
  </DataDictionary>
  <RegressionModel algorithmName="linearRegression" functionName="regression" modelName="LinReg" normalizationMethod="logit" targetFieldName="fld4">
    <MiningSchema>
      <MiningField name="fld1"/>
      <MiningField name="fld2"/>
      <MiningField name="fld3"/>
      <MiningField name="fld4" usageType="predicted"/>
      <MiningField name="fld5" usageType="target"/>
    </MiningSchema>
    <RegressionTable intercept="0.5">
      <NumericPredictor coefficient="5" exponent="2" name="fld1"/>
      <NumericPredictor coefficient="2" exponent="1" name="fld2"/>
      <CategoricalPredictor coefficient="-3" name="fld3" value="x"/>
      <CategoricalPredictor coefficient="3" name="fld3" value="y"/>
      <PredictorTerm coefficient="0.4">
        <FieldRef field="fld1"/>
        <FieldRef field="fld2"/>
      </PredictorTerm>
    </RegressionTable>
  </RegressionModel>
</PMML>

PMML スコアカードモデルの例

<PMML version="4.2" xsi:schemaLocation="http://www.dmg.org/PMML-4_2 http://www.dmg.org/v4-2-1/pmml-4-2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.dmg.org/PMML-4_2">
  <Header copyright="JBoss"/>
  <DataDictionary numberOfFields="4">
    <DataField name="param1" optype="continuous" dataType="double"/>
    <DataField name="param2" optype="continuous" dataType="double"/>
    <DataField name="overallScore" optype="continuous" dataType="double" />
    <DataField name="finalscore" optype="continuous" dataType="double" />
  </DataDictionary>
  <Scorecard modelName="ScorecardCompoundPredicate" useReasonCodes="true" isScorable="true" functionName="regression"    baselineScore="15" initialScore="0.8" reasonCodeAlgorithm="pointsAbove">
    <MiningSchema>
      <MiningField name="param1" usageType="active" invalidValueTreatment="asMissing">
      </MiningField>
      <MiningField name="param2" usageType="active" invalidValueTreatment="asMissing">
      </MiningField>
      <MiningField name="overallScore" usageType="target"/>
      <MiningField name="finalscore" usageType="predicted"/>
    </MiningSchema>
    <Characteristics>
      <Characteristic name="ch1" baselineScore="50" reasonCode="reasonCh1">
        <Attribute partialScore="20">
          <SimplePredicate field="param1" operator="lessThan" value="20"/>
        </Attribute>
        <Attribute partialScore="100">
          <CompoundPredicate booleanOperator="and">
            <SimplePredicate field="param1" operator="greaterOrEqual" value="20"/>
            <SimplePredicate field="param2" operator="lessOrEqual" value="25"/>
          </CompoundPredicate>
        </Attribute>
        <Attribute partialScore="200">
          <CompoundPredicate booleanOperator="and">
            <SimplePredicate field="param1" operator="greaterOrEqual" value="20"/>
            <SimplePredicate field="param2" operator="greaterThan" value="25"/>
          </CompoundPredicate>
        </Attribute>
      </Characteristic>
      <Characteristic name="ch2" reasonCode="reasonCh2">
        <Attribute partialScore="10">
          <CompoundPredicate booleanOperator="or">
            <SimplePredicate field="param2" operator="lessOrEqual" value="-5"/>
            <SimplePredicate field="param2" operator="greaterOrEqual" value="50"/>
          </CompoundPredicate>
        </Attribute>
        <Attribute partialScore="20">
          <CompoundPredicate booleanOperator="and">
            <SimplePredicate field="param2" operator="greaterThan" value="-5"/>
            <SimplePredicate field="param2" operator="lessThan" value="50"/>
          </CompoundPredicate>
        </Attribute>
      </Characteristic>
    </Characteristics>
  </Scorecard>
</PMML>

PMML ツリーモデルの例

<PMML version="4.2" xsi:schemaLocation="http://www.dmg.org/PMML-4_2 http://www.dmg.org/v4-2-1/pmml-4-2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.dmg.org/PMML-4_2">
  <Header copyright="JBOSS"/>
  <DataDictionary numberOfFields="5">
    <DataField dataType="double" name="fld1" optype="continuous"/>
    <DataField dataType="double" name="fld2" optype="continuous"/>
    <DataField dataType="string" name="fld3" optype="categorical">
      <Value value="true"/>
      <Value value="false"/>
    </DataField>
    <DataField dataType="string" name="fld4" optype="categorical">
      <Value value="optA"/>
      <Value value="optB"/>
      <Value value="optC"/>
    </DataField>
    <DataField dataType="string" name="fld5" optype="categorical">
      <Value value="tgtX"/>
      <Value value="tgtY"/>
      <Value value="tgtZ"/>
    </DataField>
  </DataDictionary>
  <TreeModel functionName="classification" modelName="TreeTest">
    <MiningSchema>
      <MiningField name="fld1"/>
      <MiningField name="fld2"/>
      <MiningField name="fld3"/>
      <MiningField name="fld4"/>
      <MiningField name="fld5" usageType="predicted"/>
    </MiningSchema>
    <Node score="tgtX">
      <True/>
      <Node score="tgtX">
        <SimplePredicate field="fld4" operator="equal" value="optA"/>
        <Node score="tgtX">
          <CompoundPredicate booleanOperator="surrogate">
            <SimplePredicate field="fld1" operator="lessThan" value="30.0"/>
            <SimplePredicate field="fld2" operator="greaterThan" value="20.0"/>
          </CompoundPredicate>
          <Node score="tgtX">
            <SimplePredicate field="fld2" operator="lessThan" value="40.0"/>
          </Node>
          <Node score="tgtZ">
            <SimplePredicate field="fld2" operator="greaterOrEqual" value="10.0"/>
          </Node>
        </Node>
        <Node score="tgtZ">
          <CompoundPredicate booleanOperator="or">
            <SimplePredicate field="fld1" operator="greaterOrEqual" value="60.0"/>
            <SimplePredicate field="fld1" operator="lessOrEqual" value="70.0"/>
          </CompoundPredicate>
          <Node score="tgtZ">
            <SimpleSetPredicate booleanOperator="isNotIn" field="fld4">
              <Array type="string">optA optB</Array>
            </SimpleSetPredicate>
          </Node>
        </Node>
      </Node>
      <Node score="tgtY">
        <CompoundPredicate booleanOperator="or">
          <SimplePredicate field="fld4" operator="equal" value="optA"/>
          <SimplePredicate field="fld4" operator="equal" value="optC"/>
        </CompoundPredicate>
        <Node score="tgtY">
          <CompoundPredicate booleanOperator="and">
            <SimplePredicate field="fld1" operator="greaterThan" value="10.0"/>
            <SimplePredicate field="fld1" operator="lessThan" value="50.0"/>
            <SimplePredicate field="fld4" operator="equal" value="optA"/>
            <SimplePredicate field="fld2" operator="lessThan" value="100.0"/>
            <SimplePredicate field="fld3" operator="equal" value="false"/>
          </CompoundPredicate>
        </Node>
        <Node score="tgtZ">
          <CompoundPredicate booleanOperator="and">
            <SimplePredicate field="fld4" operator="equal" value="optC"/>
            <SimplePredicate field="fld2" operator="lessThan" value="30.0"/>
          </CompoundPredicate>
        </Node>
      </Node>
    </Node>
  </TreeModel>
</PMML>

PMML マイニングモデルの例 (modelChain)

<PMML version="4.2" xsi:schemaLocation="http://www.dmg.org/PMML-4_2 http://www.dmg.org/v4-2-1/pmml-4-2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://www.dmg.org/PMML-4_2">
  <Header>
    <Application name="Drools-PMML" version="7.0.0-SNAPSHOT" />
  </Header>
  <DataDictionary numberOfFields="7">
    <DataField name="age" optype="continuous" dataType="double" />
    <DataField name="occupation" optype="categorical" dataType="string">
      <Value value="SKYDIVER" />
      <Value value="ASTRONAUT" />
      <Value value="PROGRAMMER" />
      <Value value="TEACHER" />
      <Value value="INSTRUCTOR" />
    </DataField>
    <DataField name="residenceState" optype="categorical" dataType="string">
      <Value value="AP" />
      <Value value="KN" />
      <Value value="TN" />
    </DataField>
    <DataField name="validLicense" optype="categorical" dataType="boolean" />
    <DataField name="overallScore" optype="continuous" dataType="double" />
    <DataField name="grade" optype="categorical" dataType="string">
      <Value value="A" />
      <Value value="B" />
      <Value value="C" />
      <Value value="D" />
      <Value value="F" />
    </DataField>
    <DataField name="qualificationLevel" optype="categorical" dataType="string">
      <Value value="Unqualified" />
      <Value value="Barely" />
      <Value value="Well" />
      <Value value="Over" />
    </DataField>
  </DataDictionary>
  <MiningModel modelName="SampleModelChainMine" functionName="classification">
    <MiningSchema>
      <MiningField name="age" />
      <MiningField name="occupation" />
      <MiningField name="residenceState" />
      <MiningField name="validLicense" />
      <MiningField name="overallScore" />
      <MiningField name="qualificationLevel" usageType="target"/>
    </MiningSchema>
    <Segmentation multipleModelMethod="modelChain">
      <Segment id="1">
        <True />
        <Scorecard modelName="Sample Score 1" useReasonCodes="true" isScorable="true" functionName="regression"               baselineScore="0.0" initialScore="0.345">
          <MiningSchema>
            <MiningField name="age" usageType="active" invalidValueTreatment="asMissing" />
            <MiningField name="occupation" usageType="active" invalidValueTreatment="asMissing" />
            <MiningField name="residenceState" usageType="active" invalidValueTreatment="asMissing" />
            <MiningField name="validLicense" usageType="active" invalidValueTreatment="asMissing" />
            <MiningField name="overallScore" usageType="predicted" />
          </MiningSchema>
          <Output>
            <OutputField name="calculatedScore" displayName="Final Score" dataType="double" feature="predictedValue"                     targetField="overallScore" />
          </Output>
          <Characteristics>
            <Characteristic name="AgeScore" baselineScore="0.0" reasonCode="ABZ">
              <Extension name="cellRef" value="$B$8" />
              <Attribute partialScore="10.0">
                <Extension name="cellRef" value="$C$10" />
                <SimplePredicate field="age" operator="lessOrEqual" value="5" />
              </Attribute>
              <Attribute partialScore="30.0" reasonCode="CX1">
                <Extension name="cellRef" value="$C$11" />
                <CompoundPredicate booleanOperator="and">
                  <SimplePredicate field="age" operator="greaterOrEqual" value="5" />
                  <SimplePredicate field="age" operator="lessThan" value="12" />
                </CompoundPredicate>
              </Attribute>
              <Attribute partialScore="40.0" reasonCode="CX2">
                <Extension name="cellRef" value="$C$12" />
                <CompoundPredicate booleanOperator="and">
                  <SimplePredicate field="age" operator="greaterOrEqual" value="13" />
                  <SimplePredicate field="age" operator="lessThan" value="44" />
                </CompoundPredicate>
              </Attribute>
              <Attribute partialScore="25.0">
                <Extension name="cellRef" value="$C$13" />
                <SimplePredicate field="age" operator="greaterOrEqual" value="45" />
              </Attribute>
            </Characteristic>
            <Characteristic name="OccupationScore" baselineScore="0.0">
              <Extension name="cellRef" value="$B$16" />
              <Attribute partialScore="-10.0" reasonCode="CX2">
                <Extension name="description" value="skydiving is a risky occupation" />
                <Extension name="cellRef" value="$C$18" />
                <SimpleSetPredicate field="occupation" booleanOperator="isIn">
                  <Array n="2" type="string">SKYDIVER ASTRONAUT</Array>
                </SimpleSetPredicate>
              </Attribute>
              <Attribute partialScore="10.0">
                <Extension name="cellRef" value="$C$19" />
                <SimpleSetPredicate field="occupation" booleanOperator="isIn">
                  <Array n="2" type="string">TEACHER INSTRUCTOR</Array>
                </SimpleSetPredicate>
              </Attribute>
              <Attribute partialScore="5.0">
                <Extension name="cellRef" value="$C$20" />
                <SimplePredicate field="occupation" operator="equal" value="PROGRAMMER" />
              </Attribute>
            </Characteristic>
            <Characteristic name="ResidenceStateScore" baselineScore="0.0" reasonCode="RES">
              <Extension name="cellRef" value="$B$22" />
              <Attribute partialScore="-10.0">
                <Extension name="cellRef" value="$C$24" />
                <SimplePredicate field="residenceState" operator="equal" value="AP" />
              </Attribute>
              <Attribute partialScore="10.0">
                <Extension name="cellRef" value="$C$25" />
                <SimplePredicate field="residenceState" operator="equal" value="KN" />
              </Attribute>
              <Attribute partialScore="5.0">
                <Extension name="cellRef" value="$C$26" />
                <SimplePredicate field="residenceState" operator="equal" value="TN" />
              </Attribute>
            </Characteristic>
            <Characteristic name="ValidLicenseScore" baselineScore="0.0">
              <Extension name="cellRef" value="$B$28" />
              <Attribute partialScore="1.0" reasonCode="LX00">
                <Extension name="cellRef" value="$C$30" />
                <SimplePredicate field="validLicense" operator="equal" value="true" />
              </Attribute>
              <Attribute partialScore="-1.0" reasonCode="LX00">
                <Extension name="cellRef" value="$C$31" />
                <SimplePredicate field="validLicense" operator="equal" value="false" />
              </Attribute>
            </Characteristic>
          </Characteristics>
        </Scorecard>
      </Segment>
      <Segment id="2">
        <True />
        <TreeModel modelName="SampleTree" functionName="classification" missingValueStrategy="lastPrediction" noTrueChildStrategy="returnLastPrediction">
          <MiningSchema>
            <MiningField name="age" usageType="active" />
            <MiningField name="validLicense" usageType="active" />
            <MiningField name="calculatedScore" usageType="active" />
            <MiningField name="qualificationLevel" usageType="predicted" />
          </MiningSchema>
          <Output>
            <OutputField name="qualification" displayName="Qualification Level" dataType="string" feature="predictedValue"                     targetField="qualificationLevel" />
          </Output>
          <Node score="Well" id="1">
            <True/>
            <Node score="Barely" id="2">
              <CompoundPredicate booleanOperator="and">
                <SimplePredicate field="age" operator="greaterOrEqual" value="16" />
                <SimplePredicate field="validLicense" operator="equal" value="true" />
              </CompoundPredicate>
              <Node score="Barely" id="3">
                <SimplePredicate field="calculatedScore" operator="lessOrEqual" value="50.0" />
              </Node>
              <Node score="Well" id="4">
                <CompoundPredicate booleanOperator="and">
                  <SimplePredicate field="calculatedScore" operator="greaterThan" value="50.0" />
                  <SimplePredicate field="calculatedScore" operator="lessOrEqual" value="60.0" />
                </CompoundPredicate>
              </Node>
              <Node score="Over" id="5">
                <SimplePredicate field="calculatedScore" operator="greaterThan" value="60.0" />
              </Node>
            </Node>
            <Node score="Unqualified" id="6">
              <CompoundPredicate booleanOperator="surrogate">
                <SimplePredicate field="age" operator="lessThan" value="16" />
                <SimplePredicate field="calculatedScore" operator="lessOrEqual" value="40.0" />
                <True />
              </CompoundPredicate>
            </Node>
          </Node>
        </TreeModel>
      </Segment>
    </Segmentation>
  </MiningModel>
</PMML>

第12章 Red Hat Process Automation Manager における PMML サポート

Red Hat Process Automation Manager には、以下の PMML 4.2.1 モデルタイプに対するコンシューマー適合サポートが含まれます。

Red Hat Process Automation Manager でサポートされていないモデルを含め、すべての PMML モデルタイプの一覧は、DMG の PMML specification を参照してください。

Red Hat Process Automation Manager には、PMML モデルエディターが同梱されていますが、XML または PMML 固有のオーサリングツールを使用して、Red Hat Process Automation Manager のデシジョンサービスで PMML モデルを作成して統合できます。Business Central (Menu → Design → Projects → Import Asset) でプロジェクトに PMML ファイルをインポートするか、Business Central なしにナレッジ JAR (KJAR) ファイルの一部として PMML ファイルをパッケージ化できます。

Red Hat Process Automation Manager でプロジェクトに PMML ファイルを追加する場合は複数のアセットが生成されます。PMML モデルのタイプごとに、異なるアセットのセットが生成されますが、すべての PMML モデルタイプは少なくとも以下のアセットセットを生成します。

  • PMML モデルに関連する全ルールを含む DRL ファイル
  • 少なくとも以下の Java クラス 2 つが含まれている。

    • モデルタイプのデフォルトオブエジェクトタイプとして使用するデータクラス
    • データソースとルール実行の管理に使用する RuleUnit クラス

PMML ファイルに root モデルとして MiningModel が含まれている場合は、これらのファイルごとに複数のインスタンスが生成されます。

プロジェクトのパッケージ化およびデプロイメントの方法に、PMML ファイルなどのアセットを追加する方法の詳細は、「Red Hat Process Automation Manager プロジェクトのパッケージ化およびデプロイ」を参照してください

12.1. Red Hat Process Automation Manager の PMML 命名規則

以下は、生成された PMML パッケージ、クラス、ルールの命名規則です。

  • PMML モデルファイルにパッケージ名が指定されていない場合は、"org.kie.pmml.pmml_4_2"+modelName の形式で、生成されたルールのモデル名に、デフォルトのパッケージ名 org.kie.pmml.pmml_4_2 がプリフィックスとして追加されます。
  • 生成された RuleUnit Java クラスのパッケージ名は、生成されたルールのパッケージ名と同じです。
  • 生成された RuleUnit Java クラスの名前は、RuleUnit にモデル名を追加して modelName+"RuleUnit" の形式で指定します。
  • PMML モデルにはそれぞれ、最低でも生成されたデータクラスが 1 つ含まれます。これらのクラスのパッケージ名は org.kie.pmml.pmml_4_2.model です。
  • 生成されたデータクラス名は、モデルタイプにより決まり、プリフィックスとしてモデル名を指定します。

    • 回帰モデル: modelName+"RegressionData" という名前のデータクラス 1 つ
    • スコアカードモデル: modelName+"ScoreCardData" という名前のデータクラス 1 つ
    • ツリーモデル: modelName+"TreeNode" という名前の 1 つ目のデータクラスと、modelName+"TreeToken" という名前の 2 つ目のデータクラス 2つ
    • マイニングモデル: modelName+"MiningModelData" という名前のデータクラス 1 つ
注記

マイニングモデルは、各セグメントに含まれるルールとクラスすべても生成します。

12.2. Red Hat Process Automation Manager における PMML 拡張

PMML 仕様は、PMML モデルのコンテンツを拡張する Extension 要素をサポートします。モデルの主要要素の最初と最後の子として、PMML モデル定義のほぼすべてのレベルで拡張を使用し、最大限に柔軟性をもたせることができます。PMML 拡張の詳細は DMG PMML の「Extension Mechanism」を参照してください。

Red Hat Process Automation Manager は、PMML 統合を最適化するために以下の追加の PMML 拡張をサポートします。

  • modelPackage: 生成されたルールと Java クラスのパッケージ名を指定します。PMML モデルファイルの Header セクションにこの拡張を追加します。
  • adapter: ルールの入出力データを含めるのに使用するコンストラクトタイプ (bean または trait) を指定します。PMML モデルファイルの MiningSchema または Output セクション (または両方) にこの拡張を挿入します。
  • externalClass: adapter 拡張と連携して使用し、MiningField または OutputField を定義します。この拡張には、MiningField または OutputField 要素名と一致する要素名のクラスが含まれます。

第13章 PMML モデルの実行

Business Central を使用して Red Hat Process Automation Manager に PMML ファイルをインポートする (Menu → Design → Projects → Import Asset) か、Business Central を使用しないでプロジェクトのナレッジ JAR (KJAR) ファイルの一部として DMN ファイルをパッケージ化できます。Red Hat Process Automation Manager プロジェクトに PMML ファイルに実装した後に、Java アプリケーションに直接 PMML 呼び出しを埋め込むか、設定済みの KIE Server に ApplyPmmlModelCommand コマンドを送信して、PMML ベースのデシジョンサービスを実行できます。

プロジェクトのパッケージ化およびデプロイメントの方法に PMML アセットを追加する方法の詳細は、「Red Hat Process Automation Manager プロジェクトのパッケージ化およびデプロイ」を参照してください。

注記

Business Central の Decision Model and Notation (DMN) サービスの一部として、PMML モデルを追加することもできます。DMN ファイルに PMML モデルを追加すると、その PMML モデルを DMN デシジョンノードまたはビジネスナレッジモデルノードのボックス関数式として呼び出すことができます。DMN サービスへの PMML モデルの追加に関する詳細は、「DMN モデルを使用したデシジョンサービスの作成」を参照してください。

13.1. PMML 呼び出しの Java アプリケーションへの直接組み込み

KIE コンテナーは、呼び出しプログラムにナレッジアセットを直接組み込む場合や、KJAR 用 Maven 依存関係を使用して物理的にプルする場合は、ローカルとみなされます。コードのバージョンと、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>

    <version> は、プロジェクトで現在使用している Red Hat Process Automation Manager の Maven アーティファクトバージョンです (例: 7.48.0.Final-redhat-00004)。

    重要

    従来の kie-pmml 依存関係は、Red Hat Process Automation Manager 7.10.0 で非推奨になり、将来の Red Hat Process Automation Manager リリースで kie-pmml-trusty 依存関係に置き換えられる予定です。

    注記

    個別の依存関係に対して Red Hat Process Automation Manager <version> を指定するのではなく、Red Hat Business Automation BOM (bill of materials) の依存関係をプロジェクトの pom.xml ファイルに追加することを検討してください。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.10.0.redhat-00004</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>

    Red Hat Business Automation BOM (Bill of Materials) についての詳細情報は、「What is the mapping between RHPAM product and maven library version?」 を参照してください。

  2. classpath または 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 メソッドに加え、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 オブジェクトをこれらのセッションに追加してから、run() メソッドへのパラメーターとして渡される RuleUnit をもとに、ルールを実行します。calculatePossiblePackageNamesgetStartingRuleUnit メソッドは、run() メソッドに渡される RuleUnit クラスの完全修飾名を決定します。

PMML モデル実行をスムーズに行うため、Red Hat Process Automation Manager でサポートされている PMML4ExecutionHelper クラスも使用できます。PMML ヘルパークラスに関する詳細は、「PMML 実行ヘルパークラス」を参照してください。

13.1.1. PMML 実行ヘルパークラス

Red Hat Process Automation Manager には、PMML モデル実行に必要な PMMLRequestData クラスの作成や RuleUnitExecutor クラスを使用したルールの実行をサポートする PMML4ExecutionHelper クラスがあります。

以下では、比較の目的で 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 クラスを構築するには、PMML4ExecutionHelperFactory クラスを使用して、PMML4ExecutionHelper の取得方法を決定します。

以下は、PMML4ExecutionHelper を構築するのに利用可能な PMML4ExecutionHelperFactory クラスメソッドです。

KIE ベースにある PMML アセット向けの PMML4ExecutionHelperFactory メソッド

PMML アセットがすでにコンパイルされており、既存の KIE ベースで使用されている場合には、これらのメソッドを使用します。

public static PMML4ExecutionHelper getExecutionHelper(String modelName, KieBase kbase)

public static PMML4ExecutionHelper getExecutionHelper(String modelName, KieBase kbase, boolean includeMiningDataSources)
プロジェクトクラスパスにある PMML アセット向けの PMML4ExecutionHelperFactory メソッド

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)
バイトアレイ形式の PMML アセット向けの PMML4ExecutionHelperFactory メソッド

PMML アセットがバイトアレイ形式の場合にこれらのメソッドを使用します。

public static PMML4ExecutionHelper getExecutionHelper(String modelName, byte[] content, KieBaseConfiguration kieBaseConf)

public static PMML4ExecutionHelper getExecutionHelper(String modelName, byte[] content, KieBaseConfiguration kieBaseConf, boolean includeMiningDataSources)
Resource にある PMML アセット向けの PMML4ExecutionHelperFactory メソッド

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)
注記

クラスパス、バイトアレイ、リソース PMML4ExecutionHelperFactory メソッドは、生成されたルールおよび Java クラスの KIE コンテナーを作成します。このコンテナーは、RuleUnitExecutor が使用する KIE ベースのソースとして使用します。ただし、このコンテナーには永続性はありません。PMML アセットの PMML4ExecutionHelperFactory メソッドが KIE ベースにすでにあるには、この方法では KIE コンテナーは作成されません。

13.2. KIE Server を使用した PMML モデルの実行

ApplyPmmlModelCommand コマンドを設定済みの KIE Server に送信して KIE Server にデプロイした PMML モデルを実行できます。このコマンドを使用する場合は、PMMLRequestData オブジェクトが KIE Server に送信され、PMML4Result の結果オブジェクトを返信として受信します。設定済みの Java クラスからの KIE Server REST API または、REST クライアントから直接 KIE Server に PMML 要求を送信できます。

前提条件

手順

  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 for the KIE Server Java client API -->
    <dependency>
      <groupId>org.kie.server</groupId>
      <artifactId>kie-server-client</artifactId>
      <version>${rhpam.version}</version>
    </dependency>
    
    <!-- Required if not using classpath KIE container -->
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-ci</artifactId>
      <version>${rhpam.version}</version>
    </dependency>

    <version> は、プロジェクトで現在使用している Red Hat Process Automation Manager の Maven アーティファクトバージョンです (例: 7.48.0.Final-redhat-00004)。

    重要

    従来の kie-pmml 依存関係は、Red Hat Process Automation Manager 7.10.0 で非推奨になり、将来の Red Hat Process Automation Manager リリースで kie-pmml-trusty 依存関係に置き換えられる予定です。

    注記

    個別の依存関係に対して Red Hat Process Automation Manager <version> を指定するのではなく、Red Hat Business Automation BOM (bill of materials) の依存関係をプロジェクトの pom.xml ファイルに追加することを検討してください。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.10.0.redhat-00004</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>

    Red Hat Business Automation BOM (Bill of Materials) についての詳細情報は、「What is the mapping between RHPAM product and maven library version?」 を参照してください。

  2. classpath または 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. KIE Server への要求を送信して、応答を受信するクラスを作成します。

    public class ApplyScorecardModel {
      private static final ReleaseId releaseId =
              new ReleaseId("org.acme","my-kjar","1.0.0");
      private static final String containerId = "SampleModelContainer";
      private static KieCommands commandFactory;
      private static ClassLoader kjarClassLoader; 1
      private RuleServicesClient serviceClient; 2
    
      // Attributes specific to your class instance
      private String rankedFirstCode;
      private Double score;
    
      // Initialization of non-final static attributes
      static {
        commandFactory = KieServices.Factory.get().getCommands();
    
        // Specifications for kjarClassLoader, if used
        KieMavenRepository kmp = KieMavenRepository.getMavenRepository();
        File artifactFile = kmp.resolveArtifact(releaseId).getFile();
        if (artifactFile != null) {
          URL urls[] = new URL[1];
          try {
            urls[0] = artifactFile.toURI().toURL();
            classLoader = new KieURLClassLoader(urls,PMML4Result.class.getClassLoader());
          } catch (MalformedURLException e) {
            logger.error("Error getting classLoader for "+containerId);
            logger.error(e.getMessage());
          }
        } else {
          logger.warn("Did not find the artifact file for "+releaseId.toString());
        }
      }
    
      public ApplyScorecardModel(KieServicesConfiguration kieConfig) {
        KieServicesClient clientFactory = KieServicesFactory.newKieServicesClient(kieConfig);
        serviceClient = clientFactory.getServicesClient(RuleServicesClient.class);
      }
      ...
      // Getters and setters
      ...
    
      // Method for executing the PMML model on KIE Server
      public void applyModel(String occupation, int age) {
        PMMLRequestData input = new PMMLRequestData("1234","SampleModelName"); 3
        input.addRequestParam(new ParameterInfo("1234","occupation",String.class,occupation));
        input.addRequestParam(new ParameterInfo("1234","age",Integer.class,age));
    
        CommandFactoryServiceImpl cf = (CommandFactoryServiceImpl)commandFactory;
        ApplyPmmlModelCommand command = (ApplyPmmlModelCommand) cf.newApplyPmmlModel(request); 4
    
        ServiceResponse<ExecutionResults> results =
            ruleClient.executeCommandsWithResults(CONTAINER_ID, command); 5
    
        if (results != null) {  6
          PMML4Result resultHolder = (PMML4Result)results.getResult().getValue("results");
          if (resultHolder != null && "OK".equals(resultHolder.getResultCode())) {
            this.score = resultHolder.getResultValue("ScoreCard","score",Double.class).get();
            Map<String,Object> rankingMap =
                 (Map<String,Object>)resultHolder.getResultValue("ScoreCard","ranking");
            if (rankingMap != null && !rankingMap.isEmpty()) {
              this.rankedFirstCode = rankingMap.keySet().iterator().next();
            }
          }
        }
      }
    }
    1
    クライアントプロジェクトの依存関係に KJAR を追加しなかった場合は、クラスローダーを定義します。
    2
    KIE Server REST API のアクセス認証情報など、構成設定で定義したサービスクライアントを特定します。
    3
    PMMLRequestData オブジェクトを初期化します。
    4
    ApplyPmmlModelCommand のインスタンスを作成します。
    5
    サービスクライアントを使用してコマンドを送信します。
    6
    実行済みの PMML モデルの結果を取得します。
  4. クラスインスタンスを実行して、PMML 呼び出し要求を KIE Server に送信します。

    または JMS および REST インターフェースを使用して、ApplyPmmlModelCommand コマンドを KIE Server に送信できます。REST 要求については、ApplyPmmlModelCommand コマンドを、JSON、JAXB、または XStream 要求形式で、http://SERVER:PORT/kie-server/services/rest/server/containers/instances/{containerId} への POST 要求として使用できます。

    POST エンドポイントの例

    http://localhost:8080/kie-server/services/rest/server/containers/instances/SampleModelContainer

    JSON リクエストボディの例

    {
      "commands": [ {
          "apply-pmml-model-command": {
            "outIdentifier": null,
            "packageName": null,
            "hasMining": false,
            "requestData": {
              "correlationId": "123",
              "modelName": "SimpleScorecard",
              "source": null,
              "requestParams": [
                {
                  "correlationId": "123",
                  "name": "param1",
                  "type": "java.lang.Double",
                  "value": "10.0"
                },
                {
                  "correlationId": "123",
                  "name": "param2",
                  "type": "java.lang.Double",
                  "value": "15.0"
                }
              ]
            }
          }
        }
      ]
    }

    エンドポイントよびボディーを含む curl 要求の例

    curl -X POST "http://localhost:8080/kie-server/services/rest/server/containers/instances/SampleModelContainer" -H "accept: application/json" -H "content-type: application/json" -d "{ \"commands\": [ { \"apply-pmml-model-command\": { \"outIdentifier\": null, \"packageName\": null, \"hasMining\": false, \"requestData\": { \"correlationId\": \"123\", \"modelName\": \"SimpleScorecard\", \"source\": null, \"requestParams\": [ { \"correlationId\": \"123\", \"name\": \"param1\", \"type\": \"java.lang.Double\", \"value\": \"10.0\" }, { \"correlationId\": \"123\", \"name\": \"param2\", \"type\": \"java.lang.Double\", \"value\": \"15.0\" } ] } } } ]}"

    JSON の応答例

    {
      "results" : [ {
        "value" : {"org.kie.api.pmml.DoubleFieldOutput":{
      "value" : 40.8,
      "correlationId" : "123",
      "segmentationId" : null,
      "segmentId" : null,
      "name" : "OverallScore",
      "displayValue" : "OverallScore",
      "weight" : 1.0
    }},
        "key" : "OverallScore"
      }, {
        "value" : {"org.kie.api.pmml.PMML4Result":{
      "resultVariables" : {
        "OverallScore" : {
          "value" : 40.8,
          "correlationId" : "123",
          "segmentationId" : null,
          "segmentId" : null,
          "name" : "OverallScore",
          "displayValue" : "OverallScore",
          "weight" : 1.0
        },
        "ScoreCard" : {
          "modelName" : "SimpleScorecard",
          "score" : 40.8,
          "holder" : {
            "modelName" : "SimpleScorecard",
            "correlationId" : "123",
            "voverallScore" : null,
            "moverallScore" : true,
            "vparam1" : 10.0,
            "mparam1" : false,
            "vparam2" : 15.0,
            "mparam2" : false
          },
          "enableRC" : true,
          "pointsBelow" : true,
          "ranking" : {
            "reasonCh1" : 5.0,
            "reasonCh2" : -6.0
          }
        }
      },
      "correlationId" : "123",
      "segmentationId" : null,
      "segmentId" : null,
      "segmentIndex" : 0,
      "resultCode" : "OK",
      "resultObjectName" : null
    }},
        "key" : "results"
      } ],
      "facts" : [ ]
    }

第14章 関連資料

パート III. DRL ルールを使用したデシジョンサービスの作成

ビジネスルール開発者は、Business Central で DRL (Drools Rule Language) デザイナーを使用してビジネスルールを定義できます。DRL ルールは、Business Central におけるその他のルールアセットとは異なり、ガイド付きまたは表形式ではなく、フリーフォームの.drl テキストファイルで直接定義できます。このような DRL ファイルは、プロジェクトのデシジョンサービスの中心となります。

注記

ルールベースやテーブルベースのアセットではなく、Decision Model and Notation (DMN) モデルを使用してデシジョンサービスを設計することもできます。Red Hat Process Automation Manager 7.10 の DMN サポートに関する詳細は、以下の資料を参照してください。

前提条件

  • DRL ルールのチームおよびプロジェクトが Business Central に作成されている。各アセットが、スペースに割り当てられたプロジェクトに関連付けられている。詳細は『デシジョンサービスのスタートガイド』を参照してください。

第15章 Red Hat Process Automation Manager におけるデシジョン作成アセット

Red Hat Process Automation Manager は、デシジョンサービスにビジネスデシジョンを定義するのに使用可能なアセットを複数サポートします。デシジョン作成アセットはそれぞれ長所が異なるため、目的やニーズに合わせて、アセットを 1 つ、または複数を組み合わせて使用できます。

以下の表では、デシジョンサービスでデシジョンを定義する最適な方法を選択できるように、Red Hat Process Automation Manager プロジェクトでサポートされている主要なデシジョン作成アセットを紹介します。

表15.1 Red Hat Process Automation Manager でサポートされるデシジョン作成アセット

アセット主な特徴オーサリングツールドキュメント

DMN (Decision Model and Notation) モデル

  • Object Management Group (OMG) が定義する標準記法をもとにしたデシジョンモデルである
  • 一部またはすべての意思決定要件グラフ (DRG: Decision Requirements Graph) を表すグラフィカルな意思決定要件ダイアグラム (DRD: Decision Requirements Diagram) を使用してビジネスデシジョンのフローを追跡する
  • DMN モデルが DMN 準拠プラットフォーム間で共有できるようにする XML スキーマを使用する
  • DMN デシジョンテーブルおよび他の DMN ボックス式表現 (Boxed Expression) でデシジョンロジックを定義する Friendly Enough Expression Language (FEEL) をサポートする
  • Business Process Model and Notation (BPMN) プロセスモデルと効率的に統合できる
  • 包括性、具体性、および安定性のある意思決定フローの作成に最適である

Business Central または DMN 準拠のエディター

『DMN モデルを使用したデシジョンサービスの作成』

ガイド付きデシジョンテーブル

  • Business Central の UI ベースのテーブルデザイナーで作成するルールのテーブルである
  • デシジョンテーブルにスプレッドシートで対応する代わりにウィザードで対応する
  • 条件を満たした入力に、フィールドとオプションを提供する
  • ルールテンプレートを作成するテンプレートキーと値をサポートする
  • その他のアセットではサポートされていないヒットポリシー、リアルタイム検証などの追加機能をサポートする
  • コンパイルエラーを最小限に抑えるため、制限されているテーブル形式でルールを作成するのに最適である

Business Central

「ガイド付きデシジョンテーブルを使用したデシジョンサービスの作成」

スプレッドシートのデシジョンテーブル

  • Business Central にアップロード可能な XLS または XLSX スプレッドシート形式のデシジョンテーブルである
  • ルールテンプレートを作成するテンプレートキーと値をサポートする
  • Business Central 外で管理しているデシジョンテーブルでルールを作成するのに最適である
  • アップロード時に適切にルールをコンパイルするために厳密な構文要件がある

スプレッドシートエディター

「スプレッドシート形式のデシジョンテーブルを使用したデシジョンサービスの作成」

ガイド付きルール

  • Business Central の UI ベースのルールデザイナーで作成する個々のルールである
  • 条件を満たした入力に、フィールドとオプションを提供する
  • コンパイルエラーを最小限に抑えるため、制御されている形式で単独のルールを作成するのに最適である

Business Central

「ガイド付きルールを使用したデシジョンサービスの作成」

ガイド付きルールテンプレート

  • Business Central の UI ベースのテンプレートデザイナーで作成する再利用可能なルール構造である
  • 条件を満たした入力に、フィールドとオプションを提供する
  • (このアセットの目的の基本となる) ルールテンプレートを作成するテンプレートのキーと値をサポートする
  • ルール構造が同じで、定義したフィールド値が異なるルールを多数作成するのに最適である

Business Central

「ガイド付きルールテンプレートを使用したデシジョンサービスの作成」

DRL ルール

  • .drl テキストファイルに直接定義する個々のルールである
  • 最も柔軟性が高く、ルールと、ルール動作に関するその他の技術を定義できる
  • スタンドアロン環境で作成し、Red Hat Process Automation Manager に統合可能
  • 詳細な DRL オプションを必要とするルールを作成するのに最適である
  • ルールを適切にコンパイルするための厳密な構文要件がある

Business Central または統合開発環境 (IDE)

「DRL ルールを使用したデシジョンサービスの作成」

予測モデルマークアップ言語 (PMML: Predictive Model Markup Language) モデル

  • Data Mining Group (DMG) が定義する標準記法に基づく予測データ分析モデルである
  • PMML モデルを PMML 準拠プラットフォーム間で共有できるようにする XML スキーマを使用する
  • 回帰、スコアカード、ツリー、マイニングなどのモデルタイプをサポートする
  • スタンドアロンの Red Hat Process Automation Manager プロジェクトに追加したり、Business Central のプロジェクトにインポートしたりできる
  • Red Hat Process Automation Manager のデシジョンサービスに予測データを統合するのに最適である

PMML または XML エディター

『PMML モデルでのデシジョンサービスの作成』

第16章 DRL (Drools Rule Language) ルール言語

DRL (Drools Rule Language) ルールは、.drl テキストファイルに直接定義するビジネスルールです。このような DRL ファイルは、Business Central の他のすべてのルールアセットが最終的にレンダリングされるソースとなります。Business Central インターフェースで DRL ファイルを作成して管理するか、Red Hat CodeReady Studio や別の統合開発環境 (IDE) を使用して Maven または Java プロジェクトの一部として外部で作成することができます。DRL ファイルには、最低でもルールの条件 (when) およびアクション (then) を定義するルールを 1 つ以上追加できます。Business Central の DRL デザイナーでは、Java、DRL、および XML の構文が強調表示されます。

DRL ファイルは、以下のコンポーネントで構成されます。

DRL ファイル内のコンポーネント

package

import

function  // Optional

query  // Optional

declare   // Optional

global   // Optional

rule "rule name"
    // Attributes
    when
        // Conditions
    then
        // Actions
end

rule "rule2 name"

...

以下の DRL ルールの例では、ローン申し込みのデシジョンサービスで年齢制限を指定します。

申込者の年齢制限に関するルールの例

rule "Underage"
  salience 15
  agenda-group "applicationGroup"
  when
    $application : LoanApplication()
    Applicant( age < 21 )
  then
    $application.setApproved( false );
    $application.setExplanation( "Underage" );
end

DRL ファイルには、ルール、クエリー、関数が 1 つまたは複数含まれており、このファイルで、ルールやクエリーで割り当て、使用するインポート、グローバル、属性などのリソース宣言を定義できます。DRL パッケージは、DRL ファイルの一番上に表示され、ルールは通常最後に表示されます。他の DRLコンポーネントはどのような順番でも構いません。

ルールごとに、ルールパッケージ内で一意の名前を指定する必要があります。パッケージ内の DRL ファイルで、同じルール名を複数回使用すると、ルールのコンパイルに失敗します。特にルール名にスペースを使用する場合など、ルール名には必ず二重引用符 (rule "rule name") を使用して、コンパイルエラーが発生しないようにしてください。

DRL ルールに関連するデータオブジェクトはすべて、DRL ファイルと同じ Business Central プロジェクトパッケージに置く必要があります。同じパッケージに含まれるアセットはデフォルトでインポートされます。その他のパッケージの既存アセットは、DRL ルールを使用してインポートできます。

16.1. DRL のパッケージ

パッケージは、データオブジェクト、DRL ファイル、デシジョンテーブル、他のアセットタイプなど、Red Hat Process Automation Manager に含まれる関連アセットをまとめたディレクトリーです。また、パッケージは、各ルールグループに固有の namespace としても機能します。1 つのルールベースには、複数のパッケージを含めることができます。通常、パッケージだけで自己完結できるように、パッケージのすべてのルールはパッケージ宣言と同じファイルに保存します。ただし、対象のルールで使用するのに、他のパッケージからオブジェクトをインポートできます。

以下は、ローン申請デシジョンサービスの DRL ファイルのパッケージ名と名前空間の例です。

DRL ファイルのパッケージ定義例

package org.mortgages;

16.2. DRL のインポートステートメント

Java のインポートステートメントと同様に、DRL ファイルのインポートで、ルールで使用するオブジェクトの完全修飾パスとタイプ名を識別します。packageName.objectName の形式でパッケージとデータオブジェクトを指定し、複数のインポートを指定する場合には別の行に指定します。デシジョンエンジンは自動的に、DRL パッケージと同じ名前の Java パッケージおよび、java.lang パッケージからクラスを自動的にインポートします。

以下の例は、住宅ローン申請デシジョンサービスに含まれるローン申請オブジェクトのインポートステートメントです。

DRL ファイルのインポートステートメント例

import org.mortgages.LoanApplication;

16.3. DRL の機能

DRL ファイルの関数は、Java クラスではなく、ルールのソースファイルにセマンティックコードを追加します。関数は、特に、ルールのアクション (then) 部分が繰り返し使用され、パラメーターだけがルールごとに異なる場合に便利です。DRL ファイルのルールで、関数を宣言したり、ヘルパークラスから静的メソッドを関数としてインポートしたりすることで、ルールのアクション (then) 部分で、名前を指定して関数を使用できます。

以下は、DRL ファイルで宣言またはインポートされる関数の例です。

ルールを含む関数宣言の例 (オプション 1)

function String hello(String applicantName) {
    return "Hello " + applicantName + "!";
}

rule "Using a function"
  when
    // Empty
  then
    System.out.println( hello( "James" ) );
end

ルールを含む関数インポートの例 (オプション 2)

import function my.package.applicant.hello;

rule "Using a function"
  when
    // Empty
  then
    System.out.println( hello( "James" ) );
end

16.4. DRL のクエリー

DRL ファイルのクエリーは、デシジョンエンジンのワーキングメモリーで DRL ファイル内のルールに関連するファクトを検索します。DRL ファイルにクエリー定義を追加してから、アプリケーションコードで一致する結果を取得します。クエリーは、定義した条件セットを検索するため、when または then を指定する必要はありません。クエリー名は KIE ベースでグローバルとなるため、プロジェクトにあるその他のすべてのルールクエリーと重複しないようにする必要があります。クエリーの結果を返すには、ksession.getQueryResults("name") を使用して QueryResults 定義を構成します ("name" はクエリー名)。これにより、クエリーの結果が返り、クエリーに一致したオブジェクトを取得できるようになります。DRL ファイルのルールに、クエリーとクエリー結果パラメーターを定義します。

以下は、ローン申請デシジョンサービスの未成年の申請者に関する DRL ファイルのクエリー定義と、付属のアプリケーションコードの例です。

DRL ファイルにおけるクエリー定義の例

query "people under the age of 21"
    $person : Person( age < 21 )
end

クエリー結果を取得するためのアプリケーションコードの例

QueryResults results = ksession.getQueryResults( "people under the age of 21" );
System.out.println( "we have " + results.size() + " people under the age  of 21" );

標準的な for ループを使用して、返される QueryResults を反復処理できます。各要素は QueryResultsRow で、これを使用してタプルの各列にアクセスできます。

クエリー結果を取得および反復するアプリケーションのコード例

QueryResults results = ksession.getQueryResults( "people under the age of 21" );
System.out.println( "we have " + results.size() + " people under the age of 21" );

System.out.println( "These people are under the age of 21:" );

for ( QueryResultsRow row : results ) {
    Person person = ( Person ) row.get( "person" );
    System.out.println( person.getName() + "\n" );
}

16.5. DRL でのタイプ宣言とメタデータ

DRL ファイルの宣言は、DRL ファイルのルールで使用するファクトタイプまたはメタデータを新たに定義します。

  • 新規ファクトタイプ: Red Hat Process Automation Manager に含まれる java.lang パッケージのデフォルトのファクトタイプは Object ですが、必要に応じて DRL ファイルで他のタイプを宣言できます。DRL ファイルにファクトタイプを宣言すると、Java などの低級言語でモデルを作成せず、デシジョンエンジンに直接新しいファクトモデルを定義するようになります。また、ドメインモデルがすでにビルドされていて、推論 (reasoning) のプロセスで主に使用する追加のエンティティーでこのモデルを補完する場合に、新規タイプを宣言することもできます。
  • ファクトタイプのメタデータ: @key(value) 形式のメタデータを新規または既存のファクトを関連付けることができます。メタデータには、ファクト属性で表現されていない、該当のファクトタイプのすべてのインスタンス間で一貫性のあるすべての種類のデータを使用できます。メタデータはランタイム時に、デシジョンエンジンでクエリーでき、推論 (reasoning) のプロセスで使用できます。

16.5.1. DRL のメタデータを使用しないタイプ宣言

新規ファクトの宣言にメタデータは必要ありませんが、属性またはフィールドの一覧を含める必要があります。タイプ宣言に指定属性が含まれていない場合は、デシジョンエンジンがクラスパス内で既存のファクトクラスを検索し、クラスが見つからない場合はエラーを出します。

以下の例は、DRL ファイルにメタデータがない新規ファクトタイプ Person の宣言です。

ルールが 1 つ含まれる新規ファクトタイプの宣言の例

declare Person
  name : String
  dateOfBirth : java.util.Date
  address : Address
end

rule "Using a declared type"
  when
    $p : Person( name == "James" )
  then   // Insert Mark, who is a customer of James.
    Person mark = new Person();
    mark.setName( "Mark" );
    insert( mark );
end

この例では、新規ファクトタイプ Person には namedateOfBirth、および address の 3 つの属性が含まれます。属性ごとにタイプがあり、このタイプには作成する別のクラスや以前に宣言したファクトタイプなどの、有効な Java タイプを指定できます。dateOfBirth 属性には、Java API からの java.util.Date タイプがあり、address 属性には、以前に定義したファクトタイプ Address が含まれます。

宣言するたびにクラスの完全修飾名が記述されないように、完全なクラス名を import 句の一部として定義できます。

インポートの完全修飾クラス名でのタイプ宣言例

import java.util.Date

declare Person
    name : String
    dateOfBirth : Date
    address : Address
end

新規のファクトタイプを宣言すると、デシジョンエンジンはコンパイル時にファクトタイプを表す Java クラスを生成します。生成される Java クラスはタイプ定義の一対一の JavaBeans マッピングとなります。

たとえば、以下の Java クラスはPerson タイプ宣言例から生成されます。

Person ファクトタイプの宣言用に生成された Java クラス

public class Person implements Serializable {
    private String name;
    private java.util.Date dateOfBirth;
    private Address address;

    // Empty constructor
    public Person() {...}

    // Constructor with all fields
    public Person( String name, Date dateOfBirth, Address address ) {...}

    // If keys are defined, constructor with keys
    public Person( ...keys... ) {...}

    // Getters and setters
    // `equals` and `hashCode`
    // `toString`
}

Person タイプ宣言が含まれる以前のルールの例が示すように、他のファクトと同様にルールで生成したクラスを使用できます。

宣言された Person ファクトタイプを使用するルールの例

rule "Using a declared type"
  when
    $p : Person( name == "James" )
  then   // Insert Mark, who is a customer of James.
    Person mark = new Person();
    mark.setName( "Mark" );
    insert( mark );
end

16.5.2. DRL の列挙タイプの宣言

DRL は、declare enum <factType> 形式の列挙タイプの宣言をサポートします。列挙タイプの後にはコンマ区切りの値の一覧が続き、最後はセミコロンで終了します。これにより、DRL ファイルのルールで列挙リストを使用できます。

たとえば、以下の列挙タイプの宣言では、従業員スケジュールルールの曜日を定義します。

スケジュールルールを使用した列挙タイプ宣言の例

declare enum DaysOfWeek
   SUN("Sunday"),MON("Monday"),TUE("Tuesday"),WED("Wednesday"),THU("Thursday"),FRI("Friday"),SAT("Saturday");

   fullName : String
end

rule "Using a declared Enum"
when
   $emp : Employee( dayOff == DaysOfWeek.MONDAY )
then
   ...
end

16.5.3. DRL の拡張タイプ宣言

DRL は、declare <factType1> extends <factType2> 形式のタイプ宣言の継承をサポートします。DRL で宣言したサブタイプで Java で宣言したタイプを拡張するには、フィールドなしの宣言ステートメントで親タイプを繰り返し使用します。

たとえば、以下のタイプ宣言はトップレベルの Person タイプから Student タイプを拡張し、さらに Student サブタイプから LongTermStudent タイプを拡張します。

拡張タイプ宣言の例

import org.people.Person

declare Person end

declare Student extends Person
    school : String
end

declare LongTermStudent extends Student
    years : int
    course : String
end

16.5.4. DRL のメタデータが含まれるタイプ宣言

@key(value) (値は任意) 形式のメタデータをファクトタイプまたはファクト属性に関連付けることができます。メタデータには、ファクト属性で表現されていない、該当のファクトタイプのすべてのインスタンス間で一貫性のあるすべての種類のデータを使用できます。メタデータはランタイム時に、デシジョンエンジンでクエリーでき、推論 (reasoning) のプロセスで使用できます。ファクトタイプの属性の前に宣言するメタデータはファクトタイプに割り当てられ、属性の後に宣言するメタデータはこの特定の属性に割り当てられます。

以下の例では、@author@dateOfCreation のメタデータ属性 2 つが Person ファクトタイプに、@key@maxLength のメタデータアイテム 2 つが name 属性に割り当てられています。@key メタデータ属性には必須の値がないので、括弧と値は省略されます。

ファクトタイプおよび属性のメタデータ宣言例

import java.util.Date

declare Person
    @author( Bob )
    @dateOfCreation( 01-Feb-2009 )

    name : String @key @maxLength( 30 )
    dateOfBirth : Date
    address : Address
end

既存タイプのメタデータ属性を宣言する場合には、すべての宣言の import 句の一部として、または個別の declare 句の一部として完全修飾クラス名を特定できます。

インポートタイプのメタデータ宣言の例

import org.drools.examples.Person

declare Person
    @author( Bob )
    @dateOfCreation( 01-Feb-2009 )
end

宣言タイプのメタデータ宣言例

declare org.drools.examples.Person
    @author( Bob )
    @dateOfCreation( 01-Feb-2009 )
end

16.5.5. DRL でのファクトタイプと属性宣言のメタデータタグ

DRL 宣言でカスタムメタデータ属性を定義することはできますが、デシジョンエンジンはファクトタイプまたはファクトタイプ属性の宣言についての、以下の事前定義メタデータタグもサポートします。

注記

VoiceCall クラスを参照する本セクションの例では、サンプルアプリケーションドメインモデルに以下のクラスの詳細が含まれていることを前提としています。

Telecom ドメインモデルの例における VoiceCall ファクトクラス

public class VoiceCall {
  private String  originNumber;
  private String  destinationNumber;
  private Date    callDateTime;
  private long    callDuration;  // in milliseconds

  // Constructors, getters, and setters
}

@role

このタグは、指定のファクトタイプが複雑なイベントの処理時にデシジョンエンジンにて通常のファクトまたはイベントとして処理されるかどうかを決定します。

デフォルトパラメーター: fact

サポート対象のパラメーター: factevent

@role( fact | event )

例: イベントタイプとして VoiceCall の宣言

declare VoiceCall
  @role( event )
end

@timestamp

このタグは、デシジョンエンジンのすべてのイベントに自動的に割り当てられます。デフォルトでは、この時間はセッションクロックにより提供され、デシジョンエンジンのワーキングメモリーへの挿入時にイベントに割り当てられます。セッションクロックが追加するデフォルトのタイムスタンプの代わりに、カスタムのタイムスタンプ属性を指定できます。

デフォルトパラメーター: デシジョンエンジンのセッションクロックが追加する時間

サポート対象のパラメーター: セッションクロックタイムまたはカスタムのタイムスタンプ属性

@timestamp( <attributeName> )

例: VoiceCall のタイムスタンプ属性の宣言

declare VoiceCall
  @role( event )
  @timestamp( callDateTime )
end

@duration

このタグは、デシジョンエンジンのイベントの持続期間を決定します。イベントは、interval-based イベントまたは point-in-time イベントのいずれかになります。interval-based のイベントには持続期間があり、その持続期間が経過するまでデシジョンエンジンのワーキングメモリーで持続します。point-in-time イベントに持続期間はなく、基本的には期間がゼロの interval-based イベントになります。デフォルトでは、デシジョンエンジンのすべてのイベントの持続期間は 0 です。デフォルトの代わりに、カスタムの持続期間属性を指定できます。

デフォルトパラメーター: null (ゼロ)

サポート対象のパラメーター: カスタムの持続期間属性

@duration( <attributeName> )

例: VoiceCall の持続期間属性の宣言

declare VoiceCall
  @role( event )
  @timestamp( callDateTime )
  @duration( callDuration )
end

@expires

このタグは、デシジョンエンジンのワーキングメモリーでイベントの有効期限が切れるまでの時間を決定します。デフォルトでは、イベントは現在のルールのいずれにも一致せず、それらのいずれもアクティベートできなくなった時点で失効します。イベント失効までの期間を定義できます。また、このタグの定義は、KIE ベースの一時的な制約やスライディングウィンドウから算出した暗黙的な有効期限のオフセットもオーバーライドします。デシジョンエンジンがストリームモードで実行中の場合にのみ、このタグを使用できます。

デフォルトパラメーター: Null (イベントがルールに一致せず、ルールをアクティブにできなくなるとイベントの有効期限が切れる)

サポート対象のパラメーター: [#d][#h][#m][#s][[ms]] 形式のカスタムの timeOffset 属性

@expires( <timeOffset> )

例: VoiceCall イベントに対する有効期限のオフセットの宣言

declare VoiceCall
  @role( event )
  @timestamp( callDateTime )
  @duration( callDuration )
  @expires( 1h35m )
end

@typesafe

このタグは、型安全性を有効して/有効にせずに指定のファクトタイプをコンパイルするかどうかを決定します。デフォルトでは、すべてのタイプ宣言は型安全性が有効な状態でコンパイルされます。この動作を type-unsafe の評価にオーバーライドすることもできます。type-unsafe の評価の場合、すべての制約は MVEL 制約として生成され、動的に実行されます。これは、一般的なコレクションではない場合や、タイプが混同されているコレクションを処理する場合に便利です。

デフォルトパラメーター: true

サポート対象のパラメーター: truefalse

@typesafe( <boolean> )

例: type-unsafe 評価の VoiceCall の宣言

declare VoiceCall
  @role( fact )
  @typesafe( false )
end

@serialVersionUID

このタグは、ファクト宣言でシリアル化可能なクラスの serialVersionUID の指定値を定義します。シリアル化可能なクラスで明示的に serialVersionUID が宣言されていない場合は、「Java Object Serialization Specification」に記載されているように、シリアル化のランタイムが、そのクラスのさまざまな側面に基づいてそのクラスのデフォルトの serialVersionUID 値を計算します。ただし、デシリアル化の結果を最適化し、シリアル化した KIE セッションの互換性を向上するには、関連のクラスや DRL 宣言の要件に応じて serialVersionUID を設定します。

デフォルトパラメーター: Null

サポート対象のパラメーター: カスタムの serialVersionUID 整数

@serialVersionUID( <integer> )

例: VoiceCall クラスの serialVersionUID の宣言

declare VoiceCall
  @serialVersionUID( 42 )
end

@key

このタグを指定すると、ファクトタイプ属性をファクトタイプのキー識別子として使用できるようになります。生成されたクラスは equals() メソッドと hashCode() メソッドを実装できるようになり、該当タイプの 2 つのインスタンスが同等であるかを判別できるようになります。デシジョンエンジンは、すべてのキー属性をパラメーターとして使用してコンストラクターを生成することもできます。

デフォルトパラメーター: なし

サポート対象のパラメーター: なし

<attributeDefinition> @key

例: Person タイプ属性をキーとして宣言する

declare Person
    firstName : String @key
    lastName : String @key
    age : int
end

この例では、デシジョンエンジンは firstName 属性と lastName 属性をチェックして、Person の 2 つのインスタンスが同等であるかどうかを判断しますが、age 属性はチェックしません。また、このデシジョンエンジンは暗黙的に 3 つのコンストラクターを生成します。1 つはパラメーターなし、もう 1 つ目は @key フィールドのあるコンストラクター、3 つ目はすべてのフィールドのあるコンストラクターです。

キー宣言に基づくコンストラクターの例

Person() // Empty constructor

Person( String firstName, String lastName )

Person( String firstName, String lastName, int age )

以下の例のように、キーコンストラクターに基づいてタイプのインスタンスを作成できます。

キーコンストラクターを使用したインスタンスの例

Person person = new Person( "John", "Doe" );

@position

このタグは、位置引数で宣言されたファクトタイプ属性またはフィールドの位置を決定し、デフォルトで宣言した属性の順番をオーバーライドします。このタグを使用して、タイプ宣言または位置引数で制約の形式を維持しつつ、パターンの位置制約を変更できます。このタグは、クラスパスのクラスにあるフィールドに対してのみ使用できます。1 つのクラスのフィールドでこのタグを使用する場合も、使用しない場合もありますが、このタグのない属性は、宣言の順番では最後になります。クラスの継承はサポートされますが、メソッドのインターフェースはサポートされません。

デフォルトパラメーター: なし

サポート対象のパラメーター: 整数

<attributeDefinition> @position ( <integer> )

例: ファクトタイプを宣言し、宣言した順番をオーバライドする

declare Person
    firstName : String @position( 1 )
    lastName : String @position( 0 )
    age : int @position( 2 )
    occupation: String
end

この例では、位置引数に含まれる属性の優先順位は以下のとおりです。

  1. lastName
  2. firstName
  3. age
  4. occupation

位置引数では、位置が既知の名前付きフィールドにマッピングされるため、フィールド名を指定する必要はありません。たとえば、Person( lastName == "Doe" ) の引数は Person( "Doe"; ) と同じです。ここでは、lastName フィールドには、DRL 宣言の最上位の位置アノテーションが含まれます。セミコロン ; は、その前にあるものはすべて位置引数であることを示します。セミコロンを使用して引数を区切ることで、パターンで位置引数と名前付き引数を混ぜて使用できます。バインドされていない位置引数の変数は、その位置にマッピングされているフィールドにバインドされます。

以下のパターン例では、位置引数と名前付き引数をさまざまな方法で構築する方法を示します。このパターンには、制約が 2 つ、バインディングが 1 つ含まれており、セミコロンで位置引数のセクションと名前付き引数のセクションを分けています。位置引数では、変数とリテラル、およびリテラルのみを使用する式がサポートされていますが、変数だけの使用はサポートされていません。

位置引数および名前付き引数を含むパターン例

Person( "Doe", "John", $a; )

Person( "Doe", "John"; $a : age )

Person( "Doe"; firstName == "John", $a : age )

Person( lastName == "Doe"; firstName == "John", $a : age )

位置引数は、入力引数 または 出力引数 とに分類できます。入力引数は、以前に宣言したバインディングと、ユニフィケーション (unification) を使用したそのバインディングに対する制約が含まれます。出力引数は、この宣言を生成して、バインディングがまだ存在しない場合は、これを位置引数で表現するフィールドにバインディングします。

拡張タイプの宣言で @position アノテーションを定義する場合は、属性の位置がサブタイプに継承されるため注意が必要です。このように継承されることで、属性の順番が混同し、混乱を生じさせる可能性があります。2 つのフィールドに同じ @position の値を指定でき、連続する値は宣言する必要がありません。位置が繰り返し使用される場合は、継承を使用することで競合が発生しないように解決されます。この場合は、親タイプの位置の値の優先順位が高く、その後は最初から最後の順番で宣言を使用します。

たとえば、以下の拡張タイプ宣言では、位置の優先順位が混合します。

位置アノテーションが混合した拡張ファクトタイプの例

declare Person
    firstName : String @position( 1 )
    lastName : String @position( 0 )
    age : int @position( 2 )
    occupation: String
end

declare Student extends Person
    degree : String @position( 1 )
    school : String @position( 0 )
    graduationDate : Date
end

この例では、位置引数に含まれる属性の優先順位は以下のとおりです。

  1. lastName (親タイプでの位置 0)
  2. school (サブタイプでの位置 0)
  3. firstName(親タイプでの位置 1)
  4. degree (サブタイプでの位置 1)
  5. age(親タイプでの位置 2 )
  6. occupation (位置アノテーションがない最初のフィールド)
  7. graduationDate (位置アノテーションがない 2 番目のフィールド)

16.5.6. ファクトタイプに対するプロパティー変更の設定およびリスナー

デフォルトでは、デシジョンエンジンは、ルールがトリガーされるたびに、ファクトタイプに対するすべてのファクトパターンを再評価しません。代わりに、指定のパターン内に制約またはバインドされている変更されたプロパティーのみに対応します。たとえば、ルールが、ルールアクションの一環として modify() を呼び出すものの、アクションが KIE ベースで新しいデータを生成しない場合は、データが変更されないため、デシジョンエンジンはすべてのファクトパターンを自動的に再評価しません。このプロパティーのリアクティビティー動作は、KIE ベースでの不要な再帰を阻止し、より効率的なルール評価をもたらします。また、この動作は無限再帰を回避するために no-loop ルール属性を必ずしも使用する必要がないことを意味します。

以下の KnowledgeBuilderConfiguration オプションを使用して、このプロパティーリアクティビティー動作を変更または無効にできます。次に、Java クラスまたは DRL ファイルでプロパティー変更設定を使用し、必要に応じてプロパティーリアクティビティーを調整します。

  • ALWAYS: (デフォルト) すべてのタイプはプロパティーリアクティブです。ただし、@classReactive プロパティー変更設定を使用して、特定タイプのプロパティーリアクティビティーを無効にできます。
  • ALLOWED: すべてのタイプはプロパティーリアクティブではありません。ただし、@propertyReactive プロパティー変更設定を使用して、特定タイプのプロパティーリアクティビティーを有効にできます。
  • DISABLED: すべてのタイプはプロパティーリアクティブではありません。すべてのプロパティー変更リスナーは無視されます。

KnowledgeBuilderConfiguration におけるプロパティーリアクティビティー設定の例

KnowledgeBuilderConfiguration config = KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration();
config.setOption(PropertySpecificOption.ALLOWED);
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(config);

または、Red Hat Process Automation Manager ディストリビューションにおける standalone.xml ファイルの drools.propertySpecific システムプロパティーを更新できます。

システムプロパティーにおけるプロパティーリアクティビティー設定の例

<system-properties>
  ...
  <property name="drools.propertySpecific" value="ALLOWED"/>
  ...
</system-properties>

デシジョンエンジンは、ファクトクラスまたは宣言された DRL ファクトタイプに対して、以下のプロパティー変更の設定およびリスナーをサポートします。

@classReactive

デシジョンエンジンでプロパティーリアクティビティーが ALWAYS に設定されている場合 (すべてのタイプはプロパティーリアクティブ)、このタグは特定の Java クラスまたは宣言された DRL ファクトタイプに対してデフォルトのプロパティーリアクティビティー動作を無効にします。このタグは、特定パターン内に制約またはバインドされる変更されたプロパティーのみに対応するのではなく、ルールがトリガーされるたびに指定されたファクトタイプのすべてのファクトパターンをデシジョンエンジンが再評価する必要がある場合に使用できます。

例: DRL タイプの宣言におけるデフォルトのプロパティーリアクティビティーの無効化

declare Person
  @classReactive
    firstName : String
    lastName : String
end

例: Java クラスにおけるデフォルトのプロパティーリアクティビティーの無効化

@classReactive
public static class Person {
    private String firstName;
    private String lastName;
}

@propertyReactive

プロパティーリアクティビティーがデシジョンエンジンで ALLOWED に設定されている場合 (指定されていない場合、すべてのタイプはプロパティーリアクティブではない)、このタグは特定の Java クラスまたは宣言された DRL ファクトタイプに対してプロパティーリアクティビティーを有効にします。ルールがトリガーされるたびにファクトのすべてのファクトパターンを再評価するのではなく、指定されたファクトタイプの特定のパターン内で制約またはバインドされた変更済みプロパティーにのみデシジョンエンジンを反応させる場合は、このタグを使用できます。

例: DRL タイプの宣言におけるプロパティーリアクティビティーの有効化 (リアクティビティーがグローバルに無効にされる場合)

declare Person
  @propertyReactive
    firstName : String
    lastName : String
end

例: Java クラスでのプロパティーのリアクティビティーの有効化 (リアクティビティーがグローバルに無効にされる場合)

@propertyReactive
public static class Person {
    private String firstName;
    private String lastName;
}

@watch

このタグは、DRL ルールのファクトパターンで、インラインで指定する追加のプロパティーに対するプロパティーリアクティビティーを有効にします。このタグがサポートされるのは、デシジョンエンジンでプロパティーリアクティビティーが ALWAYS に設定されている場合か、プロパティーリアクティビティーが ALLOWED に設定され、関連するファクトタイプが @propertyReactive タグを使用する場合に限られます。DRL ルールでこのタグを使用して、ファクトプロパティーリアクティビティー論理の指定されたプロパティーを追加または除外できます。

デフォルトパラメーター: なし

サポートされているパラメーター: プロパティー名、* (all)、! (not)、!* (no properties)

<factPattern> @watch ( <property> )

例: ファクトパターンにおけるプロパティーリアクティビティーの有効化または無効化

// Listens for changes in both `firstName` (inferred) and `lastName`:
Person(firstName == $expectedFirstName) @watch( lastName )

// Listens for changes in all properties of the `Person` fact:
Person(firstName == $expectedFirstName) @watch( * )

// Listens for changes in `lastName` and explicitly excludes changes in `firstName`:
Person(firstName == $expectedFirstName) @watch( lastName, !firstName )

// Listens for changes in all properties of the `Person` fact except `age`:
Person(firstName == $expectedFirstName) @watch( *, !age )

// Excludes changes in all properties of the `Person` fact (equivalent to using `@classReactivity` tag):
Person(firstName == $expectedFirstName) @watch( !* )

デシジョンエンジンは、@classReactive タグ (プロパティーリアクティビティーを無効にする) を使用するファクトタイプのプロパティーに対して @watch タグを使用する場合、またはデシジョンエンジンでプロパティーリアクティビティーが ALLOWED に設定され、関連するファクトタイプが @propertyReactive タグを使用しない場合は、コンパイルエラーを生成します。また、@watch( firstName, ! firstName ) などのリスナーアノテーションでプロパティーを複製する場合でも、コンパイルエラーが生じます。

@propertyChangeSupport

JavaBeans Specification で定義されたプロパティー変更のサポートを実装するファクトの場合は、このタグによりデシジョンエンジンがファクトプロパティーの変更を監視できるようになります。

例: JavaBeans オブジェクトでのプロパティー変更のサポートの宣言

declare Person
    @propertyChangeSupport
end

16.5.7. アプリケーションコード内の DRL で宣言されたタイプへのアクセス

DRL の宣言タイプは通常 DRL ファイル内で使用され、 Java モデルは通常モデルをルールとアプリケーション間で共有する場合に使用されます。宣言タイプは KIE ベースのコンパイル時に生成されるため、アプリケーションはアプリケーションのランタイムまでこの宣言タイプにアクセスできません。状況によっては、アプリケーションが宣言タイプからファクトに直接アクセスし、処理する必要があります (とくにアプリケーションがデシジョンエンジンをラップして、ルール管理用によりレベルの高い、ドメイン固有のユーザーインターフェースを提供する場合)。

アプリケーションコードから宣言タイプを直接処理するには、Red Hat Process Automation Manager で org.drools.definition.type.FactType API を使用します。この API を使用して、宣言ファクトタイプでフィールドのインスタンス化、読み取り、書き込みを行います。

以下のコード例では、アプリケーションから Person ファクトタイプを直接変更します。

FactType API を使用した宣言されたファクトタイプを処理するアプリケーションコード例

import java.util.Date;

import org.kie.api.definition.type.FactType;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;

...

// Get a reference to a KIE base with the declared type:
KieBase kbase = ...

// Get the declared fact type:
FactType personType = kbase.getFactType("org.drools.examples", "Person");

// Create instances:
Object bob = personType.newInstance();

// Set attribute values:
personType.set(bob, "name", "Bob" );
personType.set(bob, "dateOfBirth", new Date());
personType.set(bob, "address", new Address("King's Road","London","404"));

// Insert the fact into a KIE session:
KieSession ksession = ...
ksession.insert(bob);
ksession.fireAllRules();

// Read attributes:
String name = (String) personType.get(bob, "name");
Date date = (Date) personType.get(bob, "dateOfBirth");

API には、一度にすべての属性を設定したり、Map コレクションから値を読み取ったり、すべての属性を一度に Map コレクションに読み込んだりするなど、他の便利なメソッドも含まれます。

API の動作は Java リフレクションと似ていますが、API はリフレクションを使用せず、生成されたバイトコードで実装され性能が良いアクセサーに依存します。

16.6. DRL のグローバル変数

DRL ファイルのグローバル変数は通常、ルールの結果で使用するアプリケーションサービスなど、ルールのデータやサービスを提供し、ルールの結果で追加されるログや値など、ルールからのデータを返します。KIE セッション設定や REST 操作を使用したデシジョンエンジンのワーキングメモリーにグローバル値を設定し、DRL ファイルのルールの上にグローバル変数を宣言してから、ルールのアクション部分 (then) でこれを使用します。グローバル変数が複数ある場合は、DRL ファイルで行を分けて使用してください。

以下は、DRL ファイルにおけるデシジョンエンジンのグローバル変数一覧の設定と、対応するグローバル変数定義の例です。

デシジョンエンジンに対するグローバルリストの設定例

List<String> list = new ArrayList<>();
KieSession kieSession = kiebase.newKieSession();
kieSession.setGlobal( "myGlobalList", list );

ルールを使用したグローバル変数定義の例

global java.util.List myGlobalList;

rule "Using a global"
  when
    // Empty
  then
    myGlobalList.add( "My global list" );
end

警告

グローバル変数に定数イミュータブル値がない場合は、ルールの条件設定にグローバル変数を使用しないでください。グローバル変数はデシジョンエンジンのワーキングメモリーに挿入されないため、デシジョンエンジンでは変数の値の変更を追跡できません。

グローバル変数を使用してルール間でデータを共有しないでください。ルールは常に、ワーキングメモリーの状態に関して推論し、これに対応するため、ルールからルールにデータを渡す必要がある場合は、データをファクトとしてデシジョンエンジンのワーキングメモリーにアサートしてください。

グローバル変数のユースケースとして、メールサービスの例があります。デシジョンエンジンを呼び出す統合コードで、emailService オブジェクトを取得してから、デシジョンエンジンのワーキングメモリーでそのオブジェクトを設定します。DRL ファイルで、emailService のグローバルタイプがあり、名前が "email" であることを宣言すると、ルールの結果で email.sendSMS(number, message) などのアクションを使用できるようになります。

複数のパッケージで同じ ID のグローバル変数を宣言した場合には、すべてのパッケージを同じタイプで設定し、すべてが同じグローバル値を参照するようにする必要があります。

16.7. DRL でのルール属性

ルール属性は、ルールの動作を修正するビジネスルールを指定する追加設定です。DRL ファイルでは、ルール属性は、以下の形式で、通常ルールの条件とアクションの上に定義します。複数の属性がある場合には、別々の行に指定します。

rule "rule_name"
    // Attribute
    // Attribute
    when
        // Conditions
    then
        // Actions
end

次の表では、ルールに割り当て可能な属性の名前と、対応する値を紹介します。

表16.1 ルールの属性

属性

salience

ルールの優先順位を定義する整数。顕著性の値が高いルールは、アクティベーションキューの順番で、優先度が高くなります。

例: salience 10

enabled

ブール値。このオプションを選択すると、ルールが有効になります。このオプションを選択しないと、ルールは無効になります。

例: enabled true

date-effective

日付定義および時間定義を含む文字列。現在の日時が date-effective 属性よりも後の場合は、このルールがアクティブになります。

例: date-effective "4-Sep-2018"

date-expires

日付定義および時間定義を含む文字列。現在日時が date-expires 属性よりも後になると、このルールをアクティブにすることはできません。

例: date-expires "4-Oct-2018"

no-loop

ブール値。このオプションが選択される場合は、ルールの結果が以前一致した条件を再度トリガーすると、ルールは再アクティブ化 (ループ) されません。条件を選択しないと、この状況でルールがループされます。

例: no-loop true

agenda-group

ルールを割り当てるアジェンダグループを指定する文字列。アジェンダグループを使用すると、アジェンダをパーティションで区切り、ルールのグループに対する実行をさらに制御できます。フォーカスを取得したアジェンダグループのルールだけがアクティブになります。

例: agenda-group "GroupName"

activation-group

ルールを割り当てるアクティベーション (または XOR) グループを指定する文字列。アクティベーショングループでは、1 つのルールのみをアクティブ化できます。最初のルールが実行すると、アクティベーショングループの中で、アクティベーションが保留中のルールはすべてキャンセルされます。

例: activation-group "GroupName"

duration

ルールの条件が一致している場合に、ルールがアクティブになってからの時間をミリ秒で定義する長整数値。

例: duration 10000

timer

ルールのスケジュールに対する int (間隔) または cron タイマー定義を指定する文字列。

例: timer ( cron:* 0/15 * * * ? ) (15 分ごと)

calendar

ルールのスケジュールを指定する Quartz カレンダーの定義。

例: calendars "* * 0-7,18-23 ?* *" (営業時間外を除く)

auto-focus

アジェンダグループ内のルールにのみ適用可能なブール値。このオプションが選択されている場合は、次にルールがアクティブになった場合に、そのルールが割り当てられたアジェンダグループにフォーカスが自動的に指定されます。

例: auto-focus true

lock-on-active

ルールフローグループまたはアジェンダグループ内のルールにのみ適用可能なブール値。このオプションを選択すると、次回、ルールのルールフローグループがアクティブになるか、ルールのアジェンダグループがフォーカスを受け取ると、(ルールフローグループがアクティブでなくなるか、アジェンダグループがフォーカスを失うまで) ルールをアクティブにすることができません。これは、no-loop 属性を強力にしたものです。なぜなら、一致するルールのアクティベーションが、(ルールそのものによるものだけでなく) アップデート元にかかわらず破棄されるためです。この属性は、ファクトを修正するルールが多数あり、ルールの再一致と再発行を希望しない計算ルールに適しています。

例: lock-on-active true

ruleflow-group

ルールフローグループを指定する文字列。ルールフローグループで、関連するルールフローによってそのグループがアクティブになった場合に限りルールを発行できます。

例: ruleflow-group "GroupName"

dialect

ルールのコード表記に使用される言語を指定する文字列 (JAVA または MVEL)。デフォルトでは、ルールは、パッケージレベルに指定されている方言を使用します。ここで指定した方言は、ルールのパッケージ方言設定を上書きします。

例: dialect "JAVA"

注記

実行可能モデルなしで Red Hat Process Automation Manager を使用する場合には、dialect "JAVA" ルールの結果は、Java 5 構文のみをサポートします。実行可能モデルに関する詳細は、「Red Hat Process Automation Manager プロジェクトのパッケージ化およびデプロイ」を参照してください。

16.7.1. DRL でのタイマーおよびカレンダールール属性

タイマーおよびカレンダーは、DRL ルール属性であり、これを使用してスケジュールと時間の制約を DRL ルールに適用できます。これらの属性を使用するには、ユースケースによって追加の設定が必要になります。

DRL ルールの timer 属性は、ルールのスケジュール設定を行うための int (間隔) または cron タイマー定義を指定する文字列で、以下の形式をサポートします。

タイマー属性の形式

timer ( int: <initial delay> <repeat interval> )

timer ( cron: <cron expression> )

間隔タイマー属性の例

// Run after a 30-second delay
timer ( int: 30s )

// Run every 5 minutes after a 30-second delay each time
timer ( int: 30s 5m )

cron タイマー属性の例

// Run every 15 minutes
timer ( cron:* 0/15 * * * ? )

間隔タイマーは、最初に遅延があり、オプションで間隔が繰り返されるという java.util.Timer オブジェクトのセマンティクスに従います。Cron タイマーは標準の Unix cron 式に準拠します。

以下の DRL ルール例では、cron タイマーを使用して 15 分ごとに SMS テキストメッセージを送信します。

cron タイマーを使用した DRL ルールの例

rule "Send SMS message every 15 minutes"
  timer ( cron:* 0/15 * * * ? )
  when
    $a : Alarm( on == true )
  then
    channels[ "sms" ].insert( new Sms( $a.mobileNumber, "The alarm is still on." );
end

一般的に、タイマーが制御するルールは、ルールがトリガーされた時点でアクティブになり、タイマーの設定に合わせてルールの結果が繰り返し実行されます。実行は、ルールの条件が受信ファクトに一致しなくなる時点で停止します。ただし、デシジョンエンジンがタイマー付きのルールを処理する方法は、デシジョンエンジンが アクティブモード か、パッシブモード かによって異なります。

デフォルトでは、ユーザーまたはアプリケーションが明示的に fireAllRules() を呼び出した場合に、デシジョンエンジンは パッシブモード で実行され、定義されたタイマー設定によりルールが評価されます。一方、ユーザーまたはアプリケーションが fireUntilHalt() を呼び出す場合、デシジョンエンジンは アクティブモード でで実行され、ユーザーまたはアプリケーションが halt() を明示的に呼び出すまでルールを継続的に評価します。

デシジョンエンジンがアクティブモードの場合は、fireUntilHalt() への呼び出しからコントロールが戻った後でもルールの結果が実行され、デシジョンエンジンは、ワーキングメモリーに加えられた変更に対して リアクティブ のままになります。たとえば、タイマールールの実行のトリガーに関連したファクトを削除すると、反復実行が停止になり、ファクトが挿入されるので、ルールが一致するとそのルールが実行します。ただし、デシジョンエンジンは継続して アクティブ な訳ではなく、ルールの実行後にだけアクティブになります。そのため、タイマーで制御されるルールが次回に実行されるまで、デシジョンエンジンは非同期のファクト挿入には反応しません。KIE セッションを破棄するとタイマーアクティビティーはすべて中断されます。

デシジョンエンジンがパッシブモードの場合は、タイマー付きのルールの結果は、fireAllRules() が再度呼び出される場合にのみ評価されます。ただし、以下の例にあるように、パッシブモードでは TimedRuleExecutionOption オプションで KIE セッションを設定することで、デフォルトのタイマー実行動作を変更できます。

パッシブモードでタイマー付きルールを自動的に実行するための KIE セッションの設定

KieSessionConfiguration ksconf = KieServices.Factory.get().newKieSessionConfiguration();
ksconf.setOption( TimedRuleExecutionOption.YES );
KSession ksession = kbase.newKieSession(ksconf, null);

以下の例のように、TimedRuleExecutionOption オプションに追加で FILTERED 仕様を設定することで、対象のルールをフィルターするコールバックを定義できるようになります。

どのタイマー付きのルールを自動的に実行するかをフィルターするための KIE セッション

KieSessionConfiguration ksconf = KieServices.Factory.get().newKieSessionConfiguration();
conf.setOption( new TimedRuleExecutionOption.FILTERED(new TimedRuleExecutionFilter() {
    public boolean accept(Rule[] rules) {
        return rules[0].getName().equals("MyRule");
    }
}) );

間隔タイマーの場合は、int ではなく、expr を指定した式タイマーを使用して、固定値の代わりに、式として遅延と間隔の両方を定義できます。

以下の DRL ファイルの例では、遅延と期間でファクトタイプを宣言し、後続のルールの式タイマーでこの遅延と期間を使用します。

式タイマーが含まれるルールの例

declare Bean
  delay   : String = "30s"
  period  : long = 60000
end

rule "Expression timer"
  timer ( expr: $d, $p )
  when
    Bean( $d : delay, $p : period )
  then
    // Actions
end

この例の $d$p などの式は、ルールのパターンが一致する部分に定義した変数を使用できます。この変数には String の値を使用でき、これは期間や、期間の long 値 (ミリ秒単位) に内部で変換される数値に解析できます。

間隔と式のタイマーはいずれも、以下のオプションのパラメーターを使用できます。

  • start および end: Date、または Date または long 値を表す String。この値には、Number も指定でき、数字は new Date( ((Number) n).longValue() ) 形式の Java のDate に変換されます。
  • repeat-limit: タイマーが許可する最大反復回数を定義する整数。end および repeat-limit の両パラメーターが設定されている場合は、2 つのどちらかに先に到達した時点でタイマーが停止します。

任意の startend、および repeat-limit パラメーターが使用されるタイマー属性の例

timer (int: 30s 1h; start=3-JAN-2020, end=4-JAN-2020, repeat-limit=50)

この例では、ルールは 1 時間ごとに 30 秒の遅延の後に実行されるようにスケジュールされ、2020 年 1 月 3 日に開始し、2020 年 1 月 4 日またはサイクルが 50 回繰り返された後に終了するようにスケジュールされています。

システムが一時停止すると (セッションがシリアライズされた後にデシリアライズされる場合など)、ルールは、一時停止中に実施されなかったアクティベーションの数にかかわらず、実施されなかったアクティベーションからの回復を 1 回のみ実施するようにスケジュールされており、ルールはその後にタイマー設定と同期して再度スケジュールされます。

DRL ルールの calendar 属性は、ルールのスケジュールのための Quartz カレンダー定義であり、以下の形式をサポートします。

カレンダー属性の形式

calendars "<definition or registered name>"

カレンダー属性の例

// Exclude non-business hours
calendars "* * 0-7,18-23 ? * *"

// Weekdays only, as registered in the KIE session
calendars "weekday"

以下の例ように、Quartz カレンダー API に基づいて Quartz カレンダーを適用し、そのカレンダーを KIE セッションに登録することができます。

Quartz カレンダーの適用

Calendar weekDayCal = QuartzHelper.quartzCalendarAdapter(org.quartz.Calendar quartzCal)

KIE セッションでのカレンダーの登録

ksession.getCalendars().set( "weekday", weekDayCal );

カレンダーは、標準のルールや、タイマーを使用するルールと共に使用できます。カレンダー属性には、String リテラルとして記述された 1 つ以上のコンマ区切りのカレンダー名を含めることができます。

以下のルールの例では、カレンダーとタイマーの両方を使用してルールをスケジュールします。

カレンダーとタイマーを使用したルールの例

rule "Weekdays are high priority"
  calendars "weekday"
  timer ( int:0 1h )
  when
    Alarm()
  then
    send( "priority high - we have an alarm" );
end

rule "Weekends are low priority"
  calendars "weekend"
  timer ( int:0 4h )
  when
    Alarm()
  then
    send( "priority low - we have an alarm" );
end

16.8. DRL のルール条件 (WHEN)

DRL ルールの when 部分 (ルールの左辺 (LHS)とも言う) には、アクションを実行するのに満たされなければならない条件が含まれます。条件は、パッケージ内で使用可能なデータオブジェクトに基づいて、指定された一連の パターン および 制約、オプションの バインディング およびサポートされるルール条件要素 (キーワード) で構成されます。たとえば、銀行のローンの申し込みに年齢制限 (21 歳以上) が必要な場合、"Underage" ルールの when 条件は Applicant( age < 21 ) となります。

注記

DRL は if ではなく when を使用します。これは、if が一般に手続き型の実行フローの一部であり、条件が特定の時点でチェックされるためです。一方、when は、条件の評価が特定の評価シーケンスや時点に限定されず、いつでも継続的に行われることを示しています。条件が満たされるたびに、これらのアクションが実施されます。

when セクションを空にすると、条件は true であると見なされ、デシジョンエンジンで fireAllRules() 呼び出しが最初に実施された場合に、then セクションのアクションが実行されます。これは、デシジョンエンジンのステートを設定するルールを使用する場合に便利です。

以下のルール例では、空の条件を使用して、ルールが実行するたびにファクトを挿入します。

条件のないルール例

rule "Always insert applicant"
  when
    // Empty
  then   // Actions to be executed once
    insert( new Applicant() );
end

// The rule is internally rewritten in the following way:

rule "Always insert applicant"
  when
    eval( true )
  then
    insert( new Applicant() );
end

ルールの条件が、定義されたキーワード接続詞 (andor、または not など) なしで複数のパターンを使用する場合、デフォルトの接続詞は and になります。

キーワード接続詞なしのルールの例

rule "Underage"
  when
    application : LoanApplication()
    Applicant( age < 21 )
  then
    // Actions
end

// The rule is internally rewritten in the following way:

rule "Underage"
  when
    application : LoanApplication()
    and Applicant( age < 21 )
  then
    // Actions
end

16.8.1. パターンと制約

DRL ルール条件の パターン は、デシジョンエンジンによって照合されるセグメントです。パターンは、デシジョンエンジンのワーキングメモリーに挿入される各ファクトと一致する可能性があります。パターンには 制約 を含めることもでき、これにより一致するファクトをより詳細に定義できます。

制約のない最も単純なフォームでは、パターンは指定されたタイプのファクトに一致します。以下の例ではタイプが Person であるため、このパターンはデシジョンエンジンのワーキングメモリーのすべての Person オブジェクトに一致します。

ファクトタイプが 1 つの場合のパターン例

Person()

このタイプは、ファクトオブジェクトの実際のクラスである必要はありません。パターンは、複数の異なるクラスのファクトと一致する可能性のあるスーパーユーザーやインターフェースも参照できます。たとえば、以下のパターンは、デシジョンエンジンのワーキングメモリーにあるすべてのオブジェクトと一致します。

すべてのオブジェクトの場合のパターン例

Object() // Matches all objects in the working memory

パターンの括弧は制約を囲みます (以下のユーザーの年齢に関する制約など)。

制約のあるパターンの例

Person( age == 50 )

制約は、true または false を返す式です。DRL 内のパターンの制約は、基本的にはプロパティーのアクセスなどの拡張が設定された Java の式ですが、== および != に対する equals() および !equals() セマンティクスなど、若干の違いがあります (通常の same および not same セマンティクスではありません)。

JavaBean プロパティーはパターンの制約から直接アクセスできます。Bean プロパティーは、引数を使用せずに何かを返す標準の JavaBeans の getter を使用して内部的に公開されます。たとえば、age プロパティーは、DRL で getter の getAge() ではなく、age として記述されます。

JavaBeans プロパティーを使用した DRL 制約構文

Person( age == 50 )

// This is the same as the following getter format:

Person( getAge() == 50 )

Red Hat Process Automation Manager は標準の JDK leavingspector クラスを使用してこのマッピングを行うため、標準の JavaBeans 仕様に従います。デシジョンエンジンのパフォーマンスの最適化には、getAge() のように getter を明示的に使用するのではなく、age のようなプロパティーアクセスの形式を使用します。

警告

デシジョンエンジンは効率化のために呼び出し間で一致した結果をキャッシュするため、プロパティーアクセサーを使用してルールに影響を与える可能性がある方法でオブジェクトの状態を変更しないでください。

たとえば、プロパティーアクセサーを以下のように使用しないでください。

public int getAge() {
    age++; // Do not do this.
    return age;
}
public int getAge() {
    Date now = DateUtil.now(); // Do not do this.
    return DateUtil.differenceInYears(now, birthday);
}

2 番目の例に従う代わりに、ワーキングメモリーに現在の日付をラップするファクトを挿入し、必要に応じてそのファクトを fireAllRules() の間で更新します。

ただし、プロパティーの getter が見つからなかった場合、コンパイラーは、以下のようにこのプロパティー名をフォールバックメソッド名として引数なしで使用します。

オブジェクトが見つからない場合のフォールバックメソッド

Person( age == 50 )

// If `Person.getAge()` does not exist, the compiler uses the following syntax:

Person( age() == 50 )

以下の例のように、パターンでアクセスプロパティーをネストすることもできます。ネストされたプロパティーにはデシジョンエンジンでインデックス化されます。

ネストされたプロパティーアクセスを使用するパターンの例

Person( address.houseNumber == 50 )

// This is the same as the following format:

Person( getAddress().getHouseNumber() == 50 )

警告

ステートフルな KIE セッションでは、ネストされたアクセサーの使用に注意が必要です。デシジョンエンジンのワーキングメモリーではネストされた値は認識されず、これらの値の変更は検出されません。ネストされた値の親参照がワーキングメモリーに挿入されている場合はこれらの値を不変と見なすか、ネストされた値を変更する必要がある場合は、すべての外部ファクトを更新済みとしてマークします。前の例では、houseNumber プロパティーが変更された場合は、この Address が指定された Person は更新済みとしてマークされる必要があります。

パターンの括弧内では boolean 値を制約として返す任意の Java 式を使用できます。Java 式は、プロパティーアクセスなどの他の式の拡張機能と組み合わせることができます。

プロパティーアクセスと Java 式を使用する制約が設定されたパターンの例

Person( age == 50 )

評価の優先度は、論理式や数式のように括弧を使用して変更できます。

制約の評価順序の例

Person( age > 100 && ( age % 10 == 0 ) )

以下の例のように、制約で Java メソッドを再利用することもできます。

再利用される Java メソッドによる制約の例

Person( Math.round( weight / ( height * height ) ) < 25.0 )

警告

デシジョンエンジンは効率化を図るために呼び出し間で一致の結果をキャッシュするため、ルールに影響を与える可能性のある方法でオブジェクトの状態を変更するために制約を使用しないでください。ルール条件のファクトで実行されるメソッドは、読み取り専用のメソッドである必要があります。また、ファクトの状態は、ファクトがワーキングメモリーで更新済みとしてマークされているのでない限り、毎回変更されるたびにルールの呼び出し間で変更されません。

たとえば、以下のような方法でパターンの制約を使用しないでください。

Person( incrementAndGetAge() == 10 ) // Do not do this.
Person( System.currentTimeMillis() % 1000 == 0 ) // Do not do this.

DRL 内の制約演算子には、標準の Java 演算子の優先順位が適用されます。DRL 演算子は、== および != 演算子を除き、標準の Java セマンティクスに従います。

== 演算子は、通常の same セマンティクスではなく、null 安全な equals() セマンティクスを使用します。たとえば、Person( firstName == "John" ) というパターンは java.util.Objects.equals(person.getFirstName(), "John") と同様であり、"John" は null でないため、このパターンは "John".equals(person.getFirstName()) にも似ています。

!= 演算子は、通常の not same セマンティクスではなく null 安全な !equals() セマンティクスを使用します。たとえば、Person( firstName != "John" ) というパターンは、!java.util.Objects.equals(person.getFirstName(), "John") に似ています。

フィールドと制約の値が異なるタイプの場合、デシジョンエンジンは型強制 (type coercion) を使用して競合を解決し、コンパイルエラーを減らします。たとえば、"ten" が数値エバリュエーターで文字列として指定される場合は、コンパイルエラーが発生しますが、"10" は数値 10 に型強制されます。型強制では、フィールドのタイプは常に値のタイプより優先されます。

型強制された値を使用する制約の例

Person( age == "10" ) // "10" is coerced to 10

制約のグループの場合は、コンマ区切り (,) を使って、暗黙的な and の接続的なセマンティクスを使用することができます。

複数の制約があるパターンの例

// Person is at least 50 years old and weighs at least 80 kilograms:
Person( age > 50, weight > 80 )

// Person is at least 50 years old, weighs at least 80 kilograms, and is taller than 2 meters:
Person( age > 50, weight > 80, height > 2 )

注記

&& 演算子および , 演算子のセマンティクスは同じですが、これらは異なる優先順位で解決されます。&& 演算子は || 演算子より優先され、&& 演算子および || 演算子はどちらも , 演算子より優先されます。デシジョンエンジンのパフォーマンスと人による可読性を最適化するために、コンマ演算子は最上位レベルの制約で使用してください。

括弧内など、複合制約式にコンマ演算子を埋め込むことはできません。

複合制約式での不適切なコンマの例

// Do not use the following format:
Person( ( age > 50, weight > 80 ) || height > 2 )

// Use the following format instead:
Person( ( age > 50 && weight > 80 ) || height > 2 )

16.8.2. パターンと制約でバインドされた変数

パターンおよび制約に変数をバインドして、ルールの他の部分で一致するオブジェクトを参照することができます。バインドされた変数は、ルールをより効率的に、かつデータモデルでのファクトへのアノテーションの付け方と一貫した方法で定義するのに役立ちます。(とくに複雑なルールの場合に) ルール内で変数とフィールドを簡単に区別するには、変数に対して標準の形式である $variable を使用します。この規則は便利ですが、DRL で必須ではありません。

たとえば、以下の DRL ルールでは、Person ファクトが指定されたパターンに対して変数 $p が使用されています。

バインドされた変数が使用されているパターン

rule "simple rule"
  when
    $p : Person()
  then
    System.out.println( "Person " + $p );
end

同様に、以下の例のように、パターンの制約で変数をプロパティーにバインドすることもできます。

// Two persons of the same age:
Person( $firstAge : age ) // Binding
Person( age == $firstAge ) // Constraint expression
注記

より明確で効率的なルールを定義するには、制約のバインディングと制約式を必ず分離します。バインディングと式の組み合わせはサポートされますが、パターンが複雑になり、評価の効率に影響が及ぶ可能性があります。

// Do not use the following format:
Person( $age : age * 2 < 100 )

// Use the following format instead:
Person( age * 2 < 100, $age : age )

デシジョンエンジンは同じ宣言に対するバインディングをサポートしませんが、複数のプロパティー間での引数の ユニフィケーション をサポートします。位置引数は、常にユニフィケーションで常に処理され、名前付き引数の場合はユニフィケーション記号 := が使用されます。

以下のパターンの例では、2 つの Person ファクト間で age プロパティーを統合します。

ユニフィケーションが使用されるパターンの例

Person( $age := age )
Person( $age := age )

ユニフィケーションは、シーケンスオカレンスのバインドされたフィールドの同じ値に対して、最初のオカレンスと制約のバインディングを宣言します。

16.8.3. ネストされた制約とインラインキャスト

以下の例のように、ネストされたオブジェクトの複数のプロパティーにアクセスしなければならない場合があります。

複数のプロパティーにアクセスするパターンの例

Person( name == "mark", address.city == "london", address.country == "uk" )

以下の例のように、これらのプロパティーのアクセサーを、.( <constraints> ) という構文を使用してネストされたオブジェクトに対してグループ化することで、ルールを読みやすくすることができます。

グループ化された制約を使用したパターンの例

Person( name == "mark", address.( city == "london", country == "uk") )

注記

ピリオドのプリフィックス . は、メソッド呼び出しとネストされたオブジェクト制約を区別します。

パターンでネストされたオブジェクトを使用する場合は、構文 <type>#<subtype> を使用してサブタイプにキャストし、親タイプの getter をサブタイプに対して利用可能にします。以下の例のように、オブジェクト名または完全修飾クラス名のいずれかを使用して、1 つまたは複数のサブタイプにキャストできます。

サブタイプへのインラインキャストを使用したパターンの例

// Inline casting with subtype name:
Person( name == "mark", address#LongAddress.country == "uk" )

// Inline casting with fully qualified class name:
Person( name == "mark", address#org.domain.LongAddress.country == "uk" )

// Multiple inline casts:
Person( name == "mark", address#LongAddress.country#DetailedCountry.population > 10000000 )

これらのパターン例では、AddressLongAddress に、さらに最後の例にある DetailedCountry にキャストし、各ケースのサブタイプで親の getter を利用可能にします。

以下の例のように、instanceof 演算子を使用して、パターンを使用した後続のフィールドで指定されたタイプの結果を推測できます。

Person( name == "mark", address instanceof LongAddress, address.country == "uk" )

インラインキャストが使用できない場合 (たとえば instanceoffalse を返す場合)、評価は false と見なされます。

16.8.4. 制約内の日付リテラル

デフォルトで、デシジョンエンジンは dd-mmm-yyyy という日付形式をサポートします。この日付形式 (必要に応じて時間形式マスクを含む) は、システムプロパティー drools.dateformat="dd-mmm-yyyy hh:mm" を使用して、別の形式マスクを指定することによってカスタマイズすることができます。日付形式は、drools.defaultlanguage および drools.defaultcountry システムプロパティーを使用し、言語ロケールを変更することによってカスタマイズすることもできます (たとえば、タイのロケールは drools.defaultlanguage=th および drools.defaultcountry=TH と設定します)。

日付のリテラル制限を使用したパターンの例

Person( bornBefore < "27-Oct-2009" )

16.8.5. DRL のパターン制約でサポートされている演算子

DRL では、パターン制約の演算子で標準の Java セマンティクスがサポートされていますが、いくつかの例外があり、追加となる DRL 固有の演算子もいくつかあります。以下の一覧は、標準の Java セマンティクスとは異なる方法で処理される DRL の制約の演算子や DRL の制約に固有の演算子をまとめています。

.(), #

.() 演算子を使用すると、プロパティーのアクセサーをネストされたオブジェクトにグループ化でき、# 演算子を使用すると、ネストされたオブジェクトのサブタイプにキャストできます。サブタイプにキャストすることで、親タイプの getter をサブタイプに対して使用できるようになります。オブジェクト名または完全修飾クラス名のいずれかを使用でき、1 つまたは複数のサブタイプにキャストできます。

ネストされたオブジェクトが使用されるパターンの例

// Ungrouped property accessors:
Person( name == "mark", address.city == "london", address.country == "uk" )

// Grouped property accessors:
Person( name == "mark", address.( city == "london", country == "uk") )

注記

ピリオドのプリフィックス . は、メソッド呼び出しとネストされたオブジェクト制約を区別します。

サブタイプへのインラインキャストを使用したパターンの例

// Inline casting with subtype name:
Person( name == "mark", address#LongAddress.country == "uk" )

// Inline casting with fully qualified class name:
Person( name == "mark", address#org.domain.LongAddress.country == "uk" )

// Multiple inline casts:
Person( name == "mark", address#LongAddress.country#DetailedCountry.population > 10000000 )

!.

この演算子を使用すると、null 安全な方法でプロパティーを逆参照します。パターンマッチングの適切な結果を得るには、!. 演算子の左側の値を null にすることはできません (!= null と解釈される)。

null 安全な逆参照を使用した制約の例

Person( $streetName : address!.street )

// This is internally rewritten in the following way:

Person( address != null, $streetName : address.street )

[]

この演算子を使用して、インデックスで List 値にアクセスするか、またはキーで Map 値にアクセスします。

List および Map アクセスを使用する制約の例

// The following format is the same as `childList(0).getAge() == 18`:
Person(childList[0].age == 18)

// The following format is the same as `credentialMap.get("jdoe").isValid()`:
Person(credentialMap["jdoe"].valid)

<<=>>=

これらの演算子は、自然順序付けのあるプロパティーに使用されます。たとえば、< 演算子は、Date フィールドでは を意味し、String フィールドでは アルファベット順で前 であることを意味します。これらのプロパティーは、比較可能なプロパティーにのみ適用されます。

before 演算子を使用した制約の例

Person( birthDate < $otherBirthDate )

Person( firstName < $otherFirstName )

==, !=

制約では、これらの演算子を、通常の same および not same セマンティクスではなく、equals() および !equals() メソッドとして使用します。

null 安全な等価性を使用する制約の例

Person( firstName == "John" )

// This is similar to the following formats:

java.util.Objects.equals(person.getFirstName(), "John")
"John".equals(person.getFirstName())

null 安全な非等価性を使用する制約の例

Person( firstName != "John" )

// This is similar to the following format:

!java.util.Objects.equals(person.getFirstName(), "John")

&&, ||

これらの演算子を使用して、フィールドに複数の制約を追加する略記組合せ比較条件を作成します。再帰的な構文パターンを作成するには、括弧 () を使用して制約をグループ化します。

略記組合せ比較を使用する制約の例

// Simple abbreviated combined relation condition using a single `&&`:
Person(age > 30 && < 40)

// Complex abbreviated combined relation using groupings:
Person(age ((> 30 && < 40) || (> 20 && < 25)))

// Mixing abbreviated combined relation with constraint connectives:
Person(age > 30 && < 40 || location == "london")

matches, not matches

これらの演算子を使用して、指定された Java 正規表現にフィールドが一致するか、または一致しないかを示します。一般に、正規表現は String リテラルですが、有効な正規表現に解決される変数もサポートされます。これらの演算子は String プロパティーのみに適用されます。null 値に対して matches を使用する場合は、結果の評価が常に false になります。null 値に対して not matches を使用する場合は、結果の評価が常に true になります。Java の場合のように、String リテラルとして記述された正規表現は二重のバックスラッシュ \\ を使用してエスケープする必要があります。

正規表現と一致する制約または一致しない制約の例

Person( country matches "(USA)?\\S*UK" )

Person( country not matches "(USA)?\\S*UK" )

contains, not contains

これらの演算子を使用して、フィールドの Array または Collection が指定された値を含むか、または含まないかを検証します。これらの演算子は Array プロパティーまたは Collection プロパティーに適用されますが、これらの演算子を String.contains() および !String.contains() の制約チェックの代わりとして使用することもできます。

コレクションに対して contains および not contains が使用された制約の例

// Collection with a specified field:
FamilyTree( countries contains "UK" )

FamilyTree( countries not contains "UK" )


// Collection with a variable:
FamilyTree( countries contains $var )

FamilyTree( countries not contains $var )

String リテラルに対して contains および not contains が使用された制約の例

// Sting literal with a specified field:
Person( fullName contains "Jr" )

Person( fullName not contains "Jr" )


// String literal with a variable:
Person( fullName contains $var )

Person( fullName not contains $var )

注記

下位互換性を確保するため、excludes 演算子は not contains の同義語としてサポートされます。

memberOf, not memberOf

これらの演算子を使用して、フィールドが変数として定義されている Array または Collection のメンバーであるかどうかを検証します。Array または Collection は変数でなければなりません。

コレクションと memberOf および not memberOf を使用する制約の例

FamilyTree( person memberOf $europeanDescendants )

FamilyTree( person not memberOf $europeanDescendants )

soundslike

この演算子を使用して、ある単語を英語で発音した場合に、指定された値と発音がほぼ同じであるかどうかを検証します (matches 演算子に類似)。この演算子は Soundex アルゴリズムを使用します。

soundslike を使用した制約の例

// Match firstName "Jon" or "John":
Person( firstName soundslike "John" )

str

この演算子を使用して、String であるフィールドが指定された値で開始しているか、または終了しているかを検証します。この演算子を使用して、String の長さを検証することもできます。

str を使用する制約の例

// Verify what the String starts with:
Message( routingValue str[startsWith] "R1" )

// Verify what the String ends with:
Message( routingValue str[endsWith] "R2" )

// Verify the length of the String:
Message( routingValue str[length] 17 )

innotin

これらの演算子を使用して、制約の中で一致する可能性がある複数の値を指定します (複合値の制約)。複合値の制約についての機能をサポートするのは in 演算子および not in 演算子のみです。これらの演算子の 2 番目のオペランドは、括弧で囲み、コンマ区切り値の一覧で指定する必要があります。値は変数、リテラル、戻り値、または修飾された識別子として指定できます。これらの演算子は、== または != 演算子を使用し、複数の制約のリストとして内部に再書き込みされます。

in および notin を使用した制約の例

Person( $color : favoriteColor )
Color( type in ( "red", "blue", $color ) )

Person( $color : favoriteColor )
Color( type notin ( "red", "blue", $color ) )

16.8.6. DRL のパターン制約における演算子の優先順位

DRL では、適用可能な制約演算子の場合は標準的な Java 演算子の優先順位をサポートしていますが、一部の例外と、DRL に固有の追加の演算子がいくつかあります。以下の表には、適用可能な DRL 演算子を優先順位の高いものから低いものの順で記載しています。

表16.2 DRL のパターン制約における演算子の優先順位

演算子のタイプ演算子注記

ネストされているか、null 安全なプロパティーアクセス

..()!.

標準の Java セマンティクスではない

List または Map アクセス

[]

標準の Java セマンティクスではない

制約のバインディング

:

標準の Java セマンティクスではない

乗法

*/%

 

加法

+-

 

シフト

>>>>><<

 

リレーショナル

<<=>>=instanceof

 

等価性

== !=

標準の Java の same および not same セマンティクスではなく、equals() および !equals() を使用

非短絡 (Non-short-circuiting) AND

&

 

非短絡の排他的 OR

^

 

非短絡の包含的 OR

|

 

論理 AND

&&

 

論理 OR

||

 

三項

? :

 

コンマ区切り AND

,

標準の Java セマンティクスではない

16.8.7. DRL でサポートされるルール条件要素 (キーワード)

DRL では、DRL のルール条件で定義するパターンで使用できる以下のルール条件要素 (キーワード) がサポートされます。

and

条件コンポーネントを論理積に分類します。インフィックスおよびプリフィックスの and がサポートされます。括弧 () を使用することにより、パターンを明示的にグループ化できます。デフォルトでは、結合演算子を指定しないと、リストされているパターンがすべて and で結合されます。

and を使用したパターンの例

//Infix `and`:
Color( colorType : type ) and Person( favoriteColor == colorType )

//Infix `and` with grouping:
(Color( colorType : type ) and (Person( favoriteColor == colorType ) or Person( favoriteColor == colorType ))

// Prefix `and`:
(and Color( colorType : type ) Person( favoriteColor == colorType ))

// Default implicit `and`:
Color( colorType : type )
Person( favoriteColor == colorType )

注記

先頭の宣言のバインディングには and キーワードを使用しないでください (or などは使用できます)。宣言が参照できるのは一度に 1 つのファクトのみであり、and と宣言のバインディングを使用すると、and が満たされた場合にこの要素が両方のファクトと一致してしまうため、エラーが発生します。

and の誤った使用例

// Causes compile error:
$person : (Person( name == "Romeo" ) and Person( name == "Juliet"))

or

条件コンポーネントを論理和にグループ化します。インフィックスおよびプリフィックスの or がサポートされます。括弧 () を使用することにより、パターンを明示的にグループ化できます。or と共にパターンバインディングを使用することもできますが、各パターンは個別にバインディングする必要があります。

or を使用したパターンの例

//Infix `or`:
Color( colorType : type ) or Person( favoriteColor == colorType )

//Infix `or` with grouping:
(Color( colorType : type ) or (Person( favoriteColor == colorType ) and Person( favoriteColor == colorType ))

// Prefix `or`:
(or Color( colorType : type ) Person( favoriteColor == colorType ))

or とパターンのバインディングを使用したパターンの例

pensioner : (Person( sex == "f", age > 60 ) or Person( sex == "m", age > 65 ))

(or pensioner : Person( sex == "f", age > 60 )
    pensioner : Person( sex == "m", age > 65 ))

or 条件要素の動作は、制約や、フィールド制約の制限を対象とした接続演算子 ( ||) とは異なります。デシジョンエンジンは or 要素を直接解釈しませんが、論理変換を使用して、or が使用されているルールを複数のサブルールに書き換えます。このプロセスにより、最終的には、ルートノードおよび各条件要素のサブルールとして、1 つの or を使用するルールが生成されます。サブルール間での操作や、特別な動作なしに、各サブルールは通常のルールと同様に有効にされ、実行されます。

したがって、or 条件要素については複数の類似したルールを生成するための近道であり、複数の論理和が true である場合は、複数のアクティベーションが作成される可能性があることに留意してください。

exists

存在している必要のあるファクトおよび制約を指定します。このオプションは、最初に一致したものだけが適用され、その後一致するものは無視されます。この要素を複数のパターンで使用する場合は、これらのパターンを括弧 () で囲みます。

exists を使用したパターンの例

exists Person( firstName == "John")

exists (Person( firstName == "John", age == 42 ))

exists (Person( firstName == "John" ) and
        Person( lastName == "Doe" ))

not

存在していてはならないファクトと制約を指定します。この要素を複数のパターンで使用する場合は、これらのパターンを括弧 () で囲みます。

not を使用したパターンの例

not Person( firstName == "John")

not (Person( firstName == "John", age == 42 ))

not (Person( firstName == "John" ) and
     Person( lastName == "Doe" ))

forall

最初のパターンと一致するすべてのファクトが残りのパターンのすべてと一致するかどうかを検証します。forall 構成が満たされると、このルールが true と評価されます。この要素は範囲の区切りであるため、以前にバインドされたすべての変数を使用できますが、内部でバインドされた変数を外部で使用することはできません。

forall を使用したルールの例

rule "All full-time employees have red ID badges"
  when
    forall( $emp : Employee( type == "fulltime" )
                   Employee( this == $emp, badgeColor = "red" ) )
  then
    // True, all full-time employees have red ID badges.
end

この例では、ルールによってタイプが "fulltime" であるすべての Employee オブジェクトが選択されます。このパターンに一致するそれぞれのファクトに対して、ルールは、従うパターン (バッジの色) を評価し、一致すると、ルールは true と評価されます。

デシジョンエンジンのワーキングメモリー内の特定のタイプのすべてのファクトが一連の制約と一致する必要があることを示すために、単純化するために単一のパターンで forall を使用できます。

forall と 1 つのパターンを使用するルールの例

rule "All full-time employees have red ID badges"
  when
    forall( Employee( badgeColor = "red" ) )
  then
    // True, all full-time employees have red ID badges.
end

複数のパターンと forall 構成を使用するか、not 要素構成内など他の条件要素でネスト化することができます。

forall と複数のパターンを使用するルールの例

rule "All employees have health and dental care programs"
  when
    forall( $emp : Employee()
            HealthCare( employee == $emp )
            DentalCare( employee == $emp )
          )
  then
    // True, all employees have health and dental care.
end

forallnot を使用するルールの例

rule "Not all employees have health and dental care"
  when
    not ( forall( $emp : Employee()
                  HealthCare( employee == $emp )
                  DentalCare( employee == $emp ) )
        )
  then
    // True, not all employees have health and dental care.
end

注記

forall( p1 p2 p3 …​) の形式は not( p1 and not( and p2 p3 …​ ) ) と等価です。

from

これを使用してパターンのデータソースを指定します。これにより、デシジョンエンジンがワーキングメモリーにないデータに対して推論できるようになります。データソースには、バインドされた変数のサブフィールド、またはメソッド呼び出しの結果を指定できます。オブジェクトソースの定義に使用される式として、通常の MVEL 構文に準拠する任意の式を使用できます。このため、from 要素により、オブジェクトプロパティーのナビゲーションを使用して、メソッド呼び出しを実行し、マップとコレクション要素にアクセスすることが簡単にできます。

from およびパターンのバインディングを使用するルールの例

rule "Validate zipcode"
  when
    Person( $personAddress : address )
    Address( zipcode == "23920W" ) from $personAddress
  then
    // Zip code is okay.
end

from とグラフ表記を使用するルールの例

rule "Validate zipcode"
  when
    $p : Person()
    $a : Address( zipcode == "23920W" ) from $p.address
  then
    // Zip code is okay.
end

すべてのオブジェクトに対して反復処理される from のルールの例

rule "Apply 10% discount to all items over US$ 100 in an order"
  when
    $order : Order()
    $item  : OrderItem( value > 100 ) from $order.items
  then
    // Apply discount to `$item`.
end

注記

オブジェクトの大規模なコレクションの場合は、デシジョンエンジンが頻繁に繰り返す必要がある大きなグラフを持つオブジェクトを追加するのではなく、次の例に示すように、コレクションを直接 KIE セッションに追加して、コレクションを条件に結合します。

when
  $order : Order()
  OrderItem( value > 100, order == $order )

from および lock-on-active ルール属性を使用するルールの例

rule "Assign people in North Carolina (NC) to sales region 1"
  ruleflow-group "test"
  lock-on-active true
  when
    $p : Person()
    $a : Address( state == "NC" ) from $p.address
  then
    modify ($p) {} // Assign the person to sales region 1.
end

rule "Apply a discount to people in the city of Raleigh"
  ruleflow-group "test"
  lock-on-active true
  when
    $p : Person()
    $a : Address( city == "Raleigh" ) from $p.address
  then
    modify ($p) {} // Apply discount to the person.
end

重要

fromlock-on-active のルール属性を同時に使用すると、ルールが実行しなくなります。この問題に対しては、以下のいずれかの方法で対処できます。

  • すべてのファクトをデシジョンエンジンのワーキングメモリーに挿入したり、制約式でネストされたオブジェクト参照を使用したりする場合は、from 要素は使用しないでください。
  • ルール条件の最後の文として、modify() ブロックで使用される変数を配置します。
  • 同じルールフローグループ内のルールがアクティベーションを相互に組み込む方法を明示的に管理できる場合は、lock-on-active ルール属性を使用しないでください。

from 句を含むパターンの後に、括弧から始まる別のパターンを使用することはできません。この制限がある理由は、DRL パーサーが from 式を "from $l (String() or Number())" として読み取り、この式を関数呼び出しと区別できないためです。この最も単純な回避策は、以下の例に示すように、from 句を括弧でラップする方法です。

from が適切に使用されていないルールと適切に使用されているルールの例

// Do not use `from` in this way:
rule R
  when
    $l : List()
    String() from $l
    (String() or Number())
  then
    // Actions
end

// Use `from` in this way instead:
rule R
  when
    $l : List()
    (String() from $l)
    (String() or Number())
  then
    // Actions
end

entry-point

エントリーポイントまたはパターンのデータソースに対応した イベントストリーム を定義します。この要素は通常、from 条件要素と共に使用します。イベントのエントリーポイントを宣言し、デシジョンエンジンがそのエントリーポイントからのデータのみを使用してルールを評価することが可能です。エントリーポイントは、DRL ルールで参照することで暗黙的に宣言することも、Java アプリケーションで明示的に宣言することもできます。

from entry-point を使用したルールの例

rule "Authorize withdrawal"
  when
    WithdrawRequest( $ai : accountId, $am : amount ) from entry-point "ATM Stream"
    CheckingAccount( accountId == $ai, balance > $am )
  then
    // Authorize withdrawal.
end

EntryPoint オブジェクトが使用され、ファクトが挿入された Java アプリケーションコードの例

import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.EntryPoint;

// Create your KIE base and KIE session as usual:
KieSession session = ...

// Create a reference to the entry point:
EntryPoint atmStream = session.getEntryPoint("ATM Stream");

// Start inserting your facts into the entry point:
atmStream.insert(aWithdrawRequest);

collect

ルールで条件の一部として使用できるオブジェクトのコレクションを定義します。このルールは、指定されたソースまたはデシジョンエンジンのワーキングメモリーのいずれかからコレクションを取得します。collect 要素の結果パターンには、java.util.Collection インターフェースを実装し、デフォルトの引数を持たないパブリックコンストラクターを指定する任意の具象クラスを使用できます。ListLinkedList、および HashSet のような Java コレクションを使用することも、独自のクラスを使用することもできます。条件内で collect 要素の前に変数がバインドされている場合は、その変数を使用してソースおよび結果パターンの両方を制限することができます。ただし、collect 要素内で作成されるバインディングをその外部で使用することはできません。

collect を使用するルールの例

import java.util.List

rule "Raise priority when system has more than three pending alarms"
  when
    $system : System()
    $alarms : List( size >= 3 )
              from collect( Alarm( system == $system, status == 'pending' ) )
  then
    // Raise priority because `$system` has three or more `$alarms` pending.
end

この例では、ルールは指定された各システムのデシジョンエンジンのワーキングメモリーの保留中のすべてのアラームを評価し、それらを List にグループ化します。指定されたシステムについての 3 つ以上のアラームが見つかると、ルールが実行します。

以下の例のように、ネストされた from 要素と共に collect 要素を使用することもできます。

collect とネストされた from を使用するルールの例

import java.util.LinkedList;

rule "Send a message to all parents"
  when
    $town : Town( name == 'Paris' )
    $mothers : LinkedList()
               from collect( Person( children > 0 )
                             from $town.getPeople()
                           )
  then
    // Send a message to all parents.
end

accumulate

オブジェクトのコレクションを反復処理し、各要素に対してカスタムアクションを実行し、結果オブジェクトを返します (制約が true に評価される場合)。この要素は、collect 条件要素のより柔軟性が高い、強化された形式です。accumulate 条件で事前に定義した関数を使用するか、必要に応じてカスタム関数を実装できます。また、ルール条件で accumulate の短縮形である acc を使用することもできます。

以下の形式を使用して、ルールに accumulate 条件を定義します。

accumulate の推奨形式

accumulate( <source pattern>; <functions> [;<constraints>] )

注記

デシジョンエンジンは下位互換性を確保するために accumulate 要素の代替形式をサポートしますが、この形式は、ルールとアプリケーションの最適なパフォーマンスという点ではより適しています。

デシジョンエンジンは、以下の事前に定義された accumulate 関数をサポートします。これらの関数は、任意の式を入力として受け入れます。

  • average
  • min
  • max
  • count
  • sum
  • collectList
  • collectSet

以下のルールの例では、minmax、および averageaccumulate 関数であり、各センサーの読み取り値での最低、最高、および平均の温度値を算出します。

温度値を算出する accumulate を使用したルールの例

rule "Raise alarm"
  when
    $s : Sensor()
    accumulate( Reading( sensor == $s, $temp : temperature );
                $min : min( $temp ),
                $max : max( $temp ),
                $avg : average( $temp );
                $min < 20, $avg > 70 )
  then
    // Raise the alarm.
end

以下のルールの例では、accumulate を指定した average 関数を使用して、ある注文のすべてのアイテムの平均収益を計算します。

平均収益を計算する accumulate を使用したルールの例

rule "Average profit"
  when
    $order : Order()
    accumulate( OrderItem( order == $order, $cost : cost, $price : price );
                $avgProfit : average( 1 - $cost / $price ) )
  then
    // Average profit for `$order` is `$avgProfit`.
end

accumulate の条件でカスタムかつドメイン固有の関数を使用するには、org.kie.api.runtime.rule.AccumulateFunction インターフェースを実装する Java クラスを作成します。たとえば、以下の Java クラスは AverageData 関数のカスタム実装を定義します。

average 関数がカスタムで実装された Java クラスの例

// An implementation of an accumulator capable of calculating average values

public class AverageAccumulateFunction implements org.kie.api.runtime.rule.AccumulateFunction<AverageAccumulateFunction.AverageData> {

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {

    }

    public void writeExternal(ObjectOutput out) throws IOException {

    }

    public static class AverageData implements Externalizable {
        public int    count = 0;
        public double total = 0;

        public AverageData() {}

        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            count   = in.readInt();
            total   = in.readDouble();
        }

        public void writeExternal(ObjectOutput out) throws IOException {
            out.writeInt(count);
            out.writeDouble(total);
        }

    }

    /* (non-Javadoc)
     * @see org.kie.api.runtime.rule.AccumulateFunction#createContext()
     */
    public AverageData createContext() {
        return new AverageData();
    }

    /* (non-Javadoc)
     * @see org.kie.api.runtime.rule.AccumulateFunction#init(java.io.Serializable)
     */
    public void init(AverageData context) {
        context.count = 0;
        context.total = 0;
    }

    /* (non-Javadoc)
     * @see org.kie.api.runtime.rule.AccumulateFunction#accumulate(java.io.Serializable, java.lang.Object)
     */
    public void accumulate(AverageData context,
                           Object value) {
        context.count++;
        context.total += ((Number) value).doubleValue();
    }

    /* (non-Javadoc)
     * @see org.kie.api.runtime.rule.AccumulateFunction#reverse(java.io.Serializable, java.lang.Object)
     */
    public void reverse(AverageData context, Object value) {
        context.count--;
        context.total -= ((Number) value).doubleValue();
    }

    /* (non-Javadoc)
     * @see org.kie.api.runtime.rule.AccumulateFunction#getResult(java.io.Serializable)
     */
    public Object getResult(AverageData context) {
        return new Double( context.count == 0 ? 0 : context.total / context.count );
    }

    /* (non-Javadoc)
     * @see org.kie.api.runtime.rule.AccumulateFunction#supportsReverse()
     */
    public boolean supportsReverse() {
        return true;
    }

    /* (non-Javadoc)
     * @see org.kie.api.runtime.rule.AccumulateFunction#getResultType()
     */
    public Class< ? > getResultType() {
        return Number.class;
    }

}

DRL ルールでカスタム関数を使用するため、import accumulate ステートメントを使用してその関数をインポートします。

カスタム関数をインポートするための形式

import accumulate <class_name> <function_name>

インポートされた average 関数を使用するルールの例

import accumulate AverageAccumulateFunction.AverageData average

rule "Average profit"
  when
    $order : Order()
    accumulate( OrderItem( order == $order, $cost : cost, $price : price );
                $avgProfit : average( 1 - $cost / $price ) )
  then
    // Average profit for `$order` is `$avgProfit`.
end

16.8.8. DRL ルール条件内でオブジェクトのグラフが使用される OOPath 構文

OOPath は、DRL ルールの条件の制約でオブジェクトのグラフを参照するために設計された XPath のオブジェクト指向構文の拡張です。OOPath は、コレクションおよびフィルター制約を処理する間に XPath からのコンパクト表記を使用して関連要素を移動します。また、OOPath は特にオブジェクトグラフの場合に役に立ちます。

ファクトのフィールドがコレクションである場合は、from 条件要素 (キーワード) を使用してバインドし、そのコレクションのすべての項目を 1 つずつ判断することができます。ルール条件制約でオブジェクトのグラフを参照する必要がある場合は、from 条件要素を過度に使用すると、以下の例のように冗長かつ繰り返しの多い構文になります。

from を使用してオブジェクトのグラフを参照するルールの例

rule "Find all grades for Big Data exam"
  when
    $student: Student( $plan: plan )
    $exam: Exam( course == "Big Data" ) from $plan.exams
    $grade: Grade() from $exam.grades
  then
    // Actions
end

この例では、ドメインモデルには Student オブジェクトと学習の Plan が含まれています。Plan には、ゼロ以上の Exam インスタンスを指定でき、Exam にはゼロ以上の Grade インスタンスを指定できます。このルール設定が機能するためにデシジョンエンジンのワーキングメモリーに存在する必要があるのは、グラフのルートオブジェクト (この例では Student) のみです。

from ステートメントを使用するより効率的な別の方法として、以下の例のように短縮された OOPath 構文を使用できます。

OOPath 構文でオブジェクトのグラフを参照するルールの例

rule "Find all grades for Big Data exam"
  when
    Student( $grade: /plan/exams[course == "Big Data"]/grades )
  then
    // Actions
end

通常、OOPath 式の中核となる文法は、以下のように拡張された Backus-Naur form (EBNF) 表記で定義されます。

OOPath 式の EBNF 表記

OOPExpr = [ID ( ":" | ":=" )] ( "/" | "?/" ) OOPSegment { ( "/" | "?/" | "." ) OOPSegment } ;
OOPSegment = ID ["#" ID] ["[" ( Number | Constraints ) "]"]

OOPath 式の実際の特性および機能は以下のとおりです。

  • 非リアクティブな OOPath 式の場合は、スラッシュ / または疑問符とスラッシュ ?/ で始まります (このセクションで後述します)。
  • オブジェクトの単一プロパティーを、ピリオド . 演算子を使用して逆参照できます。
  • オブジェクトの複数のプロパティーをスラッシュ / 演算子を使用して逆参照できます。コレクションが返される場合、この式はコレクションの値を反復処理します。
  • 1 つまたは複数の制約を満たさない、走査されたオブジェクトをフィルターで除外できます。この制約は、以下の例のように、角括弧内の述語式として記述されます。

    述語式としての制約

    Student( $grade: /plan/exams[ course == "Big Data" ]/grades )

  • 汎用コレクションで宣言されたクラスのサブクラスに走査されたオブジェクトをダウンキャストできます。以下の例に示すように、後続の制約も、このサブクラスで宣言されたプロパティーにのみ安全にアクセスすることができます。このインラインキャストで指定されたクラスのインスタンスではないオブジェクトは、自動的にフィルターで除外されます。

    ダウンキャストオブジェクトが使用される制約

    Student( $grade: /plan/exams#AdvancedExam[ course == "Big Data", level > 3 ]/grades )

  • 現在の反復処理されたグラフの前に走査されたグラフのオブジェクトを前方参照できます。たとえば、以下の OOPath 式は、合格した試験の平均を上回るグレードにのみ一致します。

    前方参照オブジェクトを使用する制約

    Student( $grade: /plan/exams/grades[ result > ../averageResult ] )

  • 以下の例のように、別の OOPath 式を再帰的に使用できます。

    再帰的な制約式

    Student( $exam: /plan/exams[ /grades[ result > 20 ] ] )

  • 以下の例のように、角括弧 [] 内のオブジェクトのインデックスを使用することにより、そのオブジェクトにアクセスすることができます。Java の規則に従うために、OOPath のインデックスは 0 をベースとし、XPath のインデックスは 1 をベースとします。

    インデックスによるオブジェクトへのアクセスが設定された制約

    Student( $grade: /plan/exams[0]/grades )

OOPath 式は、リアクティブまたは非リアクティブにできます。デシジョンエンジンは、深くネスト化されており、OOPath 式の評価中に走査されたオブジェクトを含む更新には反応しません。

これらのオブジェクトが変更に反応するようにするには、org.drools.core.phreak.ReactiveObject クラスを拡張するようにオブジェクトを変更します。オブジェクトを変更して ReactiveObject クラスを拡張すると、ドメインオブジェクトはいずれかのフィールドが更新されている場合に、以下のように継承されたメソッド notifyModification を呼び出して、デシジョンエンジンに通知します。

試験が別のコースに移動したことをデシジョンエンジンに通知するオブジェクトメソッドの例

public void setCourse(String course) {
        this.course = course;
        notifyModification(this);
        }

次の対応する OOPath 式を使すると、試験が別のコースに移動された場合にルールが再実行され、そのルールに一致するグレードのリストが再計算されます。

「Big Data」ルールの OOPath 式の例

Student( $grade: /plan/exams[ course == "Big Data" ]/grades )

以下の例に示すように、/ セパレーターの代わりに ?/ セパレーターを使用して、OOPath 式の一部のみについてリアクティビティーを無効にすることもできます。

部分的に非リアクティブである OOPath 式の例

Student( $grade: /plan/exams[ course == "Big Data" ]?/grades )

この例では、デシジョンエンジンは試験に対して実施された変更や、計画に試験が追加された場合に反応しますが、既存の試験に新しいグレードが追加された場合には反応しません。

OOPath の一部が非リアクティブである場合は、OOPath 式の残りの部分も非リアクティブになります。たとえば、以下の OOPath 式は完全に非リアクティブです。

完全に非リアクティブである OOPath 式の例

Student( $grade: ?/plan/exams[ course == "Big Data" ]/grades )

こうした理由から、同じ OOPath 式内で ?/ セパレーターを複数回使用することはできません。たとえば、以下の式はコンパイルエラーの原因となります。

重複した非リアクティビティーマーカーを使用する OOPath 式の例

Student( $grade: /plan?/exams[ course == "Big Data" ]?/grades )

OOPath 式のリアクティビティーを有効にするもう 1 つの方法は、Red Hat Process Automation Manager で List インターフェースおよび Set インターフェースの専用の実装を使用することです。これらの実装は、ReactiveList クラスおよび ReactiveSet クラスです。また、ReactiveCollection クラスも使用できます。これらの実装により、Iterator クラスおよび ListIterator クラスを使用した可変操作の実行もリアクティブにサポートされます。

以下のクラスの例では、これらのクラスを使用して OOPath 式のリアクティビティーを設定します。

OOPath 式のリアクティビティーを設定する Java クラスの例

public class School extends AbstractReactiveObject {
    private String name;
    private final List<Child> children = new ReactiveList<Child>(); 1

    public void setName(String name) {
        this.name = name;
        notifyModification(); 2
    }

    public void addChild(Child child) {
        children.add(child); 3
        // No need to call `notifyModification()` here
    }
  }

1
標準の Java List インスタンスに対するリアクティブサポートのために、ReactiveList インスタンスを使用します。
2
フィールドがリアクティブなサポートで変更された場合は、必須の notifyModification() メソッドを使用します。
3
children フィールドは ReactiveList のインスタンスであるため、notifyModification() メソッド呼び出しは必要ありません。通知は、children フィールドで実行される他のすべての変更操作と同様に、自動的に処理されます。

16.9. DRL におけるルールアクション (THEN)

ルールの then 部分 (または、ルールの 右辺 (RHS)) には、ルールの条件部分が満たされる場合に実行されるアクションが含まれます。アクションは、1 つ以上の メソッド で構成されます。これらのメソッドは、ルール条件とパッケージ内で使用できる利用可能なデータオブジェクトに応じて結果を実行します。たとえば、銀行がローン申請者が 21 歳を超えていることが要件となっているにもかかわらず (ルール条件が Applicant( age < 21 ))、ローン申請者が 21 歳未満の場合は、"Underage" ルールの then アクションが setApproved( false ) となり、年齢が基準に達していないためローンの申し込みは承認されません。

ルールアクションの主な目的は、デシジョンエンジンのワーキングメモリーでデータの挿入、削除、または変更を行うことです。有効なルールアクションは小規模かつ宣言的で、可読性があるものです。ルールアクションで必須または条件付きコードを使用する必要がある場合は、ルールを小規模かつより宣言的な複数のルールに分割します。

申込者の年齢制限に関するルールの例

rule "Underage"
  when
    application : LoanApplication()
    Applicant( age < 21 )
  then
    application.setApproved( false );
    application.setExplanation( "Underage" );
end

16.9.1. DRL でサポートされるルールアクションメソッド

DRL では DRL ルールアクションで使用できる以下のルールアクションメソッドがサポートされます。これらのメソッドを使用することで、最初にワーキングメモリーインスタンスを参照せずに、デシジョンエンジンのワーキングメモリーを変更できます。これらのメソッドは Red Hat Process Automation Manager ディストリビューションの KnowledgeHelper クラスで提供されるメソッドへのショートカットとして機能します。

すべてのルールアクションメソッドの方法は、Red Hat カスタマーポータル から ZIP ファイル Red Hat Process Automation Manager 7.10.0 Source Distribution をダウンロードし、~/rhpam-7.10.0-sources/src/drools-$VERSION/drools-core/src/main/java/org/drools/core/spi/KnowledgeHelper.java に移動してください。

set

これを使用してフィールドの値を設定します。

set<field> ( <value> )

ローン申し込みの承認の値を設定するルールアクションの例

$application.setApproved ( false );
$application.setExplanation( "has been bankrupt" );

modify

ファクトの変更するフィールドを指定し、デシジョンエンジンに変更を通知します。このメソッドは、ファクトの更新に対する構造化されたアプローチを提供します。このメソッドは、update 操作とオブジェクトフィールドを変更する setter 呼び出しを組み合わせたものです。

modify ( <fact-expression> ) {
    <expression>,
    <expression>,
    ...
}

ローン申し込み件数および承認を変更するルールアクションの例

modify( LoanApplication ) {
        setAmount( 100 ),
        setApproved ( true )
}

update

フィールドと更新される関連ファクト全体を指定して、その変更をデシジョンエンジンに通知します。ファクトが変更したら、アップデートした値の影響を受ける可能性がある別のファクトを変更する前に、update を呼び出す必要があります。この追加設定を回避するには、modify メソッドを代わりに使用します。

update ( <object, <handle> )  // Informs the decision engine that an object has changed

update ( <object> )  // Causes `KieSession` to search for a fact handle of the object

ローンの申し込み件数および承認を更新するルールアクションの例

LoanApplication.setAmount( 100 );
update( LoanApplication );

注記

property-change リスナーを指定する場合は、オブジェクトの変更時にこのメソッドを呼び出す必要はありません。property-change リスナーの詳細は、「Red Hat Process Automation Manager のデシジョンエンジン」を参照してください。

insert

new ファクトをデシジョンエンジンのワーキングメモリーに挿入し、ファクトに必要な結果として生成されるフィールドと値を定義します。

insert( new <object> );

新しいローン申請者オブジェクトを挿入するルールアクションの例

insert( new Applicant() );

insertLogical

デシジョンエンジンに new ファクトを論理挿入する場合に使用します。デシジョンエンジンは、ファクトの挿入および取り消しに対して論理的な決断を行います。通常の挿入または記述による挿入の後には、ファクトは明示的に取り消される必要があります。論理挿入の後、挿入されたファクトは、ファクトを挿入したルールの条件が true でなくなると自動的に取り消されます。

insertLogical( new <object> );

新しいローン申請者オブジェクトを論理的に挿入するルールアクションの例

insertLogical( new Applicant() );

delete

デシジョンエンジンからオブジェクトを削除します。キーワード retract も DRL でサポートされており、同じアクションを実行しますが、DRL のコードでは、キーワード insert との整合性を考慮して delete が通常推奨されます。

delete( <object> );

ローン申請者オブジェクトを削除するルールアクションの例

delete( Applicant );

16.9.2. drools および kcontext 変数のその他のルールアクションメソッド

標準のルールアクションメソッドに加えて、デシジョンエンジンでは、ルールアクションで使用できる事前定義された drools 変数および kcontext 変数と組み合わせて使用できるメソッドもサポートしています。

drools 変数を使用して、Red Hat Process Automation Manager ディストリビューションの KnowledgeHelper クラスからメソッドを呼び出すことができます。これは、標準のアクションメソッドのベースとなるクラスでもあります。すべての drools ルールアクションのオプションは、Red Hat Customer Portal から ZIP ファイル Red Hat Process Automation Manager 7.10.0 Source Distribution をダウンロードし、~/rhpam-7.10.0-sources/src/drools-$VERSION/drools-core/src/main/java/org/drools/core/spi/KnowledgeHelper.java に移動してください。

以下の例は、drools 変数と共に使用できる一般的なメソッドです。

  • drools.halt(): ユーザーまたはアプリケーションで以前に fireUntilHalt() が呼び出されている場合は、ルールの実行を終了します。ユーザーまたはアプリケーションが fireUntilHalt() を呼び出す場合、デシジョンエンジンは アクティブモード で開始し、ユーザーまたはアプリケーションが halt() を明示的に呼び出すまでルールの評価を継続します。それ以外の場合、デシジョンエンジンはデフォルトで パッシブモード で実行し、ユーザーまたはアプリケーションが明示的に fireAllRules() を呼び出す場合にのみルールを評価します。
  • drools.getWorkingMemory(): WorkingMemory オブジェクトを返します。
  • drools.setFocus( "<agenda_group>" ): ルールが属する指定されたアジェンダグループにフォーカスを設定します。
  • drools.getRule().getName(): ルールの名前を返します。
  • drools.getTuple()drools.getActivation(): 現在実行されているルールに一致する Tuple を返し、対応する Activation を提供します。これらの呼び出しは、ロギングやデバッグを行う場合に役立ちます。

kcontext 変数を getKieRuntime() メソッドと共に使用して、KieContext クラスや、拡張によりご使用の Red Hat Process Automation Manager ディストリビューションの RuleContext クラスから別のメソッドを呼び出すことができます。完全な Knowledge Runtime API は kcontext 変数を通じて公開され、詳細なルールアクションメソッドを提供します。kcontext ルールアクションのすべてのオプションは、Red Hat カスタマーポータル から ZIP ファイル Red Hat Process Automation Manager 7.10.0 Source Distribution をダウンロードし、~/rhpam-7.10.0-sources/src/kie-api-parent-$VERSION/kie-api/src/main/java/org/kie/api/runtime/rule/RuleContext.java に移動してください。

以下の例は kcontext.getKieRuntime() の変数とメソッドの組み合わせで使用できる一般的なメソッドです。

  • kcontext.getKieRuntime().halt(): ユーザーまたはアプリケーションで以前に fireUntilHalt() が呼び出されている場合は、ルールの実行を終了します。このメソッドは、drools.halt() メソッドと同等です。ユーザーまたはアプリケーションが fireUntilHalt() を呼び出す場合、デシジョンエンジンは アクティブモード で開始し、ユーザーまたはアプリケーションが halt() を明示的に呼び出すまでルールの評価を継続します。それ以外の場合、デシジョンエンジンはデフォルトで パッシブモード で実行し、ユーザーまたはアプリケーションが明示的に fireAllRules() を呼び出す場合にのみルールを評価します。
  • kcontext.getKieRuntime().getAgenda(): KIE セッション Agenda への参照を返し、次にルールアクティベーショングループ、ルールアジェンダグループ、およびルールフローグループにアクセスできるようにします。

    アジェンダグループ「CleanUp」にアクセスしてフォーカスを設定する呼び出しの例

    kcontext.getKieRuntime().getAgenda().getAgendaGroup( "CleanUp" ).setFocus();

    この例は、drools.setFocus( "CleanUp" ) と同等です。

  • kcontext.getKieRuntime().getQueryResults(<string> query): クエリーを実行し、結果を返します。このメソッドは drools.getKieRuntime().getQueryResults() と同等です。
  • kcontext.getKieRuntime().getKieBase(): KieBase オブジェクトを返します。KIE ベースはルールシステムのすべてのナレッジのソースであり、現在の KIE セッションの開始元です。
  • kcontext.getKieRuntime().setGlobal()~.getGlobal()~.getGlobals(): グローバル変数を設定するか、または取得します。
  • kcontext.getKieRuntime().getEnvironment(): 使用するオペレーティングシステム環境と類似したランタイムの Environment を返します。

16.9.3. 条件付きおよび名前付きの結果を伴う高度なルールアクション

一般的に、有効なルールアクションは小規模かつ宣言的であり、可読性があります。ただし、場合によっては、ルールごとに結果を 1 つに制限することが困難であり、以下のルールの例のように、ルールの構文が冗長になったり、繰り返しが多くなる可能性があります。

冗長で繰り返しの構文の多いルールの例

rule "Give 10% discount to customers older than 60"
  when
    $customer : Customer( age > 60 )
  then
    modify($customer) { setDiscount( 0.1 ) };
end

rule "Give free parking to customers older than 60"
  when
    $customer : Customer( age > 60 )
    $car : Car( owner == $customer )
  then
    modify($car) { setFreeParking( true ) };
end

繰り返しを部分的に解決する手段として、以下の変更例にあるように、2 番目のルールで最初のルールを拡張します。

拡張された条件を使用して部分的に強化されたルールの例

rule "Give 10% discount to customers older than 60"
  when
    $customer : Customer( age > 60 )
  then
    modify($customer) { setDiscount( 0.1 ) };
end

rule "Give free parking to customers older than 60"
    extends "Give 10% discount to customers older than 60"
  when
    $car : Car( owner == $customer )
  then
    modify($car) { setFreeParking( true ) };
end

より効率的な代替方法として、以下の例に示すように、変更した条件およびラベルが付与された対応するルールアクションを使用して、2 つのルールを 1 つのルールに統合することができます。

条件および名前付きの結果を使用した統合されたルールの例

rule "Give 10% discount and free parking to customers older than 60"
  when
    $customer : Customer( age > 60 )
    do[giveDiscount]
    $car : Car( owner == $customer )
  then
    modify($car) { setFreeParking( true ) };
  then[giveDiscount]
    modify($customer) { setDiscount( 0.1 ) };
end

このルールの例では、通常のデフォルトアクションと、giveDiscount という名前のもう 1 つの別のアクションが使用されています。giveDiscount アクションは、KIE ベースで年齢が 60 歳を超えた顧客が見つかると、その顧客が車を所有しているかどうかにかかわらず、キーワード do でアクティブにされます。

名前付きの結果のアクティベーションは、次の例の if ステートメントのように、追加の条件を使用して設定できます。if ステートメント内の条件は、その直前にあるパターンで常に評価されます。

追加の条件が指定される統合されたルールの例

rule "Give free parking to customers older than 60 and 10% discount to golden ones among them"
  when
    $customer : Customer( age > 60 )
    if ( type == "Golden" ) do[giveDiscount]
    $car : Car( owner == $customer )
  then
    modify($car) { setFreeParking( true ) };
  then[giveDiscount]
    modify($customer) { setDiscount( 0.1 ) };
end

以下のより複雑な例のように、ネストされた if および else if 構成を使用して、さまざまなルール条件を評価することもできます。

より複雑な条件を使用して統合されたルールの例

rule "Give free parking and 10% discount to over 60 Golden customer and 5% to Silver ones"
  when
    $customer : Customer( age > 60 )
    if ( type == "Golden" ) do[giveDiscount10]
    else if ( type == "Silver" ) break[giveDiscount5]
    $car : Car( owner == $customer )
  then
    modify($car) { setFreeParking( true ) };
  then[giveDiscount10]
    modify($customer) { setDiscount( 0.1 ) };
  then[giveDiscount5]
    modify($customer) { setDiscount( 0.05 ) };
end

このルールの例では、60 歳を超えた Golden 顧客には 10% の割引きと無料駐車サービスが提供されますが、Silver 顧客に提供されるのは 5% の割引きのみで、無料駐車サービスは提供されません。このルールでは、do ではなく break というキーワードによって、giveDiscount5 という名前の結果がアクティブにされます。キーワード do は、デシジョンエンジンのアジェンダで結果をスケジュール設定し、ルール条件の残りの部分が引き続き評価されるようにします。一方、break は追加の条件の評価を行いません。名前付きの結果が do のいずれの条件にも一致せず、break でアクティブにされる場合は、ルールの条件部分に到達することはないため、ルールはコンパイルされません。

16.10. DRL ファイルのコメント

DRL では、二重のスラッシュ (//) が先頭に付けられた単一行コメントと、スラッシュおよびアスタリスク (/* …​ */) で囲まれた複数行のコメントがサポートされます。DRL コメントを使用して、DRL ファイルのルールまたは関連コンポーネントにアノテーションを付けることができます。DRL ファイルの処理時に、デシジョンエンジンでは DRL コメントは無視されます。

コメントが使用されるルールの例

rule "Underage"
  // This is a single-line comment.
  when
    $application : LoanApplication()  // This is an in-line comment.
    Applicant( age < 21 )
  then
    /* This is a multi-line comment
    in the rule actions. */
    $application.setApproved( false );
    $application.setExplanation( "Underage" );
end

重要

DRL コメントでは、ハッシュ記号 # はサポートされていません。

16.11. DRL トラブルシューティングのエラーメッセージ

Red Hat Process Automation Manager は、DRL ファイルの問題のトラブルシューティングと解決に役立つ、DRL エラーの標準化されたメッセージを提供します。エラーメッセージでは、以下の形式が使用されています。

図16.1 DRL ファイルの問題に関するエラーメッセージの形式

error message
  • 最初のブロック: エラーコード
  • 2 番目のブロック: DRL ソースのエラーが発生している行および列
  • 3 番目のブロック: 問題の説明
  • 4 番目のブロック: DRL ソース内のエラーが発生しているコンポーネント (ルール、関数、クエリー)
  • 5 番目のブロック: DRL ソース内のエラーが発生しているパターン (該当する場合)

Red Hat Process Automation Manager では、以下の標準化されたエラーメッセージがサポートされます。

101: no viable alternative

パーサーが決定ポイントに到達したにもかかわらず、選択肢を特定できなかったことを示します。

誤ったスペリングを含むルールの例

1: rule "simple rule"
2:   when
3:     exists Person()
4:     exits Student()  // Must be `exists`
5:   then
6: end

エラーメッセージ

[ERR 101] Line 4:4 no viable alternative at input 'exits' in rule "simple rule"

ルール名がないルールの例

1: package org.drools.examples;
2: rule    // Must be `rule "rule name"` (or `rule rule_name` if no spacing)
3:   when
4:     Object()
5:   then
6:     System.out.println("A RHS");
7: end

エラーメッセージ

[ERR 101] Line 3:2 no viable alternative at input 'when'

この例では、パーサーがキーワード when を検出しましたが、予想していたのはルール名であったため、パーサーは when に予想外の不適切なトークンというフラグを付けます。

誤った構文が使用されるルールの例

1: rule "simple rule"
2:   when
3:     Student( name == "Andy )  // Must be `"Andy"`
4:   then
5: end

エラーメッセージ

[ERR 101] Line 0:-1 no viable alternative at input '<eof>' in rule "simple rule" in pattern Student

注記

列と行の値が 0:-1 の場合は、パーサーがソースファイルの終わり (<eof>) に到達しましたが、不完全な構成を検出したことを示します。よくある原因として、引用符 "…​"、アポストロフィー '…​'、または括弧 (…​) が欠落している場合があります。

102: mismatched input

パーサーが特定の記号を予想していましたが、これが現在の入力位置で欠落していることを示します。

不完全なルールステートメントが使用されるルールの例

1: rule simple_rule
2:   when
3:     $p : Person(
        // Must be a complete rule statement

エラーメッセージ

[ERR 102] Line 0:-1 mismatched input '<eof>' expecting ')' in rule "simple rule" in pattern Person

注記

列と行の値が 0:-1 の場合は、パーサーがソースファイルの終わり (<eof>) に到達しましたが、不完全な構成を検出したことを示します。よくある原因として、引用符 "…​"、アポストロフィー '…​'、または括弧 (…​) が欠落している場合があります。

誤った構文が使用されるルールの例

1: package org.drools.examples;
2:
3: rule "Wrong syntax"
4:   when
5:     not( Car( ( type == "tesla", price == 10000 ) || ( type == "kia", price == 1000 ) ) from $carList )
       // Must use `&&` operators instead of commas `,`
6:   then
7:     System.out.println("OK");
8: end

エラーメッセージ

[ERR 102] Line 5:36 mismatched input ',' expecting ')' in rule "Wrong syntax" in pattern Car
[ERR 101] Line 5:57 no viable alternative at input 'type' in rule "Wrong syntax"
[ERR 102] Line 5:106 mismatched input ')' expecting 'then' in rule "Wrong syntax"

この例では、構文に関する問題が原因で相互に関連する複数のエラーメッセージが発生しています。&& 演算子で , を置き換えるという 1 つの解決策により、すべてのエラーが解消されます。複数のエラーが発生した場合に、エラーが前のエラーの結果である場合があるため、一度に 1 つずつ解決します。

103: failed predicate

セマンティクスの述語の検証が false と評価されたことを示します。これらのセマンティクスの述語は一般に declareruleexistsnot など、DRL ファイルのコンポーネントのキーワードを特定するために使用されます。

無効なキーワードが使用されているルールの例

 1: package nesting;
 2:
 3: import org.drools.compiler.Person
 4: import org.drools.compiler.Address
 5:
 6: Some text  // Must be a valid DRL keyword
 7:
 8: rule "test something"
 9:   when
10:     $p: Person( name=="Michael" )
11:   then
12:     $p.name = "other";
13:     System.out.println(p.name);
14: end

エラーメッセージ

[ERR 103] Line 6:0 rule 'rule_key' failed predicate: {(validateIdentifierKey(DroolsSoftKeywords.RULE))}? in rule

Some text の行は、DRL キーワード構成で始まっていないか、または DRL キーワード構成の一部ではないため、パーサーが DRL ファイルの残りの部分の評価に失敗します。

注記

このエラーは 102: mismatched input に似ていますが、通常は DRL キーワードが関係しています。

104: trailing semi-colon not allowed

ルール条件の eval() 句でセミコロン ; が使用されていますが、セミコロンは使用できません。

eval() と末尾のセミコロンが使用されているルールの例

1: rule "simple rule"
2:   when
3:     eval( abc(); )  // Must not use semicolon `;`
4:   then
5: end

エラーメッセージ

[ERR 104] Line 3:4 trailing semi-colon not allowed in rule "simple rule"

105: did not match anything

パーサーが文法内で、少なくとも 1 回は代替の選択肢に一致する必要があるサブルールに到達しましたが、サブルールがいすれにも一致しなかったことを示します。パーサーは出口のないブランチに入ります。

空の条件内に無効なテキストがあるルールの例

1: rule "empty condition"
2:   when
3:     None  // Must remove `None` if condition is empty
4:   then
5:      insert( new Person() );
6: end

エラーメッセージ

[ERR 105] Line 2:2 required (...)+ loop did not match anything at input 'WHEN' in rule "empty condition"

この例では、条件は空であることが意図されていますが、None という単語が使用されています。このエラーは、DRL の有効でないキーワード、データタイプ、またはパターン構成である None を削除することによって解決できます。

注記

解決できないその他の DRL エラーメッセージが発生した場合は、Red Hat のテクニカルアカウントマネージャーにお問い合わせください。

16.12. DRL ルールセットのルールユニット

ルールユニットは、データソース、グローバル変数、および DRL ルールのグループで、特定の目的に向けて互いに機能し合います。ルールユニットを使用して、ルールセットを小さなユニットに分割し、それらのユニットにさまざまなデータソースをバインドしてから、個別のユニットを実行します。ルールユニットは、実行制御用のルールアジェンダグループまたはアクティブ化グループなどの、ルールをグループ化する DRL 属性に代わるものとして、強化されています。

ルールユニットは、ルールの実行を調整することで、あるルールユニットが完全に実行されると別のルールユニットの開始をトリガーする場合などに便利です。たとえば、データ強化用の一連のルール、そのデータを処理する別の一連のルール、および処理されたデータを抽出して出力する別の一連のルールがあるとします。これらのルールセットを 3 つの異なるルールユニットに追加する場合は、これらのルールユニットを調整することで、1 つ目のユニットが完全に実行すると 2 つ目のユニットの開始をトリガーし、2 つ目のユニットが完全に実行すると 3 つ目のユニットの開始をトリガーすることができます。

ルールユニットを定義するには、以下の例に示すように RuleUnit インターフェースを実装します。

ルールユニットクラスの例

package org.mypackage.myunit;

public static class AdultUnit implements RuleUnit {
    private int adultAge;
    private DataSource<Person> persons;

    public AdultUnit( ) { }

    public AdultUnit( DataSource<Person> persons, int age ) {
        this.persons = persons;
        this.age = age;
    }

    // A data source of `Persons` in this rule unit:
    public DataSource<Person> getPersons() {
        return persons;
    }

    // A global variable in this rule unit:
    public int getAdultAge() {
        return adultAge;
    }

    // Life-cycle methods:
    @Override
    public void onStart() {
        System.out.println("AdultUnit started.");
    }

    @Override
    public void onEnd() {
        System.out.println("AdultUnit ended.");
    }
}

この例では、persons はタイプ Person のファクトのソースです。ルールユニットのデータソースは、指定のルールユニットで処理されるデータのソースで、デシジョンエンジンがルールユニットの評価に使用するエントリーポイントを表します。adultAge グローバル変数は、このルールユニットに属するすべてのルールからアクセスできます。最後の 2 つのメソッドは、ルールユニットのライフサイクルの一部で、デシジョンエンジンによって呼び出されます。

デシジョンエンジンは、以下のようなルールユニットの任意のライフサイクルメソッドをサポートします。

表16.3 ルールユニットのライフサイクルメソッド

メソッド呼び出されるタイミング

onStart()

ルールユニット実行開始時

onEnd()

ルールユニット実行終了時

onSuspend()

ルールユニット実行の一時停止時 (runUntilHalt() でのみを使用される)

onResume()

ルールユニット実行の再開時 (runUntilHalt() でのみ使用される)

onYield(RuleUnit other)

ルールユニットにおけるルールの結果が異なるルールユニットの実行をトリガー

ルールユニットに、ルールを 1 つ以上追加することができます。デフォルトでは、DRL ファイルのすべてのルールは、DRL ファイル名の命名規則に従うルールユニットに自動的に関連付けられます。DRL ファイルが同じパッケージにあり、RuleUnit インターフェースを実装するクラスと同じ名前を持つ場合、その DRL ファイルのすべてのルールは、そのルールユニットに暗黙的に属します。たとえば、org.mypackage.myunit パッケージの AdultUnit.drl ファイルにあるすべてのルールは、自動的にルールユニット org.mypackage.myunit.AdultUnit の一部となります。

この命名規則をオーバーライドし、DRL ファイル内のルールが属するルールユニットを明示的に宣言するには、DRL ファイル内でキーワード unit を使用します。unit 宣言は、すぐに package 宣言に従い、DRL ファイルのルールが一部となっているパッケージ内のクラス名を含む必要があります。

DRL ファイルのルールユニット宣言の例

package org.mypackage.myunit
unit AdultUnit

rule Adult
  when
    $p : Person(age >= adultAge) from persons
  then
    System.out.println($p.getName() + " is adult and greater than " + adultAge);
end

警告

同じ KIE ベースで、ルールユニットありのルールとルールユニットなしのルールを混在させないでください。KIE ベースで 2 つのルールのパラダイムを混在させると、コンパイルエラーが発生します。

以下の例のように OOPath 表記を使用して、より便利な方法で同じパターンを書き換えることもできます。

OOPath 表記を使用する DRL ファイルのルールユニット宣言の例

package org.mypackage.myunit
unit AdultUnit

rule Adult
  when
    $p : /persons[age >= adultAge]
  then
    System.out.println($p.getName() + " is adult and greater than " + adultAge);
end

注記

OOPath は、DRL ルールの条件の制約でオブジェクトのグラフを参照するために設計された XPath のオブジェクト指向構文の拡張です。OOPath は、コレクションおよびフィルター制約を処理する間に XPath からのコンパクト表記を使用して関連要素を移動します。また、OOPath は特にオブジェクトグラフの場合に役に立ちます。

この例では、ルール条件で一致するファクトはすべて、ルールユニットクラスの DataSource 定義で定義される persons のデータソースから取得されます。ルール条件およびアクションは、グローバル変数が DRL ファイルレベルで定義されるのと同じ方法で adultAge 変数を使用します。

KIE ベースに定義されたルールユニットを 1 つ以上実行するには、KIE ベースにバインドされている新規の RuleUnitExecutor クラスを作成し、関連するデータソースからルールユニットを作成して、ルールユニットエグゼキューターを実行します。

ルールユニット実行の例

// Create a `RuleUnitExecutor` class and bind it to the KIE base:
KieBase kbase = kieContainer.getKieBase();
RuleUnitExecutor executor = RuleUnitExecutor.create().bind( kbase );

// Create the `AdultUnit` rule unit using the `persons` data source and run the executor:
RuleUnit adultUnit = new AdultUnit(persons, 18);
executor.run( adultUnit );

ルールは RuleUnitExecutor クラスにより実行されます。RuleUnitExecutor クラスは KIE セッションを作成し、必要な DataSource オブジェクトをこれらのセッションに追加してから、run() メソッドへのパラメーターとして渡される RuleUnit をもとに、ルールを実行します。

例の実行コードは、関連する Person ファクトが persons データソースに挿入されると、以下の出力を生成します。

ルールユニット実行出力の例

org.mypackage.myunit.AdultUnit started.
Jane is adult and greater than 18
John is adult and greater than 18
org.mypackage.myunit.AdultUnit ended.

ルールユニットインスタンスを明示的に作成するのではなく、エグゼキューターにルールユニット変数を登録し、実行するルールユニットクラスをエグゼキューターに渡すと、エグゼキューターがルールユニットのインスタンスを作成します。続いて、ルールユニットを実行する前に DataSource 定義および他の変数を設定できます。

登録変数を含む別のルールユニット実行オプション

executor.bindVariable( "persons", persons );
        .bindVariable( "adultAge", 18 );
executor.run( AdultUnit.class );

RuleUnitExecutor.bindVariable() メソッドに渡す名前は、実行時に、同じ名前のルールユニットクラスのフィールドに変数をバインドするために使用されます。前述の例では、RuleUnitExecutor は、新しいルールユニットに "persons" の名前にバインドされているデータソースを挿入します。また、AdultUnit クラス内の対応する名前のフィールドに、文字列 "adultAge" にバインドされている値 18 を挿入します。

このデフォルトの変数バインディング動作をオーバーライドするには、@UnitVar アノテーションを使用してルールユニットクラスの各フィールドに対して論理バインディング名を明示的に定義します。たとえば、以下のクラスのフィールドバインディングは、代替名で再度定義されます。

@UnitVar を使用した変数バインディング名を変更するコード例

package org.mypackage.myunit;

public static class AdultUnit implements RuleUnit {
    @UnitVar("minAge")
    private int adultAge = 18;

    @UnitVar("data")
    private DataSource<Person> persons;
}

次に、これらの代替名を使用して、変数をエグゼキューターにバインドし、ルールユニットを実行できます。

変更した変数名を使用したルールユニット実行の例

executor.bindVariable( "data", persons );
        .bindVariable( "minAge", 18 );
executor.run( AdultUnit.class );

ルールユニットは、run() メソッド (KIE セッションで fireAllRules() を呼び出す場合と同じ) を使用して パッシブモード で、または runUntilHalt() メソッド (KIE セッションで fireUntilHalt() を呼び出す場合と同じ) を使用して アクティブモード で実行できます。デフォルトでは、デシジョンエンジンは パッシブモード で実行し、ユーザーまたはアプリケーションが明示的に run() (標準ルールでは fireAllRules()) を呼び出す場合にのみルールユニットを評価します。ユーザーまたはアプリケーションがルールユニットに runUntilHalt() (標準ルールでは fireAllRules()) を呼び出す場合、デシジョンエンジンは アクティブモード で開始し、ユーザーまたはアプリケーションが明示的に halt() を呼び出すまで、継続的にルールユニットを評価します。

runUntilHalt() メソッドを使用する場合は、メインスレッドをブロックしないように、別の実行スレッド上でメソッドを呼び出します。

別のスレッド上の runUntilHalt() を使用したルールユニットの実行例

new Thread( () -> executor.runUntilHalt( adultUnit ) ).start();

16.12.1. ルールユニットのデータソース

ルールユニットのデータソースは、指定のルールユニットで処理されるデータのソースで、デシジョンエンジンがルールユニットの評価に使用するエントリーポイントを表します。ルールユニットは、ゼロまたは複数のデータソースを持つことができ、ルールユニット内で宣言された各 DataSource の定義は、ルールユニットエグゼキューターへの異なるエントリーポイントに対応することができます。複数のルールユニットは、単一データソースを共有できます。ただし、各ルールユニットは、同じオブジェクトが挿入される異なるエントリーポイントを使用する必要があります。

以下の例で示すように、ルールユニットクラスの固定されたデータセットを使用して DataSource 定義を作成できます。

データソース定義の例

DataSource<Person> persons = DataSource.create( new Person( "John", 42 ),
                                                new Person( "Jane", 44 ),
                                                new Person( "Sally", 4 ) );

データソースはルールユニットのエントリーポイントを表すため、ルールユニットでファクトを挿入、更新、または削除できます。

ルールユニットでファクトを挿入、更新、削除するコード例

// Insert a fact:
Person john = new Person( "John", 42 );
FactHandle johnFh = persons.insert( john );

// Modify the fact and optionally specify modified properties (for property reactivity):
john.setAge( 43 );
persons.update( johnFh, john, "age" );

// Delete the fact:
persons.delete( johnFh );

16.12.2. ルールユニットの実行制御

一方のルールユニットの実行により、もう一方のルールユニットの開始がトリガーされるようにルールの実行を調整する必要がある場合に、ルールユニットは役に立ちます。

ルールユニットの実行制御を容易にするために、デシジョンエンジンは以下のルールユニットメソッドをサポートします。このメソッドは、DRL ルールアクションで使用して、ルールユニットの実行を調整することができます。

  • drools.run(): 指定されたルールユニットクラスの実行をトリガーします。このメソッドでは、ルールユニットの実行を命令的に中断し、他の指定されたルールユニットを有効化します。
  • drools.guard(): 関連付けられたルール条件が満たされるまで、指定されたルールユニットクラスが実行されないようにします (保護します)。このメソッドは、他の指定されたルールユニットの実行を宣言的にスケジュールします。デシジョンエンジンが、保護ルールの条件に対して少なくとも 1 つの一致をもたらす場合は、保護されたルールユニットが有効とみなされます。ルールユニットには、複数の保護ルールを含めることができます。

drools.run() メソッドの例として、それぞれが指定されたルールユニットに属す以下の DRL ルールを検討してください。NotAdult ルールは drools.run( AdultUnit.class ) メソッドを使用して AdultUnit ルールユニットの実行をトリガーします。

drools.run() を使用した制御された実行を含む DRL ルールの例

package org.mypackage.myunit
unit AdultUnit

rule Adult
  when
    Person(age >= 18, $name : name) from persons
  then
    System.out.println($name + " is adult");
end

package org.mypackage.myunit
unit NotAdultUnit

rule NotAdult
  when
    $p : Person(age < 18, $name : name) from persons
  then
    System.out.println($name + " is NOT adult");
    modify($p) { setAge(18); }
    drools.run( AdultUnit.class );
end

この例では、これらのルールからビルドされた KIE ベースから作成された RuleUnitExecutor クラスと、これにバインドされている personsDataSource 定義も使用します。

ルールエグゼキューターとデータソース定義の例

RuleUnitExecutor executor = RuleUnitExecutor.create().bind( kbase );
DataSource<Person> persons = executor.newDataSource( "persons",
                                                     new Person( "John", 42 ),
                                                     new Person( "Jane", 44 ),
                                                     new Person( "Sally", 4 ) );

この例では、RuleUnitExecutor クラスから DataSource 定義を直接作成し、これを単一ステートメントで "persons" 変数にバインドします。

例の実行コードは、関連する Person ファクトが persons データソースに挿入されると、以下の出力を生成します。

ルールユニット実行出力の例

Sally is NOT adult
John is adult
Jane is adult
Sally is adult

NotAdult ルールは、"Sally" という人物の評価時に一致を検出します。この人物は 18 歳未満です。続いてこのルールは、この人物の年齢を 18 に変更し、drools.run( AdultUnit.class ) メソッドを使用して AdultUnit ルールユニットの実行をトリガーします。AdultUnit ルールユニットには、DataSource 定義の 3 人の persons 全員に対して実行可能となったルールが含まれています。

drools.guard() メソッドの例として、以下の BoxOffice クラスと BoxOfficeUnit ルールユニットクラスを検討してください。

BoxOffice クラスの例

public class BoxOffice {
    private boolean open;

    public BoxOffice( boolean open ) {
        this.open = open;
    }

    public boolean isOpen() {
        return open;
    }

    public void setOpen( boolean open ) {
        this.open = open;
    }
}

BoxOfficeUnit ルールユニットクラスの例

public class BoxOfficeUnit implements RuleUnit {
    private DataSource<BoxOffice> boxOffices;

    public DataSource<BoxOffice> getBoxOffices() {
        return boxOffices;
    }
}

また、この例では、以下の TicketIssuerUnit ルールユニットクラスを使用して、少なくとも 1 つのボックスオフィス (チケット売り場) が営業中である限り、ボックスオフィスでのイベントチケットの販売を続行します。このルールユニットは persons および ticketsDataSource 定義を使用します。

TicketIssuerUnit ルールユニットクラスの例

public class TicketIssuerUnit implements RuleUnit {
    private DataSource<Person> persons;
    private DataSource<AdultTicket> tickets;

    private List<String> results;

    public TicketIssuerUnit() { }

    public TicketIssuerUnit( DataSource<Person> persons, DataSource<AdultTicket> tickets ) {
        this.persons = persons;
        this.tickets = tickets;
    }

    public DataSource<Person> getPersons() {
        return persons;
    }

    public DataSource<AdultTicket> getTickets() {
        return tickets;
    }

    public List<String> getResults() {
        return results;
    }
}

BoxOfficeUnit ルールユニットには、DRL ルール BoxOfficeIsOpen が含まれます。これは、drools.guard( TicketIssuerUnit.class ) メソッドを使用して、イベントチケットを配布する TicketIssuerUnit ルールユニットの実行を保護します。以下に DRL ルールの例を示します。

drools.guard() を使用した制御された実行を含む DRL ルールの例

package org.mypackage.myunit;
unit TicketIssuerUnit;

rule IssueAdultTicket when
    $p: /persons[ age >= 18 ]
then
    tickets.insert(new AdultTicket($p));
end
rule RegisterAdultTicket when
    $t: /tickets
then
    results.add( $t.getPerson().getName() );
end

package org.mypackage.myunit;
unit BoxOfficeUnit;

rule BoxOfficeIsOpen
  when
    $box: /boxOffices[ open ]
  then
    drools.guard( TicketIssuerUnit.class );
end

この例では、少なくとも 1 つのボックスオフィスが open である限り、保護された TicketIssuerUnit ルールユニットが有効なため、イベントチケットは配布されます。open 状態のボックスオフィスがなくなると、保護された TicketIssuerUnit ルールユニットは実行されなくなります。

以下のクラスの例は、より完全なボックスオフィスのシナリオを説明します。

ボックスオフィスシナリオのクラスの例

DataSource<Person> persons = executor.newDataSource( "persons" );
DataSource<BoxOffice> boxOffices = executor.newDataSource( "boxOffices" );
DataSource<AdultTicket> tickets = executor.newDataSource( "tickets" );

List<String> list = new ArrayList<>();
executor.bindVariable( "results", list );

// Two box offices are open:
BoxOffice office1 = new BoxOffice(true);
FactHandle officeFH1 = boxOffices.insert( office1 );
BoxOffice office2 = new BoxOffice(true);
FactHandle officeFH2 = boxOffices.insert( office2 );

persons.insert(new Person("John", 40));

// Execute `BoxOfficeIsOpen` rule, run `TicketIssuerUnit` rule unit, and execute `RegisterAdultTicket` rule:
executor.run(BoxOfficeUnit.class);

assertEquals( 1, list.size() );
assertEquals( "John", list.get(0) );
list.clear();

persons.insert(new Person("Matteo", 30));

// Execute `RegisterAdultTicket` rule:
executor.run(BoxOfficeUnit.class);

assertEquals( 1, list.size() );
assertEquals( "Matteo", list.get(0) );
list.clear();

// One box office is closed, the other is open:
office1.setOpen(false);
boxOffices.update(officeFH1, office1);
persons.insert(new Person("Mark", 35));
executor.run(BoxOfficeUnit.class);

assertEquals( 1, list.size() );
assertEquals( "Mark", list.get(0) );
list.clear();

// All box offices are closed:
office2.setOpen(false);
boxOffices.update(officeFH2, office2); // Guarding rule is no longer true.
persons.insert(new Person("Edson", 35));
executor.run(BoxOfficeUnit.class); // No execution

assertEquals( 0, list.size() );

16.12.3. ルールユニットのアイデンティティーの競合

保護されたルールユニットを使用したルール実行のシナリオでは、1 つのルールが複数のルールユニットを保護することができます。同時に、複数のルールが 1 つのルールユニットを保護してから有効にすることもできます。このような 2 通りの保護シナリオでは、ルールユニットには、アイデンティティーの競合を避けるための明確に定義されたアイデンティティーが必要です。

デフォルトでは、ルールユニットのアイデンティティーはルールユニットクラス名で、RuleUnitExecutor によりシングルトンクラスとして処理されます。この識別動作は、RuleUnit インターフェースの getUnitIdentity() のデフォルトメソッドにエンコードされています。

RuleUnit インターフェースのデフォルトのアイデンティティーメソッド

default Identity getUnitIdentity() {
    return new Identity( getClass() );
}

場合によっては、ルールユニット間のアイデンティティーの競合を避けるために、このデフォルトの識別動作をオーバーライドする必要があります。

たとえば、以下の RuleUnit クラスには、あらゆる種類のオブジェクトを許可する DataSource 定義が含まれています。

Unit0 ルールユニットクラスの例

public class Unit0 implements RuleUnit {
    private DataSource<Object> input;

    public DataSource<Object> getInput() {
        return input;
    }
}

このルールユニットには、2 つの条件 (OOPath 表記) に基づいて別のルールユニットを保護する、以下の DRL ルールが含まれています。

ルールユニットの DRL ルール GuardAgeCheck の例

package org.mypackage.myunit
unit Unit0

rule GuardAgeCheck
  when
    $i: /input#Integer
    $s: /input#String
  then
    drools.guard( new AgeCheckUnit($i) );
    drools.guard( new AgeCheckUnit($s.length()) );
end

保護された AgeCheckUnit ルールユニットは、一連の persons の年齢を検証します。AgeCheckUnit には、確認用の personsDataSource の定義、検証用の minAge 変数、および結果を集計する List が含まれます。

AgeCheckUnit ルールユニットの例

public class AgeCheckUnit implements RuleUnit {
    private final int minAge;
    private DataSource<Person> persons;
    private List<String> results;

    public AgeCheckUnit( int minAge ) {
        this.minAge = minAge;
    }

    public DataSource<Person> getPersons() {
        return persons;
    }

    public int getMinAge() {
        return minAge;
    }

    public List<String> getResults() {
        return results;
    }
}

AgeCheckUnit ルールユニットには、データソースの persons の検証を実行する以下の DRL ルールが含まれます。

ルールユニットの DRL ルール CheckAge の例

package org.mypackage.myunit
unit AgeCheckUnit

rule CheckAge
  when
    $p : /persons{ age > minAge }
  then
    results.add($p.getName() + ">" + minAge);
end

この例では、RuleUnitExecutor クラスを作成し、これらの 2 つのルールユニットが含まれる KIE ベースにクラスをバインドして、同じルールユニットの DataSource 定義を 2 つ作成します。

executor 定義とデータソース定義の例

RuleUnitExecutor executor = RuleUnitExecutor.create().bind( kbase );

DataSource<Object> input = executor.newDataSource( "input" );
DataSource<Person> persons = executor.newDataSource( "persons",
                                                     new Person( "John", 42 ),
                                                     new Person( "Sally", 4 ) );

List<String> results = new ArrayList<>();
executor.bindVariable( "results", results );

一部のオブジェクトを入力データソースに挿入し、Unit0 ルールユニットを実行できるようになりました。

挿入されたオブジェクトを使用したルールユニット実行の例

ds.insert("test");
ds.insert(3);
ds.insert(4);
executor.run(Unit0.class);

実行結果一覧の例

[Sally>3, John>3]

この例では、AgeCheckUnit という名前のルールユニットはシングルトンクラスと見なされ、1 回のみ実行されます。この時、minAge 変数は 3 に設定されます。入力データソースに挿入された文字列 "test" および整数 4 の両方は、minAge 変数が 4 に設定された 2 回目の実行をトリガーする可能性もあります。しかし、同じアイデンティティーを持つ別のルールユニットがすでに評価されているため、2 回目の実行はありません。

このルールユニットのアイデンティティーの競合を解決するには、AgeCheckUnit クラスの getUnitIdentity() メソッドをオーバーライドして、ルールユニットアイデンティティーに minAge 変数も含めます。

getUnitIdentity() メソッドをオーバーライドする変更された AgeCheckUnit ルールユニット

public class AgeCheckUnit implements RuleUnit {

    ...

    @Override
    public Identity getUnitIdentity() {
        return new Identity(getClass(), minAge);
    }
}

このオーバーライドにより、以前のルールユニットの実行例は、以下の出力を生成します。

変更したルールユニットの実行結果一覧の例

[John>4, Sally>3, John>3]

minAge34 に設定されたルールユニットは、2 つの異なるルールユニットとみなされるようになり、両方とも実行されます。

第17章 データオブジェクト

データオブジェクトは、作成するルールアセットの構成要素です。データオブジェクトは、プロジェクトで指定したパッケージに Java オブジェクトとして実装されているカスタムのデータタイプです。たとえば、データフィールド NameAddress、および DateOfBirth を使用して Person オブジェクトを作成し、ローン申し込みルールに詳細な個人情報を指定できます。このカスタムのデータ型は、アセットとデシジョンサービスがどのデータに基づいているかを指定します。

17.1. データオブジェクトの作成

次の手順は、データオブジェクトの作成の一般的な概要です。特定のビジネスアセットに固有のものではありません。

手順

  1. Business Central で、MenuDesignProjects に移動して、プロジェクト名をクリックします。
  2. Add AssetData Object をクリックします。
  3. 一意の データオブジェクト 名を入力し、パッケージ を選択します。これにより、その他のルールアセットでもデータオブジェクトを利用できるようになります。同じパッケージに、同じ名前のデータオブジェクトを複数作成することはできません。指定の DRL ファイルで、どのパッケージからでもデータオブジェクトをインポートできます。

    別のパッケージからのデータオブジェクトのインポート

    別のパッケージから直接、ガイド付きルールやガイド付きデシジョンテーブルデザイナーなどのアセットデザイナーに、既存のデータオブジェクトをインポートすることができます。プロジェクトで関連するルールアセットを選択し、アセットデザイナーで Data Objects → New item に移動して、インポートするオブジェクトを選択します。

  4. データオブジェクトを永続化するには、Persistable チェックボックスを選択します。永続型データオブジェクトは、JPA 仕様に準じてデータベースに保存できます。デフォルトの JPA は Hibernate です。
  5. OK をクリックします。
  6. データオブジェクトデザイナーで add field をクリックして、Id 属性、Label 属性、および Type 属性を使用するオブジェクトにフィールドを追加します。必須属性にはアスタリスク (*) マークが付いています。

    • Id: フィールドの一意の ID を入力します。
    • Label: (任意) フィールドのラベルを入力します。
    • Type: フィールドのデータ型を入力します。
    • List: (任意) このチェックボックスを選択すると、このフィールドで、指定したタイプのアイテムを複数保持できるようになります。

      図17.1 データオブジェクトへのデータフィールドの追加

      データオブジェクトへのデータフィールドの追加
  7. Create をクリックして、新しいフィールドを追加します。Create and continue をクリックすると、新しいフィールドが追加され、別のフィールドを引き続き作成できます。

    注記

    フィールドを編集するには、フィールド行を選択し、画面右側の general properties を使用します。

第18章 Business Central における DRL ルールの作成

Business Central で、プロジェクトに対して DRL ルールを作成して管理できます。パッケージに作成またはインポートするデータオブジェクトに基づいて、各 DRL ファイルで、ルールの条件、アクション、そしてルールに関連するその他のコンポーネントを定義します。

手順

  1. Business Central で、MenuDesignProjects に移動して、プロジェクト名をクリックします。
  2. Add AssetDRL ファイル をクリックします。
  3. 参考となる DRL ファイル 名を入力し、適切な パッケージ を選択します。指定するパッケージは、必要なデータオブジェクトが割り当てられている、またはこれから割り当てるパッケージにする必要があります。

    ドメイン固有言語 (DSL) アセットがプロジェクトに定義されている場合は、Show declared DSL sentences を選択することもできます。この DSL アセットは、DRL デザイナーで定義する条件およびアクションに使用できるオブジェクトです。

  4. OK をクリックして、ルールアセットを作成します。

    新しい DRL ファイルが、Project ExplorerDRL パネルに追加されます。Show declared DSL sentences オプションを選択した場合は、DSLR パネルに追加されます。この DRL ファイルを割り当てたパッケージは、ファイルの上位にリストされます。

  5. DRL デザイナーの左パネルの Fact types リストで、ルールに必要なすべてのデータオブジェクトとデータオブジェクトフィールドがリストされていることを確認します (それぞれを展開します)。リストされていない場合は、DRL ファイルの import 命令文を使用して、その他のパッケージから関連するデータオブジェクトをインポートするか、パッケージに データオブジェクトを作成 します。
  6. データオブジェクトをすべて配置したら、DRL デザイナーの Model タブに戻り、以下のいずれかのコンポーネントで DRL ファイルを定義します。

    DRL ファイル内のコンポーネント

    package
    
    import
    
    function  // Optional
    
    query  // Optional
    
    declare   // Optional
    
    global   // Optional
    
    rule "rule name"
        // Attributes
        when
            // Conditions
        then
            // Actions
    end
    
    rule "rule2 name"
    
    ...

    • package: (自動) これは、DRL ファイルを作成し、パッケージを選択すると定義されます。
    • import: このパッケージ、または DRL ファイルで使用するその他のパッケージのデータオブジェクトを指定します。パッケージとデータオブジェクトは packageName.objectName の形式で指定し、複数のインポートは別々の行に指定します。

      データオブジェクトのインポート

      import org.mortgages.LoanApplication;

    • function: (任意) DRL ファイルのルールが使用する関数を指定します。DRL ファイルの関数は、Java クラスではなく、ルールのソースファイルにセマンティックコードを追加します。関数は、特に、ルールのアクション (then) 部分が繰り返し使用され、パラメーターだけがルールごとに異なる場合に便利です。DRL ファイルのルールで、関数を宣言したり、ヘルパークラスから静的メソッドを関数としてインポートしたりすることで、ルールのアクション (then) 部分で、名前を指定して関数を使用できます。

      ルールに関数を宣言して使用 (オプション 1)

      function String hello(String applicantName) {
          return "Hello " + applicantName + "!";
      }
      
      rule "Using a function"
        when
          // Empty
        then
          System.out.println( hello( "James" ) );
      end

      ルールに関数をインポートして使用 (オプション 2)

      import function my.package.applicant.hello;
      
      rule "Using a function"
        when
          // Empty
        then
          System.out.println( hello( "James" ) );
      end

    • query: (任意) DRL ファイルのルールに関連するファクトに対してデシジョンエンジンを検索するのに使用します。DRL ファイルにクエリー定義を追加してから、アプリケーションコードで一致する結果を取得します。クエリーは、定義した条件セットを検索するため、when または then を指定する必要はありません。クエリー名は KIE ベースでグローバルとなるため、プロジェクトにあるその他のすべてのルールクエリーと重複しないようにする必要があります。クエリーの結果に戻るには、ksession.getQueryResults("name") を使用して、従来の QueryResults 定義を構成します ("name" はクエリー名)。これにより、クエリーの結果が返り、クエリーに一致したオブジェクトを取得できるようになります。DRL ファイルのルールに、クエリーと、クエリー結果パラメーターを定義します。

      DRL ファイルにおけるクエリー定義の例

      query "people under the age of 21"
          $person : Person( age < 21 )
      end

      クエリー結果を取得するためのアプリケーションコードの例

      QueryResults results = ksession.getQueryResults( "people under the age of 21" );
      System.out.println( "we have " + results.size() + " people under the age  of 21" );

    • declare: (任意) DRL ファイルのルールが使用する新しいファクトタイプを宣言します。Red Hat Process Automation Manager の java.lang パッケージのデフォルトのファクトタイプは Object ですが、必要に応じて DRL ファイルに別のタイプを宣言することもできます。DRL ファイルにファクトタイプを宣言すると、Java などの低級言語でモデルを作成せず、デシジョンエンジンに直接新しいファクトモデルを定義するようになります。

      新しいファクトタイプの宣言および使用

      declare Person
        name : String
        dateOfBirth : java.util.Date
        address : Address
      end
      
      rule "Using a declared type"
        when
          $p : Person( name == "James" )
        then   // Insert Mark, who is a customer of James.
          Person mark = new Person();
          mark.setName( "Mark" );
          insert( mark );
      end

    • global: (任意) DRL ファイルのルールで使用するグローバル変数を組み込みます。グローバル変数は通常、ルールの結果で使用するアプリケーションサービスなど、ルールのデータやサービスを提供し、ルールの結果で追加されるログや値など、ルールからのデータを返します。KIE セッション設定や REST 操作を使用してデシジョンエンジンのワーキングメモリーにグローバル値を設定し、DRL ファイルのルールの上にグローバル変数を宣言してから、これをルールのアクション部分 (then) で使用します。グローバル変数が複数ある場合は、DRL ファイルで行を分けて使用してください。

      デシジョンエンジンに対するグローバルリストの設定

      List<String> list = new ArrayList<>();
      KieSession kieSession = kiebase.newKieSession();
      kieSession.setGlobal( "myGlobalList", list );

      ルールでのグローバルリストの定義

      global java.util.List myGlobalList;
      
      rule "Using a global"
        when
          // Empty
        then
          myGlobalList.add( "My global list" );
      end

      警告

      グローバル変数に定数イミュータブル値がない場合は、ルールの条件設定にグローバル変数を使用しないでください。グローバル変数はデシジョンエンジンのワーキングメモリーに挿入されないため、デシジョンエンジンでは変数の値の変更を追跡できません。

      グローバル変数を使用してルール間でデータを共有しないでください。ルールは常に、ワーキングメモリーの状態に関して推論し、これに対応するため、ルールからルールにデータを渡す必要がある場合は、データをファクトとしてデシジョンエンジンのワーキングメモリーにアサートしてください。

    • rule: DRL ファイルで各ルールを定義します。ルールは、rule "name" 形式のルール名、ルールの動作 (salienceno-loop など) を定義する任意の属性、when および then 定義が続きます。ルールごとに、ルールパッケージ内で一意の名前を指定する必要があります。ルールの when 部分には、アクションを実行するのに必要な条件が含まれます。たとえば、銀行が、ローンの申し込みを 21 歳以上に限定した場合、"Underage" ルールの when 条件は Applicant( age < 21 ) になります。ルールの then 部分には、ルールの条件部分に一致したときに実行するアクションが含まれます。たとえば、ローンの申込者が 21 歳に満たない場合は、then アクションが setApproved( false ) になり、申込者の年齢条件を満たしていないためにローンの申し込みは承認されません。

      申込者の年齢制限に関するルール

      rule "Underage"
        salience 15
        when
          $application : LoanApplication()
          Applicant( age < 21 )
        then
          $application.setApproved( false );
          $application.setExplanation( "Underage" );
      end

      少なくても、各 DRL ファイルは package コンポーネント、import コンポーネント、rule コンポーネントを指定する必要があります。他のすべてのコンポーネントは任意です。

      以下は、ローン申し込みのデシジョンサービスの DRL ファイルの例です。

      ローン申し込みの DRL ファイルの例

      package org.mortgages;
      
      import org.mortgages.LoanApplication;
      import org.mortgages.Bankruptcy;
      import org.mortgages.Applicant;
      
      rule "Bankruptcy history"
      	salience 10
      	when
      		$a : LoanApplication()
      		exists (Bankruptcy( yearOfOccurrence > 1990 || amountOwed > 10000 ))
      	then
      		$a.setApproved( false );
      		$a.setExplanation( "has been bankrupt" );
      		delete( $a );
      end
      
      rule "Underage"
      	salience 15
      	when
      		$application : LoanApplication()
      		Applicant( age < 21 )
      	then
      		$application.setApproved( false );
      		$application.setExplanation( "Underage" );
      		delete( $application );
      end

      図18.1 Business Central のロール申し込み用の DRL ファイルの例

      Example DRL file with required components
  7. ルールのコンポーネントをすべて定義したら、DRL デザイナーの右上ツールバーで Validate をクリックし、DRL ファイルの妥当性を確認します。ファイルの妥当性確認に失敗したら、エラーメッセージに記載された問題に対応し、DRL ファイルの構文およびコンポーネントをすべて見直し、エラーが表示されなくなるまで再度、ファイルを検証します。
  8. DRL デザイナーで Save をクリックして、設定した内容を保存します。

18.1. DRL ルールへの WHEN 条件の追加

ルールの when 部分には、アクションを実行するのに必要な条件が含まれます。たとえば、銀行のローンの申し込みに年齢制限 (21 歳以上) が必要な場合、"Underage" ルールの when 条件は Applicant( age < 21 ) となります。パッケージで利用可能なデータオブジェクトに基づいて、指定した一連のパターンおよび制約と、任意のバインディング、その他のサポートされる DRL 要素で構成されます。

前提条件

  • package は DRL ファイルに定義されます。これは、ファイルの作成時に行われます。
  • ルールで使用したデータオブジェクトの import リストが、DRL ファイルの package 行の下に定義されます。データオブジェクトは、このパッケージ、または別の Business Central パッケージから使用できます。
  • rule 名は、packageimport、または DRL ファイル全体に適用されるその他の行の下に、rule "name" という形式で定義されます。同じパッケージでルール名を重複させることはできません。ルールの動作 (salienceno-loop など) を定義する任意のルール属性は、ルール名の下、when セクションの前に定義します。

手順

  1. DRL デザイナーで、ルールに when を入力して、条件命令文を追加します。when セクションは、ルールの条件を定義するファクトパターンで構成されますが、ファクトパターンが 1 つも追加されない場合もあります。

    when セクションを空にすると、条件は true であると見なされ、デシジョンエンジンで fireAllRules() 呼び出しが最初に実施された場合に、then セクションのアクションが実行されます。これは、デシジョンエンジンのステートを設定するルールを使用する場合に便利です。

    条件のないルール例

    rule "Always insert applicant"
      when
        // Empty
      then   // Actions to be executed once
        insert( new Applicant() );
    end
    
    // The rule is internally rewritten in the following way:
    
    rule "Always insert applicant"
      when
        eval( true )
      then
        insert( new Applicant() );
    end

  2. 一致させる最初の条件のパターンを入力し、任意で制約、バインディング、およびサポートされる DRL 要素を入力します。基本的なパターンフォーマットは <patternBinding> : <patternType> ( <constraints> ) です。パターンは、パッケージで利用可能なデータオブジェクトに基づいており、then セクションのアクションを発生させるのに必要な条件を定義します。

    • 単純なパターン: 制約のない単純なパターンは、指定したタイプのファクトに一致します。たとえば、次は、申込者が存在することだけが条件になります。

      when
        Applicant()
    • 制約のあるパターン: 制約を持つパターンは、指定したタイプのファクトと、追加制限を括弧で指定したパターン (true または false) に一致します。たとえば、次は、申込者が 21 歳に満たないことを条件としています。

      when
        Applicant( age < 21 )
    • バインディングのあるパターン: パターンのバインディングは簡単な参照となり、ルールのその他のコンポーネントが、定義したバターンに戻って参照します。たとえば、次の例では、LoanApplication のバインディング a が、underage の申込者に関連するアクションとして使用されます。

      when
        $a : LoanApplication()
        Applicant( age < 21 )
      then
        $a.setApproved( false );
        $a.setExplanation( "Underage" )
  3. 引き続き、このルールに適用する条件パターンをすべて定義します。以下は、DRL 条件を定義するいくつかのキーワードオプションです。

    • and: 条件コンポーネントを論理積に分類します。インフィックスおよびプリフィックスの and がサポートされます。デフォルトでは、結合演算子を指定しないと、リストされているパターンがすべて and で結合されます。

      // All of the following examples are interpreted the same way:
      $a : LoanApplication() and Applicant( age < 21 )
      
      $a : LoanApplication()
      and Applicant( age < 21 )
      
      $a : LoanApplication()
      Applicant( age < 21 )
      
      (and $a : LoanApplication() Applicant( age < 21 ))
    • or: 条件コンポーネントを論理和に分類します。インフィックスおよびプリフィックスの or がサポートされます。

      // All of the following examples are interpreted the same way:
      Bankruptcy( amountOwed == 100000 ) or IncomeSource( amount == 20000 )
      
      Bankruptcy( amountOwed == 100000 )
      or IncomeSource( amount == 20000 )
      
      (or Bankruptcy( amountOwed == 100000 ) IncomeSource( amount == 20000 ))
    • exists: 存在すべきファクトおよび制約を指定します。このオプションは、最初に一致したものだけが適用され、その後一致するものは無視されます。この要素を複数のパターンで使用する場合は、これらのパターンを括弧 () で囲みます。

      exists ( Bankruptcy( yearOfOccurrence > 1990 || amountOwed > 10000 ) )
    • not: 存在するべきでないファクトおよび制約を指定します。

      not ( Applicant( age < 21 ) )
    • forall: 最初のパターンに一致するすべてのファクトが残りのすべてのパターンに一致するかどうかを検証します。forall 構成が満たされると、このルールが true と評価されます。

      forall( $app : Applicant( age < 21 )
                    Applicant( this == $app, status = 'underage' ) )
    • from: パターンのデータソースを指定します。

      Applicant( ApplicantAddress : address )
      Address( zipcode == "23920W" ) from ApplicantAddress
    • entry-point: パターンのデータソースに対応する エントリーポイント を定義します。通常は from とともに使用します。

      Applicant() from entry-point "LoanApplication"
    • collect: ルールを条件の一部として使用できる、オブジェクトのコレクションを定義します。この例では、指定したそれぞれのローンについてデシジョンエンジンで保留されているすべての申し込みが List に分類されます。申し込みが 3 つ以上ある場合は、このルールが実行します。

      $m : Mortgage()
      $a : List( size >= 3 )
          from collect( LoanApplication( Mortgage == $m, status == 'pending' ) )
    • accumulate: オブジェクトのコレクションを処理し、各要素のカスタムアクションを実行し、(制約が true と評価されると) 結果オブジェクトを 1 つ以上返します。このオプションは、collect よりも強力で、柔軟性が高いオプションです。accumulate( <source pattern>; <functions> [;<constraints>] ) 形式を使用します。この例では、minmax、および average は累積関数で、各センサーのすべての測定値から、最低気温、最高気温、および平均気温の値を計算します。その他のサポートされる関数には、countsumvariancestandardDeviationcollectList、および collectSet があります。

      $s : Sensor()
      accumulate( Reading( sensor == $s, $temp : temperature );
                  $min : min( $temp ),
                  $max : max( $temp ),
                  $avg : average( $temp );
                  $min < 20, $avg > 70 )
    注記

    DRL ルール条件の詳細については、「DRL のルール条件 (WHEN)」 を参照してください。

  4. ルールの条件コンポーネントをすべて定義したら、DRL デザイナーの右上のツールバーの Validate をクリックして、DRL ファイルの妥当性を確認します。ファイルの妥当性確認に失敗したら、エラーメッセージに記載された問題に対応し、DRL ファイルの構文およびコンポーネントをすべて見直し、エラーが表示されなくなるまで再度、ファイルを検証します。
  5. DRL デザイナーで Save をクリックして、設定した内容を保存します。

18.2. DRL ルールへの THEN アクションの追加

ルールの then 部分には、ルールの条件部分に一致したときに実行するアクションが含まれます。たとえば、ローンの申請者が 21 歳に満たない場合は、"Underage" ルールの then アクションが setApproved( false ) となり、年齢が基準に達していないためローンの申し込みは承認されません。アクションは、ルールの条件とパッケージで利用可能オブジェクトに基づいて結果を実行する 1 つ以上のメソッドで構成されます。ルールアクションの主な目的は、デシジョンエンジンのワーキングメモリーでデータの挿入、削除、または変更を行うことです。

前提条件

  • package は DRL ファイルに定義されます。これは、ファイルの作成時に行われます。
  • ルールで使用したデータオブジェクトの import リストが、DRL ファイルの package 行の下に定義されます。データオブジェクトは、このパッケージ、または別の Business Central パッケージから使用できます。
  • rule 名は、packageimport、または DRL ファイル全体に適用されるその他の行の下に、rule "name" という形式で定義されます。同じパッケージでルール名を重複させることはできません。ルールの動作 (salienceno-loop など) を定義する任意のルール属性は、ルール名の下、when セクションの前に定義します。

手順

  1. DRL デザイナーで、ルールの when セクションの後に then を入力して、アクション命令文を追加します。
  2. ルールの条件に基づいて、ファクトパターンに対して実行するアクションを 1 つ以上入力します。

    次は、DRL アクションを定義するキーワードオプションの例です。

    • set: フィールドの値を設定します。

      $application.setApproved ( false );
      $application.setExplanation( "has been bankrupt" );
    • modify: ファクトに対して修正するフィールドを指定し、変更をデシジョンエンジンに通知します。このメソッドは、ファクトの更新に対する構造化されたアプローチを提供します。このメソッドは、update 操作とオブジェクトフィールドを変更する setter 呼び出しを組み合わせたものです。

      modify( LoanApplication ) {
              setAmount( 100 ),
              setApproved ( true )
      }
    • update: フィールドと、更新される関連ファクト全体を指定して、その変更をデシジョンエンジンに通知します。ファクトが変更したら、アップデートした値の影響を受ける可能性がある別のファクトを変更する前に、update を呼び出す必要があります。この追加設定を回避するには、modify メソッドを代わりに使用します。

      LoanApplication.setAmount( 100 );
      update( LoanApplication );
    • insert: new ファクトをデシジョンエンジンに挿入します。

      insert( new Applicant() );
    • insertLogical: デシジョンエンジンに new ファクトを論理挿入する場合に使用します。デシジョンエンジンは、ファクトの挿入および取り消しに対して論理的な決断を行います。通常の挿入または記述による挿入の後には、ファクトは明示的に取り消される必要があります。論理挿入の後、挿入されたファクトは、ファクトを挿入したルールの条件が true でなくなると自動的に取り消されます。

      insertLogical( new Applicant() );
    • delete: デシジョンエンジンからオブジェクトを削除します。キーワード retract も DRL でサポートされており、同じアクションを実行しますが、DRL のコードでは、キーワード insert との整合性を考慮して delete が通常推奨されます。

      delete( Applicant );
    注記

    DRL ルールアクションの詳細については、「DRL におけるルールアクション (THEN)」 を参照してください。

  3. ルールのアクションコンポーネントをすべて定義したら、DRL デザイナーの右上のツールバーの Validate をクリックして、DRL ファイルの妥当性を確認します。ファイルの妥当性確認に失敗したら、エラーメッセージに記載された問題に対応し、DRL ファイルの構文およびコンポーネントをすべて見直し、エラーが表示されなくなるまで再度、ファイルを検証します。
  4. DRL デザイナーで Save をクリックして、設定した内容を保存します。

第19章 ルールの実行

ルールの例を特定するか、Business Central でルールを作成したら、関連のプロジェクトをビルドしてデプロイし、ローカルまたは KIE Server でルールを実行してテストできます。

前提条件

手順

  1. Business Central で、MenuDesignProjects に移動して、プロジェクト名をクリックします。
  2. プロジェクトの Assets ページの右上にある Deploy をクリックして、プロジェクトをビルドして KIE Server にデプロイします。ビルドに失敗したら、画面下部の Alerts パネルに記載されている問題に対処します。

    プロジェクトデプロイメントのオプションに関する詳細は、『Red Hat Process Automation Manager プロジェクトのパッケージ化およびデプロイ』を参照してください。

    注記

    デフォルトでプロジェクト内のルールアセットが実行可能なルールモデルからビルドされていない場合は、以下の依存関係がプロジェクトの pom.xml ファイルに含まれていることを確認して、プロジェクトを再構築してください。

    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-model-compiler</artifactId>
      <version>${rhpam.version}</version>
    </dependency>

    この依存関係は、デフォルトで Red Hat Process Automation Manager のルールアセットが実行可能なルールモデルからビルドされるために必要です。Red Hat Process Automation Manager のコアパッケージに、この依存関係は同梱されていますが、Red Hat Process Automation Manager のアップグレード履歴によっては、この依存関係を手動で追加して、実行可能なルールモデルの動作を有効にする必要がある場合があります。

    実行可能なルールモデルに関する詳細は、『Red Hat Process Automation Manager プロジェクトのパッケージ化およびデプロイ』 を参照してください。

  3. ローカルでのルール実行に使用するか、KIE Server でルールを実行するクライアントアプリケーションとして使用できるように、Business Central 外に Maven または Java プロジェクトが作成されていない場合は作成します。プロジェクトには、pom.xml ファイルと、プロジェクトリソースの実行に必要なその他のコンポーネントを含める必要があります。

    テストプロジェクトの例は、「その他の DRL ルールの作成および実行方法」を参照してください。

  4. テストプロジェクトまたはクライアントアプリケーションの pom.xml ファイルを開き、以下の依存関係が追加されていない場合は追加します。

    • kie-ci: クライアントアプリケーションで、ReleaseId を使用して、Business Central プロジェクトデータをローカルに読み込みます。
    • kie-server-client: クライアントアプリケーションで、KIE Server のアセットを使用してリモートに接続します。
    • slf4j: (任意) クライアントアプリケーションで、KIE Server に接続した後に、SLF4J (Simple Logging Facade for Java) を使用して、デバッグのログ情報を返します。

    クライアントアプリケーションの pom.xml ファイルにおける Red Hat Process Automation Manager 7.10 の依存関係の例

    <!-- For local execution -->
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-ci</artifactId>
      <version>7.48.0.Final-redhat-00004</version>
    </dependency>
    
    <!-- For remote execution on KIE Server -->
    <dependency>
      <groupId>org.kie.server</groupId>
      <artifactId>kie-server-client</artifactId>
      <version>7.48.0.Final-redhat-00004</version>
    </dependency>
    
    <!-- For debug logging (optional) -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-simple</artifactId>
      <version>1.7.25</version>
    </dependency>

    このアーティファクトで利用可能なバージョンについては、オンラインの Nexus Repository Manager でグループ ID とアーティファクト ID を検索してください。

    注記

    個別の依存関係に対して Red Hat Process Automation Manager <version> を指定するのではなく、Red Hat Business Automation BOM (bill of materials) の依存関係をプロジェクトの pom.xml ファイルに追加することを検討してください。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.10.0.redhat-00004</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>

    Red Hat Business Automation BOM (Bill of Materials) に関する詳細情報は、「What is the mapping between Red Hat Process Automation Manager and the Maven library version?」 を参照してください。

  5. モデルクラスを含むアーティファクトの依存関係が、クライアントアプリケーションの pom.xml ファイルに定義されていて、デプロイしたプロジェクトの pom.xml ファイルに記載されているのと同じであることを確認します。モデルクラスの依存関係が、クライアントアプリケーションとプロジェクトで異なると、実行エラーが発生します。

    Business Central でプロジェクトの pom.xml ファイルを利用するには、プロジェクトで既存のアセットを選択し、画面左側の Project Explorer メニューで Customize View ギアアイコンをクリックし、Repository Viewpom.xml を選択します。

    たとえば、以下の Person クラスの依存関係は、クライアントと、デプロイしたプロジェクトの pom.xml ファイルの両方に表示されます。

    <dependency>
      <groupId>com.sample</groupId>
      <artifactId>Person</artifactId>
      <version>1.0.0</version>
    </dependency>
  6. デバッグ向けロギングを行うために、slf4j 依存関係を、クライアントアプリケーションの pom.xml ファイルに追加した場合は、関連するクラスパス (Maven の src/main/resources/META-INF 内など) に simplelogger.properties ファイルを作成し、以下の内容を記載します。

    org.slf4j.simpleLogger.defaultLogLevel=debug
  7. クライアントアプリケーションに、必要なインポートを含む .java メインクラスと、KIE ベースを読み込む main() メソッドを作成し、ファクトを挿入し、ルールを実行します。

    たとえば、プロジェクトの Person オブジェクトには、名前、苗字、時給、および賃金を設定および取得するゲッターメソッドおよびセッターメソッドが含まれます。プロジェクトにある以下の Wage ルールでは、賃金と時給を計算し、その結果に基づいてメッセージを表示します。

    package com.sample;
    
    import com.sample.Person;
    
    dialect "java"
    
    rule "Wage"
      when
        Person(hourlyRate * wage > 100)
        Person(name : firstName, surname : lastName)
      then
        System.out.println("Hello" + " " + name + " " + surname + "!");
        System.out.println("You are rich!");
    end

    (必要に応じて) KIE Server の外でローカルにこのルールをテストするには、.java クラスで、KIE サービス、KIE コンテナー、および KIE セッションをインポートするように設定し、その後、main() メソッドを使用して、定義したファクトモデルに対してすべてのルールを実行するようにします。

    ローカルでルールの実行

    import org.kie.api.KieServices;
    import org.kie.api.builder.ReleaseId;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    import org.drools.compiler.kproject.ReleaseIdImpl;
    
    public class RulesTest {
    
      public static final void main(String[] args) {
        try {
          // Identify the project in the local repository:
          ReleaseId rid = new ReleaseIdImpl("com.myspace", "MyProject", "1.0.0");
    
          // Load the KIE base:
          KieServices ks = KieServices.Factory.get();
          KieContainer kContainer = ks.newKieContainer(rid);
          KieSession kSession = kContainer.newKieSession();
    
          // Set up the fact model:
          Person p = new Person();
          p.setWage(12);
          p.setFirstName("Tom");
          p.setLastName("Summers");
          p.setHourlyRate(10);
    
          // Insert the person into the session:
          kSession.insert(p);
    
          // Fire all rules:
          kSession.fireAllRules();
          kSession.dispose();
        }
    
        catch (Throwable t) {
          t.printStackTrace();
        }
      }
    }

    KIE Server でこのルールをテストするには、ローカルの例と同じように、インポートとルール実行情報で .java クラスを設定し、KIE サービス設定および KIE サービスクライアントの詳細を指定します。

    KIE Server でのルールの実行

    package com.sample;
    
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    import org.kie.api.command.BatchExecutionCommand;
    import org.kie.api.command.Command;
    import org.kie.api.KieServices;
    import org.kie.api.runtime.ExecutionResults;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    import org.kie.server.api.marshalling.MarshallingFormat;
    import org.kie.server.api.model.ServiceResponse;
    import org.kie.server.client.KieServicesClient;
    import org.kie.server.client.KieServicesConfiguration;
    import org.kie.server.client.KieServicesFactory;
    import org.kie.server.client.RuleServicesClient;
    
    import com.sample.Person;
    
    public class RulesTest {
    
      private static final String containerName = "testProject";
      private static final String sessionName = "myStatelessSession";
    
      public static final void main(String[] args) {
        try {
          // Define KIE services configuration and client:
          Set<Class<?>> allClasses = new HashSet<Class<?>>();
          allClasses.add(Person.class);
          String serverUrl = "http://$HOST:$PORT/kie-server/services/rest/server";
          String username = "$USERNAME";
          String password = "$PASSWORD";
          KieServicesConfiguration config =
            KieServicesFactory.newRestConfiguration(serverUrl,
                                                    username,
                                                    password);
          config.setMarshallingFormat(MarshallingFormat.JAXB);
          config.addExtraClasses(allClasses);
          KieServicesClient kieServicesClient =
            KieServicesFactory.newKieServicesClient(config);
    
          // Set up the fact model:
          Person p = new Person();
          p.setWage(12);
          p.setFirstName("Tom");
          p.setLastName("Summers");
          p.setHourlyRate(10);
    
          // Insert Person into the session:
          KieCommands kieCommands = KieServices.Factory.get().getCommands();
          List<Command> commandList = new ArrayList<Command>();
          commandList.add(kieCommands.newInsert(p, "personReturnId"));
    
          // Fire all rules:
          commandList.add(kieCommands.newFireAllRules("numberOfFiredRules"));
          BatchExecutionCommand batch = kieCommands.newBatchExecution(commandList, sessionName);
    
          // Use rule services client to send request:
          RuleServicesClient ruleClient = kieServicesClient.getServicesClient(RuleServicesClient.class);
          ServiceResponse<ExecutionResults> executeResponse = ruleClient.executeCommandsWithResults(containerName, batch);
          System.out.println("number of fired rules:" + executeResponse.getResult().getValue("numberOfFiredRules"));
        }
    
        catch (Throwable t) {
          t.printStackTrace();
        }
      }
    }

  8. 設定した .java クラスをプロジェクトディレクトリーから実行します。(Red Hat CodeReady Studio などの) 開発プラットフォーム、またはコマンドラインでファイルを実行できます。

    (プロジェクトディレクトリーにおける) Maven の実行例

    mvn clean install exec:java -Dexec.mainClass="com.sample.app.RulesTest"

    (プロジェクトディレクトリーにおける) Java の実行例

    javac -classpath "./$DEPENDENCIES/*:." RulesTest.java
    java -classpath "./$DEPENDENCIES/*:." RulesTest
  9. コマンドラインおよびサーバーログで、ルール実行のステータスを確認します。ルールが期待通りに実行しない場合は、プロジェクトに設定したルールと、メインのクラス設定を確認して、提供されるデータの妥当性を確認します。

第20章 その他の DRL ルールの作成および実行方法

Business Central インターフェースで DRL ルールを作成し、管理する代わりに、Red Hat CodeReady Studio やその他の統合開発環境 (IDE) を使用して、Maven または Java プロジェクトの一部として DRL ルールファイルを作成できます。このスタンドアロンプロジェクトは、ナレッジ JAR (kJAR) 依存関係として、Business Central の既存の Red Hat Process Automation Manager プロジェクトに統合できます。スタンドアロンプロジェクトの DRL ファイルには、少なくても、必要な package 仕様、import リスト、および rule 定義が含まれる必要があります。グローバル変数や関数など、その他の DRL コンポーネントは任意です。DRL ルールに関連するすべてのデータオブジェクトは、スタンドアロンの DRL プロジェクトまたはデプロイメントに含まれる必要があります。

Maven または Java プロジェクトで実行可能なルールモデルを使用して、ビルド時に実行するルールセットの Java ベース表記を提供します。実行可能モデルは Red Hat Process Automation Manager の標準アセットパッケージングの代わりとなるもので、より効率的です。KIE コンテナーと KIE ベースの作成がより迅速にでき、DRL (Drools Rule Language) ファイルリストや他の Red Hat Process Automation Manager アセットが多い場合は、特に有効です。

20.1. Red Hat CodeReady Studio での DRL ルールの作成および実行

Red Hat JBoss CodeReady Studio を使用して、ルールが含まれる DRL ファイルを作成し、Red Hat Process Automation Manager デシジョンサービスにファイルを統合します。DRL ルールを作成する方法は、デシジョンサービスに Red Hat CodeReady Studio を使用する場合や、同じワークフローを継続する場合に便利です。この方法を使用していない場合は、Red Hat Process Automation Manager の代わりに Business Central インターフェースを使用して、DRL ファイルや、その他のルールアセットを作成することが推奨されます。

前提条件

手順

  1. Red Hat CodeReady Studio で、FileNewProject をクリックします。
  2. 開いた New Project ウィンドウで、DroolsDrools Project を選択し、Next をクリックします。
  3. Create a project and populate it with some example files to help you get started quickly の 2 番目のアイコンをクリックします。Next をクリックします。
  4. Project name を入力し、プロジェクトのビルドオプションで Maven ラジオボタンを選択します。GAV 値が自動的に生成されます。必要に応じて、プロジェクトに対してこの値を更新できます。

    • Group ID: com.sample
    • Artifact ID: my-project
    • Version: 1.0.0-SNAPSHOT
  5. Finish をクリックしてプロジェクトを作成します。

    これは、基本的なプロジェクト構造、クラスパス、サンプルルールを設定します。以下は、プロジェクト構造の概要です。

    my-project
     `-- src/main/java
        | `-- com.sample
        |    `-- DecisionTableTest.java
        |    `-- DroolsTest.java
        |    `-- ProcessTest.java
        |
     `-- src/main/resources
        | `-- dtables
        |    `-- Sample.xls
        | `-- process
        |    `-- sample.bpmn
        | `-- rules
        |    `-- Sample.drl
        | `-- META-INF
        |
     `-- JRE System Library
        |
     `-- Maven Dependencies
        |
     `-- Drools Library
        |
     `-- src
        |
     `-- target
        |
     `-- pom.xml

    以下の要素に注目してください。

    • src/main/resources ディレクトリーの Sample.drl ルールファイル。これには、サンプルの Hello World ルールおよび GoodBye ルールが含まれます。
    • com.sample パッケージの src/main/java ディレクトリーにある DroolsTest.java ファイル。Sample.drl ルールの実行には、DroolsTest クラスを使用できます。
    • 実行するのに必要な JAR ファイルを含むカスタムのクラスパスとなる Drools Library ディレクトリー。

    既存の Sample.drl ファイルおよび DroolsTest.java ファイルを必要に応じて新しい設定に変更するか、ルールファイルおよびオブジェクトファイルを新たに作成します。この手順では、ルールと Java オブジェクトを新たに作成します。

  6. ルールが有効な Java オブジェクトを作成します。

    この例では、my-project/src/main/java/com.samplePerson.java ファイルが作成されます。Person クラスには、名前、苗字、時給、および賃金を設定および取得するゲッターメソッドおよびセッターメソッドが含まれます。

      public class Person {
        private String firstName;
        private String lastName;
        private Integer hourlyRate;
        private Integer wage;
    
        public String getFirstName() {
          return firstName;
        }
    
        public void setFirstName(String firstName) {
          this.firstName = firstName;
        }
    
        public String getLastName() {
          return lastName;
        }
    
        public void setLastName(String lastName) {
          this.lastName = lastName;
        }
    
        public Integer getHourlyRate() {
          return hourlyRate;
        }
    
        public void setHourlyRate(Integer hourlyRate) {
          this.hourlyRate = hourlyRate;
        }
    
        public Integer getWage(){
          return wage;
        }
    
        public void setWage(Integer wage){
          this.wage = wage;
        }
      }
  7. FileSave をクリックして、ファイルを保存します。
  8. my-project/src/main/resources/rules に、.drl 形式のルールファイルを作成します。DRL ファイルには、少なくともパッケージの指定と、(1 つまたは複数の) ルールで使用されるデータオブジェクトのインポートリストと、when 条件および then アクションを持つ 1 つ以上のルールが含まれます。

    以下の Wage.drl ファイルには、Person クラスをインポートする Wage ルールが含まれ、賃金および時給の値を計算し、その結果に基づいてメッセージを表示します。

    package com.sample;
    
    import com.sample.Person;
    
    dialect "java"
    
    rule "Wage"
      when
        Person(hourlyRate * wage > 100)
        Person(name : firstName, surname : lastName)
      then
        System.out.println("Hello" + " " + name + " " + surname + "!");
        System.out.println("You are rich!");
    end
  9. FileSave をクリックして、ファイルを保存します。
  10. メインクラスを作成し、Java オブジェクトを作成したディレクトリーに保存します。メインクラスは KIE ベースを読み込み、ルールを実行します。

    注記

    また、DroolsTest.java サンプルファイルと同様に、main() メソッドと Person クラスを 1 つの Java オブジェクトファイルに追加できます。

  11. メインクラスに、KIE サービス、KIE コンテナー、および KIE セッションをインポートするのに必要な import 命令文を追加します。つぎに、KIE ベースを読み込み、ファクトを挿入し、ファクトモデルをルールに渡す main() メソッドからルールを実行します。

    この例では、必要なインポートと main() メソッドを使用して、my-project/src/main/java/com.sampleRulesTest.java ファイルを作成します。

    package com.sample;
    
    import org.kie.api.KieServices;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    
    public class RulesTest {
      public static final void main(String[] args) {
        try {
          // Load the KIE base:
          KieServices ks = KieServices.Factory.get();
          KieContainer kContainer = ks.getKieClasspathContainer();
          KieSession kSession = kContainer.newKieSession();
    
          // Set up the fact model:
          Person p = new Person();
          p.setWage(12);
          p.setFirstName("Tom");
          p.setLastName("Summers");
          p.setHourlyRate(10);
    
          // Insert the person into the session:
          kSession.insert(p);
    
          // Fire all rules:
          kSession.fireAllRules();
          kSession.dispose();
        }
    
        catch (Throwable t) {
          t.printStackTrace();
        }
      }
    }
  12. FileSave をクリックして、ファイルを保存します。
  13. プロジェクトで DRL アセットをすべて作成して保存したあと、プロジェクトフォルダーを右クリックして、Run AsJava Application を選択してプロジェクトをビルドします。プロジェクトのビルドに失敗したら、CodeReady Studio の下部ウィンドウの Problems タブに記載されている問題に対応し、プロジェクトがビルドされるまでプロジェクトの検証を行います。
Run AsJava Application オプションが利用できない場合

プロジェクトを右クリックして、Run As を選択した場合に Java Application が選択肢にない場合は、Run AsRun Configurations に移動して Java Application を右クリックし、New をクリックします。次に、Main タブで、Project と、関連する Main class を参照して選択します。Apply をクリックし、Run をクリックしてプロジェクトをテストします。再度プロジェクトフォルダーを右クリックすると、Java Application オプションが表示されます。

Red Hat Process Automation Manager で既存のプロジェクトと新しいルールアセットを統合するには、ナレッジJAR (KJAR) として新規プロジェクトをコンパイルし、Business Central でプロジェクトの pom.xml ファイルに、依存関係としてこのプロジェクトを追加します。Business Central でプロジェクト pom.xml にアクセスするには、プロジェクトで既存のアセットを選択し、画面左側の Project Explorer メニューで Customize View ギアアイコンをクリックし、Repository Viewpom.xml を選択します。

20.2. Java を使用した DRL ルールの作成および実行

Java オブジェクトを使用して、ルールを持つ DRL ファイルを作成し、オブジェクトを Red Hat Process Automation Manager デシジョンサービスに統合します。DRL ルールを作成する方法は、デシジョンサービスに外部 Java オブジェクトを使用している場合や、同じワークフローを継続する場合に便利です。この方法を使用していない場合は、Red Hat Process Automation Manager の代わりに Business Central インターフェースを使用して、DRL ファイルや、その他のルールアセットを作成することが推奨されます。

手順

  1. ルールが有効な Java オブジェクトを作成します。

    この例では、my-project ディレクトリーに Person.java ファイルが作成されます。Person クラスには、名前、苗字、時給、および賃金を設定および取得するゲッターメソッドおよびセッターメソッドが含まれます。

      public class Person {
        private String firstName;
        private String lastName;
        private Integer hourlyRate;
        private Integer wage;
    
        public String getFirstName() {
          return firstName;
        }
    
        public void setFirstName(String firstName) {
          this.firstName = firstName;
        }
    
        public String getLastName() {
          return lastName;
        }
    
        public void setLastName(String lastName) {
          this.lastName = lastName;
        }
    
        public Integer getHourlyRate() {
          return hourlyRate;
        }
    
        public void setHourlyRate(Integer hourlyRate) {
          this.hourlyRate = hourlyRate;
        }
    
        public Integer getWage(){
          return wage;
        }
    
        public void setWage(Integer wage){
          this.wage = wage;
        }
      }
  2. my-project ディレクトリーに、.drl 形式のルールファイルを作成します。DRL ファイルには、少なくともパッケージの指定 (該当する場合) と、(1 つまたは複数の) ルールで使用されるデータオブジェクトのインポートリストと、when 条件および then アクションを持つ 1 つ以上のルールが含まれます。

    以下の Wage.drl ファイルには、賃金と時給を計算し、その結果に基づいてメッセージを表示する Wage ルールが含まれています。

    package com.sample;
    
    import com.sample.Person;
    
    dialect "java"
    
    rule "Wage"
      when
        Person(hourlyRate * wage > 100)
        Person(name : firstName, surname : lastName)
      then
        System.out.println("Hello" + " " + name + " " + surname + "!");
        System.out.println("You are rich!");
    end
  3. メインクラスを作成し、Java オブジェクトを作成したディレクトリーに保存します。メインクラスは KIE ベースを読み込み、ルールを実行します。
  4. メインクラスに、KIE サービス、KIE コンテナー、および KIE セッションをインポートするのに必要な import 命令文を追加します。つぎに、KIE ベースを読み込み、ファクトを挿入し、ファクトモデルをルールに渡す main() メソッドからルールを実行します。

    この例では、必要なインポートと main() メソッドを使用して、my-projectRulesTest.java ファイルを作成します。

    import org.kie.api.KieServices;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    
    public class RulesTest {
      public static final void main(String[] args) {
        try {
          // Load the KIE base:
          KieServices ks = KieServices.Factory.get();
          KieContainer kContainer = ks.getKieClasspathContainer();
          KieSession kSession = kContainer.newKieSession();
    
          // Set up the fact model:
          Person p = new Person();
          p.setWage(12);
          p.setFirstName("Tom");
          p.setLastName("Summers");
          p.setHourlyRate(10);
    
          // Insert the person into the session:
          kSession.insert(p);
    
          // Fire all rules:
          kSession.fireAllRules();
          kSession.dispose();
        }
    
        catch (Throwable t) {
          t.printStackTrace();
        }
      }
    }
  5. Red Hat カスタマーポータル から ZIP ファイル Red Hat Process Automation Manager 7.10.0 Source Distribution をダウンロードし、my-project/pam-engine-jars/ で展開します。
  6. my-project/META-INF ディレクトリーに、以下の内容の kmodule.xml メタデータファイルを作成します。

    <?xml version="1.0" encoding="UTF-8"?>
    <kmodule xmlns="http://www.drools.org/xsd/kmodule">
    </kmodule>

    この kmodule.xml ファイルは、KIE ベースへのリソースを選択し、セッションを設定する KIE モジュールの記述子です。このファイルを使用すると、KIE ベースを 1 つ以上定義して設定し、特定の KIE ベースの特定の packages から DRL ファイルを含めることができます。各 KIE ベースから KIE セッションを 1 つ以上作成することもできます。

    次の例は、より高度な kmodule.xml ファイルを表示します。

    <?xml version="1.0" encoding="UTF-8"?>
    <kmodule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.drools.org/xsd/kmodule">
      <kbase name="KBase1" default="true" eventProcessingMode="cloud" equalsBehavior="equality" declarativeAgenda="enabled" packages="org.domain.pkg1">
        <ksession name="KSession1_1" type="stateful" default="true" />
        <ksession name="KSession1_2" type="stateful" default="true" beliefSystem="jtms" />
      </kbase>
      <kbase name="KBase2" default="false" eventProcessingMode="stream" equalsBehavior="equality" declarativeAgenda="enabled" packages="org.domain.pkg2, org.domain.pkg3" includes="KBase1">
        <ksession name="KSession2_1" type="stateless" default="true" clockType="realtime">
          <fileLogger file="debugInfo" threaded="true" interval="10" />
          <workItemHandlers>
            <workItemHandler name="name" type="new org.domain.WorkItemHandler()" />
          </workItemHandlers>
          <listeners>
            <ruleRuntimeEventListener type="org.domain.RuleRuntimeListener" />
            <agendaEventListener type="org.domain.FirstAgendaListener" />
            <agendaEventListener type="org.domain.SecondAgendaListener" />
            <processEventListener type="org.domain.ProcessListener" />
          </listeners>
        </ksession>
      </kbase>
    </kmodule>

    この例は、KIE ベースを 2 つ定義します。KIE ベース KBase1 から 2 つの KIE セッションをインスタンス化し、KBase2 から KIE セッションを 1 つインスタンス化します。KBase2 の KIE セッションは ステートレス な KIE セッションですが、これは 1 つ前の KIE セッションで呼び出されたデータ (1 つ前のセッションの状態) が、セッションの呼び出しと呼び出しの間で破棄されることを示しています。ルールアセットの特定の パッケージ は両方 KIE ベースに含まれます。この方法でパッケージを指定した場合は、指定したパッケージを反映するディレクトリー構造で DRL ファイルを整理する必要があります。

  7. Java オブジェクトですべての DRL アセットを作成して保存したあと、コマンドラインで my-project ディレクトリーに移動し、以下のコマンドを実行して Java ファイルをビルドします。RulesTest.java を、Java のメインクラスの名前に置き換えます。

    javac -classpath "./pam-engine-jars/*:." RulesTest.java

    ビルドに失敗したら、コマンドラインのエラーメッセージに記載されている問題に対応し、エラーが表示されなくなるまで Java オブジェクトの妥当性確認を行います。

  8. Java ファイルが問題なくビルトできたら、以下のコマンドを実行してローカルでルールを実行します。RulesTest を、Java のメインクラスのプリフィックスに置き換えます。

    java -classpath "./pam-engine-jars/*:." RulesTest
  9. ルールを見直して、適切に実行したことを確認し、Java ファイルで必要な変更に対応します。

Red Hat Process Automation Manager で既存のプロジェクトと新しいルールアセットを統合するには、ナレッジJAR (KJAR) として新規 Java プロジェクトをコンパイルし、Business Central でプロジェクトの pom.xml ファイルに、依存関係としてこのプロジェクトを追加します。Business Central でプロジェクト pom.xml にアクセスするには、プロジェクトで既存のアセットを選択し、画面左側の Project Explorer メニューで Customize View ギアアイコンをクリックし、Repository Viewpom.xml を選択します。

20.3. Maven を使用した DRL ルールの作成および実行

Maven アーキタイプを使用して、ルールを持つ DRL ファイルを作成し、アーキタイプを Red Hat Process Automation Manager デシジョンサービスに統合します。DRL ルールを作成する方法は、デシジョンサービスに外部 Maven アーキタイプを使用している場合や、同じワークフローを継続する場合に便利です。この方法を使用していない場合は、Red Hat Process Automation Manager の代わりに Business Central インターフェースを使用して、DRL ファイルや、その他のルールアセットを作成することが推奨されます。

手順

  1. Maven アーキタイプを作成するディレクトリーに移動して、次のコマンドを実行します。

    mvn archetype:generate -DgroupId=com.sample.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

    これにより、my-app という名前のディレクトリーが、以下の構造で作成されます。

    my-app
    |-- pom.xml
    `-- src
        |-- main
        |   `-- java
        |       `-- com
        |           `-- sample
        |               `-- app
        |                   `-- App.java
        `-- test
            `-- java
                `-- com
                    `-- sample
                        `-- app
                            `-- AppTest.java

    my-app ディレクトリーには、以下の重要なコンポーネントが含まれます。

    • アプリケーションソースを保存する src/main ディレクトリー
    • テストソースを保存する src/test ディレクトリー
    • プロジェクト設定ファイル pom.xml
  2. Maven アーキタイプに、ルールが有効な Java オブジェクトを作成します。

    この例では、my-app/src/main/java/com/sample/app ディレクトリーに Person.java ファイルが作成されます。Person クラスには、名前、苗字、時給、および賃金を設定および取得するゲッターメソッドおよびセッターメソッドが含まれます。

    package com.sample.app;
    
      public class Person {
    
        private String firstName;
        private String lastName;
        private Integer hourlyRate;
        private Integer wage;
    
        public String getFirstName() {
          return firstName;
        }
    
        public void setFirstName(String firstName) {
          this.firstName = firstName;
        }
    
        public String getLastName() {
          return lastName;
        }
    
        public void setLastName(String lastName) {
          this.lastName = lastName;
        }
    
        public Integer getHourlyRate() {
          return hourlyRate;
        }
    
        public void setHourlyRate(Integer hourlyRate) {
          this.hourlyRate = hourlyRate;
        }
    
        public Integer getWage(){
          return wage;
        }
    
        public void setWage(Integer wage){
          this.wage = wage;
        }
      }
  3. my-app/src/main/resources/rules に、.drl 形式のルールファイルを作成します。DRL ファイルには、少なくともパッケージの指定と、(1 つまたは複数の) ルールで使用されるデータオブジェクトのインポートリストと、when 条件および then アクションを持つ 1 つ以上のルールが含まれます。

    以下の Wage.drl ファイルには、Person クラスをインポートする Wage ルールが含まれ、賃金および時給の値を計算し、その結果に基づいてメッセージを表示します。

    package com.sample.app;
    
    import com.sample.app.Person;
    
    dialect "java"
    
    rule "Wage"
      when
        Person(hourlyRate * wage > 100)
        Person(name : firstName, surname : lastName)
      then
        System.out.println("Hello " + name + " " + surname + "!");
        System.out.println("You are rich!");
    end
  4. my-app/src/main/resources/META-INF ディレクトリーに、以下の内容の kmodule.xml メタデータファイルを作成します。

    <?xml version="1.0" encoding="UTF-8"?>
    <kmodule xmlns="http://www.drools.org/xsd/kmodule">
    </kmodule>

    この kmodule.xml ファイルは、KIE ベースへのリソースを選択し、セッションを設定する KIE モジュールの記述子です。このファイルを使用すると、KIE ベースを 1 つ以上定義して設定し、特定の KIE ベースの特定の packages から DRL ファイルを含めることができます。各 KIE ベースから KIE セッションを 1 つ以上作成することもできます。

    次の例は、より高度な kmodule.xml ファイルを表示します。

    <?xml version="1.0" encoding="UTF-8"?>
    <kmodule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.drools.org/xsd/kmodule">
      <kbase name="KBase1" default="true" eventProcessingMode="cloud" equalsBehavior="equality" declarativeAgenda="enabled" packages="org.domain.pkg1">
        <ksession name="KSession1_1" type="stateful" default="true" />
        <ksession name="KSession1_2" type="stateful" default="true" beliefSystem="jtms" />
      </kbase>
      <kbase name="KBase2" default="false" eventProcessingMode="stream" equalsBehavior="equality" declarativeAgenda="enabled" packages="org.domain.pkg2, org.domain.pkg3" includes="KBase1">
        <ksession name="KSession2_1" type="stateless" default="true" clockType="realtime">
          <fileLogger file="debugInfo" threaded="true" interval="10" />
          <workItemHandlers>
            <workItemHandler name="name" type="new org.domain.WorkItemHandler()" />
          </workItemHandlers>
          <listeners>
            <ruleRuntimeEventListener type="org.domain.RuleRuntimeListener" />
            <agendaEventListener type="org.domain.FirstAgendaListener" />
            <agendaEventListener type="org.domain.SecondAgendaListener" />
            <processEventListener type="org.domain.ProcessListener" />
          </listeners>
        </ksession>
      </kbase>
    </kmodule>

    この例は、KIE ベースを 2 つ定義します。KIE ベース KBase1 から 2 つの KIE セッションをインスタンス化し、KBase2 から KIE セッションを 1 つインスタンス化します。KBase2 の KIE セッションは ステートレス な KIE セッションですが、これは 1 つ前の KIE セッションで呼び出されたデータ (1 つ前のセッションの状態) が、セッションの呼び出しと呼び出しの間で破棄されることを示しています。ルールアセットの特定の パッケージ は両方 KIE ベースに含まれます。この方法でパッケージを指定した場合は、指定したパッケージを反映するディレクトリー構造で DRL ファイルを整理する必要があります。

  5. my-app/pom.xml 設定ファイルで、アプリケーションが要求するライブラリーを指定します。Red Hat Process Automation Manager の依存関係と、アプリケーションの group IDartifact ID、および version (GAV) を提供します。

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.sample.app</groupId>
    <artifactId>my-app</artifactId>
    <version>1.0.0</version>
    <repositories>
      <repository>
        <id>jboss-ga-repository</id>
        <url>http://maven.repository.redhat.com/ga/</url>
      </repository>
    </repositories>
    <dependencies>
      <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-compiler</artifactId>
        <version>VERSION</version>
      </dependency>
      <dependency>
        <groupId>org.kie</groupId>
        <artifactId>kie-api</artifactId>
        <version>VERSION</version>
      </dependency>
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
      </dependency>
    </dependencies>
    </project>

    Red Hat Process Automation Manager における Maven 依存関係および BOM (Bill of Materials) の詳細は、「What is the mapping between Red Hat Process Automation Manager and Maven library version?」を参照してください。

  6. my-app/src/test/java/com/sample/app/AppTest.javatestApp メソッドを使用してルールをテストします。Maven によって、AppTest.java ファイルがデフォルトで作成されます。
  7. AppTest.java ファイルで、KIE サービス、KIE コンテナー、および KIE セッションをインポートするのに必要な import 命令文を追加します。次に、KIE ベースを読み込み、ファクトを挿入し、ファクトモデルをルールに渡す testApp() メソッドからルールを実行します。

    import org.kie.api.KieServices;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    
    public void testApp() {
    
      // Load the KIE base:
      KieServices ks = KieServices.Factory.get();
      KieContainer kContainer = ks.getKieClasspathContainer();
      KieSession kSession = kContainer.newKieSession();
    
      // Set up the fact model:
      Person p = new Person();
      p.setWage(12);
      p.setFirstName("Tom");
      p.setLastName("Summers");
      p.setHourlyRate(10);
    
      // Insert the person into the session:
      kSession.insert(p);
    
      // Fire all rules:
      kSession.fireAllRules();
      kSession.dispose();
    }
  8. Maven アーキタイプにすべての DRL アセットを作成して保存したあと、コマンドラインで my-app ディレクトリーに移動し、以下のコマンドを実行してファイルを作成します。

    mvn clean install

    ビルドに失敗したら、コマンドラインのエラーメッセージに記載されている問題に対応し、ビルドに成功するまでファイルの妥当性確認を行います。

  9. ファイルが問題なくビルドできたら、以下のコマンドを実行してローカルでルールを実行します。com.sample.app をパッケージ名に置き換えます。

    mvn exec:java -Dexec.mainClass="com.sample.app"
  10. ルールを見直して、適切に実行したことを確認し、ファイルで必要な変更に対応します。

Red Hat Process Automation Manager で既存のプロジェクトと新しいルールアセットを統合するには、ナレッジJAR (KJAR) として新規 Maven プロジェクトをコンパイルし、Business Central でプロジェクトの pom.xml ファイルに、依存関係としてこのプロジェクトを追加します。Business Central でプロジェクト pom.xml にアクセスするには、プロジェクトで既存のアセットを選択し、画面左側の Project Explorer メニューで Customize View ギアアイコンをクリックし、Repository Viewpom.xml を選択します。

第21章 Red Hat Process Automation Manager の IDE 向けのデシジョン例

Red Hat Process Automation Manager は、統合開発環境 (IDE: integrated development environment) にインポートできるように Java クラスとして配信されるデシジョン例を提供します。これらの例は、デシジョンエンジン機能をさらに理解するために使用する目的か、Red Hat Process Automation Manager プロジェクトに定義するデシジョンの参考として使用してください。

以下のデシジョンセットの例は、Red Hat Process Automation Manager で利用可能な例の一部です。

  • Hello World の例: 基本的なルール実行や、デバッグ出力の使用方法を例示します。
  • 状態の例: ルールの顕著性やアジェンダグループを使用した前向き連鎖や競合解決を例示します。
  • フィボナッチの例: ルールの顕著性を使用した再帰や競合解決を例示します。
  • 銀行の例: パターン一致、基本的なソート、計算を例示します。
  • ペットショップの例: ルールアジェンダグループ、グローバル変数、コールバック、GUI 統合を例示します。
  • 数独の例: 複雑なパターン一致、問題解決、コールバック、GUI 統合を例示します。
  • House of Doom の例: 後向き連鎖と再帰を例示します。
注記

Red Hat Business Optimizer で提供される最適化の例は、『Red Hat Business Optimizer のスタートガイド』を参照してください。

21.1. IDE での Red Hat Process Automation Manager のデシジョン例のインポートおよび実行

Red Hat Process Automation Manager のデシジョン例を統合開発環境 (IDE) にインポートして実行し、ルールとコードがどのように機能するかをチェックできます。これらの例は、デシジョンエンジン機能をさらに理解するために使用する目的か、Red Hat Process Automation Manager プロジェクトに定義するデシジョンの参考として使用してください。

前提条件

  • Java 8 以降がインストールされている。
  • Maven 3.5.x 以降がインストールされている。
  • Red Hat CodeReady Studio などの IDE がインストールされている。

手順

  1. Red Hat カスタマーポータル から Red Hat Process Automation Manager 7.10.0 Source Distribution をダウンロードし、/rhpam-7.10.0-sources などの一時的なディレクトリーに展開します。
  2. IDE を開き、FileImportMavenExisting Maven Projects を選択するか、同等のオプションを選択して、Maven プロジェクトをインポートします。
  3. Browse をクリックして、~/rhpam-7.10.0-sources/src/drools-$VERSION/drools-examples (または、Conway の Game of Life の例の場合は、~/rhpam-7.10.0-sources/src/droolsjbpm-integration-$VERSION/droolsjbpm-integration-examples) に移動して、プロジェクトをインポートします。
  4. 実行するパッケージ例に移動して、main メソッドが含まれる Java クラスを検索します。
  5. Java クラスを右クリックし、Run AsJava Application を選択して例を実行します。

    基本的なユーザーインターフェースですべての例を実行するには、Main クラス org.drools.examplesDroolsExamplesApp.java クラス (または Conway の Game of Life の場合は DroolsJbpmIntegrationExamplesApp.java クラス) を実行します。

    図21.1 drools-examples (DroolsExamplesApp.java) 内のすべての例のインターフェース

    drools examples run all

    図21.2 droolsjbpm-integration-examples (DroolsJbpmIntegrationExamplesApp.java) のすべての例のインターフェース

    droolsjbpm examples run all

21.2. Hello World の例のデシジョン (基本ルールおよびデバッグ)

Hello World のデシジョンセットの例では、オブジェクトをデシジョンエンジンのワーキングメモリーに挿入する方法、ルールを使用してオブジェクトを一致させる方法、エンジンの内部アクティビティーを追跡するロギングの設定方法を説明します。

以下は、Hello World の例の概要です。

  • 名前: helloworld
  • Main クラス: (src/main/java 内の) org.drools.examples.helloworld.HelloWorldExample
  • モジュール: drools-examples
  • タイプ: Java アプリケーション
  • ルールファイル: (src/main/resources 内の) org.drools.examples.helloworld.HelloWorld.drl
  • 目的: 基本的なルール実行とデバッグ出力の使用方法を例示します。

Hello World の例では、KIE セッションが生成されて、ルールの実行が可能になります。すべてのルールは、実行するのに KIE セッションが必要です。

ルール実行の KIE セッション

KieServices ks = KieServices.Factory.get(); 1
KieContainer kc = ks.getKieClasspathContainer(); 2
KieSession ksession = kc.newKieSession("HelloWorldKS"); 3

1
KieServices ファクトリーを取得します。これは、アプリケーションがデシジョンエンジンとの対話に使用する主なインターフェースです。
2
プロジェクトクラスパスから KieContainer を作成します。これは、KieModuleKieContainer を設定してインスタンス化し