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

| 入力データ例 | 出力データ例 | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| master |
|
→ | updated |
|
|||||||||||||||||||||||||||||||||||||||||
| tx |
|
→ | missed |
|
|||||||||||||||||||||||||||||||||||||||||
hoge_master = {
id : TEXT;
name : TEXT;
};
hoge_transaction = {
date : DATE;
master_id : TEXT;
master_name : TEXT;
value : LONG;
};
import com.asakusafw.vocabulary.model.Key; import com.asakusafw.vocabulary.operator.MasterJoinUpdate; import com.example.modelgen.dmdl.model.HogeMaster; import com.example.modelgen.dmdl.model.HogeTransaction;
public abstract class ExampleOperator {
/**
* HogeMasterのnameをHogeTransactionにセットする
*
* @param master
* マスタデータ
* @param tx
* トランザクションデータ
*/
@MasterJoinUpdate
public void updateWithMaster(
@Key(group = "id") HogeMaster master,
@Key(group = "master_id") HogeTransaction tx
) {
tx.setMasterName(master.getName());
}
}
第1引数でマスターとなるデータモデル、第2引数でトランザクション(明細)となるデータモデルを指定する。
各引数には@Keyアノテーションを付けて、結合キーを指定する。
複数の項目を結合キーとする場合は「@Key(group = { "key1", "key2" })」のように波括弧でくくってカンマ区切りで指定する。
(MasterBranchとは異なり、)第1引数も第2引数も常にnull以外となる。[2015-03-22]
マスターが存在しない場合はmissedに出力されるので、自分がコーディングしたメソッドが呼ばれることは無い。
import com.example.modelgen.dmdl.model.HogeMaster; import com.example.modelgen.dmdl.model.HogeTransaction; import com.example.operator.ExampleOperatorFactory; import com.example.operator.ExampleOperatorFactory.UpdateWithMaster;
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();
// マスターつき更新
UpdateWithMaster updateWithMaster = operators.updateWithMaster(this.master, this.detail);
this.out1.add(exists.updated);
this.out2.add(exists.missed);
}
Flow DSLでは、自分が作ったOperatorのFactoryクラス(AsakusaFWのコンパイラーによって生成される)を使用する。
メソッド名はOperatorクラスに書いたメソッド名と同じ。
戻り値の型はAsakusaFWのコンパイラーによって生成されたクラス。(メソッド名を先頭が大文字のキャメルケースに変換したもの)
メソッドの引数は第1引数がマスターデータ、第2引数がトランザクション(明細)データ。
出力ポートの名前のデフォルトはupdatedとmissed。
出力ポート名を変えたい場合は@MasterJoinUpdateアノテーションで指定できる。
@MasterJoinUpdate(updatedPort = "updated", missedPort = "missed")
マスター更新演算子の単体テストの実装例。
package com.example.operator;
import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import org.junit.Test; import com.example.modelgen.dmdl.model.HogeMaster; import com.example.modelgen.dmdl.model.HogeTransaction;
/**
* {@link ExampleOperator}のテスト.
*/
public class ExampleOperatorTest {
@Test
public void updateWithMaster() {
ExampleOperator operator = new ExampleOperatorImpl();
HogeMaster master = new HogeMaster();
master.setNameAsString("hishidama");
HogeTransaction tx = new HogeTransaction();
operator.updateWithMaster(master, tx);
assertThat(tx.getMasterNameAsString(), is("hishidama"));
}
}
Operatorのテストクラスは、通常のJavaのJUnitのテストケースクラスとして作成する。
テスト対象のOperatorクラス自身は抽象クラスだが、Operatorクラス名の末尾に「Impl」の付いた具象クラスがAsakusaFWによって生成されるので、それを使う。
マスター分岐演算子は、マスター結合+更新+分割で同様の処理を行うことが出来る。
(分割演算子(@Split)は、結合モデルを結合元のデータモデルに戻す演算子)

つまり、後の処理で結合したデータを使うなら(分割の必要は無いので)、マスター結合+更新を使う。
マスターつき更新演算子は、SQLのJOINに似ている。
INSERT INTO updated (date, master_id, master_name, value)
SELECT tx.date, tx.master_id, master.name, tx.value FROM tx INNER JOIN master ON master.id = tx.master_id;