Asakusa Framework : ケーススタディ:多対多のデータモデル結合(CoGroup編)

f:id:teppei-studio:20131112202621j:plain

Asakusa Framework Advent Calendar 2013の4日目の記事です。

先日書いた、Asakusa Framework : ケーススタディ:多対多のデータモデル結合 - TEPPEI STUDIOの記事を受けて、某所にて「CoGroupで実装する方がいい」という指摘をいただいたので、やってみました。

ケース内容

改めて確認しておきましょう。この図にあるような結合を行いたい場合です。

f:id:teppei-studio:20131201162416p:plain

JobFlow設計

先日の記事で試した、ConfluentとFoldでやる場合は、こちらです。

f:id:teppei-studio:20131201162421p:plain

これが、CoGroupを使うとこうなります。

f:id:teppei-studio:20131204211523p:plain

ステップがひとつ減りますね。いいですね。

2013/12/5追記
Extendは必須ではありません。後述します。

Operator実装

Operatorの実装はこうなります。

package teppeistudio.operator;

import java.util.List;
import teppeistudio.modelgen.dmdl.model.ModelAb;
import com.asakusafw.runtime.core.Result;
import com.asakusafw.vocabulary.model.Key;
import com.asakusafw.vocabulary.operator.CoGroup;

public abstract class MainOperator {

	@CoGroup
	public void m2mJoined(
			@Key(group="id") List<ModelAb> listA,
			@Key(group="id") List<ModelAb> listB,
			Result<ModelAb> listAB
			){
		
		ModelAb ab = new ModelAb();
		
		//ModelAもModelBも該当キーのレコードがある場合
		if(listA.size() == 1 && listB.size() == 1){
			ab.setId(listA.get(0).getId());
			ab.setName(listA.get(0).getName());
			ab.setDataA(listA.get(0).getDataA());
			ab.setDataB(listB.get(0).getDataB());
			
		//ModelAだけ該当キーのレコードがある場合
		}else if(listA.size() != 0 && listB.size() == 0){
			ab.copyFrom(listA.get(0));

		//ModelBだけ該当キーのレコードがある場合
		}else if(listA.size() == 0 && listB.size() != 0){
			ab.copyFrom(listB.get(0));
			
		//ModelAもModelBも該当キーが無い場合、あるいはどちらかが2件以上ある場合
		}else{
			throw new Error("ここには来ないはず");
		}
		
		listAB.add(ab);
	}
}

各プロパティ毎の実装は相変わらず必要になりますね。ここをなんとかしたいところだよなぁ。

2013/12/5追記
JobFlowでExtendを入れたのは、copyFromを使って、プロパティ毎の実装を極力減らしたかったためです。ModelA、ModelBのままこのOperatorのインプットとすることも可能です。その場合はプロパティ毎にset/get処理をする必要があります。

注意

リファレンスにある通り、CoGroup演算子はなんでもできてしまうので、コンパイラの最適化を適用しにくかったり、グループごとの大きさに制限があるなどの問題もあります。注意しましょう。

特に、演算子のインプットとなるListが大きくなるような場合には、OutOfMemoryになる可能性があります。そもそもそうならないように設計を注意するか、リファレンスに回避策も記載されているようなので、このあたりを参照して対応しましょう。

おしまい

この記事のサンプルは例によって、GitHubに挙げています。