Asakusa FrameworkのOperator DSLのマスター確認演算子(@MasterCheck)のメモ。
|
|
マスター確認演算子は、レコードに合致するマスターレコードが存在するかどうかを確認する演算子。
性能特性はJoin(旧ドキュメントではReduce、最適化によってはMap)。[/2016-02-11]
| 入力 ポート数 |
入力データモデル の制約 |
イメージ | 出力 ポート数 |
出力データモデル の制約 |
入力1レコード に対する 出力レコード数 |
||
|---|---|---|---|---|---|---|---|
| 2 | master | (マスター) |
![]() |
2 | found | txと同じ データモデル |
txの1レコードに対し foundかmissedの どちらかに1レコード。 |
| tx | missed | txと同じ データモデル |
|||||
トランザクション(明細データ)レコード(の指定したキー)に合致するマスターレコードが存在したら、そのトランザクションレコードをfoundに出力する。
存在しなければmissedに出力する。
マスター確認演算子は、マスターデータの存在確認をする為に使う。
マスターと結合した新しいデータモデルを出力したい場合はマスター結合演算子(@MasterJoin)を使う。
(マスターデータは出力しないが)結合したマスターデータの内容に応じて処理を分岐したい場合はマスター分岐演算子(@MasterBranch)を使う。
(マスターデータは出力しないが)結合したマスターデータの値によってトランザクションレコードの値を変更したい場合はマスターつき更新演算子(@MasterJoinUpdate)を使う。
hoge_transactionに合致するhoge_masterが存在するかどうかを確認する例。
(この図はToad Editorを用いて作っています)

| 入力データ例 | 出力データ例 | |||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| master |
|
→ | found |
|
||||||||||||||||||||||||||||||||||||
| tx |
|
→ | missed |
|
||||||||||||||||||||||||||||||||||||
hoge_master = {
id : TEXT;
name : TEXT;
};
hoge_transaction = {
date : DATE;
master_id : TEXT;
value : LONG;
};
import com.asakusafw.vocabulary.model.Key; import com.asakusafw.vocabulary.operator.MasterCheck; import com.example.modelgen.dmdl.model.HogeMaster; import com.example.modelgen.dmdl.model.HogeTransaction;
public abstract class ExampleOperator {
/**
* HogeTransactionのレコードに対するHogeMasterが存在するかどうかを確認する
*
* @param master
* マスタデータ
* @param tx
* トランザクションデータ
* @return true:マスターが存在する場合
*/
@MasterCheck
public abstract boolean exists(
@Key(group = "id") HogeMaster master,
@Key(group = "master_id") HogeTransaction tx
);
}
マスター確認演算子は抽象メソッドとして定義する。
戻り値の型はboolean。
第1引数でマスターとなるデータモデル、第2引数でトランザクション(明細)となるデータモデルを指定する。
各引数には@Keyアノテーションを付けて、結合キーを指定する。
複数の項目を結合キーとする場合は「@Key(group = { "key1", "key2" })」のように波括弧でくくってカンマ区切りで指定する。
import com.example.modelgen.dmdl.model.HogeMaster; import com.example.modelgen.dmdl.model.HogeTransaction; import com.example.operator.ExampleOperatorFactory; import com.example.operator.ExampleOperatorFactory.Exists;
private final In<HogeMaster> master; private final In<HogeTransaction> detail; private final Out<HogeTransaction> out1; private final Out<HogeTransaction> out2;
@Override
public void describe() {
ExampleOperatorFactory operators = new ExampleOperatorFactory();
// マスター確認
Exists exists = operators.exists(this.master, this.detail);
this.out1.add(exists.found);
this.out2.add(exists.missed);
}
Flow DSLでは、自分が作ったOperatorのFactoryクラス(AsakusaFWのコンパイラーによって生成される)を使用する。
メソッド名はOperatorクラスに書いたメソッド名と同じ。
戻り値の型はAsakusaFWのコンパイラーによって生成されたクラス。(メソッド名を先頭が大文字のキャメルケースに変換したもの)
メソッドの引数は第1引数がマスターデータ、第2引数がトランザクション(明細)データ。
出力ポートの名前のデフォルトはfoundとmissed。
出力ポート名を変えたい場合は@MasterCheckアノテーションで指定できる。
@MasterCheck(foundPort = "found", missedPort = "missed")
マスター確認演算子は抽象メソッドなので、(Operatorクラスにプログラマーがメソッド本体を実装していないので)Operatorの単体テストを実装する必要は無い。
同一データモデルの入力データA, Bがあるとき、AとBを合流させたいが、同じキーのデータが双方にある場合はAだけを生かす(要するに、AにBを追加するが、かぶっていたらAを生かす(A優先))という例。[2015-10-10]
(「AにBを追加するが、かぶっていたらBを生かす(B優先)」の場合は、AとBを逆にして処理すれば同じことである)
マスター側はそのまま出力し、追加側はマスター確認演算子を使ってマスターが存在するかどうかをチェックする。
マスターが見つかった場合は(マスターを生かすので、追加側は)停止演算子につなぐ。
マスターが見つからなかった場合は出力する。

import com.asakusafw.vocabulary.flow.FlowDescription; import com.asakusafw.vocabulary.flow.FlowPart; import com.asakusafw.vocabulary.flow.In; import com.asakusafw.vocabulary.flow.Out; import com.asakusafw.vocabulary.flow.util.CoreOperators; import com.example.modelgen.dmdl.model.StoreInfo; import com.example.operator.StoreInfoOperatorFactory; import com.example.operator.StoreInfoOperatorFactory.CheckStoreInfo;
/**
* 店舗マスター統合フローパート
*/
@FlowPart
public class StoreInfoConfluentFlowPart extends FlowDescription {
/** 店舗マスタ(マスター) */ private final In<StoreInfo> masterStoreInfo; /** 店舗マスタ(追加分) */ private final In<StoreInfo> additionalStoreInfo; /** 店舗マスタ */ private final Out<StoreInfo> storeInfo;
〜コンストラクターは省略〜
@Override
public void describe() {
StoreInfoOperatorFactory operator = new StoreInfoOperatorFactory();
// 重複チェック
CheckStoreInfo check = operator.checkStoreInfo(masterStoreInfo, additionalStoreInfo);
CoreOperators.stop(check.found);
storeInfo.add(masterStoreInfo);
storeInfo.add(check.missed);
}
}
import com.asakusafw.vocabulary.model.Key; import com.asakusafw.vocabulary.operator.MasterCheck; import com.example.modelgen.dmdl.model.StoreInfo;
public abstract class StoreInfoOperator {
/**
* 店舗マスター存在チェック
*
* @param master 店舗マスタ(マスター)
* @param additional 店舗マスタ(追加分)
* @return マスターが存在する場合のみtrue
*/
@MasterCheck
public abstract boolean checkStoreInfo(
@Key(group = { "store_code" }) StoreInfo master,
@Key(group = { "store_code" }) StoreInfo additional
);
}
マスター確認演算子は、SQLのJOINに似ている。
INSERT INTO found SELECT tx.* FROM tx INNER JOIN master ON master.id = tx.master_id;
INSERT INTO missed SELECT tx.* FROM tx LEFT JOIN master ON master.id = tx.master_id WHERE master.id IS NULL;