BRMSで実験してみました-宣言的プログラミングのすすめ (2)-

Droolsを使って、ルールベース(BRMS)の動きを見るためにちょっと実験してみました。Droolsで、Projectをつくるとサンプルのプログラムをつくってくれますが、それをすこしばかり修正しての実験です。
(ルールベースの動きの基本は、プロダクションシステムとはとか、当ブログのルールベースプログラミングのカテゴリなどを参照ください)

まずは、ルール処理の対象となるファクトを準備します。

SampleFact.java

package com.sample;

public class SampleFact {
    private int num;
    private String name;

    public SampleFact() {
        super();
    }

    public SampleFact(int num, String name) {
        super();
        this.num = num;
        this.name = name;
    }

    /**
     * @return the num
     */
    public int getNum() {
        return num;
    }

    /**
     * @param num the num to set
     */
    public void setNum(int num) {
        this.num = num;
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "SampleFact [num=" + num 
                   + ", name=" + name + "]";
    }

}

そして、mainプログラム

DroolsTest.java

package com.sample;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

/**
 * This is a sample class to launch a rule.
 */
public class DroolsTest {
  public static final void main(String[] args) {
    try {
      // load up the knowledge base
      KieServices ks
       = KieServices.Factory.get();
      KieContainer kContainer
       = ks.getKieClasspathContainer();
      KieSession kSession
       = kContainer.newKieSession("ksession-rules");

      // go !
      SampleFact sf1 = new SampleFact(1, "A");
      SampleFact sf2 = new SampleFact(2, "B");
      SampleFact sf3 = new SampleFact(3, "C");
      SampleFact sf4 = new SampleFact(4, "D");
      SampleFact sf5 = new SampleFact(5, "E");
      kSession.insert(sf1);
      kSession.insert(sf2);
      kSession.insert(sf3);
      kSession.insert(sf4);
      kSession.insert(sf5);
      kSession.fireAllRules();
    } catch (Throwable t) {
      t.printStackTrace();
    }
}

上のように5つのファクトをワーキングメモリに追加して、以下のルール

Sample.drl

package com.sample

rule "サンプルルール1"
when
    SampleFact($num: num, $name: name)
then
    System.out.println("num=" + $num
         + ", name=" + $name);
end

を実行しました。
コンソールには、どのように表示されるでしょうか。

まあ、これはワーキングメモリに5つのファクトがあるので、単純に
条件節(when部分)のSampleFactにマッチして、5回ルールのサイクルが回ります。

num=5, name=E
num=4, name=D
num=3, name=C
num=2, name=B
num=1, name=A

つまり条件部にマッチしたファクトが
SampleFact(1, “A”);
SampleFact(2, “B”);
SampleFact(3, “C”);
SampleFact(4, “D”);
SampleFact(5, “E”);
の5つだったということ。

では、上記のサンプルルール1のかわりに次のルールがあった場合は
どうなるでしょうか

Sample.drl(改)

package com.sample

rule "サンプルルール1a"
when
    SampleFact($num: num > 3, $name: name)
then
    System.out.println("num=" + $num
         + ", name=" + $name);
end

このときは条件節に num > 3 という条件が加わったので
num=5, name=E
num=4, name=D
の2つのみが表示されます。

すなわち条件部にマッチしたファクトが
SampleFact(4, “D”);
SampleFact(5, “E”);
の2つということ。

さらに次はどうでしょう。

Sample.drl(改々)

package com.sample

rule "サンプルルール2"
when
    SampleFact($num: num, $name: name)
    SampleFact($num1: num, $name1: name)
then
    System.out.println("num=" + $num
         + ", name=" + $name
         + ", num1=" + $num1
         + ", name1=" + $name1);
end

今度は、条件節のSampleFactのパターンが2つになりました。結果は、
num=1, name=A, num1=1, name1=A
num=1, name=A, num1=2, name1=B
num=1, name=A, num1=3, name1=C
  ・・・(中略)・・・
num=5, name=E, num1=4, name1=D
num=5, name=E, num1=5, name1=E

以上、25行表示されました。

これは、条件節の最初のパターン
SampleFact($num: num, $name: name)
に5つのファクトがマッチして、さらに2番目のパターンにも
SampleFact($num1: num, $name1: name)
5つのファクトがマッチして結局その組合せとして5×5=25(通り)の
組合せが表示されているということを表しています。つまり

条件部にマッチしたファクトの組を
[<最初のパターンにマッチしたファクト>,<2番目のパターンにマッチしたファクト>]
の形であらわすとすると、

[SampleFact(1, “A”), SampleFact(1, “A”)]
[SampleFact(1, “A”), SampleFact(2, “B”)]
[SampleFact(1, “A”), SampleFact(3, “C”)]
  ・・・(中略)・・・
[SampleFact(5, “E”), SampleFact(4, “D”)]
[SampleFact(5, “E”), SampleFact(5, “E”)]

の25個のファクトの組が条件部にマッチしたことになります。

では、こんなルールであったらどうでしょうか。

Sample.drl(もひとつ改)

package com.sample

rule "サンプルルール2a"
when
    SampleFact($num: num, $name: name)
    SampleFact($num1: num > $num, $name1: name)
then
    System.out.println("num=" + $num
         + ", name=" + $name
         + ", num1=" + $num1
         + ", name1=" + $name1);
end

(この項続く)

プログラミングパラダイムとしてのルールベース

サグラダファミリアBRMSの多くが依拠しているルールを用いたプログラミング(ルールベースプログラミング)について、最近はなかなか正面からの解説が少ないように思います。これは、最近のBRMSの適用例の多くが入力チェックや、査定、不正検知など、あまりルールベースのプログラミングのプログラミング上の特徴が表れてこない例が多く、あえてルールベースプログラミングを強調することもないということだからでしょうか。

(なお、ここで言う「ルール」を用いたプログラミングとは、通常のプログラミング言語で言うところの if 文を手続き的に整理した「ルール」ではなく、いわゆるプロダクションシステムにおける「ルール」、すなわちアルゴリズム的にはRete(およびその改良版)、DeTI、(最近では)Phreakなどを採用しているルールエンジンの「ルール」、を用いたプログラミングのことになります)

とはいえ、やはり通常のプログラミング言語 -手続き型- の延長としてルールベースプログラミングを理解してしまうと、時によってルールベースプログラミングの良さを引き出せないままBRMSを使ってしまったり…ということがありそうな例を (かなり前ですが) 見聞きしたのでちょっとここで紹介したいと思います。

例題
ある入力画面で、氏名の入力欄(たとえば保険金受取人)が
10段並んでいる。入力チェックとして、違う欄に同じ氏名が
入力されていたらエラーとしたい。

これ、通常のプログラミング言語で書こうとすると、二重の for 文 を回して同じ氏名が入力されていないかチェックするということになると思います。ところが、ルールベースプログラミングですと 「違う欄に同じ氏名が入力されていたらエラー」 ということをそのまま一つのルールとして実装するだけでプログラミングが完了します。

rule "重複チェックルール"
    when
        c1 : Column( id1 : id_No , name1 : name != "");
           // 名前が空白のものは対象外にする
        c2 : Column( id2 : id_No > id1, name == name1 );
           // 欄は違う (id_Noが違う)  けれども 名前は同じ。
    then
        System.out.println("重複がありました。名前は" + name1
                             + "id=" + c1.getId_No()
                             + " と id=" + c2.getId_No()
                             + "です。");
end

なお、ここで名前欄を表す

public class Column {
    private int id_No;
    private String name;
    // getter, setter  ほか
}

というクラスを用いています。

このルールを以下のデータ

Column [id_No=1, name=野中]
Column [id_No=2, name=伊丹]
Column [id_No=3, name=伊丹]
Column [id_No=4, name=大前]
Column [id_No=5, name=嶋口]
Column [id_No=6, name=野中]
Column [id_No=7, name=]
Column [id_No=8, name=野中]
Column [id_No=9, name=]
Column [id_No=10, name=]

に適用してみると、

重複がありました。名前は野中id=1 と id=6です。
重複がありました。名前は野中id=1 と id=8です。
重複がありました。名前は伊丹id=2 と id=3です。
重複がありました。名前は野中id=6 と id=8です。

といった結果になります。

このようにルールベースのプログラミングでは、繰り返しを明示的に書くことは多くの場合必要ありません。もちろん、ルールベースでもカウンタにあたる属性あるいはFactなどを作って繰り返しを表現することは可能なのですが、概して繰り返しを書かずとも望む結果が得られる場合が多いです。なので、もし繰り返しが必要になりそうなときは本当にその繰り返しが必要かどうか自問自答してみるべきです。

この繰り返しを書く必要がないというところは、次のルールベースプログラムの実行原則のひとつに拠っています。

条件に合うものは「全部」実行する。実行するものがなくなったら終了。

ここの「全部」というところは、通常の手続き型のプログラミング言語では for や while などや、さらにたとえば iterator を使って繰り返しも含めたプログラミングすることになるでしょうが、この繰り返しは、ルールベースでは上記にあげた実行原則に見るように、すでに実行の機構として言語に含まれてしまっています。したがってルールベースプログラミングでは、「何をするか」というルールの記述のみを行えばよいことになります。

翻って、人間の職場の作業依頼/指示について考えてみましょう。たとえば、書類の束を渡して、「XXのチェックしておいて」とか「チェックして印鑑お願いします」とか…「何を」行うかのみの依頼/指示だけで、手続き的に「上から順に」チェックするとか、「全部」チェックするとかの指示はしないのが普通でしょう。

ルールベースプログラミングの基本は、「どのように」処理を実行するかの記述を省き、単刀直入に「何をするか」ということをルールで記述していくところにあります。これがまさにルールベースプログラミングが宣言的プログラミングであるといわれる所以であり、また、ルールベースのプログラムが人間の感覚に近いと言われる所以でもあります。

上の例のルールを見てみましょう。処理そのものを追ってみると、

条件部の1行目(c1にあたるところ)は、Column( というところだけを見ると、データとしてあげた10個のColumnファクトすべてがマッチする可能性がありますが、name != “” というところまで見ていくと、10個のファクトのうち id_No=7,9 のファクトは対象外となります。残りの8個のファクトが c1 にマッチするということになります。
次に2行目(c2)。id_Noがc1のid_Noより大きく(違う != という条件でもよいのですが、同じ結果の組が2つ出てきてしまう-たとえばid=1とid=6の組、id=6とid=1の組の2つ-ので不等号の条件にしています…念のため)、名前が同じという条件にすると、c1とc2の組み合わせで、上記に示したような結果が得られるというわけ。

ですが、ルールの条件部を先入観を持たずに見てみると、単純に例題の「違う欄に同じ氏名が入力されていたら」を記述しただけ (注1)ということがわかると思います。

以上、例題を通して、ルールベースプログラミングの特徴 (の一つ) を見てきました。最初にも書いたようにBRMSの最近の適用例はあまりルールベースプログラミングの特徴が表れにくいものが多いのですが、例題としてもあげたように、ところどころルールベース的に書くべきところも散見されるので今回、とりあげてみました。

さて、これを言ってしまうと、場合によってはルールベースの敷居の高さを感じてしまう方もおられるかもしれませんが、そもそもルールベースプログラミングは、通常の手続き型のプログラミングとはパラダイムが違います。ただ、いわゆる関数型のパラダイムの(Haskellの)モナドとか、論理型で言えばPrologのカットオペレータとか、わかりにくい概念というものはなく(注2)、「if-thenルールの条件にマッチするものを実行する」という人間の素朴な直感にマッチしたパラダイムなのでそれほど身構える必要はありません。むしろ手続き型のように、「どのように」実行するかを書いていく必要がない分、ルールベースでは単刀直入に「何を行うか」を書けるのでわかりやすいとも言えましょう。もっとも、だからこそBRMSが流行っているのだとは思いますが。

(注1) 名前が空白でないという追加の条件は加えています。
(注2) 強いて言えば競合解消戦略がわかりにくいかと思いますが、最近はあまり競合解消戦略に依存するようなルールの書き方はしないので、あまり問題にはならないでしょう。

Red Hat フォーラム 2013…生産計画とBRMS

金曜日に、Red Hat フォーラム 2013 に行ってきました。もちろんJBoss BRMS に関連するセッションを聞いてきたのですが、今回の一番の収穫は、生産計画にBRMSを適用してうまくいった事例を聞けたこと。

今まで、生産計画にBRMSというのは、昔の経験もあって個人的には二の足を踏む感があったのですが、実際成功事例を聞いてみると、ケースによっては案外行けるかも…と思わせるものでした。

話を聞いてみると、制約条件がかなり厳しいらしく、想像するに、専門家の「コツ」とかいった、アドホックで適用するべき状況の曖昧な、いわゆる「ガイドライン」的なルールが入る余地がないというケースのようで、こんな場合なら結構アリかも…。

生産計画の場合、ルールによって生成・更新された新たなファクトが、さらにルールの発火を促す…という推論過程が発生するため、ルールエンジンとしては、きちんと推論機能を持ったエンジンでないと適用は難しいかと思います。

しかし、それだけに、生産計画は、現在、BRMS適用の主流となっている、(ロジック的には単純な)、データの妥当性チェックや査定などの分野を超え、ロジックとして一段高いレベルでの適用分野となり、BRMSとしての特徴がより発揮されてくるようになるのではないでしょうか。

OpenRules入門

オープンソースのBRMSとして、OpenRulesを試してみました。Drools もBRMSとして完成度が高く、さまざまな高度な技もできたり柔軟な対応ができますが、一方でDroolsでルールを実際に動かすまでにはそれなりに準備が必要で、(プロジェクトをきっちり行うという場合にはあまり問題になりませんが、)ちょっと気軽にルールを作って動かすというのには、個人的には若干敷居を高く感じてしまいます。

いわゆるReteアルゴリズムベースのルールエンジンの動きを学ぶだけであれば、むしろ、ちょっと古いですが、とりあえずダウンロードして動かすだけで、すぐにルールを書き始められるClipsや、もっと遡ってOPS5といったようなルールベースの他にあまり余分な要素のない言語の方が(私見ではありますが)学びやすいような気もします。

OpenRulesは、エンジンの動きこそReteベースではなく、デシジョンテーブルを上から順になめて条件の一致したルールを実行するという単純な動きですが、Excelでテーブルを作るだけで大部分が完結してしまうという敷居の低さ(特にユーザが直接ルールを書く場合など)は、ちょっと興味のあるところです。

というわけで本家のサイトの方でOpenRules 入門という記事を書き始めました。もし興味がおありであればどうぞ。

OpenRules入門

暦とルールと優先度

巷のBRMSが採用しているルールエンジンの動きとしては、大きく分けて2つの流れがあります。

  1. 通常の手続き型言語のIF文と同じように上から順に判断するエンジン。
  2. 現在保持しているデータの状態に対し、その状態を満足するルールを次々と処理していくReteアルゴリズムを代表とするデータ駆動のエンジン。

代表的なBRMSは、たいてい上記 2 の動きをサポートしていますが、通常の手続き型の動きとちょっと違うところがあるので、このブログでも折に触れこういった動きの特徴となるところを取り上げていきたいと思います。

今日は優先度(salience)について。通常の手続き型の言語ですと、上から順番に処理するだけで、優先度も何もない(強いて言えば上に行くほど優先度が高い)のですが、データ駆動のルールエンジンですと、優先度が時に重要な役割を果たします。ということで、本日はうるう年の判定を優先度を使って考えてみたいと思います。

ビッグベン
もっとも、うるう年の判定など、あえてルールでやらずとも普通の言語であればライブラリを使って一発なのですが、たまたま最近読んだ本(数量化革命の中にユリウス暦から現在のグレゴリオ暦を採用するまでの経緯を記したくだりがあり、うるう年の歴史的背景とからめて順にルールで実装していくというのもおもしろいかと思い、ちょっと手すさび程度に試してみたという次第。気楽にお付き合いください。

(ちなみに、この本はヨーロッパ帝国主義が成功をおさめた理由のひとつを、人々の世界観・思考様式が数量化・視覚化に依拠したものに変化したことによるとし、数字、機械時計、楽譜、遠近法、複式簿記などを例にとりながら説明していくという本。私は結構面白く読めました)

さて、グレゴリオ暦法では、うるう年を次のように決めています。

  1. 西暦年号が4で割り切れる年をうるう年とする。
  2. 【1】の例外として、西暦年号が100で割り切れて400で割り切れない年は平年とする。
    (国立天文台の質問ページから)

以上の規則は、通常の言語で手で記述しても大した話ではなく、たとえばJavaだったら yearを判定対象の年として条件を

year % 4 == 0 && year % 100 != 0 || year % 400 == 0

と書いてしまえばよい話なので、Droolsのルールでもそのまま

Leapyear.drl

rule "JuliusLeap"
     salience 100
     when
         $year : Year( leapYear == Year.NOT_YET
             && ((year % 4) == 0
             && (year % 100) != 0
             || (year % 400) == 0))
     then
         $year.setLeapYear(Year.LEAP_YEAR);
            // うるう年判定用の属性にうるう年をセットする
         update($year);
            // Droolsのワーキングメモリ内のファクトとして更新
         System.out.println("うるう年です");
end

rule "JuliusNotLeap"
     when
         $year : Year(leapYear == Year.NOT_YET)
     then
         $year.setLeapYear(Year.COMMON_YEAR);
         update($year);
         System.out.println("うるう年ではありません");
end

と書いてしまえば用が足りてしまいます。でも、これではあまりにもあっさりしすぎているので、以下では、もう少しルールらしさが表れる方法で実装してみましょう。

(なお、ここでは、以下の Year クラスを使いました。

public static class Year {
    public static final int NOT_YET = 0;       // 未定
    public static final int COMMON_YEAR = 1;   // 通常の年
    public static final int LEAP_YEAR = 2;     // うるう年

    private int year;                       // 西暦
    private int leapYear;                   // うるう年か否か

    ... (略)
}

また、上記ルールですでに優先度(salience)が出てきていますが、これはうるう年のYearインスタンスがあった場合、両方のルールにマッチするので、うるう年の条件にマッチするのであればそちらを優先して処理するということになります)

上で、うるう年の判定条件は、

  1. 西暦年号が4で割り切れる年をうるう年とする。
  2. 【1】の例外として、西暦年号が100で割り切れて400で割り切れない年は平年とする。

と書きましたが、現在のグレゴリオ暦の元となるユリウス暦では、うるう年といえば1の条件のみでした。ユリウス暦はご存じのとおりユリウス・カエサルが定めた暦法で、紀元前45年に始まり、1年を365.25日として暦が作られています。したがって4年に1回、1日分の補正が入るわけですね。

このユリウス暦によるうるう年の判定条件をルールで書くと

Leapyear1.drl

rule "JuliusLeap"
    salience 100
    when
        $year : Year( leapYear == Year.NOT_YET
                      && (year % 4) == 0)
    then
        $year.setLeapYear(Year.LEAP_YEAR);
        update($year);
        System.out.println("うるう年です");

end

rule "JuliusNotLeap"
    when
        $year : Year(leapYear == Year.NOT_YET)
    then
        $year.setLeapYear(Year.COMMON_YEAR);
        update($year);
        System.out.println("うるう年ではありません");

end

となります。

ユリウス暦はそのはじめから1600年以上も続いたわけですが、現在の技術による観測によれば1年は、365.242 189 572日(2013年年央値)。1年を365.25日とちょっと長めにとっているユリウス暦は長い間には誤差が累積していくわけで、グレゴリオ暦を採用することになった1582年には、誤差が11日に達していました。多くのアバウトな人にとっては、まあ別にいいのでは…ということでしたが、敬虔なキリスト教徒にとっては結構な大問題だったようです。

というのもキリストの復活を祝う復活祭。これは「春分の日以降の最初の満月のあと最初の日曜日」と定められていましたが、ユリウス暦上の春分の日である3月21日が天文学的にみた春分の日と10日以上もずれていると、今祝っている復活祭が誤った日に行われているのではないかという疑念がでてきます。

そこで、当時の法王グレゴリウス13世が、1582年に有識者を集めて暦の改革をします。(ちなみに1582年と言えば、日本では「本能寺の変」の年です。)

そのころの観測データでは、1年は365.2425日=365+97/400日という値が得られており、400年のうち97回、閏年があれば十分で、400年に100回の閏年を入れるユリウス暦では400年のうちに3日分あまってしまっていくというわけ。

では、どうしたかというと、4年に1回の閏年のうち、100年に1回は閏年にしない・・・これでは、400年に96回の閏年になってしまい、ちょっと削りすぎなので、100年に1回の閏年でない年のうち、400で割り切れる年は特別に閏年とする。

といういうことにして、400年に97回の閏年を実現したわけです。さて、まずは、この例外事項のみをルールに書いてみましょう。

rule "Gregorio1"
    when
        $year : Year( leapYear == Year.NOT_YET
                      && (year % 100) == 0
                      && (year % 400) != 0 )
    then
        $year.setLeapYear(Year.COMMON_YEAR);
        update($year);
        System.out.println("うるう年ではありませんよ");

end

ルールの書き方としては、400年の条件と100年の条件をさらに分けることもできますが、あまり分けすぎてもわかりにくくなるので、ここではひとまとめのままにしておきます。

上のルールに優先度を加え、例外事項のルールとして付け加えることで、もともとあったルールをそのままに判定条件の修正ができるようになります。上のルールは他のルールの条件に比べ、より厳しい例外的な条件になるので、もしこの条件に合うケースがあった場合には最優先で処理をするという意味で、もともとあった優先度(100)以上の優先度(200)をつけています)

Leapyear2.drl

rule "JuliusLeap"
    salience 100
    when
        $year : Year( leapYear == Year.NOT_YET
                      && (year % 4) == 0)
    then
        $year.setLeapYear(Year.LEAP_YEAR);
        update($year);
        System.out.println("うるう年です");

end

rule "Gregorio1"
    salience 200
    when
        $year : Year( leapYear == Year.NOT_YET
                      && (year % 100) == 0
                      && (year % 400) != 0 )
    then
        $year.setLeapYear(Year.COMMON_YEAR);
        update($year);
        System.out.println("うるう年ではありませんよ");

end

rule "JuliusNotLeap"
    when
        $year : Year(leapYear == Year.NOT_YET)
    then
        $year.setLeapYear(Year.COMMON_YEAR);
        update($year);
        System.out.println("うるう年ではありません");

end

これでグレゴリオ暦の閏年の判定条件ルールができました。このように優先度をうまく使うと、元々あるルールをそのままに、あとから比較的見通しよく例外ルールを付け加えることができます。

ところで、閏年の判定に関して、実はちょっと前におもしろいブログ記事を見つけました。

西暦1000年は閏年かそうじゃないのか?

グレゴリオ暦の判定条件からすれば閏年でないはずなのですが、Javaでは閏年になり、MySqlの判定では閏年になっていないとのこと。これは如何に。

西暦1000年と言えば、上にのべた歴史的背景から考えると、そもそもグレゴリオ暦などない時代。したがって上のルールの1のみが適用されればよいので、Javaでは閏年と判断しているのでしょう。またルールとしても、西暦1000年においては、2のルールは全く存在していないので、ルールの判定条件として2にあたるルールの条件に1582年以降という条件を加えればよいことになります。

では、MySqlの判定条件は間違っているということでしょうか。これについては、

先発グレゴリオ暦

という考え方もあり、国際規格(ISO8601)でも定められているようなので、一概に間違いとは言えず、単なる立場の違いと考えた方がよいのでしょう。

***

今回は、優先度を用いて、一般に適用されるルールと、その中で例外的に適用されるルールの振り分けを行ってみました。データ駆動の処理の動きは、このように手続き型とちょっと違う特徴を持っています。こういった特徴を表す実例はまだ他にもあるのですが、長くなるのでまた別の機会に記事にしようと思います。では、また次回に。

Drools 5.5.0 ファイナル リリース…とか。

久しぶりの更新になってしまいましたが、いつのまにかDrools 5.5.0 のファイナル版がリリースされていました。

ほんとに最近はDroolsの更新頻度が高くてほとんど追いつけない状態ですね。またDroolsに限らず、ここ数年、BRMSに関する話題が日本・海外を問わず増えてきており、数年前、ネットを回って事例記事などを探しても数少なかった非常に牧歌的な時代と比べれば隔世の感があります。

で、今ちょっと確認のためにGoogle トレンド で BRMS をチェックしてみました。

するとここ7~8年ほど思いのほかコンスタントに BRMS というキーワードでの検索が行われています。私の感覚としてはここ数年で増えている感じがしたのですが…。もしかすると私の感じているこの隆盛感は、具体的なBRMSの事例の露出度が高まったり、オープンソースでのBRMSがメジャーデビューしてきたことが原因なのかもしれません。

もっとも BRMS のコアである「ルールエンジン」であればオープンソース版は昔からあって、CLIPS などはその代表格。Drools も最初は、この CLIPS を参考にして作っていたはず。私もその昔、時間割作成システムのプロトタイプをCLIPSとVisual Basic 3.0(!)を使って、Windows3.1(!)上に作ったことを覚えています。結構ClipsとVB3とのつなぎが面倒だったり…今でもつなぎは面倒ですが昔に比べれば…。

そういえば先日ネットを見ていたらスウェーデンのルンド大学の大学(院)で「ビジネスルールシステムの設計」という講義科目があるのを知りました。「ルール」と言えば、昔は人工知能のプロダクションシステムなどの文脈で講義されることが普通でしたが、最近ではビジネスルールそのものをテーマにした講義もあらわれてくるようになったということですね。いや、まったく時代を感じます。

レッドハットがCEPを取り込んだ「JBoss Enterprise BRMS 5.3」の提供を開始

レッドハットがBRMSの新版「JBoss Enterprise BRMS 5.3」を提供し始めました。

レッドハットがビジネスルール管理システム新版「JBoss Enterprise BRMS 5.3」

レッドハット、JBoss Enteprise BRMS 5.3を発売 ビジネスルール管理と複合イベント処理を統合

今回の目玉はおそらく、BRMSのプラットフォームの中にCEPが本格的に取り入れられたことでしょうか。JBoss BRMSのCEPは、Drools Fusionにあたる機能。このブログでも何度かとりあげていますが、今までは金融を中心に少しづつ普及してきたCEP。今後はセンサーデータやRFIDなどのデータをリアルタイムで処理したり…いわゆるビッグデータの流れと相俟って普及が加速しそうな予感。IBMも元々別の製品だったBRMSとCEPを一緒にしてWebsphere Operational Decision Management として提供するようになりました。これを見ても、CEPがディシジョンマネージメントツールの重要な機能として取りいれられていくことになることは間違いありません。

JBoss BRMS で顧客管理システム

日経コンピュータのレポートに、こんな記事がありました。

北陸コカ・コーラが顧客管理システムを刷新 - オープンソースのBRMSで投資3割減

北陸コカコーラの顧客管理システムの刷新にJBossのBRMSが採用されているそうです。記事によれば

「JBoss BRMSはシステムに組み込みたい業務プロセスのルールをフロー図上で作成でき、開発時のプログラミング作業を極力なくすことができる。保守も容易だ。組織変更で承認フローが変わっても、グラフィカルな画面でルールの定義を変更すれば済む。」

ということですが、これを見るといわゆるデシジョンとしてのルールというよりも、プロセスのフローのルールをハンドリングするためにJBossのBRMSが使われているようです。・・・ってことはむしろBPM(jBPM)の話に近い気もしますが、ともあれJBossのBRMSが使われているということでご紹介。

Drools5.4.0.Final リリース

今月の14日に、Drools5.4.0.Finalがリリースされました。

Droolsの開発は結構活発で、追いついていくのが大変。
久しぶりに新しい機能など、きちんと整理しておかなくてはと
思っている今日このごろ。

通信業界のBRMS

スマホ急増にもBRMSが効く

…実は、日本でも通信業界で(ルールエンジンを主体とした)BRMSはそれほど珍しいものではなかったり。

たとえば

日本テレコム、ILOG JRulesを採用 (2006年7月)

は、料金計算にBRMSを用いていますし(ちなみにILOG JRulesは現在のIBMのBRMS)、

Prologベースプロダクションシステムによるクラウドサービスの運用監視

などは通信の監視としてルールエンジンを用いています(Prologをルールエンジンとして使っています)。

なお料金計算にしても、ネットワークアプライアンスの監視にしても比較的ルールエンジンが適用しやすい分野です。たとえば

Cisco Active Network Abstraction Administrator Guide, 3.6.4 – Drools Rules Engine …

というのはご存知でしょうか。