9.3. 状態の例のデシジョン (前向き連鎖および競合解決)
状態の例のディジョンセットでは、デシジョンエンジンが前向き連鎖と、ワーキングメモリー内のファクトへの変更をどのように使用してルールの実行競合を順番に解決していくのかを例示します。この例では、ルールで定義可能な顕著性の値またはアジェンダグループを使用して競合を解決することにフォーカスします。
以下は、状態の例の概要です。
-
名前:
state
-
Main クラス: (
src/main/java
内の)org.drools.examples.state.StateExampleUsingSalience
、org.drools.examples.state.StateExampleUsingAgendaGroup
-
モジュール:
drools-examples
- タイプ: Java アプリケーション
-
ルールファイル: (
src/main/resources
内の)org.drools.examples.state.*.drl
- 目的: ルールの顕著性やアジェンダグループを使用した前向き連鎖や競合解決を例示します。
前向き連鎖のルールシステムは、ディジョンエンジンのワーキングメモリーにあるファクトで開始して、そのファクトへの変更に反応するデータ駆動型のシステムです。オブジェクトがワーキングメモリーに挿入されると、その変更の結果として True となるルールの条件はすべて、アジェンダによって実行されるようにスケジュールされます。
反対に、後向き連鎖のルールシステムは、しばしば再帰を使用して、デシジョンエンジンが満たそうとする結論から開始する目的駆動型のシステムです。システムが結論または目的に到達できない場合は、サブとなる目的、つまり、現在の目的の一部を完了する結論を検索します。システムは、最初の結論が満たされるか、すべてのサブとなる目的が満たされるまでこのプロセスを続行します。
Red Hat Decision Manager のデシジョンエンジンは、前向き連鎖と後向き連鎖の両方を使用してルールを評価します。
以下の図は、デシジョンエンジンが、ロジックフローで後向き連鎖のセグメントと、前向き連鎖全体を使用してルールを評価する方法を例示します。
図9.4 前向き連鎖と後向き連鎖を使用したルール評価のロジック
状態の例では、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
バージョン
状態の例のバージョンはいずれも、A
、B
、C
、および 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
に変更されます。オブジェクト C
と D
はいずれも B
に依存するため競合が発生しますが、顕著性の値で解決されます。
この例の実行フローをさらに理解するには、target/state.log
の監査ログファイルを IDE デバッグビュー (または Audit View が利用できる場合は Audit View (例: IDE の Window
この例では、Audit View は、状態が NOTRUN
のオブジェクト A
のアサーションが "Bootstrap"
ルールをアクティベートしますが、他のオブジェクトのアサーションはすぐに有効になりません。
図9.5 顕著性の状態例の監査ビュー
顕著性の状態例の "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
に変更されます。
図9.6 顕著性の状態例のアジェンダビュー
アジェンダグループを使用した状態の例
状態の例の 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 ); }