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 を編集して、再計算することもできる

Droolsブログ : 07 MVEL

07 MVEL

MVEL というのは Java ベースの言語で、 Java をより簡単に表記する事を目的にしています。超ざっくり言うと、getter/setter を省略して書いたりできます。

user.name == 'ジョン レノン'

ドキュメントはこちらを参照ください。

http://mvel.documentnode.com/

Drools ではルールを簡便に書くために MVEL を内部的に利用しています。大きく分けると 3つの箇所で、MVEL が使用されます。

1) ルール制約(Constraint)

例えば

        $p : Person( age >= 26 )

の age >= 28 の部分は はじめは MVEL によって処理されます。よって先程書いた getter の省略などが可能です。

「はじめは」 って書きましたね。実はこの制約部分は20回実行されると動的に Java クラスが生成、コンパイルされ、以降は MVEL ではなく Java クラスとして実行されます。JVMJIT と同じような考え方で、よく実行される部分は最適化してパフォーマンスを上げようというものです。

ただ「いや、そもそも最初から Java クラス生成すればいいんじゃね?」という意見から、もうその方向に開発が進んでいます。これは executable-model というオプションで、すでに Drools 7 では利用可能です。おそらくバージョン 8 ではデフォルトの動作になるでしょう。

いずれにせよユーザにとって内部的な挙動は気にしなくてもよいのですが、「しばらく実行したあとに突然ルールの挙動が変わった」ような問題が発生した場合は、動的な Java クラス生成時のバグが原因だった、なんてこともあります。

2) eval

以下のように eval という文法が使えます。

when
  p1 : Parameter()
  p2 : Parameter()
  eval( p1.getList().containsKey( p2.getItem() ) )

これは eval() 内部をまるごと MVEL で解釈し、true が返ればルールにマッチする、というものです。Java 的なロジックをゴリゴリ書けるので、一部で好まれるのですが、Drools エンジンからは最適化ができないのでパフォーマンス上おすすめしません。極力普通のフィールド制約で記述するのが Drools のパフォーマンスを上げるコツです。また、eval は近いうちに deprecated になるのではないかと言われています。

3) RHS

ルールの RHS (then の部分です)を MVEL を使って表記できます。その場合、

  dialect "mvel"

を宣言する必要があります。dialect は package 単位もしくは rule 単位で宣言できます。"mvel" 以外には "java" があります。デフォルトは "java" です。

ここで MVEL を使うメリットは。。。 BigDecimal の四則演算が簡単だからです。理由の9割くらいがそれですね。(あと getter/setter が無いと日本語フィールド名が見やすいとか)

    then
        $p.salary = $p.salary + 50000;
end

ただここまで説明しておいてなんですが、Drools チームは MVEL への依存を無くす方向へ進んでいます。ですので、新規開発では、できれば 2 と 3 の利用方法は避けていただいたほうがよいのではないかと思います。(1 は executable-model で内部的に変更される)

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

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

今日のエントリはその中の 07_mvel です。

このようなルールです。eval は使っていません。

https://github.com/tkobayas/drools-blog/blob/master/07_mvel/src/main/resources/org/example/Sample.drl

package org.example
 
import org.example.Person;

dialect "mvel"

rule "昇給"
    when
        $p : Person( age >= 26 )
    then
        $p.salary = $p.salary + 50000;
end

実行すると

$ mvn clean test

...
Running org.example.DroolsTest
...
ジョン の給料は 350000円です。
...

ルール通りに出力されましたね。

Droolsブログ : 06 Quarkus で Drools/jBPM を動かす Kogito

06 Quarkus で Drools/jBPM を動かす Kogito

これまで入門ネタを書いてきましたが、今回はちょっと最新情報を!

Drools/jBPM には Kogito という新規プロジェクトがあり、Drools/jBPM を軽量に適用するアプローチを目指しています。そしてその中心となるのが Quarkus との組み合わせです。

Quarkus についてはこちらを参照ください!

https://www.slideshare.net/agetsuma/quarkus

で、この Quarkus で Kogito を使うガイドがこちらです。

https://quarkus.io/guides/kogito-guide

ハンズオン的にアプリの作成、実行がガイドされていますが、そもそも動くモノが "using-kogito" にあるので、以下、手っ取り早く実行するための手順を書いていきます。

git clone https://github.com/quarkusio/quarkus-quickstarts.git
cd quarkus-quickstarts/using-kogito
./mvnw clean compile quarkus:dev

はい、これで dev モードで起動します。

ビルドはともかく、Quarkus は 3 秒くらいで起動します。速い!

2019-06-28 17:49:15,946 INFO  [io.quarkus] (main) Quarkus 0.18.0 started in 3.015s. Listening on: http://[::]:8080

REST アクセスでアプリを動作させます。Droolsによるルール、jBPMによるプロセスに沿って動作します。詳しくは上記ガイドを参照してください。"using-kogito" の中のソースを見れば分かりますが、とてもシンプルです。

1) Person を POST します。20才なのでルールで Adult と判定され、プロセスを通過して終了します。

curl -X POST http://localhost:8080/persons \
    -H 'content-type: application/json' \
    -H 'accept: application/json' \
    -d '{"person": {"name":"John Quark", "age": 20}}'

2) アクティブなプロセスを GET します。先程のプロセスは終了したのでレスポンスは空です。

curl -X GET http://localhost:8080/persons \
    -H 'content-type: application/json' \
    -H 'accept: application/json'

3) 別の Person を POST します。15才なのでルールで Child と判定され、"Special handling for children" タスクで停止します。

curl -X POST http://localhost:8080/persons \
    -H 'content-type: application/json' \
    -H 'accept: application/json' \
    -d '{"person": {"name":"Jenny Quark", "age": 15}}'

4) もう一度 GET で確認すると id:2 のアクティブなプロセスインスタンスがあることがわかります。

curl -X GET http://localhost:8080/persons \
    -H 'content-type: application/json' \
    -H 'accept: application/json'
[{"id":2,"person":{"adult":false,"age":15,"name":"Jenny Quark"}}]

5) 以下の POST でタスクを complete します。プロセスが進行し、終了します。

curl -X POST http://localhost:8080/persons/2/ChildrenHandling/1 \
    -H 'content-type: application/json' \
    -H 'accept: application/json' \
    -d '{}'

Ctrl+C で quarkus を停止します。

まだ終わりませんよ!

次はネイティブビルドしてみましょう。現時点(2019/06/29)で、このデモはネイティブビルドに GraalVM 19.0.2+ が必要です。https://www.graalvm.org/downloads/ からダウンロードしましょう(CE でも EE でもいいです)

$GRAALVM_HOME/bin に $PATH を通し、さらに native-image コンポーネントをインストールしておきます。

gu install native-image

using-kogito ディレクトリで以下のコマンドを実行します。ビルドには結構時間がかかります。。。

./mvnw clean package -Dnative

これでバイナリイメージ target/using-kogito-1.0-SNAPSHOT-runner が生成されるので直接実行します。

./target/using-kogito-1.0-SNAPSHOT-runner

4ms で起動。爆速ですねー

2019-06-29 12:56:18,984 INFO  [io.quarkus] (main) Quarkus 0.18.0 started in 0.004s. Listening on: http://[::]:8080

さっきと同じ REST で動作します。

Minishift 備忘録

libvirtqemu-kvm は入ってるとして

$ sudo usermod -a -G libvirt $(whoami)
$ newgrp libvirt
# curl -L https://github.com/dhiltgen/docker-machine-kvm/releases/download/v0.10.0/docker-machine-driver-kvm-centos7 > /usr/local/bin/docker-machine-driver-kvm
$ sudo chmod +x /usr/local/bin/docker-machine-driver-kvm
$ sudo systemctl status libvirtd

ここからダウンロードして解凍 https://github.com/minishift/minishift/releases/

$ ./minishift start --memory 8GB

$ oc login -u system:admin

$ oc login -u developer -p developer

rheb.hatenablog.com

eval $(minishift oc-env)
source <(oc completion bash)
sudo cp ~/.minishift/cache/oc/v3.11.0/linux/oc ~/usr/local/bin/oc
oc completion bash | sudo tee /etc/bash_completion.d/oc

Droolsブログ : 05 KJAR

05 KJAR

前回まではルールをクラスパスに配置していました。アプリケーションにリソースを組み込むという意味では普通のやりかたです。一方 Drools ではルールをアプリケーションと分離して管理する方法も強力にサポートされています。

  1. ルールを Maven を使って jar にまとめる。jar は Maven リポジトリにデプロイされる
  2. アプリケーションは jar の GAV(GroupId, ArtifactId, Version) を指定して、Maven リポジトリから jar を読み込んでルールを使用する

この jar を KJAR (Knowledge JAR) と呼びます。

おっと、随分 Maven に依存してるように見えますね。上記のステップ 1 は kie-maven-plugin という Maven プラグインを利用して実現します。ステップ 2 では実際アプリケーションは内部的に Maven のライブラリを利用して動作します。開発者はそれほど意識しなくても大丈夫です(最終的な本番環境のアーキテクチャーなどは考慮が必要です。これはまた後日)。動かしてみましょう。

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

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

今日のエントリはその中の 05_kjar です。ディレクトリ "05_kjar" の中に2つのディレクトリがあります。

  • drools-hello-kjar : こちらが KJAR のプロジェクト
  • drools-hello-client : KJAR を利用するアプリケーション
$ cd 05_kjar
$ cd drools-hello-kjar
$ mvn clean install

pom.xml をちょっと見ておきましょう。

  <groupId>org.example</groupId>
  <artifactId>drools-hello-kjar</artifactId>
  <version>1.0.0</version>
  <packaging>kjar</packaging>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.1</version>
        <configuration>
          <debug>true</debug>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.kie</groupId>
        <artifactId>kie-maven-plugin</artifactId>
        <version>${drools.version}</version>
        <extensions>true</extensions>
      </plugin>
    </plugins>
  </build>

このように <packaging> に kjar を指定し、<build> に kie-maven-plugin を設定します。

また、 src/java/resources 下に META-INF/kmodules.xml が必要です。

<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
</kmodule>

ここに kbase や ksession に関する設定が書けますが、とりあえず上記のように空っぽでも大丈夫です。

生成される jar は基本的に普通の jar と変わりませんが、ルールのコンパイルなどを行い、エラーチェックをしてくれます。

これで KJAR が Maven ローカルリポジトリ (~/.m2/repository/) にインストールされます。ローカルリポジトリにあるので、次のクライアントコードは Maven 経由でこの jar を見つけることができます。

$ cd ../drools-hello-client
$ mvn clean test
        KieServices ks = KieServices.Factory.get();
        ReleaseId releaseId = ks.newReleaseId("org.example", "drools-hello-kjar", "1.0.0");
        KieContainer kcontainer = ks.newKieContainer(releaseId);
        KieSession ksession = kcontainer.newKieSession();

このように、getKieClasspathContainer() の代わりに GAV を指定して KieContainer を生成します。後は同じです。

Hello Child, ポール
Hello Adult, ジョン
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.715 sec

KJAR をアプリケーションから分離することで、アプリケーションを変更/再デプロイせずにルールだけ更新する、という運用が可能になります。