「Drools 入門」 at 2019 日本 JBoss ユーザ・グループ勉強会

2019/12/11, 日本 JBoss ユーザ・グループ勉強会 で Drools 入門のプレゼンをしました。

結構 Drools を知ってる方も多く、懇親会でもいろいろ話せてよかったです。「Drools 使ってみようかな」と仰られていた方々が適切な適用領域を把握されているのが印象的でした。

twitter の様子。

#jjbug - Twitter Search

スライドはこちら。

speakerdeck.com

内容的には Drools ブログの 01 から 03 に相当します。興味を持っていただけたらこちらもご覧ください。

Droolsブログ カテゴリーの記事一覧 - tokobayashi’s blog

kogito-examples 利用例

WIP : たまに追加していきます

各プロジェクトで mvn clean package quarkus:dev

dmn-quarkus-example

リクエス

curl -d '{ "Driver": { "Points": 2}, "Violation": { "Type": "speed", "Actual Speed": 120, "Speed Limit": 100 }}' -H "Content-Type: application/json" -X POST http://localhost:8080/Traffic%20Violation

レスポンス

{"Violation":{"Type":"speed","Speed Limit":100,"Actual Speed":120},"Driver":{"Points":2},"Fine":{"Points":3,"Amount":500},"Should the driver be suspended?":"No"}

イタリア語

www.17-minute-world-languages.com

  • おはようございます!
    • Buon giorno! ボン・ジョールノ
  • こんにちは!
    • Buon giorno! ボン・ジョールノ
  • こんばんは!
    • Buona sera! ボナ・セーラ
  • おやすみなさい
    • Buona notte! ボナ・ノッテ
  • バイバイ!
    • Ciao! チャオ
  • さようなら!
    • Arrivederci! アリベデルチ
  • はい
    • Si. シィ
  • いいえ
    • No. ノ
  • わかりました
    • Ok.
  • ありがとう!
    • Grazie! グラツィエ
  • どういたしまして!
    • Prego! (Di niente)
  • すみません、
    • Scusi ...
  • ごめんなさい。
    • Mi dispiace.
  • 私の名前は Toshiya Kobayashi です
    • Il mio nome è Toshiya Kobayashi

MS SQL Server 備忘録

SQL Server Management Studio

SQL実行

"New Query" / File->New->Query with...

SQL Server Management StudioでSQLを実行する方法 | SQLServer初心者でもスッキリわかる

ミリ秒計測(SSMSで)

set statistics time on

<query>

set statistics time off

で、"Message"タブを見る

インデックス確認

 SELECT
     convert(varchar, i.name) AS index_name
     , convert(varchar, o.name) AS table_name
     , convert(varchar, col.name) AS column_name
 FROM
     sysindexkeys ik
     ,sysobjects o
     ,syscolumns col
     ,sysindexes i
 WHERE
         ik.id = o.id
     AND ik.id = col.id
     AND ik.colid = col.colid
     AND ik.id = i.id
     AND ik.indid = i.indid
     AND o.xtype = 'U'
     AND o.name in ('NodeInstanceLog', 'AuditTaskImpl')
 ORDER BY
     i.name
     ,ik.id
     ,ik.indid
     ,ik.keyno

Droolsブログ : 08 no-loop, lock-on-active

08 no-loop, lock-on-active

DRL には様々な属性(attribute)を指定することができます。

https://docs.jboss.org/drools/release/7.26.0.Final/drools-docs/html_single/#_rule_attributes

今回はそのなかで、no-loop と lock-on-active を紹介します。

サンプルコードはこちらから clone してください。

git clone https://github.com/tkobayas/drools-blog.git

今日のエントリはその中の 08_noloop_lockonactive です。

03 推論」のときのルールをベースにしています。このとき私が

ここで「あれ? "春のキャンペーン" や "高額商品キャンペーン" も再評価されて2重に実行されたりしないの?」と疑問に思った人もいるかも知れません。実は重要なポイントです。さっき「$o が更新されたよ、と伝える」と書きましたがこのときルールエンジンは $o のどのプロパティが変更されたかを意識します。つまり $o の extraPoint が変更された、と知っているので consumer や itemPrice は再評価しないのです。これは「Property Reactive」という機能で

と書いていたのを覚えているでしょうか。要するに Drools は変更されたプロパティと関係のないルールは再評価しない、ということです。しかし、「変更されたプロパティと関係あるルールだけど再評価して欲しくない」というパターンもありえます。今回のルールを見てください。

rule "春のキャンペーン"
    //no-loop true
    //lock-on-active true
    when
        $o : Order(consumer.memberCreatedAt >= "2019-04-01" && consumer.memberCreatedAt <=  "2019-04-30", extraPoint < 20000)
    then
        System.out.println("実行 : " + kcontext.getRule().getName());
        $o.setExtraPoint($o.getExtraPoint() + 2000);
        update($o);
end

rule "高額商品キャンペーン"
    //no-loop true
    //lock-on-active true
    when
    $o : Order(itemPrice > 100000, extraPoint < 20000)
    then
        System.out.println("実行 : " + kcontext.getRule().getName());
        $o.setExtraPoint($o.getExtraPoint() + 4000);
        update($o);
end

2つのルールに「extraPoint < 20000」という条件が足されています。20000以上のエクストラポイントのオーダーはマッチしないようにしよう、ということです。さて、この場合ルールが実行されると extraPoint が更新されるのでルールが再度ヒットします。試してみましょう。

$ mvn test
...

insert : Person [name=ジョン, memberCreatedAt=2019-04-11]
insert : Order [consumer=ジョン, itemName=ギター, itemPrice=200000, specialPointOrder=false]
実行 : 春のキャンペーン
実行 : 春のキャンペーン
実行 : 春のキャンペーン
実行 : 春のキャンペーン
実行 : 春のキャンペーン
実行 : 春のキャンペーン
実行 : 春のキャンペーン
実行 : 春のキャンペーン
実行 : 春のキャンペーン
実行 : 春のキャンペーン
実行 : 大量ポイント獲得オーダー
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 1.842 sec <<< FAILURE!
testHello(org.example.DroolsTest)  Time elapsed: 1.79 sec  <<< FAILURE!
java.lang.AssertionError: expected:<3> but was:<11>

「春のキャンペーン」が繰り返し実行されてしまいましたね。。。ここでまず「no-loop」という属性があります。これは「自分自身を繰り返して実行しない」という属性です。2つのルールに「no-loop true」という行がコメントで書かれているので、コメントをはずして実行してみましょう。

insert : Person [name=ジョン, memberCreatedAt=2019-04-11]
insert : Order [consumer=ジョン, itemName=ギター, itemPrice=200000, specialPointOrder=false]
実行 : 春のキャンペーン
実行 : 高額商品キャンペーン
実行 : 春のキャンペーン
実行 : 高額商品キャンペーン
実行 : 春のキャンペーン
実行 : 高額商品キャンペーン
実行 : 春のキャンペーン
実行 : 大量ポイント獲得オーダー
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 1.599 sec <<< FAILURE!
testHello(org.example.DroolsTest)  Time elapsed: 1.546 sec  <<< FAILURE!
java.lang.AssertionError: expected:<3> but was:<8>

残念!今度は「春のキャンペーン」と「高額商品キャンペーン」が交互に実行されています。「no-loop」は「自分自身の繰り返し」にしか効かないのです。無力、あまりに無力。。。

このような場合は「lock-on-active」の出番です。「no-loop」は再度コメントアウトし、「lock-on-active true」の行のコメントをはずして実行してみましょう。

insert : Person [name=ジョン, memberCreatedAt=2019-04-11]
insert : Order [consumer=ジョン, itemName=ギター, itemPrice=200000, specialPointOrder=false]
実行 : 春のキャンペーン
実行 : 高額商品キャンペーン
実行 : 大量ポイント獲得オーダー
======================================
ポイントキャンペーンのご活用ありがとうございます!
======================================
----
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.533 sec

うまくいきましたね!「lock-on-active」は「一度呼ばれると二度と再実行されない(ruleflow-group/agenda-groupが変わらない限り)」です。こちらのほうが no-loop より求められていることが多いでしょう。

今日はここまで!

OptaPlanner 備忘録

XStream の input ファイルが reference を XPATH で書いている場合

<com.example.MySolution>
  <id>1</id>
  <locationList>
    <com.example.model.Location>
      <id>0</id>
      <name>xxxx</name>
    </com.rekeep.domain.model.Location>
  </locationList>
  <officeList>
    <com.example.model.Office>
      <id>0</id>
      <location reference="../../../locationList/com.example.model.Location" />
    </com.example.model.Office>
    ...
com.thoughtworks.xstream.converters.ConversionException: Invalid reference

にヒットする。

		XStreamSolutionFileIO<EmployeeRoutingSolution> xStreamSolutionFileIO = new XStreamSolutionFileIO<>(MySolution.class);
		xStreamSolutionFileIO.getXStream().setMode(XStream.XPATH_RELATIVE_REFERENCES);
		File inputFile = new File("src/test/resources/input/test_input.txt");
		MySolution inputSolution = xStreamSolutionFileIO.read(inputFile);

のように mode を指定する。

solution の スコア計算だけする

保存しておく

		File outputFile = new File("src/test/resources/output/my_test_OUTPUT1.txt");
		xStreamSolutionFileIO.write(bestSolution, outputFile);

読み出してから

		ScoreDirector<MyRoutingSolution> scoreDirector = solver.getScoreDirectorFactory().buildScoreDirector();
		scoreDirector.setWorkingSolution(inputSolution);
		Score score = scoreDirector.calculateScore();

inputSolution を編集して、再計算することもできる