89.3. 状態の例のデシジョン (前向き連鎖および競合解決)

状態の例のディジョンセットでは、デシジョンエンジンが前向き連鎖と、ワーキングメモリー内のファクトへの変更をどのように使用してルールの実行競合を順番に解決していくのかを例示します。この例では、ルールで定義可能な顕著性の値またはアジェンダグループを使用して競合を解決することにフォーカスします。

以下は、状態の例の概要です。

  • 名前: state
  • Main クラス: (src/main/java 内の) org.drools.examples.state.StateExampleUsingSalienceorg.drools.examples.state.StateExampleUsingAgendaGroup
  • モジュール: drools-examples
  • タイプ: Java アプリケーション
  • ルールファイル: (src/main/resources 内の) org.drools.examples.state.*.drl
  • 目的: ルールの顕著性やアジェンダグループを使用した前向き連鎖や競合解決を例示します。

前向き連鎖のルールシステムは、ディジョンエンジンのワーキングメモリーにあるファクトで開始して、そのファクトへの変更に反応するデータ駆動型のシステムです。オブジェクトがワーキングメモリーに挿入されると、その変更の結果として True となるルールの条件はすべて、アジェンダによって実行されるようにスケジュールされます。

反対に、後向き連鎖のルールシステムは、しばしば再帰を使用して、デシジョンエンジンが満たそうとする結論から開始する目的駆動型のシステムです。システムが結論または目的に到達できない場合は、サブとなる目的、つまり、現在の目的の一部を完了する結論を検索します。システムは、最初の結論が満たされるか、すべてのサブとなる目的が満たされるまでこのプロセスを続行します。

Red Hat Process Automation Manager のデシジョンエンジンは、前向き連鎖と後向き連鎖の両方を使用してルールを評価します。

以下の図は、デシジョンエンジンが、ロジックフローで後向き連鎖のセグメントと、前向き連鎖全体を使用してルールを評価する方法を例示します。

図89.4 前向き連鎖と後向き連鎖を使用したルール評価のロジック

RuleEvaluation Enterprise

状態の例では、State クラスごとに、名前や現在の状態のフィールドが含まれます (org.drools.examples.state.State のクラス参照)。以下の状態は、各プロジェクトで考えられる 2 つの状態です。

  • NOTRUN
  • FINISHED

State クラス

public class State {
    public static final int NOTRUN   = 0;
    public static final int FINISHED = 1;

    private final PropertyChangeSupport changes =
        new PropertyChangeSupport( this );

    private String name;
    private int    state;

    ... setters and getters go here...
}

状態の例には、同じ例が 2 つのバージョンとして提供されており、それぞれルール実行の競合を解決します。

  • ルールの顕著性を使用して競合を解決する StateExampleUsingSalience バージョン
  • ルールアジェンダグループを使用して競合を解決する StateExampleUsingAgendaGroups バージョン

状態の例のバージョンはいずれも、ABC、および D の 4 つの State オブジェクトを使用します。最初に、それぞれの状態は、NOTRUN に設定されます。NOTRUN は、例が使用するコンストラクターのデフォルト値です。

顕著性を使用した状態の例

状態の例の StateExampleUsingSalience バージョンでは、ルールで顕著性の値を使用し、ルール実行の競合を解決します。顕著性の値が高いルールは、アクティベーションキューの順番で、優先度が高くなります。

この例では、各 State インスタンスを KIE セッションに挿入して、fireAllRules() を呼び出します。

顕著性の状態例の実行

final State a = new State( "A" );
final State b = new State( "B" );
final State c = new State( "C" );
final State d = new State( "D" );

ksession.insert( a );
ksession.insert( b );
ksession.insert( c );
ksession.insert( d );

ksession.fireAllRules();

// Dispose KIE session if stateful (not required if stateless).
ksession.dispose();

この例を実行するには、IDE で Java アプリケーションとして org.drools.examples.state.StateExampleUsingSalience クラスを実行します。

実行後に、以下の出力が IDE コンソールウィンドウに表示されます。

IDE コンソールでの顕著性の状態例の出力

A finished
B finished
C finished
D finished

4 つのルールが存在します。

まず、"Bootstrap" ルールが実行され、A の状態が FINISHED に設定されます。次に、B の状態が FINISHED に変更されます。オブジェクト CD はいずれも B に依存するため競合が発生しますが、顕著性の値で解決されます。

この例の実行フローをさらに理解するには、target/state.log の監査ログファイルを IDE デバッグビュー (または Audit View が利用できる場合は Audit View (例: IDE の WindowShow View)) に読み込みます。

この例では、Audit View は、状態が NOTRUN のオブジェクト A のアサーションが "Bootstrap" ルールをアクティベートしますが、他のオブジェクトのアサーションはすぐに有効になりません。

図89.5 顕著性の状態例の監査ビュー

state example audit1

顕著性の状態例の "Bootstrap" ルール

rule "Bootstrap"
  when
    a : State(name == "A", state == State.NOTRUN )
  then
    System.out.println(a.getName() + " finished" );
    a.setState( State.FINISHED );
end

"Bootstrap" ルールを実行すると、A の状態が FINISHED に変わり、ルール "A to B" をアクティベートします。

顕著性の状態例の "A to B" ルール

rule "A to B"
  when
    State(name == "A", state == State.FINISHED )
    b : State(name == "B", state == State.NOTRUN )
  then
    System.out.println(b.getName() + " finished" );
    b.setState( State.FINISHED );
end

"A to B" ルールを実行すると、B の状態を FINISHED に変更し、"B to C""B to D" の両方のルールをアクティベートして、これらのアクティベーションをデシジョンエンジンアジェンダに配置します。

顕著性の状態例の "B to C" および "B to D" ルール

rule "B to C"
    salience 10
  when
    State(name == "B", state == State.FINISHED )
    c : State(name == "C", state == State.NOTRUN )
  then
    System.out.println(c.getName() + " finished" );
    c.setState( State.FINISHED );
end

rule "B to D"
  when
    State(name == "B", state == State.FINISHED )
    d : State(name == "D", state == State.NOTRUN )
  then
    System.out.println(d.getName() + " finished" );
    d.setState( State.FINISHED );
end

この時点から、両方のルールが実行される可能性があるため、これらのルールは競合しています。競合解決ストラテジーを使用すると、デシジョンエンジンアジェンダがどのルールを実行するかを決定できます。"B to C" は、顕著性の値が高いため (デフォルトの顕著性の値 0 に対して 10) 先に実行し、オブジェクト C の状態が FINISHED に変更されます。

IDE の Audit View では、ルール "A to B"State オブジェクトが変更され、2 つのアクティベーションが競合する結果になることが分かります。

IDE で Agenda View を使用して、デシジョンエンジンアジェンダの状態を調査できます。この例では Agenda View で、ルール "A to B" のブレークポイントと、2 つの競合するルールを持つアジェンダの状態が分かります。最後にルール "B to D" が実行され、オブジェクト D の状態が FINISHED に変更されます。

図89.6 顕著性の状態例のアジェンダビュー

state example agenda1

アジェンダグループを使用した状態の例

状態の例の StateExampleUsingAgendaGroups バージョンでは、ルールでアジェンダグループを使用し、ルール実行における競合を解決します。アジェンダグループを使用すると、デシジョンエンジンアジェンダが分割され、ルールのグループの実行に対してこれまで以上に制御ができるようになります。デフォルトでは、ルールはすべてアジェンダグループ MAIN に含まれています。agenda-group 属性を使用して、ルールに異なるアジェンダグループを指定できます。

最初は、ワーキングメモリーは、アジェンダグループ MAIN にフォーカスを当てます。アジェンダグループのルールは、グループがこのフォーカスを受けた場合のみ実行されます。setFocus() メソッドか、auto-focus ルール属性を使用してフォーカスを設定できます。auto-focus 属性を使用すると、ルールが一致してアクティベートされた場合のみ、ルールにアジェンダグループのフォーカスが自動的に当てられます。

この例では、auto-focus 属性を使用すると "B to D" の前に "B to C" ルールを実行できます。

アジェンダグループの状態例のルール "B to C"

rule "B to C"
    agenda-group "B to C"
    auto-focus true
  when
    State(name == "B", state == State.FINISHED )
    c : State(name == "C", state == State.NOTRUN )
  then
    System.out.println(c.getName() + " finished" );
    c.setState( State.FINISHED );
    kcontext.getKnowledgeRuntime().getAgenda().getAgendaGroup( "B to D" ).setFocus();
end

ルール "B to C" は、アジェンダグループ "B to D"setFocus() を呼び出し、アクティブなルールを実行できるようにします。その後にルール "B to D" が実行できるようになります。

アジェンダグループの状態例のルール "B to D"

rule "B to D"
    agenda-group "B to D"
  when
    State(name == "B", state == State.FINISHED )
    d : State(name == "D", state == State.NOTRUN )
  then
    System.out.println(d.getName() + " finished" );
    d.setState( State.FINISHED );
end

この例を実行するには、IDE で Java アプリケーションとして org.drools.examples.state.StateExampleUsingAgendaGroups クラスを実行します。

実行後に、以下の出力が IDE コンソールウィンドウに表示されます (状態の例の顕著性バージョンと同じ)。

IDE コンソールでのアジェンダグループの状態例の出力

A finished
B finished
C finished
D finished

状態の例の含まれる動的なファクト

状態の例に含まれる主なコンセプトとしては、他にも PropertyChangeListener オブジェクトを実装するオブジェクトに基づいて 動的ファクト を使用するというものがあります。デシジョンエンジンがファクトプロパティーへの変更を確認し、対応するためには、アプリケーションがデシジョンエンジンに対して、変更があったことを通知する必要があります。modify ステートメントを使用して、このコミュニケーションをルールで明示的に設定するか、JavaBeans 仕様で定義されているようにファクトが PropertyChangeSupport インターフェイスを実装するように指定することで暗黙的に設定できます。

この例は、ルールで modify ステートメントを明示的に指定しなくても良いように PropertyChangeSupport インターフェイスを使用する方法が示されています。このインターフェイスを使用するには、org.drools.example.State クラスと同じ方法で、ファクトに PropertyChangeSupport が実装されていることを確認し、DRL ルールファイルで以下のコードを使用して、これらのファクトでプロパティー変更がないかをリッスンするようにデシジョンエンジンを設定してください。

動的ファクトの宣言

declare type State
  @propertyChangeSupport
end

PropertyChangeListener オブジェクトを使用する場合に、各セッターは通知用に追加のコードを実装する必要があります。たとえば、state の以下のセッターは org.drools.examples のクラスに含まれます。

PropertyChangeSupport のセッター例

public void setState(final int newState) {
    int oldState = this.state;
    this.state = newState;
    this.changes.firePropertyChange( "state",
                                     oldState,
                                     newState );
}