S-JIS[2013-11-10/2016-02-11] 変更履歴

Asakusa Framework マスター確認演算子

Asakusa FrameworkOperator 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
hoge_master
id name group
a apple 1
b orange 2
c toy 100
d game 101
e other 900
f other2 999
found
hoge_transaction
date master_id value
2013-11-29 a 123
2013-11-29 b 456
2013-11-29 d 789
2013-11-29 e 111
tx
hoge_transaction
date master_id value
2013-11-29 a 123
2013-11-29 b 456
2013-11-29 d 789
2013-11-29 e 111
2013-11-29 z 222
missed
hoge_transaction
date master_id value
2013-11-29 z 222

example.dmdl(DMDL):

hoge_master = {

    id : TEXT;

    name : TEXT;
};

hoge_transaction = {

    date : DATE;

    master_id : TEXT;

    value : LONG;
};

ExampleOperator.java(Operator DSL):

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" })」のように波括弧でくくってカンマ区切りで指定する。

ExampleJob.java(Flow DSL):

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を逆にして処理すれば同じことである)


マスター側はそのまま出力し、追加側はマスター確認演算子を使ってマスターが存在するかどうかをチェックする。
マスターが見つかった場合は(マスターを生かすので、追加側は)停止演算子につなぐ。
マスターが見つからなかった場合は出力する。

StoreInfoConfluentFlowPart.java(Flow DSL):

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);
	}
}

StoreInfoOperator.java(Operator DSL):

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;

Operator DSLへ戻る / AsakusaFW目次へ戻る / 技術メモへ戻る
メールの送信先:ひしだま