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;