Asakusa Framework : ケーススタディ:多対多のデータモデル結合(CoGroup編)
Asakusa Framework Advent Calendar 2013の4日目の記事です。
先日書いた、Asakusa Framework : ケーススタディ:多対多のデータモデル結合 - TEPPEI STUDIOの記事を受けて、某所にて「CoGroupで実装する方がいい」という指摘をいただいたので、やってみました。
これまでのAsakusa Framework関連記事
ハマりやすいところシリーズ
ケース内容
改めて確認しておきましょう。この図にあるような結合を行いたい場合です。
JobFlow設計
先日の記事で試した、ConfluentとFoldでやる場合は、こちらです。
これが、CoGroupを使うとこうなります。
ステップがひとつ減りますね。いいですね。
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に挙げています。