Kogito を使用してアプリケーションにルールエンジン機能を追加します。
このガイドでは、QuarkusアプリケーションがKogitoを使用してルール付きのDRLファイルを追加する方法を説明します。
Kogitoは、有名なオープンソースプロジェクトであるDrools (ビジネスルール用)とjBPM (ビジネスプロセス用)から生まれた次世代のビジネスオートメーションツールキットです。Kogitoは、ビジネスナレッジ(プロセス、ルール、意思決定)をドメイン固有の方法で公開することを主なメッセージとするビジネスオートメーションへの別のアプローチを提供することを目的としています。
前提条件
このガイドを完成させるには、以下が必要です:
-
約15分
-
IDE
-
JDK 11+ がインストールされ、
JAVA_HOMEが適切に設定されていること -
Apache Maven 3.8.6
-
動作するコンテナランタイム(Docker, Podman)
-
使用したい場合は、 Quarkus CLI
-
ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること
アーキテクチャ
この例では、1つのRESTエンドポイントを提供する非常にシンプルなマイクロサービスを構築します。
-
/find-approved
このエンドポイントは、DRLファイルのRule Unitに挿入されたクエリに基づいて自動的に生成されます。これは、ビジネス・ルールの実行が副作用を伴わないステートレス呼び出し(「純粋な関数呼び出し」とも呼ばれる)の例です。返される出力値は、提供された入力に一意に基づいています。
ソリューション
次の章で紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、完成した例にそのまま進んでも構いません。
Gitレポジトリをクローンするか git clone https://github.com/quarkusio/quarkus-quickstarts.git 、 アーカイブ をダウンロードします。
このソリューションは kogito-drl-quickstart directory にあります。
Mavenプロジェクトの作成
まず、新しいプロジェクトが必要です。以下のコマンドで新規プロジェクトを作成します。
このコマンドはMavenプロジェクトを生成し、アプリケーションにビジネス・オートメーションの機能を追加するために必要な依存関係と構成をすべて備えた kogito-quarkus-rules エクステンションをインポートします。また、KogitoがRESTサービスを公開するのに必要な resteasy-jackson エクステンションをインポートします。
すでにQuarkusプロジェクトが設定されている場合は、プロジェクトのベースディレクトリで以下のコマンドを実行することで、 kogito-quarkus-rules エクステンションをプロジェクトに追加することができます。
quarkus extension add 'kogito-quarkus-rules'
./mvnw quarkus:add-extension -Dextensions='kogito-quarkus-rules'
./gradlew addExtension --extensions='kogito-quarkus-rules'
これにより、 pom.xml に以下が追加されます:
<dependency>
<groupId>org.kie.kogito</groupId>
<artifactId>kogito-quarkus-rules</artifactId>
</dependency>
implementation("org.kie.kogito:kogito-quarkus-rules")
アプリケーションの記述
まず、アプリケーションのドメインモデルから始めましょう。このアプリケーションはローンの申請を承認するものなので、希望するローンのすべての詳細を持つクラスを用意します:
package org.acme.kogito.model;
public class LoanApplication {
private String id;
private Applicant applicant;
private int amount;
private int deposit;
private boolean approved = false;
public LoanApplication() {
}
public LoanApplication(String id, Applicant applicant,
int amount, int deposit) {
this.id = id;
this.applicant = applicant;
this.amount = amount;
this.deposit = deposit;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Applicant getApplicant() {
return applicant;
}
public void setApplicant(Applicant applicant) {
this.applicant = applicant;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
public int getDeposit() {
return deposit;
}
public void setDeposit(int deposit) {
this.deposit = deposit;
}
public boolean isApproved() {
return approved;
}
public void setApproved(boolean approved) {
this.approved = approved;
}
}
そして、申請者の詳細を記載した別のクラスを用意します:
package org.acme.kogito.model;
public class Applicant {
private String name;
private int age;
public Applicant() {
}
public Applicant(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
次に、生成されたプロジェクトの src/main/resources/org/acme/kogito/queries フォルダ内にルールファイル loan-rules.drl を作成します。
package org.acme.kogito.queries;
unit LoanUnit; // no need to using globals, all variables and facts are stored in the rule unit
import org.acme.kogito.model.Applicant;
import org.acme.kogito.model.LoanApplication;
rule LargeDepositApprove when
$l: /loanApplications[ applicant.age >= 20, deposit >= 1000, amount <= maxAmount ] // oopath style
then
modify($l) { setApproved(true) };
end
rule LargeDepositReject when
$l: /loanApplications[ applicant.age >= 20, deposit >= 1000, amount > maxAmount ]
then
modify($l) { setApproved(false) };
end
// ... more loans approval/rejections business rules ...
// approved loan applications are now retrieved through a query
query FindApproved
$l: /loanApplications[ approved ]
end
このファイルには、ローンが承認されるべきかどうかを決定するためのルールの例があります。このサービスでは、申請者の年齢が20歳以上で、銀行口座に1,000通貨以上の預金があることを求めています。ローンの金額は maxAmount を超えてはいけません。
この例では、Kogitoに導入された新しい概念であるルール・ユニットを使用しています。これは、ルールのセットと、それらのルールが照合されるファクトをカプセル化するのに役立ちます。
挿入されたファクトは、タイプセーフのエントリーポイントである DataStore に挿入されます。すべてを機能させるには、RuleUnitとDataStoreの両方を定義する必要があります。
package org.acme.kogito.queries;
import org.acme.kogito.model.LoanApplication;
import org.kie.kogito.rules.DataSource;
import org.kie.kogito.rules.DataStore;
import org.kie.kogito.rules.RuleUnitData;
public class LoanUnit implements RuleUnitData {
private int maxAmount;
private DataStore<LoanApplication> loanApplications;
public LoanUnit() {
this(DataSource.createStore(), 0);
}
public LoanUnit(DataStore<LoanApplication> loanApplications, int maxAmount) {
this.loanApplications = loanApplications;
this.maxAmount = maxAmount;
}
public DataStore<LoanApplication> getLoanApplications() { return loanApplications; }
public void setLoanApplications(DataStore<LoanApplication> loanApplications) {
this.loanApplications = loanApplications;
}
public int getMaxAmount() { return maxAmount; }
public void setMaxAmount(int maxAmount) { this.maxAmount = maxAmount; }
}
これで完了です。ローン申請を検証するためのRESTエンドポイントが、このRule Unitから自動的に生成されます。
アプリケーションの実行と使用
開発モードでの実行
マイクロサービスをdevモードで実行するには:
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
JVMモードでの動作
「開発モード」で遊び終わったら、標準のJavaアプリケーションとして実行することができます。
まずコンパイルします。
quarkus build
./mvnw install
./gradlew build
次に、以下を実行してください。
java -jar target/quarkus-app/quarkus-run.jar
ネイティブモードでの実行
同じデモをネイティブコードにコンパイルすることができます。
これは、生成されたバイナリーにランタイム技術が含まれており、最小限のリソースオーバーヘッドで実行できるように最適化されているため、本番環境にJVMをインストールする必要がないことを意味します。
コンパイルには少し時間がかかるので、このステップはデフォルトでは無効になっています。以下のコマンドでネイティブ実行可能ファイルをビルドしてみましょう。
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.package.type=native
コーヒーを飲み終わると、このバイナリーは以下のように直接実行出来るようになります:
target/kogito-drl-quickstart-1.0.0-SNAPSHOT-runner
アプリケーションのテスト
アプリケーションをテストするには、人をJSONペイロードとして指定してサービスにリクエストを送信するだけです。
curl -X POST http://localhost:8080/find-approved \
-H 'Content-Type: application/json'\
-H 'Accept: application/json' \
-d '{"maxAmount":5000,
"loanApplications":[
{"id":"ABC10001","amount":2000,"deposit":1000,
"applicant":{"age":45,"name":"John"}},
{"id":"ABC10002","amount":5000,"deposit":100,
"applicant":{"age":25,"name":"Paul"}},
{"id":"ABC10015","amount":1000,"deposit":100,
"applicant":{"age":12,"name":"George"}}
]}'
レスポンスでは、承認されたアプリケーションのリストが返されます:
[{"id":"ABC10001",
"applicant":{"name":"John","age":45},
"amount":2000,"deposit":100,"approved":true}]