第5章 スプレッドシートのデシジョンテーブルの使用

本章を読んで、デシジョンテーブル の使用方法について学びましょう。
デシジョンテーブルは 条件論理 を表現する手段で、ビジネス レベルのルールを表現するタスクに適しています。
JBoss Rules は、 CSV.XLS などのスプレッドシート形式でルールを保存し、ルールを管理できるようにします。
JBoss Rules はデシジョンテーブルを使用して、スプレッドシートに入力されたデータから生じるルールを生成します。データキャプチャやデータ操作など、スプレッドシートの通常機能をすべて利用して、このようなデータセットを構築できます。

5.1. デシジョンテーブルを使用する場合

テンプレートやデータとして表現できるルールが存在する場合、デシジョンテーブルの使用を考慮してください。デシジョンテーブルの各行でデータが収集され、収集されたデータとテンプレートを組み合わせてルールが生成されます。
該当のルールセットがテンプレートに従わない場合や、ルールの数が少ない場合はデシジョンテーブルを使用しないでください。また、これは個人的な好みの問題でもあります。スプレッドシートアプリケーションを使用したいユーザーもいれば、使用したくないユーザーもいます。
また、デシジョンテーブルはユーザー基盤のオブジェクトモデルを隔離できますが、これが望ましい場合と望ましくない場合があります。

5.2. 概要

デシジョンテーブルの一例は次の通りです。
Excel を使用してデシジョンテーブルを編集

図5.1 Excel を使用してデシジョンテーブルを編集

ルール行の複数のアクション

図5.2 ルール行の複数のアクション

OpenOffice.org Calc の使用

図5.3 OpenOffice.org Calc の使用

注記

上記の例では、デシジョンテーブルの技術的な部分は隠されています (標準的なスプレッドシートの機能)。
ルールは 17 行から始まります (各行は 1 つのルールになります)。条件は C、D、E 列などにあります (アクションは画面外になります)。セルにある値は比較的単純で、16 行のヘッダーを確認すると意味が分かります (B 列は説明です)。

注記

色を使用してテーブルの異なる領域の意味を示すと便利な場合があります。

重要

デシジョンテーブルは上から下へデータを処理するように見えますが、必ずしもそうであるとは限りません。順番が関係ないようにルールを記述することが推奨されます (これにより維持が簡単になり、行を頻繁に移動する必要がなくなるため)。
各行は 1 つのルールを表し、同じ原則が適用されます。ルールエンジンがファクトを処理すると、一致するルールが実行されます。これに戸惑うユーザーもいます。ルールが実行された時に agenda を消去し、最初の一致が存在する場所に大変単純なデシジョンテーブルをシミュレートすることが可能です。デシジョンテーブルは基本的に DRL パッケージを自動的に生成するツールです。

注記

1 つのスプレッドシートに複数のテーブルを使用することも可能です。共通のテンプレートを共有する場合にルールをグループ化でき、最終的にすべてが 1 つのルールパッケージにまとめられるため便利です。
複数のテーブルを使用して同様のルールをグループ化する実例

図5.4 複数のテーブルを使用して同様のルールをグループ化する実例

5.3. デシジョンテーブルの仕組み

重要

デシジョンテーブルでは各行が 1 つのルールであり、その行の各列はそのルールの条件またはアクションになることに留意することが重要となります。
行と列

図5.5 行と列

スプレッドシートは、ルールテーブルの開始行と開始列を示す RuleTable キーワードを探します。(他のパッケージレベル属性を定義するために使用される他のキーワードは本章で後ほど説明します)。キーワードを 1 つの列に収めることが重要になります。慣習的に、これには 2 つ目の列 ("B") が使用されますが、どの列でも使用できます (慣習としては左側に注意書き用の余白を残します)。下図では、C が実際の開始列になります。この列の左側はすべて無視されます。

注記

分かりやすい場合は隠れたセクションを展開します。
C 列にキーワードがあることに注意してください。
ルールテンプレートの展開

図5.6 ルールテンプレートの展開

RuleSet キーワードは、ルールがすべてグループ化される rule package で使用される名前を示します (名前は任意です。デフォルト値もありますが、RuleSet キーワードが存在する必要があります)。C 列に表示される他のキーワードは ImportSequential です。これらについては本章で後ほど説明します。この段階では、通常、キーワードが名前と値のペアを作成します。
従うルールのグループを示し、これらのルールが一部のルールテンプレートのベースとなるため、 RuleTable は重要になります。
RuleTable キーワードの後には名前があります。この名前は生成されたルール名の先頭に追加するために使用されます (一意のルール名を作成するために行番号が付加されます)。RuleTable の列はルールが開始する列を示します (左側の列は無視されます)。
14 行の CONDITION および ACTION キーワードは、下の列にあるデータがルールの LHS または RHS 部分であることを示しています (このように任意に設定できる他の属性もあります)。
15 行には ObjectTypes の宣言が含まれます。この行の内容は任意で、内容を使用したくない場合は行を空白のままにします。この行が使用されると、下のセル (16 行) の値がそのオブジェクトタイプの制約になります。上記の例では、Person(age=="42") (42 は 18 行から取得) が生成されます。この場合、== は暗黙的で、フィールド名のみを指定すると完全一致の検索と見なされます。

注記

ObjectType の宣言は複数の列にまたがることができます (マージされたセルにより)。そのため、マージされた範囲の下にあるすべての列が 1 つの制約セットにまとめられます。
16 行には、ルールテンプレート自体が含まれます。$para プレースホルダーを使用して、セルからのデータが投入される場所を示します。$param または $1$2 などを使用して下のセルにあるコンマ区切りリストからのパラメーターを示します。
17 行はルールテンプレートの説明テキストであるため、無視されます。
18 行から 19 行は、実際のルールを生成するために 15 行のテンプレートと組み合わされる (補間される) データを示します。セルにデータがない場合は、テンプレートが無視されます。ルール行は空白行の前まで読み取られます。1 つのシートに複数の RuleTables を使用できます。
20 行には別のキーワードと値が含まれます。このようなキーワードの行位置は重要ではありませんが、上部に配置することが推奨されます。しかし、列は RuleTable または RuleSet キーワードが表示される場所と同じである必要があります (この例では、C 列を選択しましたが、代わりに A 列を選択することも可能です)。
上記の例では、 ルールは以下のようにレンダリングされます (ObjectType 行が使用されるため)。
//row 18
rule "Cheese_fans_18"
  when
    Person(age=="42")
    Cheese(type=="stilton")
  then
    list.add("Old man stilton");
end
[age=="42"][type=="stilton"]は上のセルにある対象の ObjectType に追加される単一の制約として解釈されます (上のセルが複数にまたがる場合は、1 つの「列」に対して複数の制約が存在することがあります)。

5.4. キーワードと構文

5.4.1. テンプレートの構文

テンプレートで使用する構文は、列が CONDITION または ACTION であるかによって異なります。ほとんどの場合、LHS (CONDITIONの場合) または RHS (ACTION の場合) の 「vanilla」DRL と同じです。そのため、LHS では制約言語を使用する必要があり、RHS は実行目的のコードのスニペットになります。
セルのデータが補間される場所を示すため、テンプレートで $param プレースホルダーが使用されます。$1 を使用することも可能です。セルに値のコンマ区切りリストが含まれる場合、$1 や $2 などのシンボルを使用して、セルの値リストよりどの位置パラメーターを使用するか示すことができます。forall(DELIMITER){SNIPPET} 関数を使用して、使用できるコンマ区切りの値をすべてループすることが可能です。
例は次の通りです。
テンプレートが [Foo(bar == $param)] で、セルが [ 42 ] である場合、結果は [Foo(bar == 42)] になります。
 テンプレートが [Foo(bar < $1, baz == $2)] で、セルが [42,43] である場合、結果は [Foo(bar > 42, baz ==43)] になります。
条件の場合、スニペットのレンダリングは上の行に ObjectType 宣言が存在するかどうかによって異なります。存在する場合、スニペットは ObjectType の個別の制約としてレンダリングされます。存在しない場合、そのままレンダリングされます (値は置換されます)。上記の例のようにプレーンフィールドのみが入力された場合、相等であると見なされます。スニペットの最後に別の演算子がある場合、制約の最後で値が補間されます。スニペットの最後に別の演算子がない場合は、前述の通り $param を探します。
結果の場合、スニペットのレンダリングはすぐ上の行に存在するものがあるかどうかによって異なります。エントリーがない場合、補間されたスニペットが出力されます。バインドされた変数やグローバルなど (上記の例のように) がある場合、オブジェクトのメソッド呼び出しとして追加されます。
例は次の通りです。
またがった列

図5.7 またがった列

上記の例は、Person ObjectType 宣言がどのように 2 つのスプレッドシート列にまたがっているかを表しています。そのため、両方の制約は Person(age == ... , type == ...) として表示されます。これまでと同様に、フィールド名のみがスニペットに存在するため、等価テストを意味します。
パラメーターの使用

図5.8 パラメーターの使用

この例では、値をスニペットに指定するために補間が使用されています (結果は Person(age == "42") になります)。
演算子の補完

図5.9 演算子の補完

上記の条件の例は、演算子が最後に配置されると、演算子の後に値が自動的に配置されることを表しています。
バインディングの使用

図5.10 バインディングの使用

列の前にバインディングを指定できます (下のセルから制約が追加されます)。ObjectType 行にはどのような値でも入力することができます (たとえば、後続するスプレッドシートの列に対する事前条件など)。
結果

図5.11 結果

最後の例は、結果がどのように単純な補間によって行われるかを表しています (上のセルを空白のままにします。条件の列も同様です)。 このようにして、 結果には 1 つのメソッド呼び出しだけでなく、どのような値でも入力することができます。

5.4.2. キーワード

以下の表は、ルールテーブル構造に必要なキーワードについて説明しています。

表5.1 キーワード

キーワード 説明 含まれる状態
RuleSet この右側のセルにはルールセット名が含まれます。 1 つのみ (指定しない場合はデフォルト値が使用されます)
Sequential この右側のセルは true または false になります。true の場合は salience が使用され、ルールが上から順に実行されるようにします。 任意
Import 右側のセルには、インポートする Java クラスのコンマ区切りリストが含まれます。 任意
RuleTable RuleTable はルールテーブルの定義の始まりを示します (実際のルールテーブルは次の行で開始します)。ルールテーブルは次の空白行まで、左から右、そして上から下の順に読み取られます。 最低 1 つ。複数ある場合は、1 つのルールセットにすべてが追加されます。
CONDITION この列がルール条件用であることを示します。 ルールテーブルごとに最低 1 つ。
ACTION この列がルール結果用であることを示します。 ルールテーブルごとに最低 1 つ。
PRIORITY この列の値がルール行に対して salience 値を設定することを示します。Sequential フラグを上書きします。 任意
DURATION この列の値がルール行に対して期間の値を設定することを示します。 任意
NAME この列の値がその行から生成されたルールに対して名前を設定することを示します。 任意
Functions すぐ右側のセルには、ルールスニペットで使用できる関数を指定できます。JBoss Rules は DRL で定義された関数をサポートし、ハードコーディングせずに論理をルールに組み込んだり、論理を変更したりすることができます。使用する際は注意して使用してください。構文は通常の DRL と同じです。 任意
Variables すぐ右側のセルには JBoss Rules がサポートするグローバル宣言を指定できます。タイプの後に変数名を指定したものです。複数の変数が必要な場合はコンマで区切ります。 任意
No-loop または Unloop no-loop または unloop は、テーブルのヘッダーに指定され、ルール (行) のループを許可しない同じ関数を補完します。このオプションが適切に機能するには、セルに値 (true または false) が存在しなければなりません。セルが空白のままであると、このオプションは行に対して設定されません。 任意
XOR-GROUP この列のセル値は、ルール行が指定のアクティベーショングループに属することを意味します。アクティベーショングループとは、名前付きグループの 1 つのルールのみが実行されることを意味します (最初に実行されるルールが他のルールのアクティベーションをキャンセルします)。 任意
AGENDA-GROUP この列のセル値は、ルール行が指定のアジェンダグループに属することを意味します (ルールのグループ間のフローを制御する方法の 1 つです。「ルールフロー」を参照してください)。 任意
RULEFLOW-GROUP この列のセル値は、ルール行が指定のルールフローグループに属することを意味します。 任意
Worksheet デフォルトでは、デシジョンテーブルで最初のワークシートだけが参照されます。 該当なし
各行に対して生成されたルールに影響する HEADER キーワードのユースケースは次の通りです。ほとんどの場合でヘッダー名が最も重要になります。下のセルに値がないと、特定の行に属性が適用されません。
キーワードの使用例

図5.12 キーワードの使用例

以下は、Import (コンマ区切り)、Variables (グローバル、コンマ区切り)、および function block (複数の関数で構成されることもあり、普通の DRL 構文を使用) の例になります。RuleSet キーワードと同じ列に指定したり、すべてのルール行の下に指定することもできます。
関数などのキーワードの使用例

図5.13 関数などのキーワードの使用例

5.5. スプレッドシートベースのデシジョンテーブルの作成と統合

drools-decisiontables モジュールのスプレッドシートベースのデシジョンテーブルと共に使用されるアプリケーションプログラミングインターフェースを探します。1 つのクラスのみが関連しますが、そのクラスが SpreadsheetCompiler です。このクラスはさまざまな形式のスプレッドシートを取得し、通常通りに使用できる DRL ルールを生成します。
また、SpreadsheetCompiler を使用して部分的なルールファイルを生成し、後で完全なルールパッケージへアセンブルすることができます (これを使用してルールの技術的な側面と非技術的な側面を区別します)。
サンプルのスプレッドシートをベースとします。または、Rule Workbench IDE プラグインを使用する場合はインビルドの Wizard を使用してテンプレートよりスプレッドシートを生成し、XLS 対応のスプレッドシートアプリケーションを用いて編集します。
統合開発環境の使用

図5.14 統合開発環境の使用

5.6. デシジョンテーブルにおけるビジネスルールの管理

5.6.1. ワークフローとコラボレーション

デシジョンテーブルは、IT の専門家とドメインの専門家が密接に協力する必要がある場合に適しています。デシジョンテーブルを使用すると、ビジネスルールがアナリストにとって明確になります。
ビジネスルールを作成するには、次の手順に従います。
  1. ビジネスアナリストがテンプレートのデシジョンテーブルを取得します (リポジトリまたは IT 部門から)。
  2. ビジネスアナリストがデシジョンテーブルのビジネス言語の説明をテンプレートに入力します。
  3. デシジョンテーブルルール (行) が入力されます (下書きとして)。
  4. デシジョンテーブルが、ビジネス言語 (説明) をスクリプトへマッピングするプログラマーへ渡されます (新しいアプリケーションやデータモデルの場合、ソフトウェアの開発が関係することがあります)。
  5. プログラマーがビジネスアナリストと共に変更を確認します。
  6. ビジネスアナリストは必要に応じてルール行の編集を継続して行えます (列の移動など)。
  7. プログラマーは、システム稼働後にルールの変更を検証するために使用するルールのテストケースを開発します。

5.6.2. スプレッドシート機能の使用

LibreOffice Calc の機能を使用すると、スプレッドシートへのデータの入力を容易にすることができます。また、他のワークシートに保存されたリストを使用して、セルの値の有効なリストを提供することができます。
スプレッドシートリストの使用

図5.15 スプレッドシートリストの使用

重要

Red Hat はバージョン制御システムを使用して変更履歴を維持することを推奨します。