Red Hat Training

A Red Hat training course is available for Red Hat Decision Manager

第1章 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』を参照してください。

1.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 Decision Manager には、適合レベル 3 の DMN 1.2 モデルに対するデザインとランタイムの両方のサポートがあります。Decision Central で直接 DMN モデルを設計したり、既存の DMN モデルをご自分の Red Hat Decision Manager プロジェクトにインポートしたりしてデプロイし、実行することもできます。

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

意思決定要件ダイアグラム (DRD) は、DMN モデルの図解で、このダイアグラムには、DRD 全体における特定のドメインを表現する意思決定要件グラフ (DRG) 1 つまたは複数が含まれています。DRG はデシジョンノード、ビジネスナレッジオデル、ビジネナレッジのソース、入力データ、デシジョンサービスを使用してビジネスデシジョンを追跡します。

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

表1.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 要素間で使用可能なコネクターについてまとめています。

表1.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 コンポーネントの実際の使用例です。

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

dmn example drd

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

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

dmn example drd3

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

1.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』を参照してください。

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

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

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

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

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

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

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

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

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

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

1.3.2. FEEL のデータ型

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

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

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

以下は、各データ型の説明です。

数値

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

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

Red Hat Decision 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 は 1 日の時間 (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 リテラル (または無名関数) があります。FEEL では、DMN 仕様で変数を function として宣言する明示的な方法が提供されていませんが、Red Hat Decision Manager では、関数をサポートするように DMN 型が拡張されています。

例:

function(a, b) a + b

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

コンテキスト

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

例:

{ x : 5, y : 3 }

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

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

Red Hat Decision 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 Decision 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 Decision Manager では、範囲をサポートするように DMN 型が拡張されています。

例:

[ 2, 3, 4, 5 ]

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

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

x[2]

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

x[-2]

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

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

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

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

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

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

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

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

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

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

dmn decision table example

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

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

dmn decision table example2

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

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

dmn decision table example3

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

重要

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

1.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#): 一致するルールの数を出力します。

1.4.2. ボックスリテラル式

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

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

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

dmn literal expression example2

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

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

dmn literal expression example3b

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

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

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

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

dmn context expression example

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

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

dmn context expression example2

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

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

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

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

dmn relation expression example

1.4.5. ボックス関数式

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

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

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

dmn function expression example

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

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

dmn function expression example2

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

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

dmn function expression example3

1.4.6. ボックス呼び出し式

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

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

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

dmn invocation example

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

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

dmn invocation example2

1.5. DMN モデルの例

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

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

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

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

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

dmn passenger rebooking drd

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

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

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

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

dmn context expression example

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

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

dmn reassign passenger

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

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