Red Hat Training
A Red Hat training course is available for JBoss Enterprise SOA Platform
JBoss Rules 5 リファンレンスガイド
このガイドは開発者向けです。
概要
はじめに
1. ドキュメント規則
1.1. 表記規則
等幅ボールド
現在の作業ディレクトリーのファイルmy_next_bestselling_novel
の内容を表示するには、シェルプロンプトで cat my_next_bestselling_novel コマンドを入力し、Enter を押してコマンドを実行します。
Enter を押してコマンドを実行します。Ctrl+Alt+F2 を押して、仮想ターミナルに切り替えます。
等幅ボールド
で示されます。以下に例を示します。
ファイル関連のクラスには、ファイルシステムのfilesystem
、ファイルのfile
、ディレクトリーのdir
が含まれます。各クラスには、独自の関連付けられたパーミッションセットがあります。
メインメニューバーから System → Preferences → Mouse を選択し、Mouse Preferences を起動します。Buttons タブで、Left-handed mouse チェックボックスを選択し、Close をクリックしてメインのマウスボタンを左から右に切り替えます (マウスを左手で使い易くします)。特殊文字を gedit ファイルに挿入するには、メインメニューバーから Applications → Accessories → Character Map を選択します。次に、Character Map メニューバーから Search → Find… を選択し、Search フィールドに文字の名前を入力して Next をクリックします。目的の文字が Character Table で強調表示されます。この強調表示した文字をダブルクリックして Text to copy フィールドに配置し、Copy ボタンをクリックします。ここでドキュメントに戻り、gedit メニューバーから Edit → Paste を選択します。
ssh を使用してリモートマシンに接続するには、シェルプロンプトで ssh username@domain.name を入力します。リモートマシンがexample.com
で、そのマシン上でのユーザー名が john の場合は、ssh john@example.com と入力します。mount -o remount file-system コマンドにより、指定したファイルシステムが再マウントされます。たとえば、/home
ファイルシステムを再マウントする場合、コマンドは mount -o remount /home となります。現在インストールされているパッケージのバージョンを表示するには、rpm -q package コマンドを使用します。これにより、package-version-release のような結果が返されます。
Publican は DocBook 公開システムです。
1.2. 引用規則
mono-spaced roman
に設定され、以下のように表示されます。
books Desktop documentation drafts mss photos stuff svn books_tests Desktop1 downloads images notes scripts svgs
mono-spaced roman
に設定されますが、以下のように構文の強調表示が追加されます。
static int kvm_vm_ioctl_deassign_device(struct kvm *kvm, struct kvm_assigned_pci_dev *assigned_dev) { int r = 0; struct kvm_assigned_dev_kernel *match; mutex_lock(&kvm->lock); match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head, assigned_dev->assigned_dev_id); if (!match) { printk(KERN_INFO "%s: device hasn't been assigned before, " "so cannot be deassigned\n", __func__); r = -EINVAL; goto out; } kvm_deassign_device(kvm, match); kvm_free_assigned_device(kvm, match); out: mutex_unlock(&kvm->lock); return r; }
1.3. 注記および警告
2. ヘルプの利用とフィードバック提供
2.1. ヘルプが必要ですか ?
- Red Hat 製品に関する技術サポート記事の知識ベースの検索または閲覧。
- Red Hat グローバルサポートサービス (GSS) へのサポートケースの送信。
- その他の製品ドキュメントへのアクセス。
2.2. ご意見をお寄せください
第1章 はじめに
1.1. ビジネス統合
1.2. サービス指向アーキテクチャーとは
はじめに
SOA (Service Oriented Architecture) は単一のプログラムまたはテクノロジーではありません。ソフトウェア設計パラダイムと見なします。
1.3. サービス指向アーキテクチャーの重要なポイント
- 交換される メッセージ
- サービスリクエスターおよびプロバイダーとして動作する エージェント
- メッセージを送受信できるようにする 共有トランスポートメカニズム。
1.4. JBoss Enterprise SOA Platform とは
1.5. Service-Oriented Architecture Paradigm
- サービスプロバイダー
- サービスプロバイダーはサービスへのアクセスを許可し、サービスの説明を作成し、サービスブローカーに公開します。
- サービスリクエスター
- サービスリクエスターは、サービスブローカーが提供するサービスの説明を検索して、サービスを検出します。リクエスターはサービスプロバイダーが提供するサービスにバインドするロールも果たします。
- サービスブローカー
- サービスブローカーは、サービスの説明のレジストリーをホストします。リクエスターをサービスプロバイダーにリンクします。
1.6. コアおよびコンポーネント
1.7. JBoss Enterprise SOA Platform のコンポーネント
- 完全な Java EE 準拠のアプリケーションサーバー (JBoss Enterprise Application Platform)
- Enterprise Service Bus (JBoss ESB)
- ビジネスプロセス管理システム (jBPM)
- ビジネスルールエンジン (JBoss ルール)
- オプションの JBoss Enterprise Data Services (EDS) 製品のサポート。
1.8. JBoss Enterprise SOA Platform の機能
- JBoss Enterprise Service Bus (ESB)
- ドメインはサービス間でメッセージを送信し、それらを変換して、異なるタイプのシステムで処理できるようにします。
- Business Process Execution Language (BPEL)
- Web サービスを使用して、この言語を使用してビジネスルールをオーケストレーションできます。これは、ビジネスプロセス命令を簡単に実行するために SOA に含まれています。
- Java Universal Description、Discovery and Integration (jUDDI)
- これは SOA のデフォルトサービスレジストリーです。ここで説明する内容は、インストラクター上のサービスに関する情報をすべて保管する場所です。
- Smooks
- この変換エンジンは SOA と組み合わせて使用してメッセージを処理できます。また、メッセージを分割して正しい宛先に送信するためにも使用できます。
- JBoss ルール
- これは、SOA にパッケージ化されたルールエンジンです。受信するメッセージからデータを推測して、実行する必要があるアクションを判別できます。
1.9. JBoss Enterprise SOA Platform の JBossESB コンポーネントの機能
- 複数のトランスポートおよびプロトコル
- リスナーアクションモデル (これにより、サービスを相互に選択可能)
- コンテンツベースのルーティング (JBoss Rules エンジン、XPath、Regex、および Smooks 経由)
- サービスオーケストレーション機能を提供するために JBoss Business Process Manager (jBPM) との統合
- ビジネスルールの開発機能を提供するために、JBoss ルールとの統合
- BPEL エンジンとの統合。
- さまざまなトランスポートメカニズム (電子メールや JMS など) と連携するよう設定されます。
- 汎用オブジェクトリポジトリーとして使用します。
- プラグ可能なデータ変換メカニズムを実装できるようにします。
- 対話のロギングをサポートします。
org.jboss.internal.soa.esb
と org.jboss.soa.esb
の 2 つのツリーがあります。org.jboss.internal.soa.esb
パッケージの内容をそのまま使用します。これは、通知なしに変更される可能性があるためです。これとは対照的に、org.jboss.soa.esb
パッケージ内のすべての内容は、Red Hat の非推奨ポリシーでカバーされます。
1.10. タスク管理
1.11. 統合のユースケース
1.12. ビジネス環境での JBoss Enterprise SOA Platform の使用
第2章 はじめに
2.1. 対象読者
2.2. ガイドの目的
第3章 クイックスタート
3.1. JBoss Rules
3.2. JBoss Rules Engine
3.3. 実稼働ルール
when <conditions> then <actions>
3.4. 推論エンジン
3.5. ReteOO
3.6. 実稼働メモリー
実稼働メモリー
は、ルールが保存される場所です。
3.7. ワーキングメモリー
ワーキングメモリー
は、ファクトがアサートされる JBoss Rules エンジンの一部です。ここから、ファクトを変更または取り消すことができます。
3.8. 競合解決ストラテジー
3.9. ハイブリッドルールシステム
3.10. forward-Chaining
3.11. 後向き連鎖
Prolog
は、後向き連鎖エンジンの例です。
3.12. 推論機能
3.13. エキスパートシステム
3.14. Rete Root ノード
3.15. ObjectTypeNode
instanceof
チェックと一致するすべてのクラス型と照合できます。
3.16. AlphaNodes
3.17. ハッシュ
3.18. BetaNodes
3.19. アルファメモリー
3.20. ベータ版メモリー
3.21. BetaNodes でのルックアップ
3.22. LeftInputNodeAdapters
3.23. ターミナルノード
3.24. ノードの共有
3.25. ノードの共有の例
rule when vehicle( $car : name == "car" ) $driver: Driver( typeCar == $sedan ) then System.out.println( $driver.getName() + " drives sedan" ); end
rule when Vehicle( $sedan : name == "sedan" ) $driver : Driver( typeCar != $sedan ) then System.out.println( $driver.getName() + " does not drive sedan" ); end
3.26. ルーズカップリング
3.27. 強力な結合
3.28. 宣言型プログラミング
3.29. ロジックとデータの分離
3.30. ナレッジベース
KnowledgeBuilder
でコンパイルしたルールのコレクションです。これは、すべてのアプリケーションのナレッジ定義のリポジトリーです。ルール、プロセス、関数、タイプモデルを含めることができます。ナレッジベース自体には、インスタンスデータ(ファクトと呼ばれる)は含まれません。代わりに、セッションは、データを挿入できるナレッジベースから作成され、プロセスインスタンスを開始できる場所です。セッションを繰り返し作成できるように、可能な場合はナレッジベースをキャッシュすることが推奨されます。
第4章 ユーザーガイド
4.1. ステートレスナレッジセッション
4.2. ステートレスセッションでのルールの設定
手順4.1 タスク
- 以下のドライバーのライセンス例のようなデータモデルを作成します。
public class Applicant { private String name; private int age; private boolean valid; // getter and setter methods here }
- 最初のルールを書き込みます。この例では、18 を超える申請者が解消するルールが追加されます。
package com.company.license rule "Is of valid age" when $a : Applicant( age < 18 ) then $a.setValid( false ); end
Applicant
オブジェクトがルールエンジンに挿入されると、各ルールの制約がそれを評価し、一致を検索します。(その後にオブジェクトタイプの暗黙的な制約が常にあり、その後に明示的なフィールド制約はいくつでも存在できます。)Is of valid age
ルールには、以下の 2 つの制約があります。- 一致するファクトのタイプは Applicant である必要があります。
- Age の値は 8 未満である必要があります。
$a
はバインディング変数です。(オブジェクトのプロパティーを更新できるように)ルールの結果で一致したオブジェクトへの参照を可能にするためにあります。注記ドル記号($
)の使用は任意です。これは、変数名とフィールド名を区別するのに役立ちます。注記ルールがクラスと同じフォルダーにある場合、クラスパスリソースローダーを使用して最初のナレッジベースを構築できます。- KnowledgeBuilder を使用して、以下のようにルールのリストをナレッジベースにコンパイルします。
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kbuilder.add( ResourceFactory.newClassPathResource( "licenseApplication.drl", getClass() ), ResourceType.DRL ); if ( kbuilder.hasErrors() ) { System.err.println( kbuilder.getErrors().toString() ); } KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
上記のコードスニペットは、newClassPathResource()
メソッドを使用してlicenseApplication.drl
ファイルのクラスパスを検索します。(リソースタイプは DRL で、Drools Rule Language に短縮されます。) - KnowledgeBuilder でエラーの有無を確認します。セッションがない場合には、セッションをビルドできます。
- ルールに対してデータを実行します。(申請者が 8 歳未満であるため、アプリケーションは invalid とマークされます。)
StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession(); Applicant applicant = new Applicant( "Mr John Smith", 16 ); assertTrue( applicant.isValid() ); ksession.execute( applicant ); assertFalse( applicant.isValid() );
結果
上記のコードは、ルールに対してデータを実行します。申請者が 18 歳未満であるため、アプリケーションは無効としてマークされます。
4.3. 複数のオブジェクトを使用したルールの設定
手順4.2 タスク
- (コレクションなど)
反復可能な
オブジェクトにルールを実行するには、以下のコード例のように別のクラスを追加します。public class Applicant { private String name; private int age; // getter and setter methods here } public class Application { private Date dateApplied; private boolean valid; // getter and setter methods here }
- アプリケーションが正当な時間枠内で行われたことを確認するには、次のルールを追加します。
package com.company.license rule "Is of valid age" when Applicant( age < 18 ) $a : Application() then $a.setValid( false ); end rule "Application was made this year" when $a : Application( dateApplied > "01-jan-2009" ) then $a.setValid( false ); end
- JDK コンバーターを使用して、反復可能なインターフェイスを実装します。(このメソッドは
Arrays.asList (...)
の行で始まります) 以下のコードは、反復可能なリストに対してルールを実行します。すべてのコレクション要素は、一致したルールが実行される前に挿入されます。StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession(); Applicant applicant = new Applicant( "Mr John Smith", 16 ); Application application = new Application(); assertTrue( application.isValid() ); ksession.execute( Arrays.asList( new Object[] { application, applicant } ) ); assertFalse( application.isValid() );
注記execute (Object object)
およびexecute (Iterable objects)
メソッドは、実際にはBatchExecutor
インターフェイスから取得されるexecute (Command command)
という追加メソッドのラッパーです。 CommandFactory
を使用して命令を作成し、以下が(反復可能な)実行
と同じになるようにします。ksession.execute( CommandFactory.newInsertIterable( new Object[] { application, applicant } ) );
- 多くの異なるコマンドまたは結果出力識別子を使用する場合は、
BatchExecutor
とCommandFactory
を使用します。List<Command> cmds = new ArrayList<Command>(); cmds.add( CommandFactory.newInsert( new Person( "Mr John Smith" ), "mrSmith" ); cmds.add( CommandFactory.newInsert( new Person( "Mr John Doe" ), "mrDoe" ); BatchExecutionResults results = ksession.execute( CommandFactory.newBatchExecution( cmds ) ); assertEquals( new Person( "Mr John Smith" ), results.getValue( "mrSmith" ) );
注記CommandFactory
は、BatchExecutor
で使用できる他の多くのコマンドをサポートしています。これらの一部は、StartProcess
、Query
、およびSetGlobal
です。
4.4. ステートフルセッション
StatelessKnowledgeSession
と同様に、StatefulKnowledgeSession
は BatchExecutor
インターフェイスをサポートします。唯一の違いは、FireAllRules
コマンドは最後に自動的に呼び出されません。
dispose ()
メソッドが呼び出されていることを確認します。これにより、メモリーリークが発生しないようにします。これは、ナレッジベースの作成時に、ステートフルなナレッジセッションへの参照を取得するためです。
4.5. ステートフルセッションの一般的なユースケース
- モニタリング
- たとえば、株式市場を監視し、購入プロセスを自動化できます。
- 診断
- ステートフルセッションを使用して、障害検出プロセスを実行できます。また、これらの診断をマネージメントプロセスに使用することもできます。
- Logistical
- たとえば、parcel の追跡および配信プロビジョニングに関連する問題に適用できます。
- コンプライアンスの確保
- たとえば、市場取引における法的性を検証するには、以下を行います。
4.6. ステートフルセッションの監視例
手順4.3 タスク
- モニターするモデルを作成します。たとえば、火災のアラームに関するこの例では、家の部屋がリストされています。それぞれにスプリンクラーが 1 つあります。実行はどの部屋でも開始できます。
public class Room { private String name // getter and setter methods here } public class Sprinkler { private Room room; private boolean on; // getter and setter methods here } public class Fire { private Room room; // getter and setter methods here } public class Alarm { }
- ルールは、複数のオブジェクト間の関係を表す必要があります(特定の部屋にスプリンクラーの存在などを定義するため)。これを行うには、バインディング変数 をパターンの制約として使用します。これにより、製品がまたがります。
Fire
クラスのインスタンスを作成し、セッションに挿入します。以下のルールは、Fire
オブジェクトの room フィールドにバインディングを追加して、一致を制限します。これにより、その部屋のスプリンクラーのみがチェックされます。このルールが実行され、結果が実行されると、スプリンクラーが有効になります。rule "When there is a fire turn on the sprinkler" when Fire($room : room) $sprinkler : Sprinkler( room == $room, on == false ) then modify( $sprinkler ) { setOn( true ) }; System.out.println("Turn on the sprinkler for room "+$room.getName()); end
ステートレスセッションは標準の Java 構文を使用してフィールドを変更しましたが、上記のルールはmodify
ステートメントを使用します。(with ステートメントとよく似ています。)
4.7. 最初の順序ログ
4.8. 最初の順序ログを使用したルールの設定
手順4.4 タスク
Not
キーワードが含まれるパターンを設定します。最初の順序ロジックにより、他のキーワードが存在しない場合のみルールがマッチします。この例では、実行が拡張されると、ルールはスプリンクラーをオフにします。rule "When the fire is gone turn off the sprinkler" when $room : Room( ) $sprinkler : Sprinkler( room == $room, on == true ) not Fire( room == $room ) then modify( $sprinkler ) { setOn( false ) }; System.out.println("Turn off the sprinkler for room "+$room.getName()); end
Alarm
オブジェクトは、実行がある場合に作成されますが、実行回数に関係なく、ビルド全体にはAlarm
が 1 つだけ必要です。は補完されず
、が存在
するようになりました。カテゴリーの 1 つまたは複数のインスタンスと一致します。rule "Raise the alarm when we have one or more fires" when exists Fire() then insert( new Alarm() ); System.out.println( "Raise the alarm" ); end
- これ以上発生しない場合は、アラームを非アクティブにする必要があります。これを無効にするには、再度
Not
を使用します。rule "Cancel the alarm when all the fires have gone" when not Fire() $alarm : Alarm() then retract( $alarm ); System.out.println( "Cancel the alarm" ); end
- このコードを使用して、アプリケーションの初回起動時に、アラームとスプリンクラーがすべて非アクティブ化されたときにも一般的なヘルスステータスメッセージを出力します。
rule "Status output when things are ok" when not Alarm() not Sprinkler( on == true ) then System.out.println( "Everything is ok" ); end
- ルールを
fireAlarm.drl
という名前のファイルに保存します。このファイルをクラスパス上のサブディレクトリーに保存します。 - 最後に、新しい名前
fireAlarm.drl
を使用して、ナレッジベース
を構築します。KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kbuilder.add( ResourceFactory.newClassPathResource( "fireAlarm.drl", getClass() ), ResourceType.DRL ); if ( kbuilder.hasErrors() ) System.err.println( kbuilder.getErrors().toString() ); StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
4.9. ルールシステムサンプルの設定
手順4.5 タスク
- Insert
ksession.fireAllRules()
.これにより、実行するルールパーミッションが付与されますが、この例では fire がないため、正常性メッセージが生成されます。String[] names = new String[]{"kitchen","bedroom","office","livingroom"}; Map<String,Room> name2room = new HashMap<String,Room>(); for( String name: names ) { Room room = new Room( name ); name2room.put( name, room ); ksession.insert( room ); Sprinkler sprinkler = new Sprinkler( room ); ksession.insert( sprinkler ); } ksession.fireAllRules();
生成されるメッセージは以下を読み取ります。> Everything is okay
- 2 つの実行を作成して挿入します。(ファクトハンドルは保持されます。)
- エンジンで fireAllRules ()を呼び出すと、
fireAllRules ()
を呼び出します。アラームが発生し、それぞれのスプリンクラーが有効になります。Fire kitchenFire = new Fire( name2room.get( "kitchen" ) ); Fire officeFire = new Fire( name2room.get( "office" ) ); FactHandle kitchenFireHandle = ksession.insert( kitchenFire ); FactHandle officeFireHandle = ksession.insert( officeFire ); ksession.fireAllRules();
生成されるメッセージは以下を読み取ります。> Raise the alarm > Turn on the sprinkler for room kitchen > Turn on the sprinkler for room office
- 実行が拡張されると、fire オブジェクトは取り消され、スプリンクラーはオフになります。この時点で、アラームはキャンセルされ、ヘルスメッセージが複数回表示されます。
ksession.retract( kitchenFireHandle ); ksession.retract( officeFireHandle ); ksession.fireAllRules();
生成されるメッセージは以下を読み取ります。> Turn off the sprinkler for room office > Turn off the sprinkler for room kitchen > Cancel the alarm > Everything is okay
4.10. JBoss ルールのメソッド
4.11. メソッドの例
public void helloWorld(Person person) { if ( person.getName().equals( "Chuck" ) ) { System.out.println( "Hello Chuck" ); } }
4.12. ルールの例
rule "Hello World" when Person( name == "Chuck" ) then System.out.println( "Hello Chuck" ); end
4.13. クロス製品
4.14. クロス製品コンセント
手順4.6 タスク
- ルールが大量のクロス製品を出力しないようにするには、複数の製品自体を制限する必要があります。これは、以下に示す変数制約を使用して行います。
rule when $room : Room() $sprinkler : Sprinkler( room == $room ) then System.out.println( "room:" + $room.getName() + " sprinkler:" + $sprinkler.getRoom().getName() ); end
以下の出力が表示されます。room:office sprinkler:office room:kitchen sprinkler:kitchen room:livingroom sprinkler:livingroom room:bedroom sprinkler:bedroom
結果
各部屋に正しいスリンクラーを持つ 4 つの行のみが出力されます。この変数がないと、Room テーブル内のすべての行がスプリンクラーテーブルの各行に参加し、大量の出力になります。
4.15. 推論エンジン
4.16. 推論の例
rule "Infer Adult" when $p : Person( age >= 18 ) then insert( new IsAdult( $p ) ) end
$p : Person() IsAdult( person == $p )
4.17. 論理アサーション
4.18. 記述挿入
HashMap
およびカウンターを使用すると、特定の等価性が 記載される 回数を追跡できます。つまり、等しい異なるインスタンスをカウントできます。
4.19. 正当化挿入
4.20. WM_BEHAVIOR_PRESERVE 設定
WM_BEHAVIOR_PRESERVE
によって異なります。プロパティーが discard
に設定されている場合は、既存のハンドルを使用して、既存のインスタンスを新しいオブジェクト(デフォルトの動作)に置き換えることができます。それ以外の場合は、指定 に合わせて上書きする必要がありますが、FactHandle
を新たに作成します。
4.21. 記述挿入フローチャート
[D]
4.22. 論理挿入フローチャート
[D]
4.23. The Truth Maintenance System
4.24. insertLogical ファクト
insertLogical
ファクトは JBoss Rules TMS の一部です。ルールが動作し、状況に応じて変更されるように、ロジックを挿入します。たとえば、insertLogical
ファクトを一連のルールに追加して、ルールが false になると、ファクトは自動的に取り消されます。
4.25. 推論および TMS の使用
手順4.7 タスク
- この例では、バスパススルー発行システムを使用します。以下のコードスニペットを参照してください。
rule "Issue Child Bus Pass" when $p : Person( age < 16 ) then insert(new ChildBusPass( $p ) ); end rule "Issue Adult Bus Pass" when $p : Person( age >= 16 ) then insert(new AdultBusPass( $p ) ); end
insertLogical
プロパティーを挿入して推論を提供します。rule "Infer Child" when $p : Person( age < 16 ) then insertLogical( new IsChild( $p ) ) end rule "Infer Adult" when $p : Person( age >= 16 ) then insertLogical( new IsAdult( $p ) ) end
- コードを再入力してパスを発行します。TMS は取り消しセットのカスケードに対する論理挿入の連鎖をサポートするため、これらの 2 つの設定は論理的に挿入することもできます。
rule "Issue Child Bus Pass" when $p : Person( ) IsChild( person == $p ) then insertLogical(new ChildBusPass( $p ) ); end rule "Issue Adult Bus Pass" when $p : Person( age >= 16 ) IsAdult( person =$p ) then insertLogical(new AdultBusPass( $p ) ); end
ユーザーが 15 から 16 に変更されると、IsChild
ファクトとユーザーのChildBusPass
ファクトの両方が自動的に取り消されるようになりました。 - 必要に応じて、
not
条件要素を挿入して通知を処理します。(この例では、パスを返すリクエストです。) TMS がChildBusPass
オブジェクトを自動的に取り消すと、このルールはトリガーして要求を人に送信します。rule "Return ChildBusPass Request "when $p : Person( ) not( ChildBusPass( person == $p ) ) then requestChildBusPass( $p ); end
第5章 デシジョンテーブル
5.1. デシジョンテーブル
5.2. スプレッドシートのデシジョンテーブル
5.3. オープンオフィスの例
図5.1 Open Office Screenshot
[D]
5.4. ルールおよびスプレッドシート
- 行に挿入されるルール
- 各行がルールであるため、書き込まれたコードと同じ原則が適用されます。ルールエンジンがファクトを処理すると、一致するすべてのルールが実行される可能性があります。
- Agendas
- ルールが実行され、最初の一致だけがアクションに影響する、非常に単純なデシジョンテーブルをシミュレートする際にアジェンダをクリアできます。
- 複数テーブル
- 1 つのスプレッドシートに複数のテーブルを設定できます。これにより、ルールは共通のテンプレートを共有する場所をグループ化できますが、すべてが 1 つのルールパッケージに統合されます。
5.5. RuleTable キーワード
5.6. RuleSet キーワード
5.7. ルールテンプレートの例
図5.2 ルールテンプレート
[D]
- RuleSet キーワードは、すべてのルールを含む ルールパッケージ で使用される名前を示します。この名前はオプションで あり、デフォルトですが、そのセルにはすぐに右側に RuleSet キーワードが必要です。Column C に表示される他のキーワードは Import および Sequential です。
- RuleTable キーワードの後に名前があり、生成されたルールの名前の接頭辞を付けるために使用されます。一意のルール名を保証するために、行番号が追加されます。
- RuleTable の列は、ルールが開始する列で、左側の列は無視されます。
- 行 14 (RuleTable の直後の行)を参照すると、以下の列のデータが、ルールの LHS または RHS 部分のいずれかに対するものであることを示します。ルールには他の属性があり、オプションでこの方法を設定することもできます。
- 行 15 には ObjectTypes の宣言が含まれます。この行の内容は任意ですが、このオプションが使用されていない場合は、行を空白のままにする必要があります。この行を使用すると、下のセル(行 16)の値がそのオブジェクトタイプの制約になります。上記の例では、
Person(age=="42")
およびCheese(type=="stilton")
が生成されます。42 と "stilton" は行 18 から取得されます。上記の例では、==" は暗黙です。フィールド名のみを指定すると、トランスレーターは完全一致を生成することを前提としています。 - 行 16 には、ルールテンプレート自体が含まれます。"$param" プレースホルダーを使用して、下のセルからのデータを補間する場所を指定できます。(複数の挿入の場合は "$1", "$2" などを使用し、下のセルのコンマ区切りリストのパラメーターを示します。) 行 17 は無視されます。列の目的に関するテキスト説明が含まれる可能性があります。
- 行 18 および 19 は、ルールを生成するために、行 15 のテンプレートと組み合わせ(補間)されるデータを表示します。セルにデータが含まれていない場合には、そのテンプレートは無視されます。(これは、一部の条件またはアクションがそのルール行に適用されないことを意味します。) ルール行は、空の行が存在するまで読み取られます。シートに RuleTables を複数存在させることができます。
- 行 20 には別のキーワードと値が含まれます。このようなキーワードの行の位置は重要ではありません(ほとんどの場合、最上部に配置します)。ただし、その列は、RuleTable キーワードまたは RuleSet キーワードが表示されるものと同じである必要があります。ケース列 C は重要になるように選択されていますが、代わりに他の列を使用できます。
//row 18 rule "Cheese_fans_18" when Person(age=="42") Cheese(type=="stilton") then list.add("Old man stilton"); end
age=="42"
および type=="stilton"
は単一の制約として解釈されます。上記のセルがスパンされた場合は、1 つの列に複数の制約がある可能性があります。
5.8. データ定義セル
RuleSet
)は、ルールを除くすべての DRL アイテムを定義します。もう 1 つは繰り返し発生する可能性があり、右側と、コンテンツが RuleTable
で始まるセルの下に発生します。これらのエリアは実際のデシジョンテーブルを表し、各領域により同様の構造のルールセットが作成されます。
RuleSet
5.9. ルールテーブル列
RuleTable
のマークが付いたセルの行に続く最初の 4 つの行は、ヘッダー領域として表示されます。主に、コードの定義にルールを設定するために使用されます。別のルールを生成する 4 つのヘッダー行の下に追加行があり、そのデータは Rule Table ヘッダーで定義されたコードのバリエーションを提供します。
5.10. ルールセットエントリー
RuleSet
5.11. ルールセットエリアのエントリー
表5.1 Rule Set エリアのエントリー
キーワード | 値 | 使用方法 |
---|---|---|
RuleSet | 生成した DRL ファイルのパッケージ名。任意設定、デフォルトは rule_table です。 | First エントリー でなければなりません。 |
Sequential | true または false。true の場合、ルールを上から適用する優先順位が使用されます。 | 任意。1 つまで指定可能。1 つまで指定可能。省略すると、適用順は指定されません。 |
EscapeQuotes | true または false。true の場合は、引用符がエスケープされ、DRL に文字通り表示されます。 | 任意。1 つまで指定可能。1 回まで指定可能。省略すると、引用符がエスケープされます。 |
インポート | インポートする Java クラスのコンマ区切りリスト。 | 任意。繰り返して使用可能。 |
Variables | DRL グローバルの宣言。つまり、型の後に変数名が続きます。グローバル定義が複数になる場合は、コンマで区切る必要があります。 | 任意。繰り返して使用可能。 |
関数 | DRL 構文に準拠している 1 つまたは複数の関数定義。 | 任意。繰り返して使用可能。 |
Queries | DRL 構文に準拠している 1 つまたは複数のクエリー定義。 | 任意。繰り返して使用可能。 |
Declare | DRL 構文に準拠している 1 つまたは複数の宣言型。 | 任意。繰り返して使用可能。 |
5.12. ルールセットエリアのルール属性エントリー
表5.2 ルールセットエリアのルール属性エントリー
キーワード | 初期 | 値 |
---|---|---|
PRIORITY | P | ルールのsalience 値を定義する整数。Sequential フラグで上書きされます。 |
DURATION | D | ルールの "duration" 値を定義する長い整数値。 |
TIMER | T | タイマー定義。タイマーおよびカレンダーを参照してください。 |
CALENDARS | E | カレンダーの定義。タイマーおよびカレンダーを参照してください。 |
NO-LOOP | U | ブール値。"true" は、結果による変更によりルールのループを抑制します。 |
LOCK-ON-ACTIVE | L | ブール値。"true" は、同じルールフローまたはアジェンダグループ内にこのフラグが設定されたすべてのルールの追加アクティベーションを禁止します。 |
AUTO-FOCUS | F | ブール値。アジェンダグループ内のルールに対して "true" を指定すると、ルールのアクティベーションが自動的にグループにフォーカスされます。 |
ACTIVATION-GROUP | X | アクティベーション(または XOR)グループを指定する文字列。アクティベーショングループ内のルールが 1 つだけ実行されます。つまり、実行する最初のルールは、同じグループ内の他のルールの既存のアクティベーションを取り消します。 |
AGENDA-GROUP | G | アジェンダグループを指定する文字列。"focus" を指定してアクティブにする必要があります。これは、ルールのグループ間のフローを制御する 1 つの方法です。 |
RULEFLOW-GROUP | R | ルールフローグループを指定する文字列。 |
5.13. RuleTable セル
5.14. 列タイプ
5.15. ルールテーブルの列ヘッダー
表5.3 ルールテーブルの列ヘッダー
キーワード | 初期 | 値 | 使用方法 |
---|---|---|---|
NAME | N | その行で生成したルールの名前を提供します。デフォルトは、RuleTable タグと行番号に続くテキストから作成されます。 | 最大 1 列 |
説明 | I | 生成されたルール内のコメントとなるテキスト。 | 最大 1 列 |
CONDITION | C | 条件内のパターンに制約を構築するコードスニペットおよび補間値。 | ルールテーブルごとに少なくとも 1 つ |
ACTION | A | ルールの結果に対するアクションを構築するコードスニペットおよび補間値。 | ルールテーブルごとに少なくとも 1 つ |
METADATA | @ | ルールに対するメタデータエントリーを構築するコードスニペットおよび補間値。 | 任意。任意の数の列 |
5.16. 条件要素
- CONDITION のすぐ下のセルのテキストは、ルール条件のパターンに開発され、次の行のスニペットは制約になります。セルが 1 つ以上のニービーと結合されている場合は、複数の制約を持つパターンが 1 つ形成されます。すべての制約は括弧で結合され、このセルのテキストに追加されます。セルは空白のままにすることができます。つまり、次の行のコードスニペットが自動的に有効な条件要素となります。制約のないパターンを含めるには、別のパターンのテキストの前にパターンを記述します。パターンは、括弧の空のペアで記述することも、なしで記述することもできます。パターンに from 句を追加できます。パターンが eval で終了すると、コードスニペットは、eval の後に括弧のペアに含めるブール値式を生成することになります。
- CONDITION の 2 つ下のセルのテキストは、2 つの手順で処理されます。
- このセルのコードスニペットは、その列のさらに下にあるセルから値が補間されます。以下のセルからの値で "==" を使用した比較で設定される制約を作成する場合は、フィールドセレクターだけで十分です。その他の比較演算子は、スニペットの最後に指定する必要があり、値は下のセルから追加されます。その他の制約形式については、
$param
の記号でセルの内容を追加する場所を指定する必要があります。シンボル$1
、$2
などを使用し、下のセルの値のコンマ区切りリストを使用すると、複数の挿入が可能です。パターンforall(
区切り文字){
スニペット}
に従ってテキストが展開されます。これは、以下の各セルで、コンマ区切りの値リストの値ごとに スニ ペットを 1 回繰り返し実行し、シンボル$
の代わりに値を挿入し、これらの拡張を指定の 区切り文字 で結合します。forall コンストラクトは他のテキストで囲むことができることに注意してください。 - 上記の行のセルが空でない場合は、そのセルから条件要素に完全なコードスニペットが追加されます。括弧のペアと、(結合したセルのパターンに複数の制約が追加されている場合は) 区切り文字のコンマが自動的に提供されます。上記のセルが空の場合は、挿入の結果がそのまま使用されます。
- CONDITION の 3 つ下のセルのテキストは、ドキュメントのみ用です。列の目的を人間のリーダーに示すために使用する必要があります。
- 4 行目から、空白以外のエントリーは、上記のように挿入用のデータを提供します。セルが空の場合は、このルールで条件付き要素または制約が省略されます。
5.17. アクションステートメント
- ACTION の下の最初のセルのテキストは任意です。存在する場合は、オブジェクト参照として解釈されます。
- ACTION の 2 つ下のセルのテキストは、2 つの手順で処理されます。
- このセルのコードスニペットは、その列のさらに下にあるセルから値が補間されます。挿入(singular insert)の場合は、
$param
の記号でセルの内容を追加する場所をマークします。シンボル$1
、$2
などを使用し、下のセルの値のコンマ区切りリストを使用すると、複数の挿入が可能です。挿入のないメソッド呼び出しは、マーカーシンボルのないテキストで実現できます。この場合は、以下の行に空白以外のエントリーを使用して ステートメントを追加します。forall コンストラクトもここで利用できます。 - 1 つ下のセルが空でない場合は、そのテキストの後にピリオドが続くと、2 つ下のセルのテキストと終了セミコロンが 1 つの文字列で囲まれ、その結果のアクションステートメントとして追加されるメソッド呼び出しが作成されます。上記のセルが空の場合は、挿入の結果がそのまま使用されます。
- ACTION の 3 つ下のセルのテキストは、ドキュメントのみ用です。列の目的を人間のリーダーに示すために使用する必要があります。
- 4 行目から、空白以外のエントリーは、上記のように挿入用のデータを提供します。セルが空の場合は、このルールの action ステートメントが省略されます。
$param
の代わりに $1
を使用すると失敗します。
5.18. メタデータステートメント
- METADATA の下の最初のセルのテキストは無視されます。
- 上記のように METADATA の 2 つ下のセルのテキストは、ルール行のセルの値を使用して補間されます。メタデータマーカー文字
@
は自動的に接頭辞として付加されるため、このセルのテキストに含めないでください。 - METADATA の 3 つ下のセルのテキストは、ドキュメントのみを目的としています。列の目的を人間のリーダーに示すために使用する必要があります。
- 4 行目から、空白以外のエントリーは、上記のように挿入用のデータを提供します。セルが空の場合は、このルールでメタデータアノテーションが省略されます。
5.19. セルデータの交差例
- テンプレートが
Foo(bar == $param)
で、セルが42
の場合、結果はFoo(bar == 42)
になります。 - テンプレートが
Foo(bar < $1, baz == $2)
で、セルに42,43
が含まれている場合、結果はFoo(bar < 42, baz ==43)
になります。 42,43
が含まれるセルを含むテンプレートforall(&&){bar != $}
は、bar != 42 && bar != 43
になります。
5.20. セルでの作業に関するヒント
- 同じセル内に複数のパッケージ名をコンマで区切る必要があります。
- タイプ名と変数名のペアはコンマで区切る必要があります。
- 関数は、DRL ファイルに表示されるように記述する必要があります。これは、RuleSet キーワードと同じ列に表示されるはずです。これは、すべてのルール行間または下に置くことができます。
- 複数の定義を 1 つのセルにパックする代わりに、Import、Variables、functions、および queryueries を繰り返し使用できます。
- 末尾の挿入マーカーは省略できます。
- バインディング変数の定義を指定できます。
- オブジェクトタイプの行には、すべて配置できます。バインディング変数の定義以外に、リテラル的に挿入される追加のパターンを使用することもできます。
- ACTION ヘッダーの下のセルは空白のままにすることができます。このスタイルを使用すると、単一のメソッド呼び出しだけでなく、すべてのものを結果に配置できます。(同じ手法は CONDITION 列内で適用されます。)
5.21. SpreadsheetCompiler クラス
SpreadsheetCompiler
クラスは、drools-decisiontables モジュールの API スプレッドシートベースのデシジョンテーブルで使用されるメインクラスです。このクラスは、さまざまな形式のスプレッドシートを取得し、DRL にルールを生成します。
SpreadsheetCompiler
を使用すると、部分的なルールファイルを生成し、ファクトの後に完全なルールパッケージにアセンブルできます。これにより、必要に応じてルールの技術と技術以外の側面の分離が可能になります。
5.22. スプレッドシートベースのデシジョンテーブルの使用
手順5.1 タスク
- ベースとして使用するサンプルスプレッドシートを生成します。
- Rule Workbench IDE プラグインが使用されている場合は、ウィザードを使用してテンプレートからスプレッドシートを生成します。
- XSL 互換のスプレッドシートエディターを使用して XSL を変更します。
5.23. リスト
lists
を作成できます。これらは他のワークシートに保存し、セルの有効な値のリストを提供できます。
5.24. リビジョン制御
5.25. tabular Data Sources
5.26. ルールテンプレートの機能
- データをデータベース(またはその他の形式)に保存します。
- データの値に基づいて条件付きでルールを生成します。
- ルールの一部(条件演算子、クラス名、プロパティー名など)にデータを使用します。
- 同じデータで異なるテンプレートを実行します。
5.27. ルールテンプレートの例
1 template header 2 age 3 type 4 log 5 6 package org.drools.examples.templates; 7 8 global java.util.List list; 9 10 template "employees" 11 12 rule "Current employee_@{row.rowNumber}" 13 when 14 Name(location == @{location}) 15 role(type == "@{type}") 16 then 17 list.add("@{log}"); 18 end 19 20 end template
- 行 1: すべてのルールテンプレートは
template header
で始まります。 - 2 行目:ヘッダーのフォローは、データに表示される順序で列のリストになります。ここでは、最初の列
location
、2 番目のtype
と 3 番目のlog
を呼び出します。 - 5 行目:空の行は、列定義の最後を示します。
- 6-9 行目:標準のルールヘッダーテキスト。これは標準的なルール DRL で、生成された DRL の上部に表示されます。package ステートメントと、インポート、グローバル、および関数の定義をこのセクションに配置します。
- 10 行目:キーワード
template
は、ルールテンプレートの開始を通知します。テンプレートファイルには複数のテンプレートが存在する可能性がありますが、各テンプレートには一意の名前を付ける必要があります。 - 11-18 行目:ルールテンプレート。
- 20 行目:キーワード
end template
は、テンプレートの最後を示します。
package org.drools.examples.templates; global java.util.List list; rule "Current employee_1" when Person(location == Melbourne) role(type == "receptionist") then list.add("melbourne admin"); end rule "Current employee_2" when Person(location == Sydney) Cheese(type == "recruiter") then list.add("sydney HR"); end
5.28. ルールテンプレートの実行
手順5.2 タスク
- このコードを実行して、ルールテンプレートを実行します。
DecisionTableConfiguration dtableconfiguration = KnowledgeBuilderFactory.newDecisionTableConfiguration(); dtableconfiguration.setInputType( DecisionTableInputType.XLS ); KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kbuilder.add( ResourceFactory.newClassPathResource( getSpreadsheetName(), getClass() ), ResourceType.DTABLE, dtableconfiguration );
5.29. 拡張された変更セットの例
<change-set xmlns='http://drools.org/drools-5.0/change-set' xmlns:xs='http://www.w3.org/2001/XMLSchema-instance' xs:schemaLocation='http://drools.org/drools-5.0/change-set.xsd http://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/drools-api/src/main/resources/change-set-1.0.0.xsd' > <add> <resource source='http:org/domain/myrules.drl' type='DRL' /> <resource source='classpath:data/IntegrationExampleTest.xls' type="DTABLE"> <decisiontable-conf input-type="XLS" worksheet-name="Tables_2" /> </resource> </add> </change-set>
5.30. Changesets および directories の例
<change-set xmlns='http://drools.org/drools-5.0/change-set' xmlns:xs='http://www.w3.org/2001/XMLSchema-instance' xs:schemaLocation='http://drools.org/drools-5.0/change-set.xsd http://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/drools-api/src/main/resources/change-set-1.0.0.xsd' > <add> <resource source='file://myfolder/' type='DRL' /> </add> </change-set>
5.31. ナレッジエージェント
5.32. ナレッジエージェントの例
KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "MyAgent" ); kagent.applyChangeSet( ResourceFactory.newUrlResource( url ) ); KnowledgeBase kbase = kagent.getKnowledgeBase();
5.33. KnowledgeAgent オブジェクト
KnowledgeAgent
オブジェクトは、デフォルトのポーリング間隔 60 秒を使用して、すべてのリソースを継続的にスキャンします。変更日を更新すると、新しいリソースを使用してキャッシュされたナレッジベースに変更を適用します。以前の KnowledgeBase
参照は引き続き存在し、新たにビルドされた KnowledgeBase
にアクセスするには getKnowledgeBase()
を呼び出す必要があります。ディレクトリーが変更セットの一部として指定されている場合、そのディレクトリーの内容全体が変更に対してスキャンされます。変更の適用方法は、エージェントに渡される KnowledgeAgentConfiguration オブジェクトに存在する drools.agent.newInstance
プロパティーによって異なります。
5.34. ポーリングサービスの起動
手順5.3 タスク
- ポーリングを実行するには、ポーリングおよび通知機能サービスを開始する必要があります。このコードを使用します。
ResourceFactory.getResourceChangeNotifierService().start(); ResourceFactory.getResourceChangeScannerService().start();
5.35. KnowledgeBuilder のカスタム ClassLoaders
手順5.4 タスク
- KnowledgeBuilderConfiguration を開き、カスタムクラ出力ダーを指定します。
- カスタム設定をこれらのコンパイラーに渡す必要がある場合は、KnowledgeBuilderConfiguration オブジェクトを KnowledgeAgentFactory.newKnowledgeAgent ()に送信します。
5.36. ナレッジベース ClassLoader の再利用
drools.agent.useKBaseClassLoaderForCompiling
プロパティーを使用する必要があります。
5.37. KnowledgeAgentConfiguration の例
KnowledgeBaseConfiguration kbaseConfig = KnowledgeBaseFactory.newKnowledgeBaseConfiguration(null, customClassLoader); KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(kbaseConfig); //kbase with custom classloader KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguration(); aconf.setProperty("drools.agent.newInstance", "false"); //incremental change set processing enabled aconf.setProperty("drools.agent.useKBaseClassLoaderForCompiling", "true"); KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "test agent", kbase, aconf);
5.38. newInstance プロパティー
5.39. newInstance プロパティーの使用
5.40. newInstance の例
KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguration(); aconf.setProperty("drools.agent.newInstance", "false"); KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent("test agent", null, aconf);
5.41. リモート HTTP リソースキャッシング
5.42. 再起動後のリソースキャッシングの復元
手順5.5 タスク
- リソースがリモートで利用できない場合に再起動後も存続するには(リモートサーバーの再起動など)、システムプロパティー(
drools.resource.urlcache
)を設定します。(アプリケーションの書き込みパーミッションを持つディレクトリーに設定されていることを確認します。) ナレッジストアは、そのディレクトリー内のリモートリソースのコピーをキャッシュします。たとえば、java コマンドライン-Ddrools.resource.urlcache=/users/someone/KnowledgeCache
を使用すると、エージェントが再起動する際に使用するリソース(ルール、パッケージなど)のローカルコピーをそのディレクトリーに保持します。(リモートリソースが利用可能になり、更新されると、ローカルキャッシュコピーが自動的に更新されます。)
第6章 処理
6.1. アジェンダ
WorkingMemory
のアクション中にルールが完全に一致し、実行の対象となる場合があります。単一の作業メモリーアクションにより、複数のルールが適用される場合があります。ルールが完全に一致すると、アクティベーションが作成され、ルールと一致したファクトを参照し、Agenda に配置されます。アジェンダは、競合解決ストラテジーを使用して、これらのアクティベーションの実行順序を制御します。
6.2. アジェンダ処理
- ワーキングメモリーアクション。これは、Consequence (RHS 自体)またはメインの Java アプリケーションプロセスのいずれかで、ほとんどの作業が行われる場所です。Consequence が終了するか、またはメインの Java アプリケーションプロセスが
fireAllRules()
を呼び出すと、エンジンは Agenda Evaluation フェーズに切り替わります。 - アジェンダ評価。これにより、実行するルールの選択が試行されます。ルールが見つからない場合は終了し、見つからない場合は、検出ルールが実行され、フェーズを Working Memory Actions に切り替えます。
6.3. デフォルトの競合解決ストラテジー
- 顕著性(優先度)
- ユーザーは、特定のルールの優先度を(数値で)他のルールよりも高く指定できます。この場合、顕著性が高いルールが優先されます。
- LIFO (last in, first out)
- LIFO 優先度は、割り当てられた Working Memory Action カウンター値に基づいています。同じ優先度値を持つ一連の起動の実行順序は任意です。
6.4. AgendaGroup
6.5. setFocus()
setFocus()
が呼び出されるたびに、指定されたアジェンダグループをスタックにプッシュします。フォーカスグループが空の場合は、スタックからポップアップされ、上位評価上にあるフォーカスグループになります。アジェンダグループは、スタックの複数の場所に表示されます。デフォルトの Agenda Group は "MAIN" で、このグループにアジェンダグループを指定しないすべてのルールは MAIN です。これは、デフォルトで最初にフォーカスされるスタックの最初のグループでもあります。
6.6. setFocus() Example
ksession.getAgenda().getAgendaGroup( "Group A" ).setFocus();
6.7. ActivationGroup
clear()
メソッドはいつでも呼び出すことができます。これにより、アクティベーションが実行される前にすべてのアクティベーションが取り消されます。
6.8. ActivationGroup の例
ksession.getAgenda().getActivationGroup( "Group B" ).clear();
6.9. RuleFlowGroup
clear()
メソッドはいつでも呼び出すことで、アジェンダに残っているすべてのアクティベーションをキャンセルできます。
6.10. RuleFlowGroup Example
ksession.getAgenda().getRuleFlowGroup( "Group C" ).clear();
6.11. ルールとメソッドの違い
- メソッドは直接呼び出されます。
- 特定のインスタンスが渡されます。
- 1 回の呼び出しを行うと、1 回の実行になります。
- ルールは、エンジンに挿入されている限り、任意のデータに対して一致して実行されます。
- ルールは直接呼び出すことはできません。
- 特定のインスタンスをルールに渡すことはできません。
- 一致によっては、ルールは 1 回または複数回実行されるか、まったく実行されない場合があります。
6.12. クロス製品の例
rule when $room : Room() $sprinkler : Sprinkler() then System.out.println( "room:" + $room.getName() + " sprinkler:" + $sprinkler.getRoom().getName() ); end
select * from Room, Sprinkler
であり、Room テーブルのすべての行は、Sprinkler テーブルのすべての行に参加して、以下の出力になります。
room:office sprinkler:office room:office sprinkler:kitchen room:office sprinkler:livingroom room:office sprinkler:bedroom room:kitchen sprinkler:office room:kitchen sprinkler:kitchen room:kitchen sprinkler:livingroom room:kitchen sprinkler:bedroom room:livingroom sprinkler:office room:livingroom sprinkler:kitchen room:livingroom sprinkler:livingroom room:livingroom sprinkler:bedroom room:bedroom sprinkler:office room:bedroom sprinkler:kitchen room:bedroom sprinkler:livingroom room:bedroom sprinkler:bedroom
rule when $room : Room() $sprinkler : Sprinkler( room == $room ) then System.out.println( "room:" + $room.getName() + " sprinkler:" + $sprinkler.getRoom().getName() ); end
select * from Room, Sprinkler where Room == Sprinkler.room
になります。
room:office sprinkler:office room:kitchen sprinkler:kitchen room:livingroom sprinkler:livingroom room:bedroom sprinkler:bedroom
6.13. アクティベーション、アジェンダ、および競合セットの例
public class CashFlow { private Date date; private double amount; private int type; long accountNo; // getter and setter methods here } public class Account { private long accountNo; private double balance; // getter and setter methods here } public AccountPeriod { private Date start; private Date end; // getter and setter methods here }
rule "increase balance for credits" when ap : AccountPeriod() acc : Account( $accountNo : accountNo ) CashFlow( type == CREDIT, accountNo == $accountNo, date >= ap.start && <= ap.end, $amount : amount ) then acc.balance += $amount; end |
rule "decrease balance for debits" when ap : AccountPeriod() acc : Account( $accountNo : accountNo ) CashFlow( type == DEBIT, accountNo == $accountNo, date >= ap.start && <= ap.end, $amount : amount ) then acc.balance -= $amount; end |
AccountPeriod
が最初の年に設定され、"increase balance for credits" のルールが 2 つのデータ行で実行され、1 行のデータに対応するように derease balance for debits のルールを制限します。
fireAllRules()
が呼び出された後にのみ実行されます。一方で、ルールとその一致したデータは Agenda に配置され、Activation と呼ばれます。Agenda は、fireAllRules ()が呼び出されるとすぐに実行できるアクティベーションの表で、結果が実行されます。アジェンダでのアクティベーションは順番に実行されます。これまでの実行の順序は任意とみなされることに注意してください。
AccountPeriod
が 2 年 2 年に更新されると、一致するデータの行が 1 つだけであるため、Agenda の 1 つの Activation のみになります。
6.14. 競合リゾルバーストラテジー
6.15. 競合リゾルバーストラテジーの例
rule "Print balance for AccountPeriod" salience -50 when ap : AccountPeriod() acc : Account() then System.out.println( acc.accountNo + " : " + acc.balance ); end
6.16. トリガーの例
表6.1 トリガーの例
ルールビュー | トリガーの表示 |
---|---|
select * from Account acc, Cashflow cf, AccountPeriod ap where acc.accountNo == cf.accountNo and cf.type == CREDIT and cf.date >= ap.start and cf.date <= ap.end |
select * from Account acc, Cashflow cf, AccountPeriod ap where acc.accountNo == cf.accountNo and cf.type == DEBIT and cf.date >= ap.start and cf.date <= ap.end |
trigger : acc.balance += cf.amount |
trigger : acc.balance -= cf.amount |
6.17. ruleflow-group の例
rule "increase balance for credits" ruleflow-group "calculation" when ap : AccountPeriod() acc : Account( $accountNo : accountNo ) CashFlow( type == CREDIT, accountNo == $accountNo, date >= ap.start && <= ap.end, $amount : amount ) then acc.balance += $amount; end
rule "Print balance for AccountPeriod" ruleflow-group "report" when ap : AccountPeriod() acc : Account() then System.out.println( acc.accountNo + " : " + acc.balance ); end
6.18. 推論の例
rule "Infer Adult" when $p : Person( age >= 18 ) then insert( new IsAdult( $p ) ) end
$p : Person() IsAdult( person == $p )
6.19. Inference および TruthMaintenance の実装
手順6.1 タスク
- 一連のルールを開きます。この例では、バスが発行システムを使用します。
rule "Issue Child Bus Pass" when $p : Person( age < 16 ) then insert(new ChildBusPass( $p ) ); end rule "Issue Adult Bus Pass" when $p : Person( age >= 16 ) then insert(new AdultBusPass( $p ) ); end
insertLogical
ファクトを挿入し、推測する用語を追加します。rule "Infer Child" when $p : Person( age < 16 ) then insertLogical( new IsChild( $p ) ) end rule "Infer Adult" when $p : Person( age >= 16 ) then insertLogical( new IsAdult( $p ) ) end
ファクトが論理的に挿入されている。このファクトは、when 句の真理によって異なります。これは、ルールが false になると、ファクトは自動的に取り消されることを意味します。これは特に 2 つのルールは相互に排他的です。上記のルールでは、子が 16 未満の場合に IsChild ファクトが挿入されます。ユーザーが 16 を超え、IsAdult ファクトが挿入されると、自動的に取り消されます。- コードを入力してパスを発行します。TMS は取り消しセットのカスケードに対する論理挿入の連鎖をサポートするため、これらは論理的に挿入することもできます。
rule "Issue Child Bus Pass" when $p : Person( ) IsChild( person == $p ) then insertLogical(new ChildBusPass( $p ) ); end rule "Issue Adult Bus Pass" when $p : Person( age >= 16 ) IsAdult( person =$p ) then insertLogical(new AdultBusPass( $p ) ); end
現在、ユーザーが 15 から 16 に変更すると、IsChild ファクトは自動的に取り消されるだけでなく、はユーザーの ChildBusPass ファクトになります。 - not 条件要素を挿入して通知を処理します。(この場合、パスを返すリクエスト。) TMS が ChildBusPass オブジェクトを自動的に取り消すと、このルールはトリガーして要求を人に送信します。
rule "Return ChildBusPass Request "when $p : Person( ) not( ChildBusPass( person == $p ) ) then requestChildBusPass( $p ); end
第7章 ルール言語
7.1. KnowledgeBuilder
ResourceType
クラスのオブジェクトは、ビルダーが処理を求められているリソースのタイプを示します。
7.2. ResourceFactory
ResourceFactory
は、java.io.Reader、クラスパス、URL、java.io.File、またはバイト配列など、複数のソースからリソースを読み込む機能を提供します。デシジョンテーブル(Excel の .xls ファイル)などのバイナリーファイルを Reader で渡すことはできません。これは、テキストベースのリソースにのみ適しています。
7.3. 新しい KnowledgeBuilder の作成
手順7.1 タスク
- KnowledgeBuilderFactory を開きます。
- 新しいデフォルト設定を作成します。
- 以下を設定に入力します。
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
最初のパラメーターはプロパティー用で、は任意です。空白のままにすると、デフォルトのオプションが使用されます。options パラメーターは、ダイアレクトの変更や新しいアクセラレーター関数の登録などに使用できます。 - カスタム ClassLoader を使用して KnowledgeBuilder を追加するには、以下のコードを使用します。
KnowledgeBuilderConfiguration kbuilderConf = KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration(null, classLoader ); KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(kbuilderConf);
7.4. DRL リソースの追加
手順7.2 タスク
- 任意のタイプのリソースは繰り返し追加できます。以下に DRL ファイルを追加します。ナレッジストアは複数の namespace を処理できるため、namespace に関係なくリソースを組み合わせることができます。
kbuilder.add( ResourceFactory.newFileResource( "/project/myrules.drl" ), ResourceType.DRL);
- 各リソースの追加後にコンパイル結果を確認します。KnowledgeBuilder は、ERROR、WARNING、および INFO の 3 つの異なる重大度のコンパイル結果を報告できます。
ERROR
は、リソースのコンパイルが失敗したことを示します。エラーが発生する場合は、リソースを追加したり、ナレッジパッケージを取得したりしないでください。getKnowledgePackages()
エラーがある場合は、空の一覧を返します。WARNING
およびINFO
の結果は無視できますが、検査にも使用できます。
7.5. KnowledgeBuilder Result Inspection メソッド
/** * Return the knowledge builder results for the listed severities. * @param severities * @return */ KnowledgeBuilderResults getResults(ResultSeverity... severities); /** * Checks if the builder generated any results of the listed severities * @param severities * @return */ boolean hasResults(ResultSeverity... severities ;
hasErrors()
getErrors()
if( kbuilder.hasErrors() ) { System.out.println( kbuilder.getErrors() ); return; }
7.6. KnowledgePackages の取得
Collection<KnowledgePackage> kpkgs = kbuilder.getKnowledgePackages();
7.7. 拡張ナレッジBuilder の例
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); if( kbuilder.hasErrors() ) { System.out.println( kbuilder.getErrors() ); return; } KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kbuilder.add( ResourceFactory.newFileResource( "/project/myrules1.drl" ), ResourceType.DRL); kbuilder.add( ResourceFactory.newFileResource( "/project/myrules2.drl" ), ResourceType.DRL); if( kbuilder.hasErrors() ) { System.out.println( kbuilder.getErrors() ); return; } Collection<KnowledgePackage> kpkgs = kbuilder.getKnowledgePackages();
7.8. バッチモードでの KnowledgeBuilder の使用
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kbuilder.batch() .add( ResourceFactory.newFileResource( "/project/myrules1.drl" ), ResourceType.DRL ) .add( ResourceFactory.newFileResource( "/project/myrules2.drl" ), ResourceType.DRL ) .add( ResourceFactory.newFileResource( "/project/mytypes1.drl" ), ResourceType.DRL ) .build();
7.9. 最後に追加した DRL のビルドの破棄
kbuilder.add( ResourceFactory.newFileResource( "/project/wrong.drl" ), ResourceType.DRL ); if ( kbuilder.hasErrors() ) { kbuilder.undo(); }
7.10. 設定および ChangeSet XML を使用したビルド
7.11. ChangeSet XML の XML スキーマ(正規化ではありません)
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://drools.org/drools-5.0/change-set" targetNamespace="http://drools.org/drools-5.0/change-set"> <xs:element name="change-set" type="ChangeSet"/> <xs:complexType name="ChangeSet"> <xs:choice maxOccurs="unbounded"> <xs:element name="add" type="Operation"/> <xs:element name="remove" type="Operation"/> <xs:element name="modify" type="Operation"/> </xs:choice> </xs:complexType> <xs:complexType name="Operation"> <xs:sequence> <xs:element name="resource" type="Resource" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <xs:complexType name="Resource"> <xs:sequence> <!-- To be used with <resource type="DTABLE"...> --> <xs:element name="decisiontable-conf" type="DecTabConf" minOccurs="0"/> </xs:sequence> <!-- java.net.URL, plus "classpath" protocol --> <xs:attribute name="source" type="xs:string"/> <xs:attribute name="type" type="ResourceType"/> </xs:complexType> <xs:complexType name="DecTabConf"> <xs:attribute name="input-type" type="DecTabInpType"/> <xs:attribute name="worksheet-name" type="xs:string" use="optional"/> </xs:complexType> <!-- according to org.drools.builder.ResourceType --> <xs:simpleType name="ResourceType"> <xs:restriction base="xs:string"> <xs:enumeration value="DRL"/> <xs:enumeration value="XDRL"/> <xs:enumeration value="DSL"/> <xs:enumeration value="DSLR"/> <xs:enumeration value="DRF"/> <xs:enumeration value="DTABLE"/> <xs:enumeration value="PKG"/> <xs:enumeration value="BRL"/> <xs:enumeration value="CHANGE_SET"/> </xs:restriction> </xs:simpleType> <!-- according to org.drools.builder.DecisionTableInputType --> <xs:simpleType name="DecTabInpType"> <xs:restriction base="xs:string"> <xs:enumeration value="XLS"/> <xs:enumeration value="CSV"/> </xs:restriction> </xs:simpleType> </xs:schema>
第8章 Changesets
8.1. Changesets
changeset.xml
ファイルには、このファイルのリソース一覧が含まれます。別の changeset XML ファイルに再帰的にポイントすることもできます。
8.2. 変更セットの例
java.net.URL
が提供するすべてのプロトコルと、追加のクラスパスがサポートされています。現在、ファイル名拡張子から推測されないため、type 属性はリソースに対して常に指定する必要があります。これは以下の例で示されています。
<change-set xmlns='http://drools.org/drools-5.0/change-set' xmlns:xs='http://www.w3.org/2001/XMLSchema-instance' xs:schemaLocation='http://drools.org/drools-5.0/change-set http://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/drools-api/src/main/resources/change-set-1.0.0.xsd' > <add> <resource source='http:org/domain/myrules.drl' type='DRL' /> </add> </change-set>
CHANGE_SET
に変更することで使用できます。
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kbuilder.add( ResourceFactory.newClasspathResource( "myChangeSet.xml", getClass() ), ResourceType.CHANGE_SET ); if ( kbuilder.hasErrors() ) { System.err.println( builder.getErrors().toString() ); }
8.3. Changeset XML の例
<change-set xmlns='http://drools.org/drools-5.0/change-set' xmlns:xs='http://www.w3.org/2001/XMLSchema-instance' xs:schemaLocation='http://drools.org/drools-5.0/change-set.xsd http://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/drools-api/src/main/resources/change-set-1.0.0.xsd' > <add> <resource source='file:/project/myrules.drl' type='DRL' /> </add> </change-set>
8.4. Changeset Protocols
file:
接頭辞を使用して、リソースのプロトコルを示します。
8.5. ChangeSet XML の読み込み
手順8.1 タスク
- API を使用して ChangeSet をロードします。
- このコードを使用して ChangeSet XML にアクセスします。
kbuilder.add( ResourceFactory.newUrlResource( url ), ResourceType.CHANGE_SET );
8.6. リソース設定による XML の変更例
<change-set xmlns='http://drools.org/drools-5.0/change-set' xmlns:xs='http://www.w3.org/2001/XMLSchema-instance' xs:schemaLocation='http://drools.org/drools-5.0/change-set.xsd http://anonsvn.jboss.org/repos/labs/labs/drools/trunk/drools-api/src/main/resources/change-set-1.0.0.xsd' > <add> <resource source='http:org/domain/myrules.drl' type='DRL' /> <resource source='classpath:data/IntegrationExampleTest.xls' type="DTABLE"> <decisiontable-conf input-type="XLS" worksheet-name="Tables_2" /> </resource> </add> </change-set>
8.7. Changeset XML およびディレクトリー
<change-set xmlns='http://drools.org/drools-5.0/change-set' xmlns:xs='http://www.w3.org/2001/XMLSchema-instance' xs:schemaLocation='http://drools.org/drools-5.0/change-set.xsd http://anonsvn.jboss.org/repos/labs/labs/drools/trunk/drools-api/src/main/resources/change-set-1.0.0.xsd' > <add> <resource source='file:/projects/myproject/myrules' type='DRL' /> </add> </change-set>
第9章 ビルド
9.1. ビルド結果の重大度
9.2. デフォルトのビルド結果の重大度の設定
手順9.1 タスク
- システムプロパティーまたは設定ファイルを使用して設定するには、以下のプロパティーを挿入します。
// sets the severity of rule updates drools.kbuilder.severity.duplicateRule = <INFO|WARNING|ERROR> // sets the severity of function updates drools.kbuilder.severity.duplicateFunction = <INFO|WARNING|ERROR>
- API を使用して重大度を変更するには、以下のコードを使用します。
KnowledgeBuilderConfiguration kbconf = ... // sets the severity of rule updates to error kbconf.setOption( KBuilderSeverityOption.get( "drools.kbuilder.severity.duplicateRule", ResultSeverity.ERROR ) ); // sets the severity of function updates to error kbconf.setOption( KBuilderSeverityOption.get( "drools.kbuilder.severity.duplicateFunction", ResultSeverity.ERROR ) );
9.3. KnowledgePackage
9.4. 新規ナレッジベースの作成
手順9.2 タスク
- このデフォルト設定を使用して、新しいナレッジベースを作成します。
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
- カスタムクラ出力ダーが
KnowledgeBuilder
で使用され、デフォルトのクラ出力ダーにないタイプを解決する場合は、KnowledgeBase
にも設定する必要があります。この手法はKnowledgeBuilder
と同じですが、以下のようになります。KnowledgeBaseConfiguration kbaseConf = KnowledgeBaseFactory.createKnowledgeBaseConfiguration( null, cl ); KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase( kbaseConf );
9.5. プロセスの構築およびデプロイメント
drools-core.jar
および drools-compiler.jar
がクラスパス上になければなりません。
9.6. ナレッジベースへの KnowledgePackages の追加
手順9.3 タスク
- KnowledgePackages を KnowledgeBase に追加するには、以下のコードを使用します。
Collection<KnowledgePackage> kpkgs = kbuilder.getKnowledgePackages(); KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); kbase.addKnowledgePackages( kpkgs );
addKnowledgePackages(kpkgs)
メソッドを繰り返し呼び出すと、さらに知識を追加できます。
9.7. 別のプロセスでのビルドとデプロイメント
KnowledgeBase
と KnowledgePackage
はどちらもデプロイメント単位であり、シリアライズが可能です。つまり、1 台のマシンに必要なビルドを実行し、drools-compiler.jar
を必要とし、別のマシンが drools-core.jar
のみを必要とするものをすべてデプロイおよび実行できます。
9.8. KnowledgePackage の OutputStream への書き込み
ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream( fileName ) ); out.writeObject( kpkgs ); out.close();
9.9. InputStream からの KnowledgePackage の読み取り
ObjectInputStream in = new ObjectInputStream( new FileInputStream( fileName ) ); // The input stream might contain an individual // package or a collection. @SuppressWarnings( "unchecked" ) Collection<KnowledgePackage> kpkgs = ()in.readObject( Collection<KnowledgePackage> ); in.close(); KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); kbase.addKnowledgePackages( kpkgs );
9.10. JBoss Rules Management System
9.11. StatefulknowledgeSessions および KnowledgeBase Modifications
KnowledgeBase
は、StatefulKnowledgeSession
オブジェクトを作成および返し、オプションでそれらへの参照を保持することができます。
KnowledgeBase
の変更が発生すると、セッションのデータに対して適用されます。この参照は弱い参照であり、オプションでもあります。これはブール値フラグによって制御されます。
9.12. 新しい KnowledgeAgents
KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "MyAgent" );
9.13. KnowledgePackage の OutputStream への書き込み
KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "MyAgent" ); kagent.applyChangeSet( ResourceFactory.newUrlResource( url ) ); KnowledgeBase kbase = kagent.getKnowledgeBase();
9.14. スキャンおよび通知サービスの起動
ResourceFactory.getResourceChangeNotifierService().start(); ResourceFactory.getResourceChangeScannerService().start();
9.15. ResourceChangeScanner
ResourceChangeScannerService
から変更できます。適切に更新される ResourceChangeScannerConfiguration
オブジェクトはサービスの configure()
メソッドに渡されます。これにより、サービスがオンデマンドで再設定されます。
9.16. スキャン間隔の変更
ResourceChangeScannerConfiguration sconf = ResourceFactory.getResourceChangeScannerService().newResourceChangeScannerConfiguration(); // Set the disk scanning interval to 30s, default is 60s. sconf.setProperty( "drools.resource.scanner.interval", "30" ); ResourceFactory.getResourceChangeScannerService().configure( sconf );
9.17. ナレッジベースとナレッジベース間の対話
applyChangeSet(Resource)
メソッドの一部として指定されたディレクトリーのみが監視されます。
KnowledgeBase
を開始点として提供する利点の 1 つは、KnowledgeBaseConfiguration
を提供することです。リソースの変更が検出され、新しい KnowledgeBase
オブジェクトがインスタンス化されると、以前の KnowledgeBase
オブジェクトの KnowledgeBaseConfiguration
が使用されます。
9.18. 既存のナレッジベースの使用
KnowledgeBaseConfiguration kbaseConf = KnowledgeBaseFactory.createKnowledgeBaseConfiguration( null, cl ); KnowledgeBase kbase KnowledgeBaseFactory.newKnowledgeBase( kbaseConf ); // Populate kbase with resources here. KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "MyAgent", kbase ); KnowledgeBase kbase = kagent.getKnowledgeBase();
getKnowledgeBase()
は、リソースの変更が検出され、新しいナレッジベースがビルドされるまで、同じ提供される kbase インスタンスを返します。新しいナレッジベースを構築すると、前の KnowledgeBase
に提供された KnowledgeBaseConfiguration
で実行されます。
9.19. applyChangeSet ()メソッド
applyChangeSet()
メソッドで使用すると、ディレクトリーがスキャンプロセスに追加されます。ディレクトリースキャンが追加のファイルを検出すると、ナレッジベースに追加されます。削除されたファイルは ナレッジベース から削除され、変更されたファイルは ナレッジベース から削除されます。
9.20. ディレクトリーコンテンツを追加するように XML を変更します。
<change-set xmlns='http://drools.org/drools-5.0/change-set' xmlns:xs='http://www.w3.org/2001/XMLSchema-instance' xs:schemaLocation='http://drools.org/drools-5.0/change-set.xsd' > <add> <resource source='file:/projects/myproject/myrules' type='PKG' /> </add> </change-set>
9.21. KnowledgeAgentConfiguration プロパティー
KnowledgeAgentConfiguration
を使用して、ナレッジエージェントのデフォルトの動作を変更できます。これを使用して、そのディレクトリーの変更を継続的にスキャンしないようにしながら、ディレクトリーからリソースを読み込むことができます。
9.22. スキャン動作の変更
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); KnowledgeAgentConfiguration kaconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguation(); // Do not scan directories, just files. kaconf.setProperty( "drools.agent.scanDirectories", "false" ); KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "test agent", kaconf );
第10章 Sessions
10.1. JBoss ルールのセッション
KnowledgeBase
から作成されます。データは挿入でき、どのプロセスインスタンスを開始できるか。KnowledgeBase
を作成すると、リソースを大量に消費できますが、セッションの作成はできません。このため、セッションを繰り返し作成できるように、可能な限りナレッジベースのキャッシュを行うことが推奨されます。
10.2. ナレッジベースから StatefulKnowledgeSession を作成する
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
10.3. WorkingMemoryEntryPoint メソッド
WorkingMemoryEntryPoint
は、ファクトの挿入、更新、および取得を行うメソッドを提供します。エントリーポイント という用語は、作業メモリーに複数のパーティションがあり、どのパーティションに挿入するかを選択できます。ほとんどのルールベースのアプリケーションは、デフォルトのエントリーポイントのみで動作します。
10.4. KnowledgeRuntime インターフェイス
KnowledgeRuntime
インターフェイスは、エンジンとの主な対話を提供します。これは、ルール結果およびプロセスアクションで利用できます。KnowledgeRuntime
は、WorkingMemory
と ProcessRuntime
の両方からメソッドを継承するため、プロセスおよびルールを操作するための統合 API が提供されます。ルールを使用する場合には、KnowledgeRuntime
、WorkingMemoryEntryPoint
、および WorkingMemory
自体の 3 つのインターフェイスが形成されます。KnowledgeRuntime
10.5. ファクトの挿入
WorkingMemory
にファクトを伝える動作です。これは、ksession.insert(yourObject)
などを使用して実行できます。ファクトを挿入すると、ルールに対する一致について検査されます。つまり、ルールの実行または実行を決定する作業は すべて 挿入時に実行されます。ただし、fireAllRules()
を呼び出すまでルールは実行されません。このルールは、ファクトの挿入を終了した後に呼び出します。
10.6. FactHandle トークン
FactHandle
を返します。この FactHandle
は、WorkingMemory
内に挿入されたオブジェクトを表すために使用されるトークンです。また、オブジェクトを取り消したり変更したりする場合に WorkingMemory
との対話にも使用されます。
10.7. FactHandle の例
Job accountant = new Job("accountant"); FactHandle accountantHandle = ksession.insert( accountant );
10.8. Identity および Equality
- アイデンティティー
- これは、Working Memory が
IdentityHashMap
を使用してアサートされたすべてのオブジェクトを保存することを意味します。新しいインスタンスアサーションは常に新しいFactHandle
を返しますが、インスタンスが再度アサートされると、元のファクトハンドルが返されます(つまり、同じオブジェクトに対して繰り返し挿入を無視します)。 - 等号
- これは、Working Memory が
HashMap
を使用してアサートされたすべてのオブジェクトを保存することを意味します。オブジェクトインスタンスのアサーションは、(equal
メソッドにより)挿入されたオブジェクトが既存のファクトと等しくない場合のみ新しいFactHandle
を返します。
FactHandle
を返しますが、インスタンスが再度アサートされると、元のファクトハンドルが返されます(つまり、同じオブジェクトに対して繰り返し挿入を無視します)。
10.9. Retraction
FactHandle
を使用して実行できます。ルールの右側にある retract
ステートメントが使用されます。これは、単純なオブジェクト参照で動作します。
10.10. 取り消しの例
Job accountant = new Job("accountant"); FactHandle accountantHandle = ksession.insert( accountant ); .... ksession.retract( accountantHandle );
10.11. update ()メソッド
update()
メソッドを使用して、WorkingMemory
自体に通知することができないオブジェクトの変更されたオブジェクトを WorkingMemory
に通知できます。update()
メソッドは、変更されたオブジェクトを常に 2 番目のパラメーターとして取ります。これにより、イミュータブルなオブジェクトに新しいインスタンスを指定できます。
modify
ステートメントが推奨されます。これは、変更を加え、エンジンを単一のステートメントで通知するためです。または、セッターメソッドの呼び出しを介してファクトオブジェクトのフィールド値を変更したら、すぐに update
を呼び出すか、別のファクトを変更する前にイベントを呼び出す必要があります。そうしないと、ルールエンジン内のインデックスで問題が発生する可能性があります。modify ステートメントにより、この問題を回避できます。
10.12. update ()の例
Job accountant = new Job("accountant"); FactHandle accountantHandle = workingMemory.insert( accountant ); ... accountant.setSalary( 45000 ); workingMemory.update( accountantHandle, accountant );
10.13. クエリー
get
メソッドを呼び出すことで、対応するファクトまたはファクトフィールドにアクセスできます。バインディングがファクトオブジェクトを参照する場合、FactHandle は getFactHandle
を呼び出して、変数名をパラメーターとして使用して取得できます。
10.14. クエリーの例
QueryResults results = ksession.getQueryResults( "my query", new Object[] { "string" } ); for ( QueryResultsRow row : results ) { System.out.println( row.get( "varName" ) ); }
10.15. ライブクエリー
dispose
メソッドはクエリーを終了し、このリアクティブシナリオを終了します。
10.16. ViewChangedEventListener 実装の例
final List updated = new ArrayList(); final List removed = new ArrayList(); final List added = new ArrayList(); ViewChangedEventListener listener = new ViewChangedEventListener() { public void rowUpdated(Row row) { updated.add( row.get( "$price" ) ); } public void rowRemoved(Row row) { removed.add( row.get( "$price" ) ); } public void rowAdded(Row row) { added.add( row.get( "$price" ) ); } }; // Open the LiveQuery LiveQuery query = ksession.openLiveQuery( "cars", new Object[] { "sedan", "hatchback" }, listener ); ... ... query.dispose() // calling dispose to terminate the live query
10.17. KnowledgeRuntime
KnowledgeRuntime
は、グローバルの設定やチャネルの登録など、ルールとプロセスの両方に適用されるメソッドを提供します。(Exit point は、チャネルの古い同意語です。)
第11章 オブジェクトおよびインターフェイス
11.1. グローバル
11.2. グローバルの使用
手順11.1 タスク
- グローバルの作業メモリーへの実装を開始するには、ルールファイルでグローバルを宣言し、Java オブジェクトでバックアップします。
global java.util.List list
- ナレッジベースはグローバル識別子とそのタイプを認識するように、グローバルの名前とオブジェクト(任意のセッション)で
ksession.setGlobal()
を呼び出して、オブジェクトをグローバルに関連付けることができます。List list = new ArrayList(); ksession.setGlobal("list", list);
重要DRL コードでグローバルタイプと識別子を宣言しないと、この呼び出しから例外が出力されます。 - ルールの評価で使用される前にグローバルを設定します。これを行わないと、
NullPointerException
が作成されます。
11.3. グローバルの解決
- getGlobals()
- ステートレスナレッジセッションメソッド
getGlobals()
は、セッションのグローバルへのアクセスを提供する Globals インスタンスを返します。これらは、すべての実行呼び出しで共有されます。実行呼び出しは異なるスレッドで同時に実行できるため、変更可能なグローバルには注意が必要です。 - delegates
- 委譲の使用は、グローバル解決を提供するもう 1 つの方法です。グローバル(
setGlobal(String, Object)
を使用)に値を割り当てると、値は内部コレクションマッピング識別子の値に保存されます。この内部コレクションの識別子は、提供されたデリゲートよりも優先されます。この内部コレクションで識別子が見つからない場合は、デリゲートグローバル(存在する場合)が使用されます。 - 実行
- 実行スコープのグローバルは
Command
を使用して、CommandExecutor
に渡されるグローバルを設定します。
11.4. セッションスコープのグローバル例
StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession(); // Set a global hbnSession, that can be used for DB interactions in the rules. ksession.setGlobal( "hbnSession", hibernateSession ); // Execute while being able to resolve the "hbnSession" identifier. ksession.execute( collection );
11.5. StatefulRuleSessions
StatefulRuleSession
プロパティーは StatefulKnowledgeSession
によって継承され、エンジン外に関連するルール関連のメソッドを提供します。
11.6. AgendaFilter オブジェクト
AgendaFilter
オブジェクトは、アクティベーションの実行を許可または拒否するために使用されるフィルターインターフェイスのオプションの実装です。フィルターの対象は、実装によって異なります。
11.7. AgendaFilter の使用
手順11.2 タスク
- フィルターを使用するには、
fireAllRules()
の呼び出し中に指定します。以下の例では、文字列"Test"
で終わるルールのみを許可します。その他はすべてフィルターリングされます。ksession.fireAllRules( new RuleNameEndsWithAgendaFilter( "Test" ) );
11.8. ルールエンジンフェーズ
- ワーキングメモリーアクション
- これは、Consequence (RHS 自体)またはメインの Java アプリケーションプロセスのいずれかで、ほとんどの作業が行われる場所です。Consequence が終了するか、またはメインの Java アプリケーションプロセスが
fireAllRules()
を呼び出すと、エンジンは Agenda Evaluation フェーズに切り替わります。 - アジェンダ評価
- これにより、実行するルールの選択が試行されます。ルールが見つからない場合は終了します。それ以外の場合は、見つかったルールを実行し、フェーズを Working Memory Actions に戻します。
11.9. イベントモデル
11.10. The KnowlegeRuntimeEventManager
KnowlegeRuntimeEventManager
インターフェイスは KnowledgeRuntime
によって実装され、WorkingMemoryEventManager
と ProcessEventManager
の 2 つのインターフェイスを提供します。
11.11. The WorkingMemoryEventManager
WorkingMemoryEventManager
では、リスナーを追加および削除できるため、ワーキングメモリーとアジェンダのイベントをリッスンできます。
11.12. Adding an AgendaEventListener
ksession.addEventListener( new DefaultAgendaEventListener() { public void afterActivationFired(AfterActivationFiredEvent event) { super.afterActivationFired( event ); System.out.println( event ); } });
11.13. 作業メモリーイベントの印刷
ksession.addEventListener( new DebugWorkingMemoryEventListener() );
11.14. KnowlegeRuntimeEvents
KnowlegeRuntimeEvent
インターフェイスを実装し、イベントの発信元の実際の KnowlegeRuntime
の取得に使用できます。
11.15. KnowledgeRuntimeEvent インターフェイスでサポートされるイベント
- ActivationCreatedEvent
- ActivationCancelledEvent
- BeforeActivationFiredEvent
- AfterActivationFiredEvent
- AgendaGroupPushedEvent
- AgendaGroupPoppedEvent
- ObjectInsertEvent
- ObjectRetractedEvent
- ObjectUpdatedEvent
- ProcessCompletedEvent
- ProcessNodeLeftEvent
- ProcessNodeTriggeredEvent
- ProcessStartEvent
11.16. The KnowledgeRuntimeLogger
11.17. Enabling a FileLogger
KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "logdir/mylogfile"); ... logger.close();
11.18. JBoss ルールでの StatelessKnowledgeSession の使用
StatelessKnowledgeSession
は、拡張せずに StatefulKnowledgeSession
をラップします。その主なことは、デシジョンサービスタイプのシナリオに焦点を当てています。これにより、dispose()
を呼び出す必要がなくなります。ステートレスセッションは、Java コードからの反復挿入とメソッド呼び出し fireAllRules()
をサポートしません。execute()
を呼び出す動作は、StatefulKnowledgeSession
を内部にインスタンス化し、すべてのユーザーデータを追加してユーザーコマンドを実行し、fireAllRules()
を呼び出してから、単一のショットメソッドです。dispose()
このクラスを使用する主な方法は、BatchExecution
( Command
インターフェイスでサポートされるサブインターフェイス)を使用することですが、単純なオブジェクト挿入のみが必要な場合には、2 つの便利なメソッドが提供されます。CommandExecutor
CommandExecutor
および BatchExecution
は、独自のセクションで詳しく話されています。
11.19. コレクションを使用した StatelessKnowledgeSession の実行
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kbuilder.add( ResourceFactory.newFileSystemResource( fileName ), ResourceType.DRL ); if (kbuilder.hasErrors() ) { System.out.println( kbuilder.getErrors() ); } else { KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() ); StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession(); ksession.execute( collection ); }
11.20. InsertElements コマンドを使用した StatelessKnowledgeSession の実行
ksession.execute( CommandFactory.newInsertElements( collection ) );
CommandFactory.newInsert(collection)
を使用します。
11.21. BatchExecutionHelper
CommandFactory
のメソッドでは、サポートされるコマンドを作成します。これらはすべて XStream と BatchExecutionHelper
を使用してマーシャリングできます。BatchExecutionHelper
XML 形式の詳細と、JBoss Rules Pipeline を使用して BatchExecution
および ExecutionResults
のマーシャリングを自動化する方法を説明します。
11.22. CommandExecutor インターフェイス
CommandExecutor
インターフェイスでは、ユーザーは out パラメーターを使用してデータをエクスポートできます。つまり、挿入されたファクト、グローバル、およびクエリーの結果はすべて、このインターフェイスを使用して返されることができます。
11.23. Out Identifiers
// Set up a list of commands List cmds = new ArrayList(); cmds.add( CommandFactory.newSetGlobal( "list1", new ArrayList(), true ) ); cmds.add( CommandFactory.newInsert( new Person( "jon", 102 ), "person" ) ); cmds.add( CommandFactory.newQuery( "Get People" "getPeople" ); // Execute the list ExecutionResults results = ksession.execute( CommandFactory.newBatchExecution( cmds ) ); // Retrieve the ArrayList results.getValue( "list1" ); // Retrieve the inserted Person fact results.getValue( "person" ); // Retrieve the query as a QueryResults instance. results.getValue( "Get People" );
第12章 モードとメソッド
12.1. 順次モード
12.2. 順次モードオプション
- ルールセットの顕著性および位置(ルールの端末ノードに sequence 属性を設定して)ルールの順序を設定します。
- 配列を作成します(可能なルールのアクティベーションごとに 1 つの要素)。要素の位置は、実行順序を示します。
- right-input オブジェクトメモリーを除く、すべてのノードメモリーをオフにします。
- 左入力アダプターノードの伝播を切断し、オブジェクトとノードを Command オブジェクトで参照できるようにします。これは、後で実行するために作業メモリーのリストに追加されます。
- すべてのオブジェクトをアサートします。すべてのアサーションが終了し、right-input ノードメモリーが設定されると、Command リストを確認して、それぞれを順番に実行できます。
- 結果となるすべてのアクティベーションは、ルールで決定されたシーケンス番号に基づいてアレイに配置する必要があります。反復範囲を減らすために、最初と最後に生成された要素を記録します。
- Activations の配列を繰り返し、入力された要素を順番に実行します。
- 許可されるルール実行の最大数がある場合は、そのアレイ内のすべてのルールを実行する早い段階でネットワーク評価を終了します。
12.3. 順次モードのアクティブ化
手順12.1 タスク
- ステートレスセッションを開始します。
- 順次モードは、デフォルトではオフになります。これを有効にするには、
RuleBaseConfiguration.setSequential(true)
を呼び出します。または、ルールベース設定プロパティーdrools.sequential
を true に設定します。 - 順次モードが動的アジェンダにフォールバックできるようにするには、
SequentialAgenda.DYNAMIC
でsetSequentialAgenda
を呼び出します。 - オプションで、
JBossRules.sequential.agenda
プロパティーをsequential
またはdynamic
に設定します。
12.4. CommandFactory
CommandFactory
オブジェクトを使用すると、ステートレスセッションでコマンドを実行できます。これで、ファクトリーはセッションを破棄する前に fireAllRules()
を実行します。
12.5. サポートされる CommandFactory オプション
- FireAllRules
- GetGlobal
- SetGlobal
- InsertObject
- InsertElements
- Query
- StartProcess
- batchExecution
12.6. Insert コマンド
InsertObject
オプションの out 識別子を持つ単一のオブジェクトを挿入します。InsertElements
各要素を挿入する Iterable を繰り返し処理します。これにより、ステートレスナレッジセッションはクエリーを任意の順序で処理または実行できます。
12.7. コマンドの挿入例
StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession(); ExecutionResults bresults = ksession.execute( CommandFactory.newInsert( new Car( "sedan" ), "sedan_id" ) ); Sedan sedan = bresults.getValue( "sedan_id" );
12.8. 実行方法
ExecutionResults
インスタンスを返します。これにより、stilton_id
などの out 識別子を指定すると、任意のコマンド結果にアクセスできるようになります。
12.9. 実行方法の例
StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession(); Command cmd = CommandFactory.newInsertElements( Arrays.asList( Object[] { new Car( "sedan" ), new Car( "hatchback" ), new Car( "convertible" ), }); ExecutionResults bresults = ksession.execute( cmd );
12.10. BatchExecution コマンド
BatchExecution
コマンドを使用すると、複数のコマンドを一度に実行できます。これは、コマンドの一覧から作成される複合コマンドを表します。を実行すると一覧を繰り返し処理し、各コマンドを順次実行します。つまり、一部のオブジェクトを挿入し、プロセスを開始し、fireAllRules を呼び出してクエリーを実行することができます(すべて 1 つの execute(...)
呼び出し)。
12.11. The FireAllRules Command
FireAllRules
コマンドは、最後にルールの自動実行を無効にします。これは、手動のオーバーライド機能の一種です。
12.12. Out Identifiers
12.13. アウト識別子の例
StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession(); List cmds = new ArrayList(); cmds.add( CommandFactory.newInsertObject( new Car( "red", 1), "red") ); cmds.add( CommandFactory.newStartProcess( "process cars" ) ); cmds.add( CommandFactory.newQuery( "cars" ) ); ExecutionResults bresults = ksession.execute( CommandFactory.newBatchExecution( cmds ) ); Car red = ( Car ) bresults.getValue( "red" ); QueryResults qresults = ( QueryResults ) bresults.getValue( "cars" );
ExecutionResults
にデータを投入しています。query コマンドはデフォルトでクエリー名と同じ識別子を使用しますが、別の識別子にマップすることもできます。
12.14. 実行 XML の例
<batch-execution> <insert out-identifier='outRed'> <org.drools.Car> <type>red</type> <price>25000</price> <oldPrice>0</oldPrice> </org.drools.Car> </insert> </batch-execution>
<execution-results> <result identifier='outBlue'> <org.drools.Car> <type>Blue</type> <oldPrice>25</oldPrice> <price>30000</price> </org.drools.Car> </result> </execution-results>
12.15. 実行マーシャリングの例
<batch-execution> <insert out-identifier="sedan"> <org.drools.Car> <type>sedan</type> <price>1</price> <oldPrice>0</oldPrice> </org.drools.Car> </insert> <query out-identifier='cars2' name='carsWithParams'> <string>hatchback</string> <string>sedan</string> </query> </batch-execution>
CommandExecutor
は ExecutionResults
を返します。これはパイプラインコードスニペットでも処理されます。上記の <batch-execution> XML サンプルと同様の出力は以下のようになります。
<execution-results> <result identifier="sedan"> <org.drools.Car> <type>sedan</type> <price>2</price> </org.drools.Car> </result> <result identifier='cars2'> <query-results> <identifiers> <identifier>car</identifier> </identifiers> <row> <org.drools.Car> <type>hatchback</type> <price>2</price> <oldPrice>0</oldPrice> </org.drools.Car> </row> <row> <org.drools.Car> <type>hatchback</type> <price>1</price> <oldPrice>0</oldPrice> </org.drools.Car> </row> </query-results> </result> </execution-results>
12.16. batch-execution とコマンドの例
- 現在、スキーマ検証をサポートする XML スキーマはありません。これは基本的な形式です。ルート要素は <batch-execution> で、これには 0 個以上の commands 要素を含めることができます。
<batch-execution> ... </batch-execution>
- insert 要素は "out-identifier" 属性を特長とし、挿入されたオブジェクトは結果ペイロードの一部として返されます。
<batch-execution> <insert out-identifier='userVar'> ... </insert> </batch-execution>
- <insert-elements> 要素を使用してオブジェクトのコレクションを挿入することもできます。このコマンドは out-identifier をサポートしません。
org.domain.UserClass
は、XStream がシリアライズするユーザーオブジェクトです。<batch-execution> <insert-elements> <org.domain.UserClass> ... </org.domain.UserClass> <org.domain.UserClass> ... </org.domain.UserClass> <org.domain.UserClass> ... </org.domain.UserClass> </insert-elements> </batch-execution>
<set-global>
要素は、セッションのグローバルを設定します。<batch-execution> <set-global identifier='userVar'> <org.domain.UserClass> ... </org.domain.UserClass> </set-global> </batch-execution>
<set-global>
は、out
とout-identifier
の 2 つのオプション属性もサポートします。ブール値の true 値は、識別子
属性からの名前を使用して、グローバルを<batch-execution-results>
ペイロードに追加します。out-identifier
はout
のように機能しますが、さらに<batch-execution-results>
ペイロードで使用される識別子を上書きできます。<batch-execution> <set-global identifier='userVar1' out='true'> <org.domain.UserClass> ... </org.domain.UserClass> </set-global> <set-global identifier='userVar2' out-identifier='alternativeUserVar2'> <org.domain.UserClass> ... </org.domain.UserClass> </set-global> </batch-execution>
- コンテンツのない
<get-global>
要素があります。out-identifier
属性のみがあります。値の取得は<get-global>
要素の唯一の目的であるため、out
属性は必要ありません。<batch-execution> <get-global identifier='userVar1' /> <get-global identifier='userVar2' out-identifier='alternativeUserVar2'/> </batch-execution>
- query コマンドは、パラメータークエリーとパラメーターレスクエリーの両方をサポートします。
name
属性は呼び出されるクエリーの名前で、out-identifier
はクエリーに使用される識別子で、<execution-results>
ペイロードになります。<batch-execution> <query out-identifier='cars' name='cars'/> <query out-identifier='cars2' name='carsWithParams'> <string>red</string> <string>blue</string> </query> </batch-execution>
<start-process>
コマンドは、任意のパラメーターを受け入れます。<batch-execution> <startProcess processId='org.drools.actions'> <parameter identifier='person'> <org.drools.TestVariable> <name>John Doe</name> </org.drools.TestVariable> </parameter> </startProcess> </batch-execution
- signal event コマンドを使用すると、プロセスを特定できます。
<signal-event process-instance-id='1' event-type='MyEvent'> <string>MyValue</string> </signal-event>
- 完全なワークアイテムコマンドは、プロセスが完了したときにユーザーに通知します。
<complete-work-item id='" + workItem.getId() + "' > <result identifier='Result'> <string>SomeOtherString</string> </result> </complete-work-item>
- abort work item コマンドを使用すると、実行中にプロセスをキャンセルできます。
<abort-work-item id='21' />
12.17. The MarshallerFactory
MarshallerFactory
は、ステートフルセッションをマーシャリングおよびアンマーシャリングするために使用されます。
12.18. マーシャラーの例
// ksession is the StatefulKnowledgeSession // kbase is the KnowledgeBase ByteArrayOutputStream baos = new ByteArrayOutputStream(); Marshaller marshaller = MarshallerFactory.newMarshaller( kbase ); marshaller.marshall( baos, ksession ); baos.close();
12.19. マーシャリングオプション
表12.1 ** テーブルタイトル **
オプション | Description |
---|---|
ObjectMarshallingStrategy | このインターフェイスはマーシャリングの実装を提供し、柔軟性を高めることができます。 |
SerializeMarshallingStrategy |
これは、ユーザーインスタンスで
Serializable または Externalizable メソッドを呼び出すデフォルトのストラテジーです。
|
IdentityMarshallingStrategy |
このストラテジーは、各ユーザーオブジェクトの整数 ID を作成し、id がストリームに書き込まれる間に Map に保存します。
マーシャリングを解除すると、
IdentityMarshallingStrategy マップにアクセスしてインスタンスを取得します。つまり、IdentityMarshallingStrategy を使用する場合、これは Marshaller インスタンスの有効期間間ステートフルであり、ID を作成し、マーシャリングしようとするすべてのオブジェクトへの参照を保持することを意味します。
|
12.20. IdentityMarshallingStrategy の例
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectMarshallingStrategy oms = MarshallerFactory.newIdentityMarshallingStrategy() Marshaller marshaller = MarshallerFactory.newMarshaller( kbase, new ObjectMarshallingStrategy[]{ oms } ); marshaller.marshall( baos, ksession ); baos.close();
12.21. The ObjectMarshallingStrategyAcceptor
ObjectMarshallingStrategyAcceptor
は、各オブジェクトマーシャリングストラテジーに含まれるインターフェイスです。Marshaller にはストラテジーのチェーンがあります。ユーザーオブジェクトの読み取りまたは書き込みを試行すると、ObjectMarshallingStrategyAcceptor を使用して、ユーザーオブジェクトのマーシャリングに使用するかどうかを決定します。
12.22. ClassFilterAcceptor 実装
ClassFilterAcceptor
実装を使用すると、文字列とワイルドカードを使用してクラス名を照合できます。デフォルトは *.*" です。
12.23. アクセプターを使用した IdentityMarshallingStrategy
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectMarshallingStrategyAcceptor identityAcceptor = MarshallerFactory.newClassFilterAcceptor( new String[] { "org.domain.pkg1.*" } ); ObjectMarshallingStrategy identityStrategy = MarshallerFactory.newIdentityMarshallingStrategy( identityAcceptor ); ObjectMarshallingStrategy sms = MarshallerFactory.newSerializeMarshallingStrategy(); Marshaller marshaller = MarshallerFactory.newMarshaller( kbase, new ObjectMarshallingStrategy[]{ identityStrategy, sms } ); marshaller.marshall( baos, ksession ); baos.close();
12.24. JBoss ルールの永続性およびトランザクション
12.25. トランザクションの例
Environment env = KnowledgeBaseFactory.newEnvironment(); env.set( EnvironmentName.ENTITY_MANAGER_FACTORY, Persistence.createEntityManagerFactory( "emf-name" ) ); env.set( EnvironmentName.TRANSACTION_MANAGER, TransactionManagerServices.getTransactionManager() ); // KnowledgeSessionConfiguration may be null, and a default will be used StatefulKnowledgeSession ksession = JPAKnowledgeService.newStatefulKnowledgeSession( kbase, null, env ); int sessionId = ksession.getId(); UserTransaction ut = (UserTransaction) new InitialContext().lookup( "java:comp/UserTransaction" ); ut.begin(); ksession.insert( data1 ); ksession.insert( data2 ); ksession.startProcess( "process1" ); ut.commit();
12.26. JPA の使用
手順12.2 タスク
- 環境が
EntityManagerFactory
とTransactionManager
の両方で設定されていることを確認してください。 - GUI またはコマンドラインから JPA を起動します。
- id を使用して、以前に永続化したステートフルナレッジセッションをロードします。ロールバックが発生すると ksession 状態もロールバックされ、ロールバック後も引き続き使用できます。
12.27. JPA を使用した StatefulKnowledgeSession の読み込み
StatefulKnowledgeSession ksession = JPAKnowledgeService.loadStatefulKnowledgeSession( sessionId, kbase, null, env );
12.28. JPA の設定
<persistence-unit name="org.drools.persistence.jpa" transaction-type="JTA"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>jdbc/BitronixJTADataSource</jta-data-source> <class>org.drools.persistence.session.SessionInfo</class> <class>org.drools.persistence.processinstance.ProcessInstanceInfo</class> <class>org.drools.persistence.processinstance.ProcessInstanceEventInfo</class> <class>org.drools.persistence.processinstance.WorkItemInfo</class> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/> <property name="hibernate.max_fetch_depth" value="3"/> <property name="hibernate.hbm2ddl.auto" value="update" /> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.BTMTransactionManagerLookup" /> </properties> </persistence-unit>
12.29. JTA DataSource の設定
PoolingDataSource ds = new PoolingDataSource(); ds.setUniqueName( "jdbc/BitronixJTADataSource" ); ds.setClassName( "org.h2.jdbcx.JdbcDataSource" ); ds.setMaxPoolSize( 3 ); ds.setAllowLocalTransactions( true ); ds.getDriverProperties().put( "user", "sa" ); ds.getDriverProperties().put( "password", "sasa" ); ds.getDriverProperties().put( "URL", "jdbc:h2:mem:mydb" ); ds.init();
12.30. JNDI プロパティー
java.naming.factory.initial=bitronix.tm.jndi.BitronixInitialContextFactory
12.31. ナレッジベースの名前空間
- deftemplate
- defrule
- deffunction
- and/or/not/exists/test 条件要素
- リテラル、変数、戻り値、および述語フィールドの制約
第13章 スプレッドシート形式のデシジョンテーブルの使用
13.1. ハードキーワード
true
、false
などの単語で、コマンドに対して間違いがある可能性があります。
13.2. ソフトキーワード
13.3. ソフトキーワードの一覧
lock-on-active
date-effective
date-expires
no-loop
auto-focus
activation-group
agenda-group
ruleflow-group
entry-point
duration
package
import
dialect
salience
enabled
attributes
rule
extend
- when
- 次に、以下を実行します。
template
query
declare
function
global
eval
not
in
または
および
exists
forall
- accumulate
- collect
- from
action
reverse
result
end
- over
init
13.4. コメント
13.5. 単一行コメントの例
rule "Testing Comments" when // this is a single line comment eval( true ) // this is a comment in the same line of a pattern then // this is a comment inside a semantic code block end
13.6. 複数行のコメントの例
rule "Test Multi-line Comments" when /* this is a multi-line comment in the left hand side of a rule */ eval( true ) then /* and this is a multi-line comment in the right hand side of a rule */ end
13.7. エラーメッセージ
- 101: no viable alternative
- パーサーが決定ポイントになり、代替を特定できなかったことを示します。
- [ERR 101] Line 3:2 no viable alternative at input 'WHEN'
- このメッセージは、ルール名がないため、パーサーが間違った場所にあるトークン
WHEN
(ハードキーワード)が発生したことを意味します。 - [ERR 101] Line 0:-1 no viable alternative at input '<eof>' in rule simple_rule in pattern [name]
- オープン引用符、アポストロフィ、または括弧を示します。
- 102: mismatched input
- パーサーが特定のシンボルを検索していた場合、これが現在の入力位置で終了していないことを示します。
- [ERR 102] Line 0:-1 mismatched input '<eof>' expecting ')' in rule simple_rule in pattern [name]
- このエラーは、ルールステートメントが不完全の結果です。通常、0:-1 の位置を取得すると、パーサーがソースの最後に到達したことを意味します。
- 103: failed predicate
- セマンティック述語の検証が false と評価されました。通常、これらのセマンティック述語はソフトキーワードを識別するために使用されます。
- 104: trailing semi-colon not allowed
- このエラーは、式がセミコロンで終了できない
eval
句に関連付けられています。 - 105: early Exit
- アバイザーは文法のサブルールになり、少なくとも 1 回は代替の選択肢に一致する必要がありますが、サブルールはいずれにも一致しませんでした。
13.8. パッケージ
13.9. インポートステートメント
java.lang
からもインポートします。
13.10. グローバルの使用
- ルールファイルでグローバル変数を宣言し、ルールで使用します。以下に例を示します。
global java.util.List myGlobalList; rule "Using a global" when eval( true ) then myGlobalList.add( "Hello World" ); end
- ワーキングメモリーにグローバル値を設定します。ファクトをワーキングメモリーにアサートする前に、グローバル値をすべて設定することが推奨されます。以下に例を示します。
List list = new ArrayList(); WorkingMemory wm = rulebase.newStatefulSession(); wm.setGlobal( "myGlobalList", list );
13.11. From 要素
13.12. 電子メールサービスでのグローバルの使用
手順13.1 タスク
- ルールエンジンを呼び出す統合コードを開きます。
- emailService オブジェクトを取得してから、作業メモリーに設定します。
- DRL では、emailService タイプのグローバルがあり、名前が email であることを宣言します。
- ルールの結果では、email.sendSMS (number, message)などのものを使用できます。警告グローバルはルール間でデータを共有するように設計されていないため、その目的に使用しないでください。ルールは常に、ワーキングメモリーの状態に関して推論し、これに対応するため、ルールからルールにデータを渡す場合は、データをファクトとしてワーキングメモリーにアサートします。重要ルール内からグローバル値を設定または変更しないでください。ワーキングメモリーインターフェイスを使用して、アプリケーションから値を常に設定することが推奨されます。
第14章 関数
14.1. 関数
then
)部分に対してアクションを呼び出すのに最も役立ちます。
14.2. 関数宣言の例
function String hello(String name) { return "Hello "+name+"!"; }
function
キーワードは、技術的に Java の一部ではない場合でも、使用されることに注意してください。関数へのパラメーターは、メソッドの として定義されます。パラメーターが必要ない場合は指定する必要はありません。戻り値の型は、通常のメソッドと同様に定義されます。
14.3. 静的メソッドによる関数宣言の例
Foo.hello()
)の static メソッドを示しています。JBoss Rules は関数インポートの使用をサポートするため、以下のコードのみを入力する必要があります。
import function my.package.Foo.hello
14.4. 関数宣言の例の呼び出し
rule "using a static function" when eval( true ) then System.out.println( hello( "Bob" ) ); end
14.5. 型宣言
14.6. タイプ宣言ロール
表14.1 ** テーブルタイトル **
Role | Description |
---|---|
新しいタイプの宣言 |
プレーンな Java オブジェクトをファクトとして使用し、すぐに使用できる JBoss ルール。ただし、ユーザーがルールエンジンに直接モデルを定義する場合は、新しいタイプを宣言することで実行できます。これは、すでにビルドされているドメインモデルがある場合にも使用できますが、ユーザーはこのモデルを、理由処理中に主に使用する追加のエンティティーで補完します。
|
メタデータの宣言 |
ファクトにはメタ情報が関連付けられている可能性があります。メタデータ情報の例には、ファクト属性で表現されず、そのファクトタイプのすべてのインスタンス間で一貫性のあるあらゆる種類のデータが含まれます。このメタ情報はエンジンによってランタイム時にクエリーされ、推論(reasoning)プロセスで使用できます。
|
14.7. 新規タイプの宣言
declare
が使用され、フィールドの一覧とキーワード end
が使用されます。新しいファクトにはフィールドの一覧が必要です。そうしないと、エンジンはクラスパスで既存のファクトクラスを検索し、見つからない場合はエラーを発生させます。
14.8. 新しいファクトタイプの例の宣言
Address
という新しいファクトタイプが使用されます。このファクトタイプには、number
、streetName
、および city
の 3 つの属性があります。各属性には、ユーザーが作成した他のクラスや以前に宣言した他のクラスなど、有効な Java タイプであることができるタイプがあります。
declare Address number : int streetName : String city : String end
14.9. 新しいファクトタイプの追加例を宣言する
Person
の例を使用します。dateOfBirth
java.util.Date
型(Java API からの)で、address
はファクトタイプ Address です。
declare Person name : String dateOfBirth : java.util.Date address : Address end
14.10. インポート例の使用
import
機能を使用する方法を示しています。これにより、完全修飾クラス名を使用する必要がなくなります。
import java.util.Date declare Person name : String dateOfBirth : Date address : Address end
14.11. 生成された Java クラス
14.12. 生成された Java クラスの例
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/hashCode // toString }
14.13. ルールでの宣言タイプの使用例
rule "Using a declared Type" when $p : Person( name == "Bob" ) then // Insert Mark, who is Bob's manager. Person mark = new Person(); mark.setName("Mark"); insert( mark ); end
14.14. メタデータの宣言
@metadata_key( metadata_value )
14.15. メタデータ属性の操作
14.16. ファクトタイプを使用したメタデータ属性の宣言例
@author
および @dateOfCreation
)に宣言された 2 つのメタデータ項目があり、name 属性(@key
および @maxLength
)用にさらに 2 つの定義があります。@key
メタデータには必須の値がないため、括弧と値は省略されています。
import java.util.Date declare Person @author( Bob ) @dateOfCreation( 01-Feb-2009 ) name : String @key @maxLength( 30 ) dateOfBirth : Date address : Address end
14.17. @position 属性
@position
属性を使用すると、フィールドの位置を宣言し、デフォルトの宣言した順序を上書きすることができます。これは、パターンの位置制約に使用されます。
14.18. @position の例
declare Cheese name : String @position(1) shop : String @position(2) price : int @position(0) end
14.19. 事前定義されたクラスレベルのアノテーション
表14.2 事前定義されたクラスレベルのアノテーション
Annotation | Description |
---|---|
@role( <fact | event> ) |
この属性は、ロールをファクトおよびイベントに割り当てるために使用できます。
|
@typesafe( <boolean> ) |
デフォルトでは、すべてのタイプ宣言は型安全性が有効な状態でコンパイルされます。
@typesafe( false ) フォールバックを許可し、すべての制約が MVEL 制約として生成され、動的に実行される安全でない評価のタイプを許可することにより、この動作を上書きする手段を提供します。これは、一般的なコレクションではない場合や、タイプが混同されているコレクションを処理する場合に便利です。
|
@timestamp( <attribute name> ) |
タイムスタンプを作成します。
|
@duration( <attribute name> ) |
属性の実装の期間を設定します。
|
@expires( <time interval> ) |
属性の有効期限が切れるタイミングを定義できます。
|
@propertyChangeSupport |
Javabean 仕様に定義されているプロパティー変更のサポートを実装するファクトにアノテーションを付け、エンジンがファクトプロパティーの変更をリッスンするように登録できるようになりました。
|
@propertyReactive | type プロパティーをリアクティブにします。 |
14.20. @Key 属性関数
- 属性はタイプのキー識別子として使用されるため、このタイプのインスタンスを比較するときに、生成されたクラスは 属性を考慮に入れて equals ()メソッドおよび hashCode ()メソッドを実装します。
- JBoss Rules は、すべてのキー属性をパラメーターとして使用してコンストラクターを生成します。
14.21. @Key 宣言の例
declare Person firstName : String @key lastName : String @key age : int end
14.22. キーアーキテクトの例を使用したインスタンスの作成
Person person = new Person( "John", "Doe" );
14.23. 位置引数
@position
属性で定義されます。
14.24. 位置引数の例
declare Cheese name : String shop : String price : int end
declare Cheese name : String @position(1) shop : String @position(2) price : int @position(0) end
14.25. @Position アノテーション
14.26. パターンの例
Cheese( "stilton", "Cheese Shop", p; ) Cheese( "stilton", "Cheese Shop"; p : price ) Cheese( "stilton"; shop == "Cheese Shop", p : price ) Cheese( name == "stilton"; shop == "Cheese Shop", p : price )
第15章 追加の宣言
15.1. 既存タイプのメタデータの宣言
15.2. 既存タイプのメタデータの宣言例
import org.drools.examples.Person declare Person @author( Bob ) @dateOfCreation( 01-Feb-2009 ) end
15.3. 完全修飾クラス名を使用したメタデータの宣言例
declare org.drools.examples.Person @author( Bob ) @dateOfCreation( 01-Feb-2009 ) end
15.4. 宣言タイプの例用のパラメーター化されたコンストラクター
declare Person firstName : String @key lastName : String @key age : int end
Person() // parameterless constructor Person( String firstName, String lastName ) Person( String firstName, String lastName, int age )
15.5. 非タイプセーフクラス
15.6. アプリケーションコードから宣言タイプへのアクセス
15.7. タイプの宣言
package org.drools.examples import java.util.Date declare Person name : String dateOfBirth : Date address : Address end
15.8. API の例を使用した宣言的ファクトタイプの処理
// get a reference to a knowledge base with a declared type: KnowledgeBase kbase = ... // get the declared FactType FactType personType = kbase.getFactType( "org.drools.examples", "Person" ); // handle the type as necessary: // create instances: Object bob = personType.newInstance(); // set attributes values personType.set( bob, "name", "Bob" ); personType.set( bob, "age", 42 ); // insert fact into a session StatefulKnowledgeSession ksession = ... ksession.insert( bob ); ksession.fireAllRules(); // read attributes String name = personType.get( bob, "name" ); int age = personType.get( bob, "age" );
15.9. タイプ宣言の拡張
15.10. タイプ宣言の拡張例
extends
アノテーションの使用を示しています。
import org.people.Person declare Person end declare Student extends Person school : String end declare LongTermStudent extends Student years : int course : String end
15.11. 特性
@format(trait)
アノテーションが DRL の宣言に追加されます。
15.12. トレイトの例
declare GoldenCustomer @format(trait) // fields will map to getters/setters code : String balance : long discount : int maxExpense : long end
when $c : Customer() then GoldenCustomer gc = don( $c, Customer.class ); end
15.13. コアオブジェクトおよびトレイト
15.14. @Traitable Example
declare Customer @Traitable code : String balance : long end
15.15. トレイトを使用したルールの作成
15.16. トレイトを使用したルールの例
when $o: OrderItem( $p : price, $code : custCode ) $c: GoldenCustomer( code == $code, $a : balance, $d: discount ) then $c.setBalance( $a - $p*$d ); end
15.17. 非表示のフィールド
15.18. 2 つのパートナープロキシー
15.19. ラッパー
15.20. ラッパーの例
when $sc : GoldenCustomer( $c : code, // hard getter $maxExpense : maxExpense > 1000 // soft getter ) then $sc.setDiscount( ... ); // soft setter end
15.21. isA アノテーションを持つラッパーの例
$sc : GoldenCustomer( $maxExpense : maxExpense > 1000, this isA "SeniorCustomer" )
15.22. トレイトの削除
- 論理ド
- トレイト操作により、プロキシーの論理挿入が行われます。
then don( $x, // core object Customer.class, // trait class true // optional flag for logical insertion )
- shed キーワード
- shed キーワードにより、指定の引数タイプに対応するプロキシーが取り消されます。
then Thing t = shed( $x, GoldenCustomer.class )
この操作は、org.drools.factmodel.traits.Thing インターフェイスを実装する別のプロキシーを返します。ここで、getFields ()メソッドおよび getCore ()メソッドが定義されます。内部的には、宣言された特性はすべて生成されます(指定された他の特性に加えて)。これにより、ラッパーをソフトフィールドで保持でき、それ以外は失われます。
15.23. ルール構文の例
rule "<name>" <attribute>* when <conditional element>* then <action>* end
15.24. タイマー属性の例
timer
属性の例です。
timer ( int: <initial delay> <repeat interval>? ) timer ( int: 30s ) timer ( int: 30s 5m ) timer ( cron: <cron expression> ) timer ( cron:* 0/15 * * * ? )
15.25. タイマー
- Interval
- タイマーの間隔(int: で示されます)は、java.util.Timer オブジェクトのセマンティクスに従い、初期遅延とオプションの繰り返し間隔を使用します。
- Cron
- cron (cron: で示されます)タイマーは、標準の Unix cron 式に従います。
15.26. Cron タイマーの例
rule "Send SMS 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
15.27. calendars
15.28. Quartz カレンダーの例
Calendar weekDayCal = QuartzHelper.quartzCalendarAdapter(org.quartz.Calendar quartzCal)
15.29. カレンダーの登録
手順15.1 タスク
- StatefulKnowledgeSession を起動します。
- 次のコードを使用してカレンダーを登録します。
ksession.getCalendars().set( "weekday", weekDayCal );
- カレンダーとタイマーを同時に使用する場合は、以下のコードを使用します。
rule "weekdays are high priority" calendars "weekday" timer (int:0 1h) when Alarm() then send( "priority high - we have an alarm” ); end rule "weekend are low priority" calendars "weekend" timer (int:0 4h) when Alarm() then send( "priority low - we have an alarm” ); end
15.30. 左辺(Left Hand Side)
15.31. 条件要素
および
です。いずれの方法でも接続されていないルールの LHS に複数のパターンがある場合は暗黙的になります。
15.32. Conditional 要素のないルールの例
rule "no CEs" when // empty then ... // actions (executed once) end // The above rule is internally rewritten as: rule "eval(true)" when eval( true ) then ... // actions (executed once) end
第16章 パターン
16.1. パターン
16.2. パターンの例
rule "2 unconnected patterns" when Pattern1() Pattern2() then ... // actions end // The above rule is internally rewritten as: rule "2 and connected patterns" when Pattern1() and Pattern2() then ... // actions end
および には、
先頭の宣言バインディングを含めることはできません。これは、宣言が一度に 1 つのファクトのみを参照し、と が満たされると両方のファクトに一致するためです。
16.3. パターンマッチング
16.4. パターンバインディング
$p
などのパターンバインディング変数を使用して実行できます。
16.5. 変数の例を使用したパターンバインディング
rule ... when $p : Person() then System.out.println( "Person " + $p ); end
$
)は必須ではありません。
16.6. 制約
true
または false
を返す式です。たとえば、5 の状態が 6 未満である制約を設定できます。
第17章 要素および変数
17.1. Java Bean (POJO)のプロパティーアクセス
getMyProperty
()(また はプリミティブブール値の場合は isMyProperty
())で、引数なしで何かを返します。
Introspector
クラスを使用してこのマッピングを行うため、標準の Java Bean 仕様に従います。
17.2. POJO の例
Person( age == 50 ) // this is the same as: Person( getAge() == 50 )
- age プロパティー
- age プロパティーは、ゲッター
getAge ()
ではなく DRL でage
として記述されます。 - プロパティーアクセサー
- フィールドインデックス作成によるパフォーマンスの向上により、ゲッター(
getAge
())の代わりにプロパティーアクセス(age
)を使用できます。
17.3. POJO の使用
手順17.1 タスク
- 以下の例を確認してください。
public int getAge() { Date now = DateUtil.now(); // Do NOT do this return DateUtil.differenceInYears(now, birthday); }
- この問題を解決するには、現在の日付を作業メモリーにラップするファクトを挿入し、必要に応じてそのファクトを
fireAllRules
の間で更新します。
17.4. POJO フォールバック
17.5. フォールバックの例
Person( age == 50 ) // If Person.getAge() does not exists, this falls back to: Person( age() == 50 )
Person( address.houseNumber == 50 ) // this is the same as: Person( getAddress().getHouseNumber() == 50 )
houseNumber
が変更されると、その Address
が指定された Person
は更新済みとしてマークされる必要があります。
17.6. Java 式
表17.1 Java 式
機能 | 例 |
---|---|
パターンの括弧内の制約として
ブール値 を返す任意の Java 式を使用できます。Java 式は、プロパティーアクセスなどの他の式の拡張機能と組み合わせることができます。
|
Person( age == 50 ) |
評価の優先度は、ロジックや数学式のように括弧を使用して変更できます。
|
Person( age > 100 && ( age % 10 == 0 ) ) |
Java メソッドは再利用できます。
|
Person( Math.round( weight / ( height * height ) ) < 25.0 ) |
フィールドと値が異なるタイプの場合、タイプ強制は常に試行されます。不良強制を試行すると例外が出力されます。
|
Person( age == "10" ) // "10" is coerced to 10 |
Person( System.currentTimeMillis() % 1000 == 0 ) // Do NOT do this
==
および !=
以外の通常の Java セマンティクスがあります。
==
演算子には null 安全な equals ()セマンティクスが
あります。
// Similar to: java.util.Objects.equals(person.getFirstName(), "John") // so (because "John" is not null) similar to: // "John".equals(person.getFirstName()) Person( firstName == "John" )
!=
演算子には null 安全な !equals ()セマンティクスが
あります。
// Similar to: !java.util.Objects.equals(person.getFirstName(), "John") Person( firstName != "John" )
17.7. コンマ区切りの Operator
,
')が使用されます。暗黙的な接続セマンティクスがあります。
17.8. コンマ区切りの Operator の例
// Person is at least 50 and weighs at least 80 kg Person( age > 50, weight > 80 )
// Person is at least 50, weighs at least 80 kg and is taller than 2 meter. Person( age > 50, weight > 80, height > 2 )
、
)演算子は括弧などの複合制約式に埋め込むことはできません。
17.9. バインド変数
17.10. バインド変数の例
// 2 persons of the same age Person( $firstAge : age ) // binding Person( age == $firstAge ) // constraint expression
// Not recommended Person( $age : age * 2 < 100 )
// Recommended (separates bindings and constraint expressions) Person( age * 2 < 100, $age : age )
17.11. ユニフィケーション
17.12. ユニフィケーションの例
Person( $age := age ) Person( $age := age)
17.13. JBoss ルールのオプションおよび演算子
表17.2 JBoss ルールのオプションおよび演算子
オプション | 説明 | 例 |
---|---|---|
日付リテラル
|
日付形式
dd-mmm-yyyy はデフォルトでサポートされます。これをカスタマイズするには、drools.dateformat という名前のシステムプロパティーとして別の日付形式マスクを指定します。より詳細な制御が必要な場合は、制限を使用します。
|
Cheese( bestBefore < "27-Oct-2009" ) |
List および Map アクセス |
インデックスで
List 値に直接アクセスできます。
|
// Same as childList(0).getAge() == 18 Person( childList[0].age == 18 ) |
値キー |
キーで
Map 値に直接アクセスできます。
|
// Same as credentialMap.get("jsmith").isValid() Person( credentialMap["jsmith"].valid ) |
省略された組み合わせ比較条件
|
これにより、制限接続 &&
; または || を使用してフィールドに複数の制限を設定することができます。括弧によるグループ化が許可され、再帰的な構文パターンが発生します。
|
// 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" ) |
Operator |
Operator は自然順序付けのあるプロパティーで使用できます。たとえば、Date フィールドの < は、
String フィールドの の 前 を意味し、アルファベット順で小さいことを意味します。
|
Person( firstName < $otherFirstName ) Person( birthDate < $otherBirthDate ) |
Operator が一致する
|
有効な Java
regular expression に対してフィールドを一致させます。通常、regexp は文字列リテラルですが、有効な正規表現に解決される変数も使用できます。String プロパティーにのみ適用されます。null 値に対して matches を使用すると、常に false と評価されます。
|
Cheese( type matches "(Buffalo)?\\S*Mozarella" ) |
Operator が一致しない
|
文字列が正規表現と一致しない場合、演算子は true を返します。
matches 演算子と同じルールが適用されます。String プロパティーにのみ適用されます。
|
Cheese( type not matches "(Buffulo)?\\S*Mozarella" ) |
オペレーターに が含まれる
|
CheeseCounter( cheeses contains "stilton" ) // contains with a String literal CheeseCounter( cheeses contains $var ) // contains with a variable | |
Operator が含まれていない
|
含んで
いない演算子は、 れて いない かどうかを確認するために使用されます。これは Collection プロパティーにのみ適用されます。
|
CheeseCounter( cheeses not contains "cheddar" ) // not contains with a String literal CheeseCounter( cheeses not contains $var ) // not contains with a variable |
演算子 memberOf
|
演算子
memberOf は、フィールドがコレクションまたは配列のメンバーであるかどうかを確認するために使用されます。そのコレクションは変数である必要があります。
|
CheeseCounter( cheese memberOf $matureCheeses ) |
演算子が memberOf ではない
| memberOf 以外の演算子は、フィールドがコレクションまたは配列のメンバーではないかどうかを確認するために使用されます。そのコレクションは変数である必要があります。
|
CheeseCounter( cheese not memberOf $matureCheeses ) |
オペレーターのサウンドのような
|
この演算子は と
一致 するのと似ていますが、単語が指定の値とほぼ同じサウンド(英語の通知を使用)を持っているかどうかを確認します。
|
// match cheese "fubar" or "foobar" Cheese( name soundslike 'foobar' ) |
演算子 str
|
演算子
str は、String であるフィールドが特定の値で開始するか、または終了するかを確認するために使用されます。文字列の長さを確認するのにも使用できます。
|
Message( routingValue str[startsWith] "R1" ) Message( routingValue str[endsWith] "R2" ) Message( routingValue str[length] 17 ) |
複合値の制限
|
複合値の制限では、一致する値が複数ある場合に使用されます。現在、evaluators
で は現在、これ をサポートしていません 。この演算子の 2 番目のオペランドは、括弧で囲まれた値のコンマ区切りリストである必要があります。値は変数、リテラル、戻り値、または修飾識別子として指定できます。エバリュエーターはいずれも実際には 構文上の sugar で、演算子 != および == を使用して複数の制限のリストとして内部的に書き換えられます。
|
Person( $cheese : favouriteCheese ) Cheese( type in ( "stilton", "cheddar", $cheese ) ) |
17.14. Operator の優先順位
表17.3 Operator の優先順位
演算子のタイプ | 演算子 | 注記 |
---|---|---|
(ネストされた)プロパティーアクセス | をクリックします。 | 通常の Java セマンティクスではない |
List/Map アクセス | [ ] | 通常の Java セマンティクスではない |
制約バインディング | : | 通常の Java セマンティクスではない |
Multiplicative | * / % | |
加法 | + - | |
shift | << >> >>> | |
Relational | < > <= >= instanceof | |
等価 | == != | 通常の Java (ではなく)セマンティクスを使用しません。代わりに(ではなく) 等号 セマンティクスを使用します。 |
非短時間の回転 AND | & | |
非短時間排他的 OR | ^ | |
non-short circuiting inclusive OR | | | |
論理 AND | && | |
論理 OR | || | |
ternary | ? : | |
コンマ区切り AND | , | 通常の Java セマンティクスではない |
17.15. きめ細かなプロパティー変更リスナー
17.16. きめ細かなプロパティー変更リスナーの例
- DRL の例
declare Person @propertyReactive firstName : String lastName : String end
- Java クラスの例
@PropertyReactive public static class Person { private String firstName; private String lastName; }
17.17. 粒度の細かいプロパティー変更リスナーの使用
17.18. @watch でのパターンの使用
!
で開始し、ワイルドカード *
と !*
を使用してパターンで使用されるタイプのプロパティーをすべてリッスンするか、または何もリッスンするようにパターンによって明示的に除外できます。
17.19. @watch の例
// listens for changes on both firstName (inferred) and lastName Person( firstName == $expectedFirstName ) @watch( lastName ) // listens for all the properties of the Person bean Person( firstName == $expectedFirstName ) @watch( * ) // listens for changes on lastName and explicitly exclude firstName Person( firstName == $expectedFirstName ) @watch( lastName, !firstName ) // listens for changes on all the properties except the age one Person( firstName == $expectedFirstName ) @watch( *, !age )
17.20. @PropertySpecificOption の使用
on
オプションを使用して、デフォルトで @watch を有効にするか、完全に拒否できます。この新しい PropertySpecificOption には、以下の 3 つの値のいずれかを指定できます。
- DISABLED => the feature is turned off and all the other related annotations are just ignored - ALLOWED => this is the default behavior: types are not property reactive unless they are not annotated with @PropertySpecific - ALWAYS => all types are property reactive by default
17.21. 基本的な条件要素
表17.4 基本的な条件要素
名前 | 説明 | 例 | 追加オプション |
---|---|---|---|
および
|
Conditional 要素
および は、他の Conditional 要素を論理積にグループ化するために使用されます。JBoss ルールは 、 接頭辞 と インフィックス と の両方をサポート し ます。括弧を使用した明示的なグループ化をサポートします。従来の infix および prefix および を使用することもできます。
|
//infixAnd Cheese( cheeseType : type ) and Person( favouriteCheese == cheeseType ) //infixAnd with grouping ( Cheese( cheeseType : type ) and ( Person( favouriteCheese == cheeseType ) or Person( favouriteCheese == cheeseType ) ) |
接頭辞
および もサポートされます。
(and Cheese( cheeseType : type ) Person( favouriteCheese == cheeseType ) )
LHS のルート要素は暗黙的な接頭辞であるため
、 指定する必要はありません。
when Cheese( cheeseType : type ) Person( favouriteCheese == cheeseType ) then ... |
または
|
これは、2 つ以上の同様のルールを生成するためのショートカットです。JBoss ルールは、接頭辞
または infix の両方をサポートします。従来の infix、接頭辞、および明示的なグループ化の括弧を使用できます。
|
//infixOr Cheese( cheeseType : type ) or Person( favouriteCheese == cheeseType ) //infixOr with grouping ( Cheese( cheeseType : type ) or ( Person( favouriteCheese == cheeseType ) and Person( favouriteCheese == cheeseType ) ) (or Person( sex == "f", age > 60 ) Person( sex == "m", age > 65 ) |
オプションのパターンバインディングを許可します。各パターンは、ディープ変数を使用して個別にバインドする必要があります。
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 ) ) |
not
|
これにより、存在しないと指定されたオブジェクトが作業メモリーに含まれていないことを確認します。これは、適用する条件要素の括弧の後に続きます。(単一のパターンでは、括弧を省略できます。)
|
// Brackets are optional:
not Bus(color == "red")
// Brackets are optional:
not ( Bus(color == "red", number == 42) )
// "not" with nested infix
| |
exists |
これにより、ワーキングメモリーがチェックされ、指定したアイテムが存在するかどうかを確認します。キーワードが
存在 するには、適用する CE の周りの括弧が続く必要があります。(単一のパターンでは、括弧を省略できます。)
|
exists Bus(color == "red")
// brackets are optional:
exists ( Bus(color == "red", number == 42) )
// "exists" with nested infix
| |
また
は の動作は、フィールド制約の制約と制約のために接続 ||
とは異なります。エンジンは Conditional 要素 また
は を解釈できません。代わりに、また
は が指定されたルールは、複数のサブルールとして書き換えられます。このプロセスにより、最終的には、ルートノードおよび各 CE に 1 つのサブルールを持つルールが作成されます。
各サブルールは通常のルールと同様にアクティベートおよび実行できます。これらのサブルールの間には、特別な動作や対話はありません。
17.22. 条件要素 Forall
Forall
他の CE 内でネストできます。たとえば、forall
は not
CE 内で使用できます。オプションの括弧は 1 つのパターンのみであるため、ネストされた forall
括弧を使用する必要があります。
17.23. forall の例
- true への評価
rule "All English buses are red" when forall( $bus : Bus( type == 'english') Bus( this == $bus, color = 'red' ) ) then // all English buses are red end
- 単一のパターン forall
rule "All Buses are Red" when forall( Bus( color == 'red' ) ) then // all Bus facts are red end
- マルチパターン forall
rule "all employees have health and dental care programs" when forall( $emp : Employee() HealthCare( employee == $emp ) DentalCare( employee == $emp ) ) then // all employees have health and dental care end
- ネストされた forall
rule "not all employees have health and dental care" when not ( forall( $emp : Employee() HealthCare( employee == $emp ) DentalCare( employee == $emp ) ) ) then // not all employees have health and dental care end
17.24. 条件要素(Conditioning 要素)
これにより、エンジンは作業メモリーにないデータよりも推論できます。データソースは、バインドされた変数のサブフィールド、またはメソッド呼び出しの結果になります。すぐに使用できる他のアプリケーションコンポーネントやフレームワークとの統合を可能にする強力な構築です。一般的な例としては、ハイバネート名前付きクエリーを使用してデータベースからオンデマンドで取得されるデータとの統合があります。
from
を lock-on-active
ルール属性で使用すると、ルールが実行されない可能性があります。
- すべてのファクトを作業メモリーにアサートしたり、制約式でネストされたオブジェクト参照を使用したりできる場合は
from
は使用しないでください。 - 条件(LHS)の最後の文として modify ブロックで使用される変数を配置します。
- 同じルールフローグループ内のルールがアクティベーションをどのように配置するかを明示的に管理できる場合は、
lock-on-active
を使用しないでください。
17.25. 例
- パターンの理由およびバインディング
rule "validate zipcode" when Person( $personAddress : address ) Address( zipcode == "23920W") from $personAddress then // zip code is ok end
- グラフ表記の使用
rule "validate zipcode" when $p : Person( ) $a : Address( zipcode == "23920W") from $p.address then // zip code is ok end
- すべてのオブジェクトの反復
rule "apply 10% discount to all items over US$ 100,00 in an order" when $order : Order() $item : OrderItem( value > 100 ) from $order.items then // apply discount to $item end
- lock-on-active で使用します。
rule "Assign people in North Carolina (NC) to sales region 1" ruleflow-group "test" lock-on-active true when $p : Person(address.state == "NC" ) then modify ($p) {} // Assign person to sales region 1 in a modify block end rule "Apply a discount to people in the city of Raleigh" ruleflow-group "test" lock-on-active true when $p : Person(address.city == "Raleigh" ) then modify ($p) {} //Apply discount to person in a modify block end
17.26. 条件要素の収集
collect
を使用すると、指定のソースまたはワーキングメモリーから取得したオブジェクトのコレクションを推論できます。First Oder Logic では、これはカーディナリティー数量です。
collect
の結果パターンは、java.util.Collection
インターフェイスを実装し、デフォルトの no-arg パブリックコンストラクターを提供する任意の具象クラスにすることができます。java.util.Collection
インターフェイスを実装し、デフォルトの no-arg パブリックコンストラクターを提供する限り、ArrayList、LinkedList、HashSet、または独自のクラスなどの Java コレクションを使用できます。
収集
CE の前にバインドされた変数はソースと結果の両方のパターンの範囲にあるため、これを使用してソースパターンと結果パターンの両方を制限することができます。collect
内で作成されたバインディングは、その外部では使用できません。
17.27. 条件要素アクセラレーション
accumulate
は、collect
のより柔軟で強力な形式で、収集
の機能を行うために使用でき、CE が 収集
する結果も達成できるという意味です。これにより、ルールはオブジェクトのコレクションを反復処理し、各要素に対してカスタムアクションを実行できます。最後に、結果オブジェクトを返します。
17.28. 条件要素の構文アクセラレーション
- 最上位の累積構文
accumulate(
<source pattern>;
<functions>[;
<constraints>] )
- 構文の例
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
上記の例では、min、max、および average は Accumulate Functions で、各センサーのすべての測定値に対して、最低気温、最高気温、平均気温の値を計算します。
17.29. 条件要素の関数がアクセラレートする
- average
- min
- max
- count
- sum
- collectList
- collectSet
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
17.30. Conditional 要素の累積およびプラグイン性
org.drools.runtime.rule.TypedAccumulateFunction
インターフェイスを実装し、設定ファイルに行を追加するか、システムプロパティーを設定して新しい関数について認識させる必要があります。
17.31. Conditional 要素の累積およびプラグイン性の例
average
関数の実装になります。
/** * An implementation of an accumulator capable of calculating average values */ public class AverageAccumulateFunction implements org.drools.runtime.rule.TypedAccumulateFunction { 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.drools.base.accumulators.AccumulateFunction#createContext() */ public Serializable createContext() { return new AverageData(); } /* (non-Javadoc) * @see org.drools.base.accumulators.AccumulateFunction#init(java.lang.Object) */ public void init(Serializable context) throws Exception { AverageData data = (AverageData) context; data.count = 0; data.total = 0; } /* (non-Javadoc) * @see org.drools.base.accumulators.AccumulateFunction#accumulate(java.lang.Object, java.lang.Object) */ public void accumulate(Serializable context, Object value) { AverageData data = (AverageData) context; data.count++; data.total += ((Number) value).doubleValue(); } /* (non-Javadoc) * @see org.drools.base.accumulators.AccumulateFunction#reverse(java.lang.Object, java.lang.Object) */ public void reverse(Serializable context, Object value) throws Exception { AverageData data = (AverageData) context; data.count--; data.total -= ((Number) value).doubleValue(); } /* (non-Javadoc) * @see org.drools.base.accumulators.AccumulateFunction#getResult(java.lang.Object) */ public Object getResult(Serializable context) throws Exception { AverageData data = (AverageData) context; return new Double( data.count == 0 ? 0 : data.total / data.count ); } /* (non-Javadoc) * @see org.drools.base.accumulators.AccumulateFunction#supportsReverse() */ public boolean supportsReverse() { return true; } /** * {@inheritDoc} */ public Class< ? > getResultType() { return Number.class; } }
17.32. Conditional 要素の関数のコード
- 関数内のプラグイン用のコード(設定ファイルに入力)
jbossrules.accumulate.function.average = org.jbossrules.base.accumulators.AverageAccumulateFunction
- 代替構文:戻り値の型を持つ単一の関数
rule "Apply 10% discount to orders over US$ 100,00" when $order : Order() $total : Number( doubleValue > 100 ) from accumulate( OrderItem( order == $order, $value : value ), sum( $value ) ) then # apply discount to $order end
- ** 項目名 **
- **アイテムの説明 **
17.33. インラインのカスタムコードで累積
accumulate
CE の一般的な構文は次のとおりです。
<result pattern>from accumulate(
<source pattern>,
init(
<init code>),
action(
<action code>),
reverse(
<reverse code>),
result(
<result expression>) )
- <source pattern >: ソースパターンは、エンジンが各ソースオブジェクトと照合しようとする通常のパターンです。
- <init code > : これは、選択した方言のコードのセマンティックブロックで、ソースオブジェクトを反復する前にタプルごとに 1 回実行されます。
- <action code >: これは、各ソースオブジェクトに対して実行される、選択したダイアレクトのコードのセマンティックブロックです。
- <reverse code > : これは、選択したダイアレクトのコードのオプションのセマンティックブロックです。存在する場合は、ソースパターンに一致しなくなった各ソースオブジェクトに対して実行されます。このコードブロックの目的は、< action code > ブロックで実行された計算を元に戻すことです。これにより、ソースオブジェクトが変更または取り消されたときにエンジンが計算をデクリメントできるため、これらの操作のパフォーマンスが大幅に向上します。
- & lt;result expression& gt; : これは、すべてのソースオブジェクトが反復された後に実行される、選択した方言のセマンティック式です。
- <result pattern > : これは、エンジンが < result expression> から返されたオブジェクトと照合しようとする正規表現です。一致する場合、
accumulate
条件要素は true と評価され、エンジンはルール内の次の CE の評価を続行します。一致しない場合、累積
CE は false に評価され、エンジンはそのルールの CE の評価を停止します。
17.34. インラインのカスタムコード例で累積
- インラインのカスタムコード
rule "Apply 10% discount to orders over US$ 100,00" when $order : Order() $total : Number( doubleValue > 100 ) from accumulate( OrderItem( order == $order, $value : value ), init( double total = 0; ), action( total += $value; ), reverse( total -= $value; ), result( total ) ) then # apply discount to $order end
上記の例では、Working Memory の各Order
に対して、エンジンは total 変数をゼロに初期化する init コード を実行します。次に、この順番に対してOrderItem
のすべてのオブジェクトを繰り返し処理し、それぞれに アクション を実行します(この例では、すべての項目の値を total 変数に合計します)。OrderItem
オブジェクトをすべて反復すると、結果式 (上記の例では変数total
)に対応する値が返されます。最後に、エンジンはNumber
パターンで結果を照合しようとし、double 値が 100 を超える場合はルールが実行されます。- カスタムオブジェクトのインスタンス化および入力
rule "Accumulate using custom objects" when $person : Person( $likes : likes ) $cheesery : Cheesery( totalAmount > 100 ) from accumulate( $cheese : Cheese( type == $likes ), init( Cheesery cheesery = new Cheesery(); ), action( cheesery.addCheese( $cheese ); ), reverse( cheesery.removeCheese( $cheese ); ), result( cheesery ) ); then // do something end
17.35. 条件要素評価
eval
は基本的に catch-all で、セマンティックコード(プリミティブブール値を返す)を実行できます。このコードは、ルールの LHS にバインドされていた変数と、ルールパッケージの関数を参照できます。eval を過剰に使用するとルールの宣言性が低くなり、エンジンの実行が悪くなる可能性があります。eval
はパターンのどこでも使用できますが、ルールの LHS の最後の条件要素として追加することがベストプラクティスです。
17.36. 条件要素評価の例
評価
の例です。
p1 : Parameter() p2 : Parameter() eval( p1.getList().containsKey( p2.getItem() ) )
p1 : Parameter() p2 : Parameter() // call function isValid in the LHS eval( isValid( p1, p2 ) )
17.37. 右辺(Right Hand Side)
17.38. RHS 規則メソッド
表17.5 RHS 規則メソッド
名前 | Description |
---|---|
update ( object, handle);
|
オブジェクトが変更されている(LHS 上のものにバインドされているオブジェクト)と、再編成する必要があるルールがエンジンに指示します。
|
update( object);
| update ( )を使用すると、ナレッジヘルパーは、渡されたオブジェクトのアイデンティティーチェックを介してファクトハンドルを検索します。(プロパティー Change Listeners をエンジンに挿入する Java Bean に提供すると、オブジェクトの変更時に update() を呼び出す必要がなくなります)。ファクトのフィールド値を変更したら、別のファクトを変更する前に update を呼び出す必要があります。そうしないと、ルールエンジン内のインデックス作成に問題が発生します。modify キーワードは、この問題を回避します。
|
insert(new object());
|
作成用の新規オブジェクトを作業メモリーに配置します。
|
insertLogical(new object());
|
insert と同様ですが、現在実行中のルールの真理をサポートするファクトがない場合には、オブジェクトは自動的に取り消されます。
|
retract( handle);
|
作業メモリーからオブジェクトを削除します。
|
17.39. Drools 変数を使用した便利なメソッド
drools.halt()
呼び出しは、ルールの実行をすぐに終了します。これは、現行セッションがfireUntilHalt()
と機能したときにコントロールをポイントに戻すために必要です。- メソッド
insert(Object o)
、update(Object o)
、およびretract(Object o)
もdrools
で呼び出すことができますが、頻繁に使用されるため、オブジェクト参照なしで呼び出すことができます。 drools.getWorkingMemory()
WorkingMemory
オブジェクトを返します。drools.setFocus( String s)
指定したアジェンダグループにフォーカスを設定します。drools.getRule().getName()
ルールの RHS から呼び出される は、ルールの名前を返します。drools.getTuple()
現在実行中のルールに一致する Tuple を返し、drools.getActivation()
は対応する Activation を提供します。(呼び出しは、ロギングやデバッグに役立ちます。)
17.40. Kcontext 変数を使用した便利なメソッド
kcontext.getKnowledgeRuntime().halt()
呼び出しは、ルールの実行をすぐに終了します。- アクセサー
getAgenda()
はセッションのAgenda
への参照を返します。次に、さまざまなルールグループ(アクティベーショングループ、アジェンダグループ、およびルールフローグループ)へのアクセスが提供されます。非常に一般的なパラダイムとは、一部のアジェンダグループのアクティベーションであり、長い呼び出しで行うことができます。// give focus to the agenda group CleanUp kcontext.getKnowledgeRuntime().getAgenda().getAgendaGroup( "CleanUp" ).setFocus();
(drools.setFocus( "CleanUp" )
を使用しても同じことができます。) - クエリーを実行するには、
getQueryResults(String query)
を呼び出します。ここで、結果を処理できます。 - イベント管理を処理するメソッドのセットを使用すると、作業メモリーと Agenda のイベントリスナーを追加および削除できます。
- メソッド
getKnowledgeBase()
は、KnowledgeBase
オブジェクト、システム内のすべてのナレッジのバックボーン、および現行セッションの発信元を返します。 - グローバルは、
setGlobal(...)
、getGlobal(...)
、およびgetGlobals()
で管理できます。 - メソッド
getEnvironment()
はランタイムのEnvironment
を返します。
17.41. Modify ステートメント
表17.6 Modify ステートメント
名前 | Description | 構文 | 例 |
---|---|---|---|
modify |
これにより、ファクトの更新に対する構造化されたアプローチが提供されます。これは、更新操作と、オブジェクトのフィールドを変更するセッター呼び出しを多数組み合わせます。
|
括弧化された & lt;fact-expression> は、ファクトオブジェクト参照を生成する必要があります。ブロックの式リストは、通常のオブジェクト参照なしで記述される、指定のオブジェクトのセッター呼び出しで設定され、コンパイラーによって自動的に付加される必要があります。
| rule "modify stilton" when $stilton : Cheese(type == "stilton") then modify( $stilton ){ setPrice( 20 ), setAge( "overripe" ) } end |
17.42. クエリーの例
ksession.getQueryResults("name")
を使用します。name はクエリーの名前です。これにより、クエリー結果のリストが返されます。これにより、クエリーに一致するオブジェクトを取得できます。
- 30 歳未満のユーザーに対するクエリー
query "people over the age of 30" person : Person( age > 30 ) end
- X 歳を超えたユーザー、および Y に存在するユーザーに対するクエリー
query "people over the age of x" (int x, String y) person : Person( age > x, location == y ) end
17.43. QueryResults の例
QueryResults results = ksession.getQueryResults( "people over the age of 30" ); System.out.println( "we have " + results.size() + " people over the age of 30" ); System.out.println( "These people are are over 30:" ); for ( QueryResultsRow row : results ) { Person person = ( Person ) row.get( "person" ); System.out.println( person.getName() + "\n" ); }
17.44. 他のクエリーを呼び出すクエリー
17.45. 他のクエリーの例を呼び出すクエリー
- 別のクエリーを呼び出すクエリー
declare Location thing : String location : String end query isContainedIn( String x, String y ) Location(x, y;) or ( Location(z, y;) and ?isContainedIn(x, z;) ) end
- クエリー結果から時間の経過とともに変更をリアクティブに受信するためのライブクエリーの使用
query isContainedIn( String x, String y ) Location(x, y;) or ( Location(z, y;) and isContainedIn(x, z;) ) end rule look when Person( $l : likes ) isContainedIn( $l, 'office'; ) then insertLogical( $l 'is in the office' ); end
17.46. 派生クエリーのユニフィケーション
第18章 ドメイン固有言語(DSL)
18.1. ドメイン固有の言語
18.2. DSL の使用
18.3. DSL の例
表18.1 DSL の例
例 | Description |
---|---|
[when]Something is {colour}=Something(colour=="{colour}") | [when] 式の範囲を示します(つまり、これが LHS またはルールの RHS に対して有効であるか)。
bracketed キーワードの後の部分は、ルールで使用する式です。
等号(=")の右側にある部分は、式のルール言語へのマッピングです。この文字列の形式は、宛先、RHS、または LHS によって異なります。LHS の場合、通常の LHS 構文に従って用語である必要があります。RHS の場合は、Java ステートメントである可能性があります。
|
18.4. DSL パーサーの仕組み
- DSL は、式に変数名が括弧に含まれる文字列値を抽出します。
- これらのキャプチャーから取得した値は、マッピングの右側の名前が発生した場合に補間されます。
- 補間文字列は、DSL ルールファイルの行にある式全体によって一致したものを置き換えます。
18.5. DSL コンパイラー
18.6. DSL 構文の例
表18.2 DSL 構文の例
名前 | 説明 | 例 |
---|---|---|
引用符 | ルールエディターが入力する可能性のあるテキストデータには引用符を使用します。キャプチャーを単語で囲むことで、テキストが正しく一致することを確認することもできます。 |
[when]something is "{color}"=Something(color=="{color}") [when]another {state} thing=OtherThing(state=="{state}" |
中かっこ | DSL マッピングでは、変数定義または参照を囲むためにのみ中括弧 "{" と "}" を使用する必要があります。これによりキャプチャーが実行されます。式または右側の代替テキスト内で文字通り発生する場合は、前のバックスラッシュ("\")でエスケープする必要があります。 |
[then]do something= if (foo) \{ doSomething(); \} |
正しい構文を使用したマッピングの例 | 該当なし |
# This is a comment to be ignored. [when]There is a person with name of "{name}"=Person(name=="{name}") [when]Person is at least {age} years old and lives in "{location}"= Person(age >= {age}, location=="{location}") [then]Log "{message}"=System.out.println("{message}"); [when]And = and |
拡張された DSL の例 | 該当なし |
There is a person with name of "Kitty" ==> Person(name="Kitty") Person is at least 42 years old and lives in "Atlanta" ==> Person(age >= 42, location="Atlanta") Log "boo" ==> System.out.println("boo"); There is a person with name of "Bob" and Person is at least 30 years old and lives in "Utah" ==> Person(name="Bob") and Person(age >= 30, location="Utah") |
18.7. DSL 式の連鎖
18.8. ファクトへの制約の追加
表18.3 ファクトへの制約の追加
名前 | 説明 | 例 |
---|---|---|
LHS 条件の表現 |
DSL ファシリティーを使用すると、単純な規則によりパターンに制約を追加できます。DSL 式がハイフン(マイナス文字、-)で始まる場合は、フィールド制約であると仮定されるため、が前の最後のパターン行に追加されます。
この例では、
Cheese クラスには type、price、age、および country のフィールドがあります。通常の DRL では、一部の LHS 条件を表現できます。
|
Cheese(age < 5, price == 20, type=="stilton", country=="ch") |
DSL 定義 |
この例の DSL 定義では、3 つの DSL フレーズが作成され、これらのフィールドに関連する制約の組み合わせを作成できます。
|
[when]There is a Cheese with=Cheese() [when]- age is less than {age}=age<{age} [when]- type is '{type}'=type=='{type}' [when]- country equal to '{country}'=country=='{country}' |
"-" |
パーサーは-で始まる行を取得し、これを前述のパターンに制約として追加し、必要に応じてコンマを挿入します。
| There is a Cheese with - age is less than 42 - type is 'stilton' Cheese(age<42, type=='stilton') |
DSL フレーズの定義 |
さまざまな演算子と、任意のフィールド制約を処理する汎用式の DSL フレーズを定義すると、DSL エントリーの量が減少します。
|
[when][]is less than or equal to=<= [when][]is less than=< [when][]is greater than or equal to=>= [when][]is greater than=> [when][]is equal to=== [when][]equals=== [when][]There is a Cheese with=Cheese()[when][]- {field:\w*} {operator} {value:\d*}={field} {operator} {value} |
DSL 定義ルール | 該当なし |
There is a Cheese with - age is less than 42 - rating is greater than 50 - type equals 'stilton'
この場合、is less than などのフレーズは
< に置き換えられ、行が最後の DSL エントリーと一致します。これによりハイフンが削除されますが、最終的な結果は引き続き前述のパターンに制約として追加されます。すべての行を処理した後、生成される DRL テキストは以下のようになります。
Cheese(age<42, rating > 50, type=='stilton') |
18.9. DSL の開発に関するヒント
- アプリケーションが必要とするルールの代表的なサンプルを記述し、開発時にテストします。
- DRL および DSLR の両方で、ルールに定義された推論プロセスが適用される必要があるアプリケーションデータを表すデータモデルに応じてエンティティーを参照します。
- ほとんどのデータモデルのタイプがファクトである場合、ルールの作成が容易になります。
- 変数の部分をパラメーターとしてマーク付けします。これにより、有用な DSL エントリーの信頼できるリードが提供されます。
- この最初の設計フェーズでは、特定の条件要素とアクションについて実装の意思決定を延期するには、行をより大きな記号(">)で接頭辞を付けることで、特定の条件要素とアクションを DRL フォームに残すことができます。(これはデバッグステートメントの挿入にも便利です。)
- 既存の DSL 定義を再利用するか、既存の条件または結果エントリーにパラメーターを追加して、新しいルールを作成することができます。
- DSL エントリーの数を小さくします。パラメーターを使用すると、同様のルールパターンまたは制約に同じ DSL 文を適用できます。
18.10. DSL および DSLR リファレンス
- "#" または "//" で始まる行(空白の前後または空白なし)は、コメントとして扱われます。デバッグオプションを要求する単語については、#/で始まるコメント行がスキャンされます。以下を参照してください。
- ブラクト("[")で始まる行は、DSL エントリー定義の最初の行であると想定されます。
- その他の行は、前の DSL エントリー定義に追加され、行末はスペースに置き換えられます。
18.11. DSL エントリーの作成
- スコープの定義。when、condition、then、または "consequence"、"*" および keyword" のキーワード([" と "]")で囲まれています。これは、DSL エントリーがルールの条件または結果に対して有効であるか、またはその両方であるかを示します。キーワードのスコープは、エントリーにグローバル重要性があることを意味します。つまり、DSLR ファイルのどこにでも認識されます。
- Java クラス名として記述された型定義。括弧で囲まれたものです。次の部分がオープンブラケットで始まる場合を除き、この部分はオプションになります。括弧の空のペアも有効です。
- DSL 式は(Java)正規表現で設定されており、任意の数の組み込み 変数定義があり、 等号("=")で終了します。変数の定義は中括弧({" と "}")で囲まれています。これは、コロン(:)で区切られた、変数名と 2 つのオプションの添付ファイルで設定されます。アタッチメントが 1 つある場合は、変数に割り当てられるテキストに一致する正規表現になります。添付ファイルが 2 つある場合には、最初に GUI エディターのヒント、2 つ目は正規表現です。正規表現でマジックな文字はすべて、式内で文字通り発生する必要がある場合は、前のバックスラッシュ("\)でエスケープする必要があります。
- 等号記号の後の行の残りの部分は、正規表現に一致する DSLR テキストの代替テキストです。変数参照、つまり中括弧で囲まれた変数名が含まれる場合があります。必要に応じて、変数名の後に感嘆符("!")と変換関数が続きます。以下を参照してください。置き換え文字列内で文字通り発生する必要がある場合は、括弧("{" and "}")を前のバックスラッシュ("\")でエスケープする必要があります。
18.12. DSL 拡張のデバッグオプション
表18.4 DSL 拡張のデバッグオプション
単語 | Description |
---|---|
result | 作成される DRL テキストを行番号で出力します。 |
steps | 条件および結果行の各拡張ステップを出力します。 |
キーワード | スコープキーワードを使用して、すべての DSL エントリーの内部表現をダンプします。 |
when | スコープ when または "*" ですべての DSL エントリーの内部表現をダンプします。 |
次に、以下を実行します。 | スコープ "then" または "*" ですべての DSL エントリーの内部表現をダンプします。 |
使用方法 | すべての DSL エントリーの使用状況の統計を表示します。 |
18.13. DSL 定義の例
# Comment: DSL examples #/ debug: display result and usage # keyword definition: replaces "regula" by "rule" [keyword][]regula=rule # conditional element: "T" or "t", "a" or "an", convert matched word [when][][Tt]here is an? {entity:\w+}= ${entity!lc}: {entity!ucfirst} () # consequence statement: convert matched word, literal braces [then][]update {entity:\w+}=modify( ${entity!lc} )\{ \}
18.14. DSLR ファイルの変換
- テキストがメモリーに読み込まれます。
- 各キーワードエントリーはテキスト全体に適用されます。キーワード定義の正規表現は、空白シーケンスを、任意の数の空白文字に一致するパターンに置き換え、変数定義を定義で提供される正規表現から行ったキャプチャーに置き換えるか、またはデフォルト(.*?")に置き換えることで変更されます。次に、DSLR テキストが、変更された正規表現に一致する文字列の発生を完全に検索します。変数キャプチャーに対応する一致する文字列のサブ文字列が抽出され、対応する置換テキストの変数参照を置き換えます。このテキストは DSLR テキストの一致する文字列を置き換えます。
- when と then と end の間の DSLR テキストのセクションはそれぞれ、以下で説明されているように、行ごとに統一された方法で配置および処理されます。行については、DSL ファイルに表示される順序で、行の セクションに関連する各 DSL エントリーが順番に実行されます。この正規表現の部分が変更されました。空白は、任意の数の空白文字に一致するパターンに置き換えられます。正規表現を使用した変数定義は、この正規表現でキャプチャーされ、デフォルトは ".*?" になります。作成される正規表現が行のすべてまたは一部と一致する場合、一致した部分は適切に変更された置換テキストに置き換えられます。代替テキストの変更は、変数参照を正規表現キャプチャーに対応するテキストに置き換えて行います。このテキストは、変数参照で指定した文字列変換関数に従って変更できます。詳細は、以下を参照してください。同じエントリーに定義されていない変数の名前付けの変数参照がある場合、展開担当者は現在のルールの前の行のいずれかで定義された場合に、その名前の変数にバインドされている値を置き換えます。
- 状態の DSLR 行が先頭のハイフンで記述されている場合は、拡張結果が最後の行に挿入されます。この行には、パターン CE、つまり型名の後に括弧のペアが含まれている必要があります。このペアが空の場合は、拡張された行(有効な制約を含む)が単純に挿入されます。それ以外の場合は、コンマ(",")が事前に挿入されます。結果内の DSLR 行が先頭のハイフンで書き込まれた場合、拡張された結果は最後の行に挿入されます。この行には modify ステートメントが含まれ、括弧({" と "}")のペアで終わります。このペアが空の場合は、拡張行(有効なメソッド呼び出しを含む)が単純に挿入されます。挿入しないと、コンマ(",")が事前に挿入されます。
18.15. string Transformation Functions
表18.5 string Transformation Functions
名前 | Description |
---|---|
uc | すべての文字を大文字に変換します。 |
lc | すべての文字を小文字に変換します。 |
ucfirst | 最初の文字を大文字に変換し、他のすべての文字を小文字に変換します。 |
num | 文字列からすべての数字と-を抽出します。元の文字列の最後の 2 桁の数字の前に "." または "," が付けられている場合、対応する位置に 10 進数のピリオドが挿入されます。 |
a?b/c | 文字列を文字列で比較 し、等しい場合は b に置き換えます。それ以外の場合は c に置き換えます。ただし、c は、構造全体が翻訳テーブルのように、b、c などのトリプレットにすることができます。 |
18.16. DSL 変換機能の文字列設定
表18.6 DSL 変換機能の文字列設定
名前 | 説明 | 例 |
---|---|---|
.dsl |
DSL 定義が含まれるファイルには、通常 エクステンション
.dsl が付与されます。ResourceType.DSL で Knowledge Builder に渡されます。DSL 定義を使用するファイルの場合、拡張子 .dslr を使用する必要があります。Knowledge Builder には ResourceType.DSLR が必要です。ただし、IDE はファイル拡張子に依存して、ルールファイルを正しく認識して操作します。
|
# definitions for conditions [when][]There is an? {entity}=${entity!lc}: {entity!ucfirst}() [when][]- with an? {attr} greater than {amount}={attr} <= {amount!num} [when][]- with a {what} {attr}={attr} {what!positive?>0/negative?%lt;0/zero?==0/ERROR} |
DSL の合格 |
DSL は、DSL を使用してルールファイルの前に Knowledge Builder に渡す必要があります。
DSLR ファイルを解析および拡張する場合、DSL 設定は読み取り、パーサーに提供されます。したがって、パーサーは DSL 式を認識し、それらをネイティブルール言語式に変換できます。
|
KnowledgeBuilder kBuilder = new KnowledgeBuilder(); Resource dsl = ResourceFactory.newClassPathResource( dslPath, getClass() ); kBuilder.add( dsl, ResourceType.DSL ); Resource dslr = ResourceFactory.newClassPathResource( dslrPath, getClass() ); kBuilder.add( dslr, ResourceType.DSLR ); |
第19章 XML
19.1. XML 形式
19.2. XML ルールの例
<?xml version="1.0" encoding="UTF-8"?> <package name="com.sample" xmlns="http://drools.org/drools-5.0" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:schemaLocation="http://drools.org/drools-5.0 drools-5.0.xsd"> <import name="java.util.HashMap" /> <import name="org.drools.*" /> <global identifier="x" type="com.sample.X" /> <global identifier="yada" type="com.sample.Yada" /> <function return-type="void" name="myFunc"> <parameter identifier="foo" type="Bar" /> <parameter identifier="bada" type="Bing" /> <body> System.out.println("hello world"); </body> </function> <rule name="simple_rule"> <rule-attribute name="salience" value="10" /> <rule-attribute name="no-loop" value="true" /> <rule-attribute name="agenda-group" value="agenda-group" /> <rule-attribute name="activation-group" value="activation-group" /> <lhs> <pattern identifier="foo2" object-type="Bar" > <or-constraint-connective> <and-constraint-connective> <field-constraint field-name="a"> <or-restriction-connective> <and-restriction-connective> <literal-restriction evaluator=">" value="60" /> <literal-restriction evaluator="<" value="70" /> </and-restriction-connective> <and-restriction-connective> <literal-restriction evaluator="<" value="50" /> <literal-restriction evaluator=">" value="55" /> </and-restriction-connective> </or-restriction-connective> </field-constraint> <field-constraint field-name="a3"> <literal-restriction evaluator="==" value="black" /> </field-constraint> </and-constraint-connective> <and-constraint-connective> <field-constraint field-name="a"> <literal-restriction evaluator="==" value="40" /> </field-constraint> <field-constraint field-name="a3"> <literal-restriction evaluator="==" value="pink" /> </field-constraint> </and-constraint-connective> <and-constraint-connective> <field-constraint field-name="a"> <literal-restriction evaluator="==" value="12"/> </field-constraint> <field-constraint field-name="a3"> <or-restriction-connective> <literal-restriction evaluator="==" value="yellow"/> <literal-restriction evaluator="==" value="blue" /> </or-restriction-connective> </field-constraint> </and-constraint-connective> </or-constraint-connective> </pattern> <not> <pattern object-type="Person"> <field-constraint field-name="likes"> <variable-restriction evaluator="==" identifier="type"/> </field-constraint> </pattern> <exists> <pattern object-type="Person"> <field-constraint field-name="likes"> <variable-restriction evaluator="==" identifier="type"/> </field-constraint> </pattern> </exists> </not> <or-conditional-element> <pattern identifier="foo3" object-type="Bar" > <field-constraint field-name="a"> <or-restriction-connective> <literal-restriction evaluator="==" value="3" /> <literal-restriction evaluator="==" value="4" /> </or-restriction-connective> </field-constraint> <field-constraint field-name="a3"> <literal-restriction evaluator="==" value="hello" /> </field-constraint> <field-constraint field-name="a4"> <literal-restriction evaluator="==" value="null" /> </field-constraint> </pattern> <pattern identifier="foo4" object-type="Bar" > <field-binding field-name="a" identifier="a4" /> <field-constraint field-name="a"> <literal-restriction evaluator="!=" value="4" /> <literal-restriction evaluator="!=" value="5" /> </field-constraint> </pattern> </or-conditional-element> <pattern identifier="foo5" object-type="Bar" > <field-constraint field-name="b"> <or-restriction-connective> <return-value-restriction evaluator="==" >a4 + 1</return-value-restriction> <variable-restriction evaluator=">" identifier="a4" /> <qualified-identifier-restriction evaluator="=="> org.drools.Bar.BAR_ENUM_VALUE </qualified-identifier-restriction> </or-restriction-connective> </field-constraint> </pattern> <pattern identifier="foo6" object-type="Bar" > <field-binding field-name="a" identifier="a4" /> <field-constraint field-name="b"> <literal-restriction evaluator="==" value="6" /> </field-constraint> </pattern> </lhs> <rhs> if ( a == b ) { assert( foo3 ); } else { retract( foo4 ); } System.out.println( a4 ); </rhs> </rule> </package>
19.3. XML 要素
表19.1 XML 要素
名前 | Description |
---|---|
global |
ルールで参照できるグローバルオブジェクトを定義します。
|
function |
ルールで使用される関数の関数宣言が含まれます。本文で戻り値のタイプ、一意の名前、およびパラメーターを指定する必要があります。
|
import |
ルールで使用するタイプをインポートします。
|
19.4. ルール要素の詳細
<rule name="simple_rule"> <rule-attribute name="salience" value="10" /> <rule-attribute name="no-loop" value="true" /> <rule-attribute name="agenda-group" value="agenda-group" /> <rule-attribute name="activation-group" value="activation-group" /> <lhs> <pattern identifier="cheese" object-type="Cheese"> <from> <accumulate> <pattern object-type="Person"></pattern> <init> int total = 0; </init> <action> total += $cheese.getPrice(); </action> <result> new Integer( total ) ); </result> </accumulate> </from> </pattern> <pattern identifier="max" object-type="Number"> <from> <accumulate> <pattern identifier="cheese" object-type="Cheese"></pattern> <external-function evaluator="max" expression="$price"/> </accumulate> </from> </pattern> </lhs> <rhs> list1.add( $cheese ); </rhs> </rule>
19.5. XML ルール要素
表19.2 XML ルール要素
要素 | Description |
---|---|
Pattern |
これにより、型(クラス)を指定し、変数をそのクラスのインスタンスにバインドできます。pattern オブジェクトで入れ子になっているのは、満たさなければならない制約と制約です。Predicate と Return Value の制約により、Java 式を埋め込むことができます。
|
条件要素(not、exists、および or) |
これらの作業は DRL の対応するように機能します。の下にネスト化され、and 要素は論理的に結合されます。または と同じように(さらにネスト化することができます)。パターンの構文および "Not" は回避し、パターンの制約を満たすファクトの存在や、何もないかを確認します。
|
eval |
ブール値を評価する限り、有効な Java コードの有効なスニペットを実行できます(フラグメントであるため、セミコロンで終了しないでください)。これには、関数の呼び出しが含まれます。ルールエンジンは毎回評価する必要があるため、Eval は列よりも効率が低くなりますが、Column 制約で行う必要がある内容を表現できる場合はキャッチ all 機能です。
|
19.6. XML と DRL 間での自動変換
19.7. XML と DRL 間で自動変換を行うためのクラス
- DrlDumper - DRL をエクスポートする場合
- DrlParser - DRL を読み取る場合
- XmlPackageReader - for reading XML
第20章 Java Rule Engine アプリケーションプログラミングインターフェイス
20.1. JSR94
20.2. Javax.rules Interfaces
handle
Handle は、StatefulRuleSession
で追加されたWorkingMemory
からオブジェクトを取得するために使用されます。Handle
を使用すると、WorkingMemory
からオブジェクト
を変更または削除できます。StatefulRuleSession
からオブジェクト呼び出しupdateObject()
を変更するには、以下を実行します。これを削除するには、Handle
を Parameter として指定してremoveObject()
を呼び出します。Java Rule Engine API の実装内で、カプセル化されたナレッジ(Drools および jBPM) API のmodifyObject()
メソッドおよびretractObject()
メソッドと呼ばれます。ObjectFilter
このインターフェイスは、RuleSession のオブジェクトをフィルターするために使用されます。RuleExecutionSetMetadata
RuleExecutionSetMetadata は、RuleExecutionSet の名前、説明、および URI を保存するために使用されます。RuleRuntime
RuleRuntime は RuleSession へのキーです。RuleServiceProvider から取得した RuleRuntime。RuleRuntime 呼び出し createRuleSession ()を取得して RuleSession を開きます。RuleRuntime を使用して、RuleAdministrator によって登録されたすべての RuleExecutionSets の URI の一覧を取得できます。ルールエンジンに対して RuleSession を開くには、URI を文字列として指定する必要があります。ルールエンジンは、RuleSession 内の RuleExecutionSet のルールを使用します。マップはグローバルに使用されます。グローバルは、以前は(Drools 2.x で) ApplicationData と呼ばれていました。キーは Global の識別子と、Global として使用するオブジェクトの Value である必要があります。RuleSession
RuleSession は、ルールエンジンに問い合わせる場合に作業しているオブジェクトです。RuleRuntime から RuleSession を取得する場合、StatefulRuleSession または StatelessRuleSession になります。すべてのリソースが解放されるように、release ()-method を呼び出します。StatefulRuleSession
ルールエンジンを複数回実行する必要がある場合は、StatefulRuleSession を実行します。オブジェクトをアサートしたり、ルールを実行したりできます。Rule Session にアサートしているすべてのオブジェクトに対して Handle を取得します。それを失わないでください。作業メモリー内のオブジェクトを取り消したり、変更したりする必要があります。実装内で使用する Drools の作業メモリーに直接アクセスしていないので、RuleSession が取得されました。StatelessRuleSession
StatelessRuleSession は、ルールエンジンへの接続が 1 つだけであることを意味します。ルールエンジンにオブジェクトの一覧を提供し、ルールエンジンがそれらをすべてアサートし、実行をすぐに開始します。結果はオブジェクトの一覧です。結果一覧の内容はルールによって異なります。ルールが作業メモリーからオブジェクトを変更または取り消さない場合は、再度追加したすべてのオブジェクトを取得する必要があります。オブジェクトを取得する前に、結果のオブジェクトリストをフィルターリングする ObjectFilter を使用できます。
20.3. Javax.rules Classes
RuleServiceProvider
RuleServiceProvider は、新しい Rule Session を開く必要がある RuleAdministrator または RuleRuntime へのアクセスを提供します。RuleServiceProvider を取得するには、RuleServiceProviderManager.getRuleServiceProvider ()を呼び出します。J2EE 環境では、RuleServiceProvider を JNDI にバインドし、ルックアップを作成してすべてのアプリケーションに配置できます。RuleServiceProviderManager
RuleServiceProvider は、JDBC で使用する DriverManager と比較されることが多くあります。DataBase の Driver の設定と同じように機能します。
20.4. javax.rules 例外
ConfigurationException
この例外は、ユーザー設定エラーが発生すると出力されます。InvalidHandleException
クライアントが無効なハンドルをルールエンジンに渡すと、この例外が発生します。InvalidRuleSessionException
RuleSession でメソッドが呼び出され、RuleSession の内部状態が無効になると、InvalidRuleSessionException を出力する必要があります。これは、StatefulRuleSession がシリアライズされ、外部リソースにアクセスできないために発生する可能性があります。この例外は、(リリースメソッドが呼び出された後に使用しようとした場合など)RuleSession が無効な状態にあることを示すためにも使用されます(JCP API ドキュメント から取得)。RuleException
javax.rules パッケージ内のすべての Exception クラスのベースクラス。RuleExecutionException
この例外は、Drools 3 JSR 94 実装では出力されません。RuleExecutionSetNotFoundException
この例外は、クライアントが RuleRuntime から RuleExecutionSet を要求し、URI または RuleExecutionSet が見つからない場合に出力されます(JCP API ドキュメント から必要)。RuleSessionCreateException
この例外は、クライアントが RuleRuntime から RuleSession を要求し、RuleSession が返されないエラーが発生すると出力されます(JCP API ドキュメント から取得)。RuleSessionTypeUnsupportedException
この例外は、クライアントが RuleSession を要求し、ベンダーが(RuleRuntime で定義)指定されたタイプをサポートしていない場合、または RuleExecutionSet 自体が要求されたモードをサポートしていない場合(JCP API ドキュメント から取られる)に出力されます。
20.5. ルールサービスプロバイダーの使用
手順20.1 タスク
- 以下のコードを使用して JBoss Rules ルールサービスプロバイダーをロードします。
Class ruleServiceProviderClass = Class.forName("org.drools.jsr94.rules.RuleServiceProviderImpl");
- 以下のコードを使用して登録します。
RuleServiceProviderManager.registerRuleServiceProvider( "http://jboss.com/products/rules", ruleServiceProviderClass);
- 以下のコードを使用して RuleServiceProvider を呼び出します。
RuleServiceProviderManager.getRuleServiceProvider("http://jboss.com/products/rules")
; - ルールサービスを停止するには、以下のコードで登録を解除します。
RuleServiceProviderManager.deregisterRuleServiceProvider( "http://jboss.com/products/rules");
20.6. Javax.rules.admin Interfaces
LocalRuleExecutionSetProvider
**ルール**
RuleAdministrator
RuleExecutionSet
RuleExecutionSetProvider
20.7. Javax.rules.admin Exceptions
RuleAdministrationException
javax.rules.admin パッケージの全管理 RuleException クラスのベースクラス(JCP API ドキュメント から取る)。RuleExecutionSetCreateException
ルールセットの作成時にエラーが発生した場合に発生します。RuleExecutionSetDeregistrationException
URI からルールセットの登録を解除しようとすると、エラーが発生します。RuleExecutionSetRegisterException
URI にルールセットを登録しようとすると、エラーが発生します。
20.8. The RuleServiceProvider
20.9. The RuleServiceProviderManager
20.10. RuleServiceProvider 自動登録の例
// RuleServiceProviderImpl is registered to "http://drools.org/" // via a static initialization block Class.forName("org.drools.jsr94.rules.RuleServiceProviderImpl"); // Get the rule service provider from the provider manager. RuleServiceProvider ruleServiceProvider = RuleServiceProviderManager.getRuleServiceProvider("http://drools.org/");
20.11. RuleAdministrator API を使用した LocalRuleExecutionSet の登録
手順20.2 タスク
- RuleExecutionSet を作成します。これは、空の LocalRuleExecutionSetProvider または RuleExecutionSetProvider を返すファクトリーメソッドを提供する RuleAdministrator を使用して実行できます。
- RuleExecutionSet の名前を指定します。
- RuleExecutionSet を以下のように登録します。
// Register the RuleExecutionSet with the RuleAdministrator String uri = ruleExecutionSet.getName(); ruleAdministrator.registerRuleExecutionSet(uri, ruleExecutionSet, null);
- LocalRuleExecutionSetProvider を使用して、Streams など、シリアライズできないローカルソースから RuleExecutionSets をロードします。
- RuleExecutionSetProvider を使用して、DOM 要素やパッケージなどのシリアル化可能なソースから RuleExecutionSets をロードします。"ruleAdministrator.getLocalRuleExecutionSetProvider (null);" と "ruleAdministrator.getRuleExecutionSetProvider (null);" の両方(null をパラメーターとして使用)。
- 以下の例は、LocalRuleExecutionSet の登録方法を説明します。
// Get the RuleAdministration RuleAdministrator ruleAdministrator = ruleServiceProvider.getRuleAdministrator(); LocalRuleExecutionSetProvider ruleExecutionSetProvider = ruleAdministrator.getLocalRuleExecutionSetProvider( null ); // Create a Reader for the drl URL drlUrl = new URL("http://mydomain.org/sources/myrules.drl"); Reader drlReader = new InputStreamReader( drlUrl.openStream() ); // Create the RuleExecutionSet for the drl RuleExecutionSet ruleExecutionSet = ruleExecutionSetProvider.createRuleExecutionSet( drlReader, null );
- "ruleExecutionSetProvider.createRuleExecutionSet (reader, null) " プロパティーを使用して、受信ソースの設定を提供できます。null が渡されると、デフォルトを使用して入力を drl としてロードします。マップに許可されるキーは source および dsl です。キー source は、"drl" または "xml" を値として取ります。
- "source" を "drl" に設定して DRL を読み込むか、xml に設定して XML ソースを読み込みます。xml は、dsl キー/値の設定を無視します。dsl キーは、Reader または String (dse の内容)を値として指定できます。以下の dsl の例を参照してください。
// Get the RuleAdministration RuleAdministration ruleAdministrator = ruleServiceProvider.getRuleAdministrator(); LocalRuleExecutionSetProvider ruleExecutionSetProvider = ruleAdministrator.getLocalRuleExecutionSetProvider( null ); // Create a Reader for the drl URL drlUrl = new URL("http://mydomain.org/sources/myrules.drl"); Reader drlReader = new InputStreamReader( drlUrl.openStream() ); // Create a Reader for the dsl and a put in the properties map URL dslUrl = new URL("http://mydomain.org/sources/myrules.dsl"); Reader dslReader = new InputStreamReader( dslUrl.openStream() ); Map properties = new HashMap(); properties.put( "source", "drl" ); properties.put( "dsl", dslReader ); // Create the RuleExecutionSet for the drl and dsl RuleExecutionSet ruleExecutionSet = ruleExecutionSetProvider.createRuleExecutionSet( reader, properties );
20.12. ステートフルおよびステートレスの RuleSession の使用
手順20.3 タスク
- 以下に示すように RuleServiceProvider にアクセスしてランタイムを取得します。
RuleRuntime ruleRuntime = ruleServiceProvider.getRuleRuntime();
- ルールセッションを作成するには、2 つの RuleRuntime パブリック定数のいずれかを使用します。これらは "RuleRuntime.STATEFUL_SESSION_TYPE" および "RuleRuntime.STATELESS_SESSION_TYPE" で、RuleSession をインスタンス化する RuleExecutionSet に URI が付随します。
- 必要に応じて、プロパティーにアクセスしてグローバルを指定します。
- createRuleSession (...)メソッドは RuleSession インスタンスを返します。StatefulRuleSession または StatelessRuleSession にキャストする必要があります。
(StatefulRuleSession) session = ruleRuntime.createRuleSession( uri, null, RuleRuntime.STATEFUL_SESSION_TYPE ); session.addObject( new PurchaseOrder( "cheese" ) ); session.executeRules();
- StatelessRuleSession を使用すると、オブジェクトのリストと任意のフィルターを渡す executeRules (List list)のみを呼び出すと、作成されるオブジェクトが返されます。
(StatelessRuleSession) session = ruleRuntime.createRuleSession( uri, null, RuleRuntime.STATELESS_SESSION_TYPE ); List list = new ArrayList(); list.add( new PurchaseOrder( "even more cheese" ) ); List results = new ArrayList(); results = session.executeRules( list );
20.13. JSR94 でのグローバルの使用
20.14. JSR94 の例でのグローバルの使用
java.util.List globalList = new java.util.ArrayList( ); java.util.Map map = new java.util.HashMap( ); map.put( "list", globalList ); //Open a stateless Session StatelessRuleSession srs = (StatelessRuleSession) runtime.createRuleSession( "SistersRules", map, RuleRuntime.STATELESS_SESSION_TYPE ); ... // Persons added to List // call executeRules( ) giving a List of Objects as parameter // There are rules which will put Objects in the List // fetch the list from the map List list = (java.util.List) map.get("list");
package SistersRules; import org.drools.jsr94.rules.Person; global java.util.List list rule FindSisters when $person1 : Person ( $name1:name ) $person2 : Person ( $name2:name ) eval( $person1.hasSister($person2) ) then list.add($person1.getName() + " and " + $person2.getName() +" are sisters"); assert( $person1.getName() + " and " + $person2.getName() +" are sisters"); end
20.15. JSR94 について
- Java Rule Engine API の公式 JCP 仕様(JSR 94)
- Java Rule Engine API ドキュメント
- The Logic From The Bottom Line: An Introduction to The Drools Project.2004 年に TheServiceSide.com で公開されている N. Warehouse Rupp
- Getting Started with the Java Rule Engine API (JSR 94): ルールベースのアプリケーションへDr.Qusay H. Mahmoud (2005 年に Sun Developer Network で公開)
- Jess および javax.rules API。2003 年に TheServerSide.com で公開されている Ernest Friedman-Hill
第21章 JBoss Developer Studio
21.1. ルール統合開発環境(IDE)
21.2. ルール IDE 機能
- テキストエディター/グラフィカルルールエディター
- DRL 構文を認識し、コンテンツサポートを提供します(概要ビューを含む)。
- DSL (ドメイン固有の言語)拡張機能を認識し、コンテンツ支援を提供するエディター。
- ルールフローグラフィカルエディタープロセスを表す視覚グラフ(ルールフロー)を編集できます。次に、RuleFlow をルールパッケージに適用して、命令的な制御を行うことができます。
- 高速な作成ウィザード
- ルールプロジェクト
- ルールリソース(DRL ファイル)
- ドメイン固有の言語
- デシジョンテーブル
- ルールフロー
- ドメイン固有の言語エディター
- ユーザーの言語からルール言語へのマッピングの作成および管理
- ルールの検証
- ルールが入力されると、ルールはバックグラウンドでビルドされ、可能な場合は問題ビューでエラーが報告されます。
21.3. JBoss Rules Runtimes
21.4. JBoss Rules Runtime の定義
手順21.1 タスク
- JBoss Rules で新しいセッションを作成します。
- Window Preferences を選択します。設定ダイアログが表示されます。
- このダイアログの左側で、JBoss Rules カテゴリーで Installed JBoss Rules runtimes を選択します。右側のパネルには、現在定義されている JBoss Rules ランタイムが表示されます。
- 追加 ボタンをクリックします。ランタイムの名前とファイルシステムの場所を求めるダイアログがポップアップ表示されます。
- JBoss Rules Eclipse プラグインからデフォルトの jar ファイルを使用するには、Create a new Drools 5 runtime ... ボタンをクリックして、新しい JBoss Rules ランタイムを自動的に作成します。ファイルブラウザーが表示され、このランタイムを作成するファイルシステムのフォルダーを選択するように求められます。次に、プラグインは必要な依存関係をすべて指定されたフォルダーに自動的にコピーします。
- JBoss Rules プロジェクトの特定のリリースを使用するには、必要な JBoss Rules ライブラリーおよび依存関係がすべて含まれるディレクトリーに、ファイルシステム上に作成します。ランタイムに名前を付け、必要なすべての jar を含むこのフォルダーの場所を選択します。OK をクリックします。
- ランタイムはインストールされた JBoss Rules ランタイムのテーブルに表示されます。新しく作成されたランタイムの前にあるチェックボックスをクリックして、デフォルトの JBoss Rules ランタイムにします。デフォルトの JBoss Rules ランタイムは、プロジェクト固有のランタイムを選択していないすべての JBoss Rules プロジェクトのランタイムとして使用されます。
- デフォルトのランタイムを変更し、デフォルトのランタイムを使用しているすべてのプロジェクトがクラスパスを適宜更新する場合は、Eclipse を再起動します。
21.5. JBoss Rules プロジェクトのランタイムの選択
手順21.2 タスク
New JBoss Rules Project
ウィザードを使用して新しい JBoss Rules プロジェクトを作成します。- または、Java オブジェクトを右クリックし、
Convert to JBoss Rules Project
ダイアログをクリックし、アクションを使用して既存の Java プロジェクトを JBoss Rules プロジェクトに変換します。プラグインは、必要なすべての jar をプロジェクトのクラスパスに自動的に追加します。 - オプションで、
New JBoss Rules Project
ウィザードの最後のページで、プロジェクト固有のランタイムを選択できます。Use default JBoss Rules runtime
チェックボックスの選択を解除し、ドロップダウンボックスで適切なランタイムを選択します。 - 設定にアクセスし、ランタイムを追加するには、ワークスペース設定に移動し、
Configure workspace settings ...
をクリックします。 - プロジェクトプロパティーを開き、JBoss Rules カテゴリーを選択すると、いつでも JBoss Rules プロジェクトのランタイムを変更できます。
Enable project specific settings
チェックボックスを選択し、ドロップダウンボックスから適切なランタイムを選択します。 Configure workspace settings ...
リンクをクリックします。これにより、現在インストールされているランタイムを示すワークスペース設定が開きます。メニューを使用して、このスペースに新しいランタイムを追加します。Enable project specific settings
チェックボックスの選択を解除すると、グローバル設定で定義されているデフォルトのランタイムが使用されます。
21.6. ルールファイルの例
21.7. JBoss Rules Builder
21.8. 新しいルールの作成
手順21.3 タスク
- 空のテキストの .drl ファイルを作成します。
- ルールをコピーして貼り付けます。
- 保存して終了します。
- または、Rules Wizard を使用してルールを作成しますが、
Ctrl+N
を押すか、ツールバーから選択します。 - ウィザードは、ルールリソースを生成するための基本的なオプションを要求します。ルールファイルを保存するには、通常、src/rules ディレクトリーを作成し、適切な名前が付けられたサブディレクトリーを作成します。パッケージ名は必須であり、Java のパッケージ名に似ています。(つまり、関連するルールをグループ化するための namespace を確立します。)
- 最適なオプションを選択し、
Finish
をクリックします。
結果
これで、拡張できるルールのスケルトンができました。
21.9. ルールエディター
Ctrl+Space
を押すと、ポップアップコンテンツのサポートを呼び出すことができます。
21.10. JBoss ルールビュー
- ワーキングメモリービュー
- JBoss Rules ワーキングメモリーのすべての要素を表示します。
- アジェンダビュー
- アジェンダのすべての要素を表示します。アジェンダのルールごとに、ルール名とバインド変数が表示されます。
- グローバルデータビュー
- JBoss Rules のワーキングメモリーで現在定義されているグローバルデータをすべて表示します。
- 監査ビュー
- ルールエンジンの実行中にログに記録されたイベントを含む監査ログをツリー形式で表示するために使用できます。
- Rete ビュー
- これにより、DRL ファイルの現在の Rete Network が表示されます。DRL エディターウィンドウの下部にある Rete Tree タブをクリックして表示します。Rete Network ビジュアライゼーションを開いた状態で、個別のノードでドラッグアンドドロップを使用して、最適なネットワークの概要を配置できます。また、長方形をドラッグして複数のノードを選択して、グループ全体を移動することもできます。注記Rete ビューは、JBoss Rules Builder がプロジェクトのプロパティーに設定されているプロジェクトでのみ機能します。他のプロジェクトでは、回避策を使用できます。現在のプロジェクトの横にある JBoss Rule Project を設定し、Rete ビューで検査するライブラリーと DRL を転送します。DRL エディターの右下のタブをクリックし、Generate Rete View をクリックします。
21.11. JBoss ルールビューの使用
手順21.4 タスク
- JBoss Rules ビューを使用できるようにするには、ワーキングメモリーを呼び出して、コードでブレークポイントを作成します。たとえば、
workingMemory.fireAllRules()
を呼び出す行は、休止を配置するための理想的な場所です。 - デバッガーが結合ポイントで停止する場合は、デバッグ変数ビューで作業メモリー変数を選択します。その後、利用可能なビューを使用して、選択した作業メモリーの詳細を表示できます。
21.12. 論理構造の表示
21.13. 監査ログの作成
手順21.5 タスク
- 監査ログを作成するには、ルールエンジンを実行します。新しい監査ログを作成するオプションが表示されます。
- 次のコードを入力します。
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession(); // Create a new Knowledge Runtime Logger, that logs to file. // An event.log file is created in the subdirectory log dir (which must exist) of the working directory KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger( ksession, "log/event"); ksession.insert(...); ksession.fireAllRules(); // stop logging logger.close();
- Open Log アクション、Audit View の最初のアイコンをクリックしてログを開き、ファイルを選択します。Audit View には、ルールの実行中にログに記録されたすべてのイベントが表示されるようになりました。
21.14. 監査ビューのイベントアイコン
表21.1 監査ビューのイベントアイコン
アイコン | Description |
---|---|
緑の角度 | オブジェクトが挿入されている。 |
黄色の角角 | オブジェクトが更新されました。 |
赤色 | オブジェクトが削除されました。 |
右矢印 | アクティベーションが作成されている。 |
左矢印 | アクティベーションがキャンセルされました。 |
青色の diamond | アクティベーションが実行されました。 |
プロセスアイコン | ルールフローが開始または終了しました。 |
アクティビティーアイコン | ruleflow-group のアクティブ化または非アクティブ化。 |
JBoss Rules アイコン | ルールパッケージを追加または削除しました。 |
21.15. 原因を取得するメソッド
- オブジェクトの変更または取り消しのイベントの原因は、そのオブジェクトの最後のオブジェクトイベントです。これは、オブジェクトをアサートされたイベントまたはそのオブジェクトの最後のオブジェクト変更イベントです。
- アクティベーションがキャンセルまたは実行されたイベントの原因は、対応するアクティベーション作成されたイベントです。
21.16. DSL エディター
21.17. ルール言語マッピング
スコープ
アイテムは式が属する場所を示し、when
項目は LHS、続いて RHS を示し、*
項目はどこにも移動できることを意味します。キーワードのエイリアスを作成することもできます。
21.18. ルール言語マッピングの使用
手順21.6 タスク
- DSL エディターを開き、マッピングタブを選択します。
- マッピング項目(表の行)を選択して、テーブルのテキストフィールドで式とマッピングを確認します。
- ダブルクリックするか、編集ボタンを押して編集ダイアログを開きます。
- 他のボタンでは、マッピングを削除および追加できます。マッピングがまだ使用中の間は削除しないでください。
21.19. DSL 翻訳コンポーネント
表21.2 DSL 翻訳コンポーネント
名前 | duty |
---|---|
parser | パーサーは、DSL 行のルールテキストを行で読み取り、言語式の一部に一致しようとします。一致後、中括弧({age} など)間のプレースホルダーに対応する値はルールソースから抽出されます。 |
プレースホルダー | 対応するルール式のプレースホルダーは、対応する値に置き換えられます。たとえば、自然言語式は、フィールドの年齢と場所に基づいて Person タイプのファクトの 2 つの制約にマップされます。{age} および {location} の値は元のルールテキストから抽出されます。 |
21.20. 大きな DRL ファイルでの操作に関するヒント
- 使用する JDK に応じて、永続的な生成の最大サイズを増やすことができます。これを行うには、で Eclipse を起動します。
-XX:MaxPermSize=###m
- 4000 以上のルールセットでは、永続生成を少なくとも 128Mb に設定する必要があります。
.rule
拡張子を持つファイルにルールを配置することができます。バックグラウンドビルダーは、IDE の実行時間を短縮する変更があるたびにコンパイルを試みません。
21.21. ブレークポイントの作成
手順21.7 タスク
- ルールのデバッグを容易にするブレークポイントを作成するには、DRL エディターを開き、使用する DRL ファイルを読み込みます。
- ブレークポイントを追加する行で、DRL エディターのルールャーをダブルクリックします。ルールブレークポイントは、ルールの結果でのみ作成できることに注意してください。ブレークポイントが許可されていない行をダブルクリックしても何も起こりません。ブレークポイントは、さらにルールャーをダブルクリックすることで削除できます。
- ルーラーを右クリックします。
Toggle breakpoint
アクションが含まれるポップアップメニューが表示されます。ルールブレークポイントは、ルールの結果でのみ作成できることに注意してください。その行でルールブレークポイントが許可されていない場合は、アクションは自動的に無効になります。 - アクションをクリックして選択した行にブレークポイントを追加するか、すでにある場合は削除します。注記Debug パースペクティブには、定義したすべてのブレークポイントの表示、プロパティーの取得、有効化/無効化、削除などに使用できる Breakpoints ビューが含まれます。
21.22. JBoss ルールアプリケーションとしてのデバッグ
手順21.8 タスク
- DRL エディターを開きます。
- アプリケーションのメインクラスを選択します。
- これを右クリックし
、Debug As > サブメニューを
選択し、JBoss Rules Application
を選択します。または、Debug ...
メニュー項目を選択して、デバッグ設定を作成、管理、および実行するための新しいダイアログを開くこともできます。 - 左側のツリーで
Drools Application
項目を選択し、New launch configuration
ボタン(ツリーの上にあるツールバーの左端のアイコン)をクリックします。これにより、最初に選択したメインクラスに基づいて、すでに入力されているプロパティーの一部を持つ新しい設定が作成されます。 - デバッグ設定の名前を意味のあるものに変更します。その他のすべてのプロパティーにはデフォルト値を使用できます。
- 下部の
Debug
ボタンをクリックして、アプリケーションのデバッグを開始します。デバッグ設定は一度だけ定義する必要があります。次回 JBoss Rules アプリケーションを実行すると、ツリーで JBoss Rules ツリーノードのサブ要素として以前に定義した設定を選択し、JBoss Rules ボタンをクリックします。Eclipse ツールバーには、前の設定のいずれかを迅速に再実行するためのショートカットボタンも含まれています。
結果
Debug
ボタンをクリックすると、アプリケーションは実行を開始し、ブレークポイントが発生すると停止します。JBoss Rules ブレークポイントが発生すると、対応する DRL ファイルが開き、アクティブな行が強調表示されます。Variables ビューには、すべてのルールパラメーターとその値も含まれます。その後、デフォルトの Java デバッグアクションを使用して、再開、終了、ステップオーバーなどの次のステップを決定できます。デバッグビューを使用して、作業メモリーの内容と、その時点で Agenda を検証することもできます。現在実行している作業メモリーが自動的に表示されるため、作業メモリーを選択する必要はありません。
21.23. ルール IDE 設定
- Java リソースが変更された場合は、すべてのルールを自動的に再解析します。
- Java クラスが変更されたときに、すべてのルールの再構築をトリガーします。
- DRL ファイルでの相互参照の許可
- DRL ファイルに、別のファイルで定義されている別のリソースを参照させるリソースを指定できるようにします。たとえば、別のファイルで宣言されたタイプを使用して、ファイルにルールを設定できます。このオプションを有効にすると、2 つの異なる DRL ファイルで同じリソース(つまり、同じパッケージに同じ名前の 2 つのルール)を宣言できなくなりました。
- 内部 Drools クラスの使用
- パブリック API で公開されない JBoss Rules クラスの使用を許可または拒否(警告の生成)します。
第22章 Hello World の例
22.1. helloworld 例:ナレッジベースおよびセッションの作成
final KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); // this will parse and compile in one step kbuilder.add(ResourceFactory.newClassPathResource("HelloWorld.drl", HelloWorldExample.class), ResourceType.DRL); // Check the builder for errors if (kbuilder.hasErrors()) { System.out.println(kbuilder.getErrors().toString()); throw new RuntimeException("Unable to compile \"HelloWorld.drl\"."); } // get the compiled packages (which are serializable) final Collection<KnowledgePackage> pkgs = kbuilder.getKnowledgePackages(); // add the packages to a KnowledgeBase (deploy the knowledge packages). final KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); kbase.addKnowledgePackages(pkgs); final StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
KnowledgeBuilder
を使用して、DRL ソースファイルをPackage
オブジェクトに変換します。このオブジェクトは、ナレッジベースが消費できます。- add メソッドは、
Resource
インターフェイスと Resource Type をパラメーターとして取ります。Resource
を使用して、さまざまな場所から DRL ソースファイルを取得できます。この場合、DRL ファイルはResourceFactory
を使用してクラスパスから取得されますが、ディスクファイルまたは URL から取得できます。 - 異なる名前空間の複数のパッケージを同じナレッジベースに追加できます。
- ナレッジベースはパッケージを検証しますが、エラー情報には String としてのみアクセスできます。そのため、エラー情報をデバッグしたい場合は、
KnowledgeBuilder
インスタンスで実行する必要があります。 - ビルダーにエラーが発生したら、
Package
コレクションを取得し、KnowledgeBaseFactory
からKnowledgeBase
をインスタンス化し、パッケージコレクションを追加します。
22.2. helloworld 例:イベントロギングおよび監査
// setup the debug listeners ksession.addEventListener( new DebugAgendaEventListener() ); ksession.addEventListener( new DebugWorkingMemoryEventListener() ); // setup the audit logging KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "log/helloworld");
- デフォルトのデバッグリスナーは、
DebugAgendaEventListener
とDebugWorkingMemoryEventListener
の 2 つです。これらは、コンソールウィンドウに表示されるSystem.err
ストリームにデバッグイベント情報を出力します。 KnowledgeRuntimeLogger
は、グラフィカルビューアーで表示できる実行監査を提供します。このロガーは、Agenda および Working Memory リスナーに構築された特別な実装です。- エンジンの実行が終了したら、
logger.close()
を呼び出す必要があります。
22.3. helloworld 例:メッセージクラス
public static class Message { public static final int HELLO = 0; public static final int GOODBYE = 1; private String message; private int status; ... }
- この例で使用される単一のクラスには、メッセージ(String)と、2 つの整数
HELLO
またはGOODBYE
のいずれかであるステータスの 2 つのフィールドがあります。
22.4. helloworld 例:実行
final Message message = new Message(); message.setMessage("Hello World"); message.setStatus(Message.HELLO); ksession.insert(message); ksession.fireAllRules(); logger.close(); ksession.dispose();
- メッセージテキスト Hello World とステータス
HELLO
で単一のMessage
オブジェクトが作成され、その時点でfireAllRules()
が実行されるエンジンに挿入されます。 - すべてのネットワーク評価は、挿入時に行われます。プログラムの実行が
fireAllRules()
メソッドを呼び出すと、エンジンはすでにどのルールに完全に一致し、実行できるかを認識します。
- Eclipse IDE で
org.drools.examples.helloworld.HelloWorldExample
クラスを開きます。 - クラスを右クリックし、
Run as...
を選択してからJava application
を選択します。
22.5. helloworld 例:コンソールウィンドウの System.out
Hello Goodbye
==>[ActivationCreated(0): rule=Hello World; tuple=[fid:1:1:org.drools.examples.helloworld.HelloWorldExample$Message@17cec96]] [ObjectInserted: handle=[fid:1:1:org.drools.examples.helloworld.HelloWorldExample$Message@17cec96]; object=org.drools.examples.helloworld.HelloWorldExample$Message@17cec96] [BeforeActivationFired: rule=Hello World; tuple=[fid:1:1:org.drools.examples.helloworld.HelloWorldExample$Message@17cec96]] ==>[ActivationCreated(4): rule=Good Bye; tuple=[fid:1:2:org.drools.examples.helloworld.HelloWorldExample$Message@17cec96]] [ObjectUpdated: handle=[fid:1:2:org.drools.examples.helloworld.HelloWorldExample$Message@17cec96]; old_object=org.drools.examples.helloworld.HelloWorldExample$Message@17cec96; new_object=org.drools.examples.helloworld.HelloWorldExample$Message@17cec96] [AfterActivationFired(0): rule=Hello World] [BeforeActivationFired: rule=Good Bye; tuple=[fid:1:2:org.drools.examples.helloworld.HelloWorldExample$Message@17cec96]] [AfterActivationFired(4): rule=Good Bye]
fireAllRules()
メソッドにブレークポイントを配置し、ksession
変数を選択すると、"Hello World" ルールがすでにアクティベートされ、Agenda で、挿入中にすべてのパターンマッチングの作業がすでに行われていることを確認できます。- デバッグリスナーが
System.err
を出力すると、アプリケーションはSystem.out
に移動します。
22.6. helloworld 例:ルール Hello World
rule "Hello World" dialect "mvel" when m : Message( status == Message.HELLO, message : message ) then System.out.println( message ); modify ( m ) { message = "Goodbye cruel world", status = Message.GOODBYE }; end
- ルールの LHS (の後)セクションでは、ステータスが
Message.HELLO
のワーキングメモリーに挿入される各Message
オブジェクトに対してアクティベートされることを示しています。 - 変数バインディングが 2 つ作成されます。変数
message
はmessage
属性にバインドされ、変数m
は一致するMessage
オブジェクト自体にバインドされます。 - ルールの RHS (その
後
)または結果部分は、ルールの属性dialect
で宣言されているように MVEL 式言語を使用して記述されます。 - バインドされた変数
message
のコンテンツをSystem.out
に出力すると、ルールはmessage
および xhtml 属性の値を PROMPT にバインドした値に変更します。status
Message
m
- MVEL の
modify
ステートメントを使用すると、1 つのステートメントに割り当てブロックを適用できます。エンジンはブロックの最後に変更を自動的に通知します。
22.7. helloworld 例:Debug as.. の使用 オプション
手順22.1 タスク
- このデバッグオプションにアクセスするには、Eclipse IDE で
org.drools.examples.HelloWorld
クラスを開きます。 - クラスを右クリックし、Debug as... を選択してから Drools application を選択します。ルールは、その場所に関する情報とともに表示されます。
22.8. helloworld 例:ルール "Good Bye"
rule "Good Bye" dialect "java" when Message( status == Message.GOODBYE, message : message ) then System.out.println( message ); end
- "java" 方言を指定する "Good Bye" ルールは、ステータスが
Message
のオブジェクトと一致する以外は、"Hello World" ルールと似ています。Message.GOODBYE
第23章 顕著性の状態の例
23.1. 顕著性の状態の例:状態クラスの例
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... }
- 各
State
クラスには、名前と現在の状態のフィールドがあります(クラスorg.drools.examples.state.State
を参照してください)。各オブジェクトで使用可能な 2 つの状態はNOTRUN
とFINISHED
です。
23.2. 顕著性の状態例:実行
State a = new State( "A" ); State b = new State( "B" ); State c = new State( "C" ); final State d = new State( "D" ); // By setting dynamic to TRUE, Drools will use JavaBean // PropertyChangeListeners so you don't have to call modify or update(). boolean dynamic = true; session.insert( a, dynamic ); session.insert( b, dynamic ); session.insert( c, dynamic ); session.insert( d, dynamic ); session.fireAllRules(); session.dispose(); // Stateful rule session must always be disposed when finished
- 各インスタンスは Session へとアサートされ、
fireAllRules()
が呼び出されます。
23.3. 顕著性の状態の例:アプリケーションの実行
手順23.1 タスク
- Eclipse IDE で
org.drools.examples.state.StateExampleUsingSalience
クラスを開きます。 - クラスを右クリックし、
Run as...
を選択してからJava アプリケーション
を選択します。以下の出力が表示されます。A finished B finished C finished D finished
23.4. 顕著性の状態の例:操作による監査ロギングの使用
手順23.2 タスク
- 操作によって生成された監査ログを表示するには、IDE を開き、
Window
をクリックしてShow View
、Other. を選択します
(Drools
およびAudit View
)。 - 監査ビューで
Open Log
ボタンをクリックし、<drools-examples-dir>/log/state.log
ファイルを選択します。
23.5. 顕著性の状態の例:ルール "Bootstrap"
rule Bootstrap when a : State(name == "A", state == State.NOTRUN ) then System.out.println(a.getName() + " finished" ); a.setState( State.FINISHED ); end
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
- すべてのアクションと対応する変更が作業メモリーに表示されます。
NOTRUN
状態の State オブジェクト A のアサーションはBootstrap
ルールをアクティブにしますが、他のState
オブジェクトのアサーションはすぐに効果がありません。- ルール Bootstrap を実行すると、A の状態が
FINISHED
に変更されます。これにより、ルール "A to B" が有効になります。
23.6. 顕著性の状態の例:"B to C" ルール
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
- 競合解決ストラテジーにより、エンジンの Agenda が実行するルールを決定できます。
- "B to C" の顕著性の値が 高いので、(デフォルトの顕著性の値 0 と比較して)最初に実行され、オブジェクト C の状態が
FINISHED
に変更されます。 - また、Agenda ビューを使用して Agenda の状態を調査し、デバッグポイントがルール自体に配置され、Agenda ビューが開かれます。
23.7. 顕著性の状態の例:"B to D" ルール
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 D" が実行され、オブジェクト D の状態が
FINISHED
に変更されます。 - および を実行するルールは他にないため、エンジンは停止します。
23.8. 顕著性の状態の例:動的ファクトの挿入
// By setting dynamic to TRUE, JBoss Rules will use JavaBean // PropertyChangeListeners so you don't have to call modify or update(). final boolean dynamic = true; session.insert( fact, dynamic );
- エンジンがファクトプロパティーの変更を確認し、これに対応するには、アプリケーションは変更が発生したことをエンジンに指示する必要があります。これは、
modify
ステートメントを使用してルールで明示的に実行することも、JavaBeans 仕様 で定義されているようにファクトがPropertyChangeSupport
を実装していることをエンジンに認識させることもできます。 - 上記の例は、
PropertyChangeSupport
を使用して、ルールで明示的な変更
ステートメントが不要になる方法を示しています。 - ファクトが
PropertyChangeSupport
を実装していることを確認してください。このクラスはorg.drools.example.State
と同じです。
23.9. 顕著性の状態例:PropertyChangeSupport を使用したセット
public void setState(final int newState) { int oldState = this.state; this.state = newState; this.changes.firePropertyChange( "state", oldState, newState ); }
org.drools.examples
クラスのstate
のセッター。PropertyChangeListener
オブジェクトを使用する場合、各セッターは通知用にいくつかの追加コードを実装する必要があります。
23.10. 顕著性の状態の例:アジェンダグループルール "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
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
- デフォルトでは、すべてのルールはアジェンダグループ "MAIN" にあります。
- "agenda-group" 属性を使用すると、ルールに異なるアジェンダグループを指定できます。最初は、作業メモリーは Agenda グループ "MAIN" にフォーカスします。
- グループのルールは、グループがフォーカスを受けた場合にのみ実行されます。これは、
setFocus()
メソッドまたはルール属性auto-focus
を使用して実現できます。 auto-focus
は、ルールが一致してアクティベートされると、ルールがアジェンダグループに自動的にフォーカスを設定することを意味します。これは、B to D の前に "B to C" ルールを実行できるようにする auto-focus です。- "B to C" のルールは、アジェンダグループ "B to D" で
setFocus()
を呼び出し、アクティブなルールを実行できるようにします。これにより、"B to D" ルールを実行できます。
23.11. 顕著性の状態の例:アジェンダグループルール "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
23.12. 顕著性の状態の例:アジェンダグループルール "D to E"
rule "D to E" when State(name == "D", state == State.FINISHED ) e : State(name == "E", state == State.NOTRUN ) then System.out.println(e.getName() + " finished" ); e.setState( State.FINISHED ); end
A finished B finished C finished D finished E finished
StateExampleWithDynamicRules
ルールベース にfireAllRules()
の後に別のルールを追加します。
第24章 フィボナッチの例
24.1. フィボナッチの例:クラス
public static class Fibonacci { private int sequence; private long value; public Fibonacci( final int sequence ) { this.sequence = sequence; this.value = -1; } ... setters and getters go here... }
- sequence フィールドは、フィボナッチ数シーケンスでのオブジェクトの位置を示すために使用されます。
- value フィールドは、そのシーケンスの位置のフィボナッチオブジェクトの値を示します。-1 を使用して、計算する必要がある値を指定します。
24.2. フィボナッチの例:実行
手順24.1 タスク
- Eclipse IED を起動します。
org.drools.examples.fibonacci.FibonacciExample
クラスを開きます。- クラスを右クリックし、
Run as...
を選択してからJava アプリケーション
を選択します。
結果
Eclipse はコンソールウィンドウに次の出力を表示します(..snip... を使用)。これは、スペースを節約するために削除された行を示します。
recurse for 50 recurse for 49 recurse for 48 recurse for 47 ...snip... recurse for 5 recurse for 4 recurse for 3 recurse for 2 1 == 1 2 == 1 3 == 2 4 == 3 5 == 5 6 == 8 ...snip... 47 == 2971215073 48 == 4807526976 49 == 7778742049 50 == 12586269025
24.3. フィボナッチの例:実行の詳細
ksession.insert( new Fibonacci( 50 ) ); ksession.fireAllRules();
- Java でこれを使用するには、sequence フィールドが 50 の Fibonacci オブジェクトが 1 つ挿入されます。
- 他の 49
Fibonacci
オブジェクトを挿入するために再帰ルールが使用されます。 - この例では MVEL 方言を使用しています。つまり、
modify
キーワードを使用できます。これにより、ブロックセッターアクションが可能になり、エンジンに変更を通知できます。
24.4. フィボナッチの例:再帰ルール
rule Recurse salience 10 when f : Fibonacci ( value == -1 ) not ( Fibonacci ( sequence == 1 ) ) then insert( new Fibonacci( f.sequence - 1 ) ); System.out.println( "recurse for " + f.sequence ); end
- Recurse ルールは、値が -1 のアサートされた各
Fibonacci
オブジェクトを照合し、現在一致したオブジェクトよりもシーケンスが 1 つ小さい新しいFibonacci
オブジェクトを作成し、アサートします。 - 1 と同等の sequence フィールドが存在しない場合に Fibonacci オブジェクトが追加されるたびに、ルールは再度一致して実行されます。
- メモリーにフィボナッチオブジェクト 50 個すべてが存在する場合には、
not
条件要素を使用して、ルールの一致を停止します。 - Recurse ルールには salience の値があるため、Bootstrap ルールの実行前に、50
Fibonacci
オブジェクトがすべてアサートされます。 - Audit ビューに切り替えて、
Fibonacci
オブジェクトの元のアサーションを表示するには、sequence フィールドが 50 で、Java コードで実行されます。そこから、Audit ビューには、ルールの継続的な再帰が表示されます。ここで、それぞれのアサートされたFibonacci
オブジェクトにより、Recurse ルールが有効になり、再度実行されます。
24.5. フィボナッチの例:ブートストラップルール
rule Bootstrap when f : Fibonacci( sequence == 1 || == 2, value == -1 ) // multi-restriction then modify ( f ){ value = 1 }; System.out.println( f.sequence + " == " + f.value ); end
- sequence フィールドが 2 の
Fibonacci
オブジェクトがアサートされると、ブートストラップルールがマッチし、Recurse ルールとともにアクティベートされます。 - フィールド
sequence
のマルチ制限に注意してください。1 または 2 と等価性をテストします。 - sequence が 1 の
Fibonacci
オブジェクトがアサートされると、Bootstrap ルールが再びマッチし、このルールで 2 つのアクティベーションが発生します。sequence が 1 のFibonacci
オブジェクトが存在するとすぐに、not
条件要素がルールの一致を停止するため、Recurse ルールは一致およびアクティブ化されません。
24.6. フィボナッチの例:ルールの計算
rule Calculate when // Bind f1 and s1 f1 : Fibonacci( s1 : sequence, value != -1 ) // Bind f2 and v2; refer to bound variable s1 f2 : Fibonacci( sequence == (s1 + 1), v2 : value != -1 ) // Bind f3 and s3; alternative reference of f2.sequence f3 : Fibonacci( s3 : sequence == (f2.sequence + 1 ), value == -1 ) then // Note the various referencing techniques. modify ( f3 ) { value = f1.value + v2 }; System.out.println( s3 + " == " + f3.value ); end
- 値が -1 以外の
Fibonacci
オブジェクトが 2 つある場合には、Calculate ルールがそれらを一致させることができます。 - 作業メモリーには 50 個の Fibonacci オブジェクトがあります。それぞれの値を順番に計算するには、適切なトリプルを選択する必要があります。
- フィールド制約のないルールでフィボナッチパターン 3 つを使用して、複数の商品を絞り込むと、多くの誤ったルールが実行されることになります。Calculate ルールは、フィールドの制約を使用して、正しい順序でフィボナッチパターンを正しく制約します。この手法は、に 一致するクロス製品 と呼ばれます。
- 最初のパターンでは、値が != -1 の Fibonacci を検索して、パターンとフィールドの両方をバインドします。2 番目の Fibonacci もこれを実行しますが、追加のフィールド制約を追加して、シーケンスが
f1
にバインドされている Fibonacci よりも 1 つ大きいようにします。このルールが初めて実行されると、f1
がシーケンス 1 およびf2
がシーケンス 2 を参照するようにします。最後のパターンでは、値が -1 と同等で、シーケンスがf2
よりも大きい Fibonacci を検索します。 - 利用可能なクロス製品から 3 つのオブジェクトが正しく選択されています。
Fibonacci
f3
にバインドされる 3 番目のFibonacci
オブジェクトの値を計算できます。 modify
ステートメントは、f3
にバインドされるFibonacci
オブジェクトの値を更新します。これは、値が -1 以外の Fibonacci オブジェクトが新たに存在することを意味します。これにより、Calculate ルールを再一致させ、次のフィボナッチ番号を算出することができます。- Audit ビューに切り替えると、最後のブートストラップが
Fibonacci
オブジェクトを変更する方法が示され、"Calculate" ルールが一致できるようになります。次に、別の Fibonacci オブジェクトが変更され、Calculate ルールが再び一致できるようになります。これは、すべてのFibonacci
オブジェクトに値が設定されるまで継続されます。
第25章 銀行の例
25.1. 銀行の例:RuleRunner
public class RuleRunner { public RuleRunner() { } public void runRules(String[] rules, Object[] facts) throws Exception { KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); for ( int i = 0; i < rules.length; i++ ) { String ruleFile = rules[i]; System.out.println( "Loading file: " + ruleFile ); kbuilder.add( ResourceFactory.newClassPathResource( ruleFile, RuleRunner.class ), ResourceType.DRL ); } Collection<KnowledgePackage> pkgs = kbuilder.getKnowledgePackages(); kbase.addKnowledgePackages( pkgs ); StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession(); for ( int i = 0; i < facts.length; i++ ) { Object fact = facts[i]; System.out.println( "Inserting fact: " + fact ); ksession.insert( fact ); } ksession.fireAllRules(); }
- クラス
RuleRunner
は、データセットに対して 1 つ以上の DRL ファイルを実行するために使用されます。パッケージをコンパイルし、実行ごとにナレッジベースを作成します。これにより、各シナリオを簡単に実行し、出力を検査できます。
25.2. 銀行の例:Example1.drl のルール
rule "Rule 01" when eval( 1==1 ) then System.out.println( "Rule 01 Works" ); end
Loading file: Example1.drl Rule 01 Works
- このルールには、常に true になる
eval
条件が 1 つあるため、このルールは開始後に一致して実行されます。 - 出力には、ルールが一致し、単一の print ステートメントを実行します。
25.3. 銀行の例:Java の例 2
public class Example2 { public static void main(String[] args) throws Exception { Number[] numbers = new Number[] {wrap(3), wrap(1), wrap(4), wrap(1), wrap(5)}; new RuleRunner().runRules( new String[] { "Example2.drl" }, numbers ); } private static Integer wrap( int i ) { return new Integer(i); } }
- この例では、基本ファクトをアサートして出力します。
25.4. 銀行の例:Example2.drl のルール
rule "Rule 02" when Number( $intValue : intValue ) then System.out.println( "Number found with value: " + $intValue ); end
Loading file: Example2.drl Inserting fact: 3 Inserting fact: 1 Inserting fact: 4 Inserting fact: 1 Inserting fact: 5 Number found with value: 5 Number found with value: 1 Number found with value: 4 Number found with value: 1 Number found with value: 3
- これは、指定した数字を出力するための基本的なルールです。
Number
オブジェクトであるファクトを特定し、値を出力します。抽象クラスNumber
を使用していることに注意してください。 - パターンマッチングエンジンは、アサートされたオブジェクトのインターフェイスとスーパークラスを照合できます。
- 出力には、DRL が読み込まれ、ファクトが挿入され、一致したルールと実行されたルールが表示されます。挿入された各番号が一致し、実行されると、出力されることが分かります。
25.5. 銀行の例:Example3.java
public class Example3 { public static void main(String[] args) throws Exception { Number[] numbers = new Number[] {wrap(3), wrap(1), wrap(4), wrap(1), wrap(5)}; new RuleRunner().runRules( new String[] { "Example3.drl" }, numbers ); } private static Integer wrap(int i) { return new Integer(i); } }
- これは、基本的なルールベースのソート手法です。
25.6. 銀行の例:Example3.drl のルール
rule "Rule 03" when $number : Number( ) not Number( intValue < $number.intValue ) then System.out.println("Number found with value: " + $number.intValue() ); retract( $number ); end
Loading file: Example3.drl Inserting fact: 3 Inserting fact: 1 Inserting fact: 4 Inserting fact: 1 Inserting fact: 5 Number found with value: 1 Number found with value: 1 Number found with value: 3 Number found with value: 4 Number found with value: 5
- ルールの最初の行は
Number
を識別し、値を抽出します。 - 2 行目は、最初のパターンで見つかった数値よりも小さい番号が存在しないことを保証します。出力後の数字の取り消しは、最小数が削除され、次の最小数を示していることを意味します。
25.7. 銀行の例:Class Cashflow
public class Cashflow { private Date date; private double amount; public Cashflow() { } public Cashflow(Date date, double amount) { this.date = date; this.amount = amount; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public double getAmount() { return amount; } public void setAmount(double amount) { this.amount = amount; } public String toString() { return "Cashflow[date=" + date + ",amount=" + amount + "]"; } }
- クラス
Cashflow
には、日付と数量の 2 つの単純な属性があります。(浮動小数点数はほとんどの数値を正確に表すことができないため、通貨単位にタイプdouble
を使用することは一般的に適切ではありません。) - 値を設定するオーバーロードされたコンストラクターがあり、cashflow を出力するメソッド
toString
があります。
25.8. 銀行の例:Example4.java
public class Example4 { public static void main(String[] args) throws Exception { Object[] cashflows = { new Cashflow(new SimpleDate("01/01/2007"), 300.00), new Cashflow(new SimpleDate("05/01/2007"), 100.00), new Cashflow(new SimpleDate("11/01/2007"), 500.00), new Cashflow(new SimpleDate("07/01/2007"), 800.00), new Cashflow(new SimpleDate("02/01/2007"), 400.00), }; new RuleRunner().runRules( new String[] { "Example4.drl" }, cashflows ); } }
- この例の Java コードは、日付や量が異なる 5 つの Cashflow オブジェクトを挿入します。
25.9. 銀行の例:Class SimpleDate
public class SimpleDate extends Date { private static final SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy"); public SimpleDate(String datestr) throws Exception { setTime(format.parse(datestr).getTime()); } }
- 便利なクラス
SimpleDate
はjava.util.Date
を拡張し、String を入力として取り、日付形式を定義するコンストラクターを提供します。
25.10. 銀行の例:Example4.drl のルール
rule "Rule 04" when $cashflow : Cashflow( $date : date, $amount : amount ) not Cashflow( date < $date) then System.out.println("Cashflow: "+$date+" :: "+$amount); retract($cashflow); end
Loading file: Example4.drl Inserting fact: Cashflow[date=Mon Jan 01 00:00:00 GMT 2007,amount=300.0] Inserting fact: Cashflow[date=Fri Jan 05 00:00:00 GMT 2007,amount=100.0] Inserting fact: Cashflow[date=Thu Jan 11 00:00:00 GMT 2007,amount=500.0] Inserting fact: Cashflow[date=Sun Jan 07 00:00:00 GMT 2007,amount=800.0] Inserting fact: Cashflow[date=Tue Jan 02 00:00:00 GMT 2007,amount=400.0] Cashflow: Mon Jan 01 00:00:00 GMT 2007 :: 300.0 Cashflow: Tue Jan 02 00:00:00 GMT 2007 :: 400.0 Cashflow: Fri Jan 05 00:00:00 GMT 2007 :: 100.0 Cashflow: Sun Jan 07 00:00:00 GMT 2007 :: 800.0 Cashflow: Thu Jan 11 00:00:00 GMT 2007 :: 500.0
Cashflow
を特定し、日付と時刻が抽出されます。- ルールの 2 行目では、見つかったものよりも前の日付の Cashflow がないかどうかを判断します。
- その結果、
Cashflow
が出力されます。これはルールを満たしてから取り除くことで、次のCashflow
を最も早いものにします。
25.11. 銀行の例:Class TypedCashflow
public class TypedCashflow extends Cashflow { public static final int CREDIT = 0; public static final int DEBIT = 1; private int type; public TypedCashflow() { } public TypedCashflow(Date date, int type, double amount) { super( date, amount ); this.type = type; } public int getType() { return type; } public void setType(int type) { this.type = type; } public String toString() { return "TypedCashflow[date=" + getDate() + ",type=" + (type == CREDIT ? "Credit" : "Debit") + ",amount=" + getAmount() + "]"; } }
Cashflow
を拡張すると、TypedCashflow
が発生します。これはクレジットまたはデビット操作になります。
25.12. 銀行の例:Example5.java
public class Example5 { public static void main(String[] args) throws Exception { Object[] cashflows = { new TypedCashflow(new SimpleDate("01/01/2007"), TypedCashflow.CREDIT, 300.00), new TypedCashflow(new SimpleDate("05/01/2007"), TypedCashflow.CREDIT, 100.00), new TypedCashflow(new SimpleDate("11/01/2007"), TypedCashflow.CREDIT, 500.00), new TypedCashflow(new SimpleDate("07/01/2007"), TypedCashflow.DEBIT, 800.00), new TypedCashflow(new SimpleDate("02/01/2007"), TypedCashflow.DEBIT, 400.00), }; new RuleRunner().runRules( new String[] { "Example5.drl" }, cashflows ); } }
rule "Rule 05" when $cashflow : TypedCashflow( $date : date, $amount : amount, type == TypedCashflow.CREDIT ) not TypedCashflow( date < $date, type == TypedCashflow.CREDIT ) then System.out.println("Credit: "+$date+" :: "+$amount); retract($cashflow); end
Loading file: Example5.drl Inserting fact: TypedCashflow[date=Mon Jan 01 00:00:00 GMT 2007,type=Credit,amount=300.0] Inserting fact: TypedCashflow[date=Fri Jan 05 00:00:00 GMT 2007,type=Credit,amount=100.0] Inserting fact: TypedCashflow[date=Thu Jan 11 00:00:00 GMT 2007,type=Credit,amount=500.0] Inserting fact: TypedCashflow[date=Sun Jan 07 00:00:00 GMT 2007,type=Debit,amount=800.0] Inserting fact: TypedCashflow[date=Tue Jan 02 00:00:00 GMT 2007,type=Debit,amount=400.0] Credit: Mon Jan 01 00:00:00 GMT 2007 :: 300.0 Credit: Fri Jan 05 00:00:00 GMT 2007 :: 100.0 Credit: Thu Jan 11 00:00:00 GMT 2007 :: 500.0
- クラスと .drl の両方がルールエンジンに提供されます。
- クラスでは、
Cashflow
オブジェクトのセットが作成され、クレジットまたはデビット操作のいずれかになります。 Cashflow
ファクトは、CREDIT
のタイプで識別され、日付と時刻を抽出します。ルールの 2 行目では、見つかったものよりも前の日付と同じタイプのCashflow
がないことを確認します。その結果、パターンを満たしている cashflow を出力してから取り消し、次に最も早いタイプの cashflow に向けてします。
25.13. 銀行の例:クラスアカウント
public class Account { private long accountNo; private double balance = 0; public Account() { } public Account(long accountNo) { this.accountNo = accountNo; } public long getAccountNo() { return accountNo; } public void setAccountNo(long accountNo) { this.accountNo = accountNo; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public String toString() { return "Account[" + "accountNo=" + accountNo + ",balance=" + balance + "]"; } }
- 2 つの別個の
Account
オブジェクトが作成され、Rule Engine に渡される前にCashflows
オブジェクトに挿入されます。
25.14. 銀行の例:Class AllocatedCashflow
public class AllocatedCashflow extends TypedCashflow { private Account account; public AllocatedCashflow() { } public AllocatedCashflow(Account account, Date date, int type, double amount) { super( date, type, amount ); this.account = account; } public Account getAccount() { return account; } public void setAccount(Account account) { this.account = account; } public String toString() { return "AllocatedCashflow[" + "account=" + account + ",date=" + getDate() + ",type=" + (getType() == CREDIT ? "Credit" : "Debit") + ",amount=" + getAmount() + "]"; } }
TypedCashflow
を拡張すると、Account
参照が含まれるAllocatedCashflow
になります。
25.15. 銀行の例:Example5.java の拡張
public class Example6 { public static void main(String[] args) throws Exception { Account acc1 = new Account(1); Account acc2 = new Account(2); Object[] cashflows = { new AllocatedCashflow(acc1,new SimpleDate("01/01/2007"), TypedCashflow.CREDIT, 300.00), new AllocatedCashflow(acc1,new SimpleDate("05/02/2007"), TypedCashflow.CREDIT, 100.00), new AllocatedCashflow(acc2,new SimpleDate("11/03/2007"), TypedCashflow.CREDIT, 500.00), new AllocatedCashflow(acc1,new SimpleDate("07/02/2007"), TypedCashflow.DEBIT, 800.00), new AllocatedCashflow(acc2,new SimpleDate("02/03/2007"), TypedCashflow.DEBIT, 400.00), new AllocatedCashflow(acc1,new SimpleDate("01/04/2007"), TypedCashflow.CREDIT, 200.00), new AllocatedCashflow(acc1,new SimpleDate("05/04/2007"), TypedCashflow.CREDIT, 300.00), new AllocatedCashflow(acc2,new SimpleDate("11/05/2007"), TypedCashflow.CREDIT, 700.00), new AllocatedCashflow(acc1,new SimpleDate("07/05/2007"), TypedCashflow.DEBIT, 900.00), new AllocatedCashflow(acc2,new SimpleDate("02/05/2007"), TypedCashflow.DEBIT, 100.00) }; new RuleRunner().runRules( new String[] { "Example6.drl" }, cashflows ); } }
- この Java コードは 2 つの
Account
オブジェクトを作成し、それらのいずれかをコンストラクター呼び出しの各 cashflow に渡します。
25.16. 銀行の例:Example6.drl のルール
rule "Rule 06 - Credit" when $cashflow : AllocatedCashflow( $account : account, $date : date, $amount : amount, type == TypedCashflow.CREDIT ) not AllocatedCashflow( account == $account, date < $date) then System.out.println("Credit: " + $date + " :: " + $amount); $account.setBalance($account.getBalance()+$amount); System.out.println("Account: " + $account.getAccountNo() + " - new balance: " + $account.getBalance()); retract($cashflow); end rule "Rule 06 - Debit" when $cashflow : AllocatedCashflow( $account : account, $date : date, $amount : amount, type == TypedCashflow.DEBIT ) not AllocatedCashflow( account == $account, date < $date) then System.out.println("Debit: " + $date + " :: " + $amount); $account.setBalance($account.getBalance() - $amount); System.out.println("Account: " + $account.getAccountNo() + " - new balance: " + $account.getBalance()); retract($cashflow); end
Loading file: Example6.drl Inserting fact: AllocatedCashflow[account=Account[accountNo=1,balance=0.0],date=Mon Jan 01 00:00:00 GMT 2007,type=Credit,amount=300.0] Inserting fact: AllocatedCashflow[account=Account[accountNo=1,balance=0.0],date=Mon Feb 05 00:00:00 GMT 2007,type=Credit,amount=100.0] Inserting fact: AllocatedCashflow[account=Account[accountNo=2,balance=0.0],date=Sun Mar 11 00:00:00 GMT 2007,type=Credit,amount=500.0] Inserting fact: AllocatedCashflow[account=Account[accountNo=1,balance=0.0],date=Wed Feb 07 00:00:00 GMT 2007,type=Debit,amount=800.0] Inserting fact: AllocatedCashflow[account=Account[accountNo=2,balance=0.0],date=Fri Mar 02 00:00:00 GMT 2007,type=Debit,amount=400.0] Inserting fact: AllocatedCashflow[account=Account[accountNo=1,balance=0.0],date=Sun Apr 01 00:00:00 BST 2007,type=Credit,amount=200.0] Inserting fact: AllocatedCashflow[account=Account[accountNo=1,balance=0.0],date=Thu Apr 05 00:00:00 BST 2007,type=Credit,amount=300.0] Inserting fact: AllocatedCashflow[account=Account[accountNo=2,balance=0.0],date=Fri May 11 00:00:00 BST 2007,type=Credit,amount=700.0] Inserting fact: AllocatedCashflow[account=Account[accountNo=1,balance=0.0],date=Mon May 07 00:00:00 BST 2007,type=Debit,amount=900.0] Inserting fact: AllocatedCashflow[account=Account[accountNo=2,balance=0.0],date=Wed May 02 00:00:00 BST 2007,type=Debit,amount=100.0] Debit: Fri Mar 02 00:00:00 GMT 2007 :: 400.0 Account: 2 - new balance: -400.0 Credit: Sun Mar 11 00:00:00 GMT 2007 :: 500.0 Account: 2 - new balance: 100.0 Debit: Wed May 02 00:00:00 BST 2007 :: 100.0 Account: 2 - new balance: 0.0 Credit: Fri May 11 00:00:00 BST 2007 :: 700.0 Account: 2 - new balance: 700.0 Credit: Mon Jan 01 00:00:00 GMT 2007 :: 300.0 Account: 1 - new balance: 300.0 Credit: Mon Feb 05 00:00:00 GMT 2007 :: 100.0 Account: 1 - new balance: 400.0 Debit: Wed Feb 07 00:00:00 GMT 2007 :: 800.0 Account: 1 - new balance: -400.0 Credit: Sun Apr 01 00:00:00 BST 2007 :: 200.0 Account: 1 - new balance: -200.0 Credit: Thu Apr 05 00:00:00 BST 2007 :: 300.0 Account: 1 - new balance: 100.0 Debit: Mon May 07 00:00:00 BST 2007 :: 900.0 Account: 1 - new balance: -800.0
- この例では、日付順序で各 cashflow が適用され、計算され、バランスを出力します。
- クレジットとデビットの個別のルールがありますが、以前の cashflows をチェックするときに型が指定されていません。これは、cashflow タイプに関係なく、すべての cashflows が日付順に適用されるためです。
- アカウントが特定され、その結果として cashflow の量が更新されます。
第26章 課金ルールの例
26.1. 課金ルールの例:価格ルールの例の実行
手順26.1 タスク
- コンソールを開きます。
PricingRuleDTExample.java
ファイルを開き、Java アプリケーションとして実行します。コンソールウィンドウで以下の出力が生成されます。Cheapest possible BASE PRICE IS: 120 DISCOUNT IS: 20
- 以下のコードを使用してサンプルを実行します。
DecisionTableConfiguration dtableconfiguration = KnowledgeBuilderFactory.newDecisionTableConfiguration(); dtableconfiguration.setInputType( DecisionTableInputType.XLS ); KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); Resource xlsRes = ResourceFactory.newClassPathResource( "ExamplePolicyPricing.xls", getClass() ); kbuilder.add( xlsRes, ResourceType.DTABLE, dtableconfiguration );
DecisionTableConfiguration
オブジェクトのタイプはDecisionTableInputType.XLS
に設定されます。この例では、Driver
とPolicy
の 2 つのファクトタイプが使用されます。いずれもデフォルト値で使用されます。Driver
は 30 歳で、以前の請求機能がなく、現在リスクプロファイルはLOW
です。適用されるPolicy
はCOMPREHENSIVE
で、まだ承認されていません。
26.2. 課金ルールの例:デシジョンテーブルの設定
図26.1 デシジョンテーブルの設定
[D]
RuleSet
宣言はパッケージ名を提供します。ここに配置できる他のオプション項目もあります。たとえば、グローバル変数の場合はVariables
、クラスをインポートする場合はImports
です。この場合、ルールの名前空間はファクトクラスと同じであるため、省略できます。RuleTable
宣言の後の名前(価格括弧)は、生成されたすべてのルールの接頭辞として使用されます。- CONDITION または ACTION は、条件の一部または生成されるルールの結果を形成するかどうかに関係なく、列の目的を示します。
- ドライバーのデータは 3 つのセルに分散されます。つまり、その下のテンプレート式が適用されます。ドライバーの年齢範囲(コンマ区切りの値で
$1
および$2
を使用)、locationRiskProfile
、およびそれぞれの列で確認することができます。priorClaims
- ポリシーベース価格とメッセージログを Action 列に設定できます。
26.3. 課金ルールの例:ベース価格の計算例
図26.2 基本価格計算の例
[D]
- カテゴリーの括弧は、左端の列のコメントで示されます。
- ドライバーの詳細は、以前に誤って識別されず 30 歳であるため、行番号 18 に一致します。これにより、120 のベース価格が提供されます。
26.4. 課金ルールの例:ディスカウント計算の例
図26.3 割引計算の例
[D]
Age
ブラケット、以前の請求数、およびポリシータイプからの割引結果。- ドライバーは以前の要求のない 30 であり、
COMPREHENSIVE
ポリシーに適用されます。これは、20% の割引を適用することができることを意味します。これは実際には同じワークシート内の別個のテーブルであるため、異なるテンプレートが適用されることに注意してください。 - ルールエンジンのすべての通常のメカニズムが適用されるため、ルールの評価は必ずしも指定の順序で行われるわけではありません。
第27章 ペットショップの例
27.1. ペットショップの例
PetStore.java
ファイルに含まれます。Swing イベントを処理する複数のクラスに加えて、以下のプリンシパルクラスを定義します。
Petstore
にはmain()
メソッドが含まれます。PetStoreUI
Swing ベースの GUI を作成して表示します。これにはいくつかの小さなクラスが含まれており、マウスボタンのクリックなど、さまざまな GUI イベントに主に応答します。TableModel
テーブルデータを保持します。Swing クラスAbstractTableModel
を拡張する JavaBean です。CheckoutCallback
GUI がルールと対話できるようにします。Ordershow
お客様が購入したいアイテムを保持します。Purchase
注文の詳細と、お客様が購入した製品を保存します。Product
は、購入可能な製品とその価格の詳細を保持する JavaBean です。
27.2. ペットショップの例:PetStore.main での PetStore RuleBase の作成
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kbuilder.add( ResourceFactory.newClassPathResource( "PetStore.drl", PetStore.class ), ResourceType.DRL ); KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() ); // Create the stock. Vector<Product> stock = new Vector<Product>(); stock.add( new Product( "Gold Fish", 5 ) ); stock.add( new Product( "Fish Tank", 25 ) ); stock.add( new Product( "Fish Food", 2 ) ); // A callback is responsible for populating the // Working Memory and for firing all rules. PetStoreUI ui = new PetStoreUI( stock, new CheckoutCallback( kbase ) ); ui.createAndShowGUI();
- 上記のコードは、クラスパスの DRL ファイルからルールを読み込みます。これは、コンストラクターを使用して
PetStoreUI
オブジェクトが作成される 2 番目の行を介して行われます。これは、製品を収集するVector
オブジェクトstock
を受け入れます。 CheckoutCallback
クラスには、読み込まれた Rule Base が含まれます。
27.3. ペットショップの例:CheckoutCallBack.checkout ()からのファアリングルール
public String checkout(JFrame frame, List<Product> items) { Order order = new Order(); // Iterate through list and add to cart for ( Product p: items ) { order.addItem( new Purchase( order, p ) ); } // Add the JFrame to the ApplicationData to allow for user interaction StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession(); ksession.setGlobal( "frame", frame ); ksession.setGlobal( "textArea", this.output ); ksession.insert( new Product( "Gold Fish", 5 ) ); ksession.insert( new Product( "Fish Tank", 25 ) ); ksession.insert( new Product( "Fish Food", 2 ) ); ksession.insert( new Product( "Fish Food Sample", 0 ) ); ksession.insert( order ); ksession.fireAllRules(); // Return the state of the cart return order.toString(); }
- ルールを実行する Java コードは
CheckoutCallBack.checkout()
メソッド内にあります。これは、ユーザーが Checkout ボタンを押すと(最終的に)トリガーされます。 - 2 つの項目がこのメソッドに渡されます。1 つは、
JFrame
Swing コンポーネントのハンドルで、GUI の下部にある出力テキストフレームを囲みます。2 つ目は注文アイテムの一覧です。これは、GUI の右上にある "Table" エリアからの情報を保存するTableModel
から取得されます。 - for ループは GUI からの注文アイテム一覧を
Order
JavaBean に変換します。これは、PetStore.java
ファイルにも含まれています。 - この例のすべての状態は Swing コンポーネントに保存されます。ルールは事実上ステートレスです。
- "Checkout" ボタンが押すたびに、コードは Swing
TableModel
の内容をセッションのワーキングメモリーにコピーします。 - ワーキングメモリーには 9 つの呼び出しがあります。まず、ナレッジベースから、ステートフルナレッジセッションとして新しい作業メモリーを作成します。次の 2 つのオブジェクトは、ルールにグローバル変数として保持される 2 つのオブジェクトを渡します。Swing テキスト領域とメッセージの書き込みに使用される Swing フレーム。
- 作業メモリーと注文一覧に製品の情報をさらに挿入します。最後の呼び出しは、標準
fireAllRules()
です。
27.4. ペットショップの例:PetStore.drl からのパッケージ、インポート、グローバル、および Dialect
package org.drools.examples import org.drools.WorkingMemory import org.drools.examples.petstore.PetStoreExample.Order import org.drools.examples.petstore.PetStoreExample.Purchase import org.drools.examples.petstore.PetStoreExample.Product import java.util.ArrayList import javax.swing.JOptionPane; import javax.swing.JFrame global JFrame frame global javax.swing.JTextArea textArea
PetStore.drl
ファイルの最初の部分には、さまざまな Java クラスをルールで使用できるようにするための標準のパッケージおよびインポートステートメントが含まれます。- 2 つの globals
frame
とtextArea
は、Swing コンポーネントJFrame
と、その参照が xhtml メソッドを呼び出す Java コードによって以前に渡されたJTextArea
コンポーネントへの参照を保持します。setGlobal()
これらのグローバル変数は、Session の存続期間中値を保持します。
27.5. ペットショップの例:PetStore.drl から抽出されたルールの Java 関数
function void doCheckout(JFrame frame, WorkingMemory workingMemory) { Object[] options = {"Yes", "No"}; int n = JOptionPane.showOptionDialog(frame, "Would you like to checkout?", "", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); if (n == 0) { workingMemory.setFocus( "checkout" ); } } function boolean requireTank(JFrame frame, WorkingMemory workingMemory, Order order, Product fishTank, int total) { Object[] options = {"Yes", "No"}; int n = JOptionPane.showOptionDialog(frame, "Would you like to buy a tank for your " + total + " fish?", "Purchase Suggestion", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); System.out.print( "SUGGESTION: Would you like to buy a tank for your " + total + " fish? - " ); if (n == 0) { Purchase purchase = new Purchase( order, fishTank ); workingMemory.insert( purchase ); order.addItem( purchase ); System.out.println( "Yes" ); } else { System.out.println( "No" ); } return true; }
- これらの関数をルールファイルに設定すると、ペットショップの例がよりコンパクトになります。
- 関数は、同じルールパッケージ内に、または標準の Java クラスの静的メソッドとして独自のファイルに関数を追加し、
import function my.package.Foo.hello
を使用してインポートできます。 doCheckout()
チェックアウトするかどうかをユーザーに尋ねるダイアログボックスを表示します。その場合、フォーカスはcheckOut
agenda-group に設定され、そのグループのルールが(今後)実行できるようにします。requireTank()
同時を購入するかどうかをユーザーに尋ねるダイアログボックスを表示します。その場合は、新しい fish tankProduct
が作業メモリーの順序リストに追加されます。
27.6. ペットショップの例:PetStore.drl からの作業メモリーへのアイテム
// Insert each item in the shopping cart into the Working Memory rule "Explode Cart" agenda-group "init" auto-focus true salience 10 dialect "java" when $order : Order( grossTotal == -1 ) $item : Purchase() from $order.items then insert( $item ); kcontext.getKnowledgeRuntime().getAgenda().getAgendaGroup( "show items" ).setFocus(); kcontext.getKnowledgeRuntime().getAgenda().getAgendaGroup( "evaluate" ).setFocus(); end
- 最初の抽出は、
auto-focus
属性がtrue
に設定されているため、最初に実行されます。 - このルールは、
grossTotal
が計算されていない全注文に対して照合されます。この順序で購入アイテムごとにループします。"Explode Cart" ルールの一部は、ルール名、顕著性(ルールが実行される順序を提案)、およびダイアレクトをjava
に設定する必要があります。 agenda-group
init
は、アジェンダグループの名前を定義します。この場合、グループにはルールが 1 つしかありません。ただし、Java コードもルール結果も、このグループにフォーカスされていないため、次の属性に依存することはありません。auto-focus
true
は、アジェンダグループの唯一のルールですが、Java コードからfireAllRules()
が呼び出されると、このルールが実行されるようにします。kcontext....setFocus()
show items
およびevaluate
のアジェンダグループにフォーカスを設定し、ルールを実行できるようにします。実際には、注文上のすべての項目をループしてメモリーに挿入し、挿入するたびに他のルールを実行できます。
27.7. ペットショップの例:PetStore.drl からの GUI のアイテムの表示
rule "Show Items" agenda-group "show items" dialect "mvel" when $order : Order( ) $p : Purchase( order == $order ) then textArea.append( $p.product + "\n"); end
show items
agenda-group には "Show Items" と呼ばれるルールが 1 つしかありません(ケースの違いに注意)。現在作業メモリー(またはセッション)の注文で購入しているたびに、GUI の下部にあるテキストエリアに詳細がログに記録されます。これに使用されるtextArea
変数はグローバル変数です。evaluate
Agenda グループは、Explode Cart
ルールからフォーカスを取得します。
27.8. ペットショップの例:PetStore.drl からのアジェンダグループの評価
// Free Fish Food sample when we buy a Gold Fish if we haven't already bought // Fish Food and don't already have a Fish Food Sample rule "Free Fish Food Sample" agenda-group "evaluate" dialect "mvel" when $order : Order() not ( $p : Product( name == "Fish Food") && Purchase( product == $p ) ) not ( $p : Product( name == "Fish Food Sample") && Purchase( product == $p ) ) exists ( $p : Product( name == "Gold Fish") && Purchase( product == $p ) ) $fishFoodSample : Product( name == "Fish Food Sample" ); then System.out.println( "Adding free Fish Food Sample to cart" ); purchase = new Purchase($order, $fishFoodSample); insert( purchase ); $order.addItem( purchase ); end // Suggest a tank if we have bought more than 5 gold fish and don't already have one rule "Suggest Tank" agenda-group "evaluate" dialect "java" when $order : Order() not ( $p : Product( name == "Fish Tank") && Purchase( product == $p ) ) ArrayList( $total : size > 5 ) from collect( Purchase( product.name == "Gold Fish" ) ) $fishTank : Product( name == "Fish Tank" ) then requireTank(frame, drools.getWorkingMemory(), $order, $fishTank, $total); end
"Free Fish Food Sample"
のルールは、以下の場合にのみ実行されます。
- ストアには fish food があり ません。
- ストアには無料の fish food サンプルがあり ません。
- ストアにはその順序で Gold Fish があります。
"Suggest Tank"
のルールは、以下の場合にのみ実行されます。
- ストアの順序で Fish Tank はあり ません。
- ストアには、5 つ以上の Gold Fish 製品が順番に 含ま れます。
- ルールが実行されると、
requireTank()
関数 を呼び出します。これにより、ユーザーにダイアログが表示され、確認された場合は Tank が注文と作業メモリーに追加されます。 - requireTank()関数を呼び出すと、このルールはグローバル フレーム 変数を渡して、関数が Swing GUI にハンドルを持つようにします。
- ルールが実行されると、新しい製品(Fish Food Sample)を作成し、作業メモリー の順序でこれを追加します。
27.9. ペットショップの例:PetStore.drl からのチェックアウトの展開の実行
rule "do checkout" dialect "java" when then doCheckout(frame, drools.getWorkingMemory()); end
- ルール
"do checkout"
にはアジェンダグループが設定されておらず、auto-focus 属性はありません。そのため、デフォルト(MAIN)アジェンダグループの一部とみなされます。このグループは、明示的にフォーカスを設定した agenda-groups のすべてのルールで、そのユニットを実行した場合に、デフォルトで重点を置いています。 - ルールには LHS がないため、RHS は常に
doCheckout()
関数を呼び出します。 doCheckout()
関数を呼び出す場合、ルールはグローバルframe
変数を渡して、関数に Swing GUI にハンドルを付与します。doCheckout()
関数には、ユーザーに確認ダイアログが表示されます。確認された場合、関数はフォーカスを checkout agenda-group に設定し、次の多くのルールを実行できます。
27.10. ペットショップの例:PetStore.drl からのチェックアウトルール
rule "Gross Total" agenda-group "checkout" dialect "mvel" when $order : Order( grossTotal == -1) Number( total : doubleValue ) from accumulate( Purchase( $price : product.price ), sum( $price ) ) then modify( $order ) { grossTotal = total }; textArea.append( "\ngross total=" + total + "\n" ); end rule "Apply 5% Discount" agenda-group "checkout" dialect "mvel" when $order : Order( grossTotal >= 10 && < 20 ) then $order.discountedTotal = $order.grossTotal * 0.95; textArea.append( "discountedTotal total=" + $order.discountedTotal + "\n" ); end rule "Apply 10% Discount" agenda-group "checkout" dialect "mvel" when $order : Order( grossTotal >= 20 ) then $order.discountedTotal = $order.grossTotal * 0.90; textArea.append( "discountedTotal total=" + $order.discountedTotal + "\n" ); end
Gross Total
製品の価格を合計に累積し、作業メモリーに配置し、textArea
グローバル変数を使用して SwingJTextArea
経由で表示します。- 総計が 10 から 20 までの場合、
Apply 5% Discount
は割引合計を計算し、作業メモリーに追加して、テキストエリアに表示します。 - 総計が 20 未満の場合は、
Apply 10% Discount
は割引合計を計算し、作業メモリーに追加して、テキストエリアに表示します。
27.11. ペットショップの例:PetStore.java の実行
main()
メソッドが実行され、ルールベースのロードが完了しましたが、ルールを実行していません。今のところ、これが、実行されたルールに関連する唯一のコードになります。- 新しい
PetStoreUI
オブジェクトが作成され、後で使用できるように、ルールベースへのハンドルが付与されます。 - Swing コンポーネントはデプロイされ、コンソールはユーザー入力を待機します。
PetStore.java
ファイルにはmain()
メソッドが含まれているため、コマンドラインまたは IDE を介して標準の Java アプリケーションとして実行することができます。これは、クラスパスが正しく設定されていることを前提としています。- 表示される最初の画面はペットショップデモです。利用可能な製品のリスト、選択した製品の空のリスト、チェックアウトおよびリセットボタン、および空のシステムメッセージエリアがあります。
- メソッド
CheckOutCallBack.checkout()
は、"Checkout" ボタンをクリックします。これにより、TableModel
オブジェクトからのデータが挿入され、セッションのワーキングメモリーに挿入されます。次にルールを実行します。 - 最初に実行するルールは、
auto-focus
が true に設定されたルールになります。カート内のすべての製品をループして、製品がワーキングメモリーにあることを確認し、Show Items
およびEvaluation
アジェンダグループに実行する機会を与えます。これらのグループのルールは、カートの内容をテキストエリア(ウィンドウ下部)に追加し、ユーザーに空き fish food を提供するかどうかを決定し、fish tank を購入するかどうかを尋ねます。
27.12. ペットショップの例:Do Checkout ルール
- Do Checkout ルールは、デフォルト(MAIN)アジェンダグループの一部です。これは常に doCheckout ()関数を呼び出し、'Would you like to Checkout?' ダイアログボックスを表示します。
doCheckout()
関数は、フォーカスをcheckout
agenda-group に設定し、そのグループのルールに実行するオプションを提供します。checkout
アジェンダグループのルールはカートの内容を表示し、適切な割引を適用します。- Swing は、他の商品をチェックアウトする(およびルールを再度実行する)か、GUI を閉じるまで待機 します。
第28章 数独の例
28.1. 数独例:例の読み込み
手順28.1 タスク
- IDE で
sudoku.drl
を開きます。 java org.drools.examples.DroolsExamplesApp
を実行し、SudokuExample
をクリックします。ウィンドウには空のグリッドが含まれていますが、プログラムには内部に保存されたグリッドが多数含まれており、ロードおよび解決が可能です。- File → Samples → Simple をクリックして、例の 1 つを読み込みます。グリッドが読み込まれるまで、すべてのボタンが無効になります。
Simple
の例を読み込むと、パズルの初期状態に応じてグリッドが埋められます。 Solve
ボタンをクリックすると、JBoss Rules エンジンが残りの値を入力します。ボタンは再度非アクティブになります。- または、
Step
ボタンをクリックして、ルールセットが見つかった次の数字を表示します。Console ウィンドウには、以下の例のような読み取り可能な形式で手順を解決するために実行されているルールに関する詳細情報が表示されます。single 8 at [0,1] column elimination due to [1,2]: remove 9 from [4,2] hidden single 9 at [1,2] row elimination due to [2,8]: remove 7 from [2,4] remove 6 from [3,8] due to naked pair at [3,2] and [3,7] hidden pair in row at [4,6] and [4,4]
Dump
ボタンをクリックして、グリッドの状態を表示します。セルには、確立された値または残りの候補が表示されます。以下の例を参照してください。Col: 0 Col: 1 Col: 2 Col: 3 Col: 4 Col: 5 Col: 6 Col: 7 Col: 8 Row 0: 2 4 7 9 2 456 4567 9 23 56 9 --- 5 --- --- 1 --- 3 67 9 --- 8 --- 4 67 Row 1: 12 7 9 --- 8 --- 1 67 9 23 6 9 --- 4 --- 23 67 1 3 67 9 3 67 9 --- 5 --- Row 2: 1 4 7 9 1 456 --- 3 --- 56 89 5 78 5678 --- 2 --- 4 67 9 1 4 67 Row 3: 1234 12345 1 45 12 5 8 --- 6 --- 2 5 78 5 78 45 7 --- 9 --- Row 4: --- 6 --- --- 7 --- 5 --- 4 --- 2 5 8 --- 9 --- 5 8 --- 1 --- --- 3 --- Row 5: --- 8 --- 12 45 1 45 9 12 5 --- 3 --- 2 5 7 567 4567 2 4 67 Row 6: 1 3 7 1 3 6 --- 2 --- 3 56 8 5 8 3 56 8 --- 4 --- 3 567 9 1 678 Row 7: --- 5 --- 1 34 6 1 4 678 3 6 8 --- 9 --- 34 6 8 1 3 678 --- 2 --- 1 678 Row 8: 34 --- 9 --- 4 6 8 --- 7 --- --- 1 --- 23456 8 3 56 8 3 56 6 8
28.2. 数独例:破損した例のデバッグ
手順28.2 タスク
- IDE で
sudoku.drl
を開きます。 - File → Samples → !DELIBERATLEY BROKEN! をクリックします。JBoss Rules エンジンはグリッドを検査し、以下の出力を生成します。
cell [0,8]: 5 has a duplicate in row 0 cell [0,0]: 5 has a duplicate in row 0 cell [6,0]: 8 has a duplicate in col 0 cell [4,0]: 8 has a duplicate in col 0 Validation complete.
Solve
ボタンをクリックして、この無効なグリッドに解決ルールを適用します。これらのルールは、問題の解決にセルの値を使用します。これらの状況を検出するルールは、指定したセルのソリューション値を含む Setting ファクトを挿入します。このファクトは、グループのすべてのセルから誤った値を削除します。
28.3. 数独例:Java ソースおよびルール
- Java ソースコードは
/src/main/java/org/drools/examples/sudoku
ディレクトリーにあります。この 2 つの DRL ファイルは、/src/main/rules/org/drools/examples/sudoku
ディレクトリーにあるルールを定義します。 - パッケージ
org.drools.examples.sudoku.swing
には、数独パズルのフレームワークを実装するクラスセットが含まれています。このパッケージには、JBoss Rules ライブラリーの依存関係はありません。 SudokuGridModel
Cell
オブジェクトの 9x9 グリッドとして数独パズルを格納するために実装できるインターフェイスを定義します。SudokuGridView
Swing コンポーネントで、SudokuGridModel
の実装を視覚化できます。SudokuGridEvent
とSudokuGridListener
は、モデルとビューの間の状態の変化の通信に使用されます。セルの値が解決または変更されると、イベントが実行されます。SudokuGridSamples
デモンストレーションの目的で、部分的に埋め込まれた数独パズルを複数提供します。- パッケージ
org.drools.examples.sudoku.rules
には、DRL ファイルをコンパイルするメソッドを持つユーティリティークラスが含まれています。 - パッケージ
org.drools.examples.sudoku
には、重要なCell
オブジェクトとそのさまざまな集約を実装するクラスのセットが含まれています。これには、CellFile
サブタイプ(CellRow
、CellCol
、およびCellSqr
が含まれており、これらはすべてサブタイプになります。CellGroup
28.4. 数独例:Cell Objects
Cell
およびCellGroup
は、SetOfNine
のサブクラスで、プロパティーfree
を提供するタイプになります。Set<Integer>
Cell
の場合は、個別の候補セットを表します。CellGroup
の場合、セットはセルの全候補セットの統合、または割り当ての必要がある数字のセットです。- セルに値を割り当てたり、候補セットから値を削除したりする特定の状況を検出するルールを作成できます。たとえば、81
Cell
および 27CellGroup
オブジェクトを含むCell
オブジェクトの一覧を作成できます。Cell
プロパティーcellRow
、cellCol
、および PROMPT プロパティーで提供されるリンクを組み合わせることもできます。cellSqr
CellGroup
cells
28.5. 数独例:クラスおよびオブジェクト
Setting
クラスに属するオブジェクトは、値の割り当てに伴う操作をトリガーするために使用されます。Setting
ファクトの存在は、プロセスの変更を検出する必要があるすべてのルールで使用されます。これは、一貫性のない中間状態に対する反応を回避するためです。- クラス
Stepping
のオブジェクトは、優先度の低いルールで使用され、"Step" が予期せず終了すると緊急停止を実行します。これは、パズルをプログラムで解決できないことを示します。 - クラス
org.drools.examples.sudoku.SudokuExample
は、上記のコンポーネントを組み合わせた Java アプリケーションを実装します。
28.6. 数独例:Validate.drl
- 数独バリデータールール(validate.drl)は、セルグループの重複番号を検出します。アジェンダグループに統合され、パズルの読み込み後にアクティベートできます。
セルで 3 つのルールが重複
しているのは非常に似ています。最初のパターンでは、値が割り当てられたセルを見つけます。2 つ目のパターンは、セルが属する 3 つのセルグループのいずれかをプルします。最後のパターンでは、それぞれ同じ行、列、または角の中の最初のセルと同じ値を持つセルを検索します。- ルール
終了グループ
は最後に実行されます。メッセージを出力し、halt を呼び出します。
28.7. 数独例:Sudoku.drl
- 数独.drl には、3 種類の解決ルールがあります。1 つのグループは、セルへの数字の割り当てを処理し、2 つ目のグループは実行可能な割り当てを検出し、3 番目のグループは候補セットからの値を削除します。
- ルール
set a value
、eliminate a value from Cell
、およびretract setting
は、このオブジェクトの存在によって異なります。Setting
Set a value
セルへの割り当てと、セルの 3 つのグループの free セットから値を削除する操作を処理します。また、ゼロの場合は、fireUntilHalt()
を呼び出した Java アプリケーションに制御を戻します。Eliminate a value from Cell
新しく割り当てられたセルに関連する全セルの候補リストを減らします。Retract setting
すべての除外が完了したら、トリガーSetting
ファクトを取り消します。- セルに数字を割り当てることができる状況を検出するルールは 2 つだけです。ルール
single
は、単一の数字を含む候補セットでCell
に対して実行されます。ルールhidden single
は、候補が含まれるセルがある場合に実行されますが、この候補は、セルが属するグループの 1 つにある他のすべてのセルに存在しない場合に実行されます。どちらのルールもSetting
ファクトを作成して挿入します。 - ルールの最大グループからのルールは、数独パズルを手動で解決する際に使用される 2 つまたは 3 つのグループのグループで実装されます。
- ルール
naked pair
は、グループの 2 つのセルで同じ候補セットを 2 つ検出します。これらの 2 つの値は、対象グループにあるその他のすべての候補セットから削除できます。 hidden pair in
ルールでは、ルールはグループの 2 つのセルで 2 つの数字のサブセットを検索しますが、このグループの他のセルには値が発生しません。つまり、他の候補はすべて、隠れたペアを持つ 2 つのセルから取り除かれることができます。- ルールのペアは、行と列で
X-wings
を処理します。2 つの異なる行(または列)のそれぞれに値にセルが 2 つしかなく、これらの候補が同じ列(または行)にある場合、列(または行)のこの値の他の候補はすべて除外できます。条件same
またはonly
の結果、適切な制約があるパターン、またはnot
の接頭辞が付けられます。 - ルールペア
intersection removal...
は、1 つの行または 1 つの列のいずれかで、角の中の数字の制限に基づいています。これは、この数字が行または列の 2 つまたは 3 つのセルのいずれかにある必要があることを意味します。これは、グループの他のすべてのセルの候補セットから削除できます。このパターンは、発生制限を確立し、同じセルファイル内で、角の外にあるセルごとに実行されます。 - 非常に困難のグリッドを解決するには、より複雑なルールでルールセットを拡張する必要があります。(最終的には、トライアルとエラーを除いて解決できないパズルがあります。)
第29章 番号に関するガイドの例
29.1. Number Guess の例:サンプルの読み込み
final KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kbuilder.add( ResourceFactory.newClassPathResource( "NumberGuess.drl", ShoppingExample.class ), ResourceType.DRL ); kbuilder.add( ResourceFactory.newClassPathResource( "NumberGuess.rf", ShoppingExample.class ), ResourceType.DRF ); final KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
NumberGuess.drl
にある Number Guess の例は、ルールが実行される順序を制御する方法である Rule Flow の使用を示しています。上記のようにロードされます。
29.2. Number Guess の例:RuleFlow の起動
final StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession(); KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "log/numberguess"); ksession.insert( new GameRules( 100, 5 ) ); ksession.insert( new RandomNumber() ); ksession.insert( new Game() ); ksession.startProcess( "Number Guess" ); ksession.fireAllRules(); logger.close(); ksession.dispose();
- 上記のコードは、パッケージの作成とルールの読み込みを示しています(
add()
メソッドを使用)。 - 同じナレッジベースに異なるルールフローを指定するオプションを提供する Rule Flow (
NumberGuess.rf
)を追加する他の行があります。 - ナレッジベースの記事が作成されると、ステートフルセッションの取得に使用できます。その後、ファクトが挿入されます。
29.3. Number Guess の例:クラスおよびメソッド
NumberGuessExample.java
ファイルに含まれます。
- クラス
GameRules
は、最大範囲と許容される数字の数を提供します。 - クラス
RandomNumber
は、0 から 100 までの数字を自動的に生成し、ルールで利用できるようにします。これは、getValue()
メソッド経由で挿入することで行います。 - クラス
Game
は、行われた数字の数を追跡します。 - プロセスを開始するために、
startProcess()
メソッドが呼び出されます。 - ルールを実行するには、
fireAllRules()
メソッドが呼び出されます。 - 作業メモリーセッションを削除するには、
dispose()
メソッドが呼び出されます。
29.4. Number Guess Example: Observing the RuleFlow
手順29.1 タスク
- Drools IDE で
NumberGuess.rf
ファイルを開きます。標準のフローチャートと同様に機能する図が表示されます。 - ダイアグラムを編集するには、IDE のダイアグラムの左側にある利用可能なコンポーネントのメニューを使用します。これは パレット と呼ばれます。
- XML でダイアグラムを保存します。(インストールされている場合は、XStream を使用してこれを行うことができます。)
- まだ開いていない場合は、Properties View が IDE に表示されることを確認します。これを開くには、Window → Show View → Other をクリックし、
Properties
ビューを選択できます。ルールフローのアイテムを選択する 前 にこれを行うと、プロパティーが表示されます。これらのプロパティーを使用してプロセスを特定し、変更を確認できます。
29.5. Number Guess 例:RuleFlow ノード
- Start node (緑色の円の左矢印)および End node (red box)のマークは、ルールフローの開始と終了です。
- Rule Flow Group ボックス(アイコンのない黄色)は、ルール(DRL)ファイルで定義された Rule Flow Groups を表します。たとえば、フローが Rule Flow Group "Too High" に到達すると、
ruleflow-group
"Too High"
の属性でマークが付けられたルールのみが実行される可能性があります。 - アクションノード(黄色の cog-shaped アイコン)は、標準の Java メソッド呼び出しを実行します。この例のほとんどのアクションノードは、
System.out.println()
を呼び出して、プログラムの進行状況をユーザーに示します。 - Split and Join Nodes (青い ovals, no icon)(Guess Correct? や More guesses Join のマークで、コントロールのフローが分割および再参加できる場所)。
- 矢印は、さまざまなノード間のフローを示します。
29.6. Number Guess の例:numberGuess.drl の特定のポイントでのルールのフェデレーション
rule "Get user Guess" ruleflow-group "Guess" no-loop when $r : RandomNumber() rules : GameRules( allowed : allowedGuesses ) game : Game( guessCount < allowed ) not ( Guess() ) then System.out.println( "You have " + ( rules.allowedGuesses - game.guessCount ) + " out of " + rules.allowedGuesses + " guesses left.\nPlease enter your guess from 0 to " + rules.maxRange ); br = new BufferedReader( new InputStreamReader( System.in ) ); i = br.readLine(); modify ( game ) { guessCount = game.guessCount + 1 } insert( new Guess( i ) ); end
- ルールと組み合わせてさまざまなノードにより、Number Guess ゲームが機能します。たとえば、"Guess" Rule Flow Group では、"Get user Guess" ルールのみが
ruleflow-group
"Guess"
の一致する属性を持つため、ルール get user Guess のみを実行できます。 - ルールの LHS セクション(の
場合
は)は、作業メモリーに挿入される各RandomNumber
オブジェクトに対してアクティベートされることを示します。ここで、guessCount
はGameRules
オブジェクトからのallowedGuesses
未満であり、ユーザーは正しい番号を推測していません。 - RHS セクション(または の
後
に)は、ユーザーにメッセージを出力し、System.in
からユーザー入力を待ちます。この入力を取得した後(戻り値が押すまでreadLine()
メソッド呼び出しがブロックされる)は、推測数を変更し、新しい数字を挿入し、両方を作業メモリーで利用できるようにします。 - パッケージは dialect を MVEL として宣言し、さまざまな Java クラスがインポートされます。
- 上記で確認したルールであるユーザーガイドを取得します。
- 最も高い数字を記録するルール。
- 最も低い数字を記録するルール。
- 正しくない場合に推測を検査し、メモリーから取り消すルール。
- すべての数字が使用されていることをユーザーに通知するルール。
29.7. Number Guess の例:RuleFlow 制約の表示
手順29.2 タスク
- IDE で
Properties
ビューに移動し、Constraints プロパティー行をクリックして Constraints Editor を開きます。 To node Too High
の横にあるEdit
ボタンをクリックして、さまざまなオプションと共に表示されるダイアログを開きます。Textual Editor
ウィンドウの値は、LHS の標準ルール形式に従い、Working Memory でオブジェクトを参照できます。結果(RHS)は、LHS 式が true と評価されると、制御のフローがこのノード(つまり Too High)に
従うことです。
29.8. Number Guess 例:コンソール出力
You have 5 out of 5 guesses left. Please enter your guess from 0 to 100 50 Your guess was too high You have 4 out of 5 guesses left. Please enter your guess from 0 to 100 25 Your guess was too low You have 3 out of 5 guesses left. Please enter your guess from 0 to 100 37 Your guess was too low You have 2 out of 5 guesses left. Please enter your guess from 0 to 100 44 Your guess was too low You have 1 out of 5 guesses left. Please enter your guess from 0 to 100 47 Your guess was too low You have no more guesses The correct guess was 48
NumberGuess.java
ファイルにはmain()
メソッドが含まれるため、コマンドラインまたは IDE を介して標準の Java アプリケーションとして実行できます。一般的なゲームにより、上記の対話が発生する可能性があります。太字の数字はユーザーによって入力されました。NumberGuessExample.java
のmain()
メソッドは、Rule Base を読み込み、Stateful Session を作成し、Game
、GameRules
、およびRandomNumber
(ターゲット番号を含む)オブジェクトを挿入します。この メソッドは、使用するプロセスフローも設定し、すべてのルールを実行します。コントロールは RuleFlow に渡されます。- RuleFlow ファイル
NumberGuess.rf
は起動ノードで開始します。 - Guess ノードで、適切な Rule Flow Group (Get user Guess)が有効になります。この場合、ルール Guess.drl (number
Guess.drl
ファイル内)がトリガーされます。このルールはユーザーにメッセージを表示し、応答を取得して、Working Memory に配置します。フローは次の Rule Flow ノードに渡されます。 - 次のノードである Guess Correct 制約は、現在のセッションを検査して、取得するパスを決定します。ステップ 4 の数字が高すぎる、または低すぎると、フローは、通常の Java コードを持つアクションノードがあるパスと、適切なメッセージと Rule Flow Group を出力するパスに進みます。これにより、最大推測または最小推測ルールがトリガーされます。フローはこれらのノードからステップ 6 に渡されます。ステップ 4 の推測が右側である場合は、RuleFlow の最後へのパスに進みます。この前は、通常の Java コードを持つアクションノードが "you guessed correctly" ステートメントを出力します。ここに結合ノードがあります(ルールフローの終了の直前に)ます。したがって、no-more-gueses パス(ステップ 7)も RuleFlow を終了することができます。
- コントロールは、結合ノードを介して RuleFlow に従って、"guess incorrect" RuleFlow Group (作業メモリーから推測を取り消しるルールをトリガーする)、および "More guesses" デシジョンノードに渡します。
- "More guesses" デシジョンノード(ルールフローの右側)は制約を使用し、ルールがワーキングメモリーに置かれた値を再度確認し、ユーザーがより多くの推測を持つかどうかを判断します。その場合は、ステップ 3 に移動します。そうでない場合には、ユーザーは RuleFlow グループを介して RuleFlow の最後に進みます。このグループで、"you have more guesses" というルールをトリガーします。
- ステップ 3 から 7 のループは、数字が正しく推測されるか、ユーザーが推測するまで継続されます。
付録A 更新履歴
改訂履歴 | |||
---|---|---|---|
改訂 5.3.1-73.400 | 2013-10-31 | Rüdiger Landmann | |
| |||
改訂 5.3.1-73 | Tue Feb 05 2013 | David Le Sage | |
|