2019/12/11, 日本 JBoss ユーザ・グループ勉強会 で Drools 入門のプレゼンをしました。
結構 Drools を知ってる方も多く、懇親会でもいろいろ話せてよかったです。「Drools 使ってみようかな」と仰られていた方々が適切な適用領域を把握されているのが印象的でした。
twitter の様子。
スライドはこちら。
内容的には Drools ブログの 01 から 03 に相当します。興味を持っていただけたらこちらもご覧ください。
WIP : たまに追加していきます
各プロジェクトで mvn clean package quarkus:dev
リクエスト
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"}
Exception で判定する場合、try/catch/fail ではなく @Test(expected=XXXException.class)
assertTrue() のとき Assertions.assertThat() が使えるか考える
Assertions.assertThat(marshall).contains("John is CustomPerson");
www.17-minute-world-languages.com
"New Query" / File->New->Query with...
SQL Server Management StudioでSQLを実行する方法 | SQLServer初心者でもスッキリわかる
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
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 より求められていることが多いでしょう。
今日はここまで!
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 を指定する。
保存しておく
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 を編集して、再計算することもできる