Asakusa FrameworkのOperator DSLのマスター結合演算子(@MasterJoin)のメモ。
|
マスター結合演算子は、レコードに合致するマスターレコードと結合した新しいデータモデルを生成する演算子。
性能特性はJoin(旧ドキュメントではReduce、最適化によってはMap)。[/2016-02-11]
入力 ポート数 |
入力データモデル の制約 |
イメージ | 出力 ポート数 |
出力データモデル の制約 |
入力1レコード に対する 出力レコード数 |
||
---|---|---|---|---|---|---|---|
2 | master | (マスター) |
![]() |
2 | joined | 結合モデル | txの1レコードに対し joinedかmissedの どちらかに1レコード。 |
tx | missed | txと同じ データモデル |
トランザクション(明細データ)レコード(の指定したキー)に合致するマスターレコードが存在したら、そのトランザクションレコード
とマスターレコードを結合したデータをjoinedに出力する。
存在しなければトランザクションレコードをmissedに出力する。
joinedのデータモデルは、DMDLで結合モデルとして定義する必要がある。
逆に、結合モデルを元の2つのデータモデルに分解するには分割演算子(@Split)を使う。
合致するマスターが存在するかどうかを確認するだけの場合はマスター確認演算子(@MasterCheck)を使う。
(マスターデータは出力しないが)結合したマスターデータの内容に応じて処理を分岐したい場合はマスター分岐演算子(@MasterBranch)を使う。
(マスターデータは出力しないが)結合したマスターデータの値によってトランザクションレコードの値を変更したい場合はマスターつき更新演算子(@MasterJoinUpdate)を使う。
hoge_transactionとhoge_masterを結合したデータを出力する例。
(この図はToad Editorを用いて作っています)
入力データ例 | 出力データ例 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
master |
|
→ | joined |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
tx |
|
→ | missed |
|
hoge_master = { id : TEXT; name : TEXT; }; hoge_transaction = { date : DATE; master_id : TEXT; value : LONG; }; joined joined_hoge = hoge_master % id + hoge_transaction % master_id;
マスター結合演算子で結合した結果を表すデータモデルは、結合モデル(joinedを先頭に付けたデータモデル)にする必要がある。
→結合モデルの書き方
import com.asakusafw.vocabulary.operator.MasterJoin; import com.example.modelgen.dmdl.model.HogeMaster; import com.example.modelgen.dmdl.model.HogeTransaction; import com.example.modelgen.dmdl.model.JoinedHoge;
public abstract class ExampleOperator { /** * HogeMasterとHogeTransactionを結合する * * @param master * マスタデータ * @param tx * トランザクションデータ * @return 結合結果 */ @MasterJoin public abstract JoinedHoge join(HogeMaster master, HogeTransaction tx); }
マスター結合演算子は抽象メソッドとして定義する。
第1引数でマスターとなるデータモデル、第2引数でトランザクション(明細)となるデータモデルを指定する。
戻り値の型は結合結果のデータモデル(結合モデル)を指定する。
他の結合系演算子(マスター確認演算子等)では@Keyアノテーションで結合キーを指定するが、
マスター結合演算子では結合モデルで結合キーを指定しているので、Operatorクラスではキーを指定する必要は無い。
import com.example.modelgen.dmdl.model.HogeMaster; import com.example.modelgen.dmdl.model.HogeTransaction; import com.example.operator.ExampleOperatorFactory; import com.example.operator.ExampleOperatorFactory.Join;
private final In<HogeMaster> master; private final In<HogeTransaction> detail; private final Out<JoinedHoge> out1; private final Out<HogeTransaction> out2;
@Override public void describe() { ExampleOperatorFactory operators = new ExampleOperatorFactory(); // マスター結合 Join join = masterOperator.join(this.master, this.detail); this.out1.add(join.joined); this.out2.add(join.missed); }
Flow DSLでは、自分が作ったOperatorのFactoryクラス(AsakusaFWのコンパイラーによって生成される)を使用する。
メソッド名はOperatorクラスに書いたメソッド名と同じ。
戻り値の型はAsakusaFWのコンパイラーによって生成されたクラス。(メソッド名を先頭が大文字のキャメルケースに変換したもの)
メソッドの引数は第1引数がマスターデータ、第2引数がトランザクション(明細)データ。
出力ポートの名前のデフォルトはjoinedとmissed。
出力ポート名を変えたい場合は@MasterJoinアノテーションで指定できる。
@MasterJoin(joinedPort = "joined", missedPort = "missed")
マスター結合演算子は抽象メソッドなので、(Operatorクラスにプログラマーがメソッド本体を実装していないので)Operatorの単体テストを実装する必要は無い。
マスター結合演算子で結合した結果を表すデータモデルは、DMDL上で結合モデルとして定義しておく必要がある。
例 | 説明 |
---|---|
joined hoge = 〜; |
モデル名の前に「joined」を付ける。 |
joined hoge = master % id + detail % master_id; |
結合元を「結合元データモデル % 結合キー」で表し、2つの結合元を「+」でつなぐ。 |
joined hoge = master % key1, key2 + detail % master_key1, master_key2; |
結合キーが複数項目の場合は、カンマ区切りで指定する。 慣れないと「+」が何をつないでいるのか分かりにくい(苦笑) |
joined hoge = master -> { id -> id; name -> name; } % id + detail -> { master_id -> master_id; value -> value; } % master_id; |
結合元のプロパティーの一部だけを出力したい場合は、 波括弧でくくって必要なプロパティーを記述する。 |
joined hoge = master -> { id -> id; name -> name; } % id + detail -> { master_id -> id; value -> value; } % id; |
プロパティーの「->」の右側は結合モデルでのプロパティー名を表す。 (結合元と異なるプロパティー名を付けることが出来る) キー項目のプロパティー名は別々の結合元であれば同じ名前を付けることが出来る。 (キー項目以外では異なる結合元でも同じプロパティー名を付けることは出来ない) 「%」の後ろに使うのは、結合モデルでのプロパティー名(「->」の右側で指定した名前)。 |
マスター結合演算子は、SQLのJOINに相当する。
INSERT INTO joined SELECT * 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;