Asakusa FrameworkのOperator DSLの射影演算子(project)のメモ。
|
射影演算子は、プロパティーを除去した別のデータモデルに変換する演算子。
性能特性はExtract(旧ドキュメントではMap)。[/2016-02-11]
入力 ポート数 |
入力データモデル の制約 |
イメージ | 出力 ポート数 |
出力データモデル の制約 |
入力1レコード に対する 出力レコード数 |
---|---|---|---|---|---|
1 | outのプロパティーは 全て存在している 必要がある。 |
![]() |
1 | 1レコード。 |
「プロパティーが除去されているデータモデル」とは、例えば以下のような状態のことを言っている。
入力データモデル | 出力データモデル | 説明 | |
---|---|---|---|
プロパティー | value1 | value1 | |
value2 | value2が除去されている。 | ||
value3 | value3 |
射影演算子の入力データモデルと出力データモデルに同一プロパティー名のプロパティーがある場合だけ値が移送される。
なお、値の移送方法に関しては、getter/setterを使って移送するコードが生成される。
(リフレクションを使うわけではないので、性能劣化については気にする必要は無い)
プロパティー名が一致しないデータモデルへの変換を行いたい場合は変換演算子(@Convert)を使う。
プロパティーを増やす場合は拡張演算子(extend)を使う。
プロパティーが増減する場合は再構築演算子(restructure)を使う。
hogeデータモデルをプロパティーの少ないfooデータモデルへ変換する例。
(この図はToad Editorを用いて作っています)
入力データ例 | 出力データ例 | |||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
in |
|
→ | out |
|
hoge = { value1 : INT; value2 : LONG; value3 : TEXT; }; foo = { value1 : INT; value3 : TEXT; };
import com.asakusafw.vocabulary.flow.util.CoreOperatorFactory; import com.asakusafw.vocabulary.flow.util.CoreOperatorFactory.Project; import com.example.modelgen.dmdl.model.Foo; import com.example.modelgen.dmdl.model.Hoge;
private final In<Hoge> in; private final Out<Foo> out;
@Override public void describe() { CoreOperatorFactory core = new CoreOperatorFactory(); // HogeをFooに変換する Project<Foo> pr = core.project(this.in, Foo.class); this.out.add(pr.out); }
射影演算子はコア演算子なので、Operatorクラスにプログラマーが何かを実装する必要は無い。
Flow DSLでは、projectメソッドの第2引数に変換先のデータモデル(のクラス)を指定する。
(変換元のデータモデルは第1引数(接続元)の情報から分かる)
なお、出力データの指定方法は、「out.add(pr)
」でも「out.add(pr.out)
」でも同じ。見た目が違うだけ。
AsakusaFW 0.7.3から、新しい表記方法が出来るようになった。[2015-04-23]
メソッドの引数にデータモデルクラスを渡すのではなく、In・SourceやOutのデータソースを指定し、それと同じデータモデルであることを表す。
private final In<HogeExtend> extendIn; private final In<Hoge> in; private final Out<Hoge> out;
// 従来の書き方 this.out.add(core.project(this.extendIn, Hoge.class)); // AsakusaFW 0.7.3 で書けるようになった書き方 this.out.add(core.project(this.extendIn).as(Hoge.class)); this.out.add(core.project(this.extendIn).as(this.in)); this.out.add(core.project(this.extendIn).as(this.out));
この表記方法は、多相データフロー(ジェネリクス(型引数)を使ってフローパートを定義する)で便利。
(Javaでは、型引数から「T.class
」のようにしてクラスを指定することは出来ない為)
@FlowPart public class ProjectFlowPart<T extends ProjHoge> extends FlowDescription {
private final In<HogeExtend> hogeIn; private final In<T> in; private final Out<T> out; public ExtendFlowPart(In<HogeExtend> hogeIn, In<T> in, Out<T> out) { this.hogeIn = hogeIn; this.in = in; this.out = out; }
@Override
public void describe() {
CoreOperatorFactory core = new CoreOperatorFactory();
core.stop(this.in);
//× this.out.add(core.project(this.hogeIn, T.class));
// this.out.add(core.project(this.hogeIn).as(this.in));
this.out.add(core.project(this.hogeIn).as(this.out));
}
}
射影演算子はコア演算子なので、(Operatorクラスにプログラマーが何も実装していないので)Operatorの単体テストを実装する必要は無い。
射影演算子は、SQLのSELECT-INSERTに似ている。
INSERT foo SELECT value1, value3 FROM hoge;
case class Hoge(value1: Int, value2: Long, value3: String) case class Foo(value1: Int, value3: String) def project(hoge: Hoge) = Foo(hoge.value1, hoge.value3) val in : List[Hoge] = 〜 val out: List[Foo] = in.map(project)