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

Asakusa Framework 射影演算子

Asakusa FrameworkOperator 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
hoge
value1 value2 value3
1 1000 aaa
12 12000 bbb
3 3333 ccc
out
foo
value1 value3
1 aaa
12 bbb
3 ccc

example.dmdl(DMDL):

hoge = {

    value1 : INT;

    value2 : LONG;

    value3 : TEXT;
};

foo = {

    value1 : INT;

    value3 : TEXT;
};

ExampleJob.java(Flow DSL):

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)」でも同じ。見た目が違うだけ。


asの例

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;

あるいは、Scalamapメソッドに似ている。

  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)

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