LoginSignup
1
0

【Drools】Rule Unitについて学ぶ

Last updated at Posted at 2023-08-20

本記事では、Droolsの「Rule Unit」について学んだことを記載していきます。

Rule Unitとは
サンプルコード
Rule Unitのメリット

Rule Unitとは

Drools version 8 で新たに追加された、ルールを実装・実行する仕組みです。

過去記事では、クラスパスに配置したDRLファイルからKieContainerを生成して、ルールを実行する方法を紹介していました。

Drools version 7 まではこの方法が一般的でしたが、version 8 からはRule Unitを使う方法が推奨されており、公式ドキュメントのチュートリアルもその方法に則ったものになっています。

Rule Unitは、アプリケーションで実行するRuleと、DataSourceという二つの要素からなります。

※ 矢印はデータの参照や更新

構成要素のうちのRuleは、これまでと同様DRLファイルなどで定義されたルールを指します。

DataSourceは、ルールが参照するデータを明示的に定義して、ルール実行時に保存できるようにするための要素です。
ルールの実行側はDataSource内のデータを操作することで、Rule Unitとやり取りすることができます。
DataSourceとしては、以下3種類が用意されています。

  • DataStream
    • データを追加するため専用のDataSourceです
    • 後述のDataStoreのように、更新や削除はできないようです
  • DataStore
    • データの追加や、追加したデータの更新・削除を行うことのできるDataSourceです
  • SingletonStore
    • DataStoreと同じようなものですが、追加できるデータは1件のみのようです
    • 公式ドキュメントのRule Unitの概念図にも登場しないですが、DataStoreの一種という扱いなのかなと思います

各要素について詳細は、公式ドキュメントも参照してください。

サンプルコード

Rule Unitの仕組みを使ってどのようにルールを作成・実行するかを見ていきます。
紹介するサンプルコードの全量はGitHubにアップしています。
題材は過去記事と同様、顧客の年齢をもとにドリンクを決定するルールとなっています。

データクラス作成

ルールで扱うデータクラスを用意します。

Drink.java
public class Drink {

    private String name;

    private int charge;
...
Person.java
public class Person {

    private String name;

    private int age;
...

Rule Unitの作成

RuleUnitDataクラスをimplementして、Rule Unitクラスを作成します。
本クラスは以下のフィールドをもちます。

  • persons
    • Personオブジェクトを保持するためのDataStore
    • Personオブジェクトは、ドリンクを決定するためのルールの入力値となります
  • drinkList
    • ルールで決定したDrinkオブジェクトを保持するためのリスト
DrinkRuleUnit.java
public class DrinkRuleUnit implements RuleUnitData {
    
    private DataStore<Person> persons;

    private List<Drink> drinkList = new ArrayList<>();

    public DrinkRuleUnit() {
        this(DataSource.createStore());
    }

    public DrinkRuleUnit(DataStore<Person> persons) {
        this.persons = persons;
    }

    public void setPersons(DataStore<Person> persons) {
        this.persons = persons;
    }

    public DataStore<Person> getPersons() {
        return persons;
    }

    public List<Drink> getDrinkList() {
        return drinkList;
    }
   
}

ルールの作成

ルールをDRLファイルに記述します。

Sample.drl
package org.example.ruleunit.drlsample;
unit DrinkRuleUnit;

rule "Child"
    when
        /persons[ age < 20 ]
    then
        drinkList.add(new Drink("Orange Juice", 100));
end

rule "Adult"
    when
        /persons[ age >= 20 ]
    then
        drinkList.add(new Drink("Beer", 200));
end

ここで

unit DrinkRuleUnit;

のようにRule Unitのクラスを指定することで、DRLファイルと作成したRule Unitとの紐づけを行っています。

また、「20歳未満のPersonオブジェクトが存在する場合」という条件を以下のように記述しています。

    when
        /persons[ age < 20 ]
    then

ここではOOPathという構文を使用して、DrinkRuleUnit内のpersonsフィールドを照合しています。
Drools version 8 ドキュメント内のDRLは、OOPathの構文を使ったものが多いため、それに倣っています。
※ 公式ドキュメント New and traditional syntax

以上でルールの実装は完了です。
Drools version 7 ではkmodule.xmlをリソースパスに追加していましたが、Rule Unitでは不要です。

ルール実行用のテストクラス作成

ルール実行のコードは以下のように書くことができます。

SampleTest.java
    @Test
    public void test_ドリンクの決定() {
        DrinkRuleUnit drinkRuleUnit = new DrinkRuleUnit();
        RuleUnitInstance<DrinkRuleUnit> instance = RuleUnitProvider.get().createRuleUnitInstance(drinkRuleUnit);

        var person = new Person("Taro", 20);
        drinkRuleUnit.getPersons().add(person);

        // execute rule 
        instance.fire();

        // assert
        var drink = drinkRuleUnit.getDrinkList().get(0);
        assertEquals("Beer", drink.getName());

        instance.close();
    }

本テストが問題なくパスするため、ルールがPersonオブジェクト(name="Taro", age=20)を受け取って、想定通りのDrink(Beer)を生成したことがわかります。

Rule Unitのメリット

公式ブログでは、以下のようにRule Unitのコンセプトが紹介されています。

a rule unit encapsulates the unit of execution for rules and the data against which the rules will be matched.

大規模なアプリケーションになると、ルールを記述したDRLファイルと、ルールが参照するデータクラスが肥大化していくことが予想されます。
Rule Unitという単位でルールとデータをカプセル化することで管理しやすくし、アプリケーションの保守性を高めるメリットがあると思います。

実際に今回サンプルコードを書いてみて、RuleUnitDataとDataSourceにより、ルールを呼び出すJavaコードとルールとの間のインターフェースが明解になっていると感じました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0