演算子リファレンス

この文書では、Asakusa Frameworkが提供する演算子について個々に紹介します。

Asakusa DSLの演算子

Asakusa FrameworkのOperator DSLとFlow DSLでは、それぞれ演算子を利用しています。

前者のOperator DSLでは、主に演算子を「作成」します。 Asakusa Frameworkが提供するのは演算子の「種類」であって、それぞれの演算子の細かな挙動はOperator DSLでカスタマイズできます。

後者のFlow DSLでは、主に演算子を「複合」します。 Operator DSLで作成する演算子はデータフローの「部品」であり、これらを複合して複雑なデータフローを構築することになります。

レコードとグループ

それぞれの演算子が処理するデータの単位は、「レコード」または「グループ」のいずれかです。

レコード
データフローに流れるデータ1つ分。 Asakusa DSLでは「データモデルオブジェクト」として表現される。
グループ
レコードを特定のキーでグループ化したもの。 Asakusa DSLでは、データモデルオブジェクトのリストや反復子などで表現される。

キー注釈

Operator DSLでは上記のグループを作成するために、 Key [1] という注釈を多用します。 これは、グループ化のための方法や、グループ内での整列順序を指定するためのものです。 詳しくは Asakusa DSLユーザーガイド - キー注釈 を参照してください。

[1]com.asakusafw.vocabulary.model.Key

演算子の分類

それぞれの演算子は、処理の内容ごとにいくつかに分類できます。

フロー制御演算子
データの流れそのものを制御する。
データ操作演算子
データフローに流れるデータを加工する。
結合演算子
複数のレコードを結合する。
集計演算子
レコードをグループごとに集計する。
特殊演算子
上記の分類に含まれない特別な演算子。

コア演算子とユーザー演算子

演算子を実装方法の面から2種類に分類できます。

コア演算子
Asakusa Frameworkが APIとして 提供する演算子。 この種類の演算子はOperator DSLで記述する必要はなく、Flow DSLから直接利用できる。
ユーザー演算子
演算子の種類ごとに演算子注釈のみを提供している演算子。 この種類の演算子を利用するには、Operator DSLで必要な演算子メソッドを定義する必要がある。 なお、ユーザー演算子にもメソッド本体の実装が必要なものと不要なものに分かれています。

Flow DSLでコア演算子を利用する場合、一般的に CoreOperatorFactory [2] というファクトリクラスが提供するメソッドを使用します。 また、上記ファクトリクラスと同名のクラスメソッド群を持つ CoreOperators [3] も利用可能です。

[2]com.asakusafw.vocabulary.flow.util.CoreOperatorFactory
[3]com.asakusafw.vocabulary.flow.util.CoreOperators

演算子の性能特性

それぞれの演算子はその性能特性から、いくつかの種類に分類できます。

Extract 系演算子

もっとも単純な演算子の種類で、入力データからデータモデルオブジェクトを一つずつ取り出して処理を行います。

この種類は並列分散処理が比較的容易で、データサイズが大きくなっても、コンピューターのCPUの個数やクラスターの台数などを増大させることで性能を向上させられるケースが多くあります。 ほとんどのコア演算子や、更新演算子、抽出演算子などはこの Extract 系演算子に含まれています。

CoGroup 系演算子

入力データを指定した条件でグループごとに分割し、それぞれのグループを一つずつ取り出して処理を行います。

この種類は、グループごとにデータを分割する操作において、データのコピー・移動や待ち合わせが発生してしまいます。 そのため、分散処理を行う際にはこの処理がバッチ全体のボトルネックになる場合があります。

また、分割したグループの大きさに偏りがある場合、処理が特定のノードに集中してしまう場合もあります。

グループ整列演算子や、グループ結合演算子などがこの CoGroup 系演算子に含まれています。

Join 系演算子

入力データに、別の入力データを結合して処理を行います。

この演算子は「トランザクション入力」と「マスタ入力」という2つの入力をとり、マスタ入力のデータが十分に小さな場合に Extract 系演算子と同程度の性能を発揮します。 そうでなく、マスタ入力のデータが大きな場合にはおよそ CoGroup 系演算子程度の性能になります。

マスタ結合演算子や、マスタ付き更新演算子などがこの Join 系演算子に含まれています。

Fold 系演算子

入力データを指定した条件でグループごとに分割し、それぞれのグループを集計する処理を行います。

この種類は CoGroup 系演算子と似通っていますが、コンパイラの設定や、処理系によっては CoGroup 系よりも効率よく動作します。

単純集計演算子や、畳み込み演算子などがこの Fold 系演算子に含まれています。

演算子の表記

この文書での演算子に関する表記を説明します。

コア演算子の表記

コア演算子は次のような表で表記します。

コア演算子の表記
項目 内容
分類 “コア”
導入 この演算子が導入されたフレームワークのバージョン
メソッド CoreOperatorFactory 内のメソッド名
性能特性 Extract | CoGroup | Join | Fold
入力数 この演算子への入力数
出力数 この演算子からの出力数

ユーザー演算子の表記

ユーザー演算子は次のような表で表記します。

ユーザー演算子の表記
項目 内容
分類 “ユーザー”
導入 この演算子が導入されたフレームワークのバージョン
演算子注釈 演算子注釈の名前
本体の実装 “必要”または”不要” [4]
性能特性 Extract | CoGroup | Join | Fold
入力数 この演算子への入力数
出力数 この演算子からの出力数
ビュー引数 この演算子にビュー引数を指定可能かどうか [5]
値引数 この演算子に値引数を指定可能かどうか
型引数 この演算子に型引数を指定可能かどうか [6]
[4]本体の実装が不要なユーザー演算子は、抽象メソッドとして宣言します。
[5]ビュー引数については、 ビューAPI を参照してください。
[6]型引数は多相演算子で使用します。詳しくは 多相データフロー を参照してください。

入出力の表記

それぞれの入出力は、次のような項目を表記します。

入出力の表記
項目 内容
分類 “入力” または “出力”
名前 標準的な名前
単位 処理単位 (“レコード”, “グループ”)
データの種類
備考 備考欄

演算子メソッドの表記

演算子メソッドの形式は、次のような項目を表記します。

演算子メソッドの表記
項目 内容
分類 返戻値または引数1~
対応 演算子の入出力との対応
指定する型
キー Key の指定
備考 備考欄

「型」には主に次のようなものがあります。

モデル
データモデル型
リスト
データモデル型を要素に取る List [7]
ビュー
データモデル型を要素に取る View および GroupView [8]
結果
データモデル型を要素に取る Result [9]
プリミティブ
Javaのプリミティブ型、または文字列型
列挙型
Javaの列挙型 ( enum )
Javaの型
Javaの対応する型
[7]java.util.List
[8]com.asakusafw.runtime.core.View および com.asakusafw.runtime.core.GroupView ビューについては、 ビューAPI を参照してください。
[9]com.asakusafw.runtime.core.Result 演算子の出力となるデータモデルオブジェクトを保持します。 add メソッドにより複数のオブジェクトを追加することができます。

フロー制御演算子

フロー制御系の演算子は、主にデータフローの構造を制御するための演算子です。

分岐演算子

レコードを入力にとって、レコードの内容に応じていずれかの出力にレコードを振り分ける演算子です。 「条件に応じて出力先を変える」などの用途に利用できます。

分岐演算子の概要
項目 説明
分類 ユーザー
導入 0.1
演算子注釈 Branch [10]
本体の実装 必要
性能特性 Extract
入力数 1
出力数 任意
ビュー引数 指定可能
値引数 指定可能
型引数 指定可能
分岐演算子の入出力
分類 名前 単位 備考
入力 in レコード 任意  
出力 (任意) レコード inと同様 任意の個数を指定可
[10]com.asakusafw.vocabulary.operator.Branch

分岐演算子の実装

分岐演算子の演算子メソッドには次のような情報を指定します。

分岐演算子の実装
分類 対応 キー 備考
返戻 全出力 列挙型 不可 列挙定数ごとに出力
引数1 入力 モデル 不可  
ビュー引数 入力 ビュー 任意  
値引数 なし プリミティブ 不可  

この演算子は一つの引数を取り、分岐先を表現する列挙定数を返します。

返戻型に指定する列挙型は、分岐先の出力名を表しています。 メソッドから列挙定数を返すと、その時点の引数に渡された入力が、返した列挙定数に対応する出力に渡されます。

引数には同メソッドで宣言した型変数を利用できますが、 戻り値の型に型変数を含めることはできません。

分岐演算子の演算子メソッドは、一般的な演算子メソッドの要件の他に、 下記の要件をすべて満たす必要があります。

  • 返戻型には分岐先を表現する列挙型を指定する
    • その列挙型は、public として宣言されている
    • その列挙型は、一つ以上の列挙定数を持つ
  • 以下の引数を宣言する
    • データモデルオブジェクト型の引数
  • 以下の修飾子を付与する
    • (特になし)
  • 以下の修飾子は付与しない
    • abstract

Attention

分岐演算子の内部では、入力の内容を変更しないようにしてください。 そのような動作を期待する場合、 更新演算子 を利用するようにしてください。

以下は実装例です。

public abstract class OperatorClass {
    ...

    /**
     * レコードの状態ごとに処理を分岐する。
     * @param hoge 対象のレコード
     * @return 分岐先を表すオブジェクト
     */
    @Branch
    public Status select(Hoge hoge) {
        int price = hoge.getPrice();
        if (price < 0) {
            return Status.ERROR;
        }
        if (price >= 1000000) {
            return Status.EXPENSIVE;
        }
        return Status.CHEAP;
    }

    /**
     * 値段に関するレコードの状態。
     */
    public enum Status {
        /**
         * 高い。
         */
        EXPENSIVE,

        /**
         * 安い。
         */
        CHEAP,

        /**
         * エラー。
         */
        ERROR,
    }

    ...
}

合流演算子

複数の入力を合流して、単一の出力にまとめる演算子です。 分岐演算子 の逆の動作を行い、SQLの UNION ALL のように動きます。

合流演算子の概要
項目 説明
分類 コア
導入 0.1
メソッド confluent
性能特性 Extract
入力数 任意
出力数 1
合流演算子の入出力
分類 名前 単位 備考
入力 (任意) レコード 任意 任意の入力数だが、全て同じ型
出力 out レコード 入力と同様  

合流演算子の実装

合流演算子はコア演算子に分類されるため、Operator DSLでの実装はありません。 Flow DSLからは次のように利用します。

In<Hoge> in1, in2, in3;
Out<Hoge> out;

@Override
protected void describe() {
    CoreOperatorFactory core = new CoreOperatorFactory();
    Confluent<Hoge> op = core.confluent(in1, in2, in3);
    out.add(op);
}

複製演算子

レコードを入力にとって、同じ内容のレコードを複数の出力にそれぞれ出力する演算子です。

複製演算子の概要
項目 説明
分類 コア
導入 0.1
メソッド 特殊 [11]
性能特性 Extract
入力数 1
出力数 任意
複製演算子の入出力
分類 名前 単位 備考
入力 in レコード 任意  
出力 (任意) レコード inと同様 任意の個数
[11]データの複製は同一の出力を何度も利用するだけで実現できるため、特別なメソッドを用意していません。

複製演算子の実装

複製演算子はコア演算子に分類されるため、Operator DSLでの実装はありません。 Flow DSLからは演算子からの出力を複数回利用すると、複製演算子と同じ効果を得られます。

Out<Hoge> out1, out2, out3;

@Override
protected void describe() {
    ...
    SomeOperator op = ...;
    out1.add(op.out);
    out2.add(op.out);
    out3.add(op.out);
}

データ操作演算子

データ操作系の演算子は、主にレコードを加工したり変形したりするための演算子です。

更新演算子

レコードの内容を更新する演算子です。 レコードの型そのものを変更したい場合には、 変換演算子 を利用します。

更新演算子の概要
項目 説明
分類 ユーザー
導入 0.1
演算子注釈 Update [12]
本体の実装 必要
性能特性 Extract
入力数 1
出力数 1
ビュー引数 指定可能
値引数 指定可能
型引数 指定可能
更新演算子の入出力
分類 名前 単位 備考
入力 in レコード 任意  
出力 out レコード inと同様  
[12]com.asakusafw.vocabulary.operator.Update

更新演算子の実装

更新演算子の演算子メソッドには次のような情報を指定します。

更新演算子の実装
分類 対応 キー 備考
返戻 なし void 不可  
引数1 入出力 モデル 不可  
ビュー引数 入力 ビュー 任意  
値引数 なし プリミティブ 不可  

この演算子は、単一の入力に流れるデータの項目を変更し、出力に流します。

対象のメソッドは一つの引数を取り、メソッドの本体で引数の内容を変更するプログラムを記述します。 メソッド内で引数のデータモデルオブジェクトを破壊的に変更すると、変更結果が演算子の出力になります。

引数には同メソッドで宣言した型変数を利用できます。

更新演算子の演算子メソッドは、一般的な演算子メソッドの要件の他に、 下記の要件をすべて満たす必要があります。

  • 返戻型にvoidを指定する
  • 以下の引数を宣言する
    • データモデルオブジェクト型の引数
  • 以下の修飾子を付与する
    • (特になし)
  • 以下の修飾子は付与しない
    • abstract

以下は実装例です。

/**
 * レコードの値に100を設定する。
 * @param hoge 更新するレコード
 */
@Update
public void edit(Hoge hoge) {
    hoge.setValue(100);
}

変換演算子

レコードを別の型のレコードに変換する演算子です。 主に「レコードから別のレコードを作成する」という目的で利用します。

変換演算子の概要
項目 説明
分類 ユーザー
導入 0.1
演算子注釈 Convert [13]
本体の実装 必要
性能特性 Extract
入力数 1
出力数 2
ビュー引数 指定可能
値引数 指定可能
型引数 指定可能
変換演算子の入出力
分類 名前 単位 備考
入力 in レコード 任意  
出力 out レコード 任意 変換後のデータ
出力 original レコード inと同様 変換前のデータ
[13]com.asakusafw.vocabulary.operator.Convert

Hint

レコードから不要なプロパティを除去したり、新たなプロパティを追加する場合は 射影演算子拡張演算子再構築演算子 の利用を推奨しています。

変換演算子の実装

変換演算子の演算子メソッドには次のような情報を指定します。

変換演算子の実装
分類 対応 キー 備考
返戻 出力 モデル 不可 型引数は指定不可
引数1 入力 モデル 不可  
ビュー引数 入力 ビュー 任意  
値引数 なし プリミティブ 不可  

この演算子は、入力されたデータを他の種類のデータに変換し、出力に流します。

一つの引数を取り、変換して別のデータモデルオブジェクトを返すプログラムを記述します。 メソッドから返したデータモデルオブジェクトが演算子の出力になります。 このデータモデルオブジェクトは、演算子クラスと一緒に一度だけインスタンス化して再利用することが可能です。

この演算子をフロー部品やジョブフローで使用する際に、出力 original は他の演算子等と結線されていなくてもエラーにならない、という特性を持ちます。 ただし、Asakusa on MapReduce 利用時には original の結線を省略することはできません。

引数には同メソッドで宣言した型変数を利用できますが、 戻り値の型に型変数を含めることはできません。

変換演算子の演算子メソッドは、一般的な演算子メソッドの要件の他に、 下記の要件をすべて満たす必要があります。

  • 返戻型に変換後のデータモデルオブジェクト型を指定する
  • 以下の引数を宣言する
    • データモデルオブジェクト型の引数
  • 以下の修飾子を付与する
    • (特になし)
  • 以下の修飾子は付与しない
    • abstract

このフレームワークを正しく利用する限り、この注釈を付与するメソッドはスレッド安全となります。 ただし、同メソッドが共有データを操作したり、または共有データを操作する別のメソッドを起動したりする場合についてはスレッド安全ではありません。

以下は実装例です。

// スレッド安全なので変換後のオブジェクトは再利用可能
private final Foo foo = new Foo();

/**
 * レコードHogeを等価なFooに変換して返す。
 * @param hoge 変換するレコード
 * @return 変換後のレコード
 */
@Convert
public Foo toFoo(Hoge hoge) {
    foo.setValue(hoge.getValue());
    return foo;
}

拡張演算子

レコードに新たなプロパティを追加した別の型に変換する演算子です。 計算のために一時的にプロパティを追加したい場合などに利用することを想定しています。

拡張演算子の概要
項目 説明
分類 コア
導入 0.2
メソッド extend
性能特性 Extract
入力数 1
出力数 1
拡張演算子の入出力
分類 名前 単位 備考
入力 in レコード 任意  
出力 out レコード 任意 入出力の型に制約あり

Attention

拡張演算子を利用する場合、変換後のレコードには変換前の型にある全てのプロパティが定義されている必要があります。 つまり、この演算子は「プロパティを増やす」場合のみに利用できます。

拡張演算子の実装

拡張演算子はコア演算子に分類されるため、Operator DSLでの実装はありません。 Flow DSLからは次のように利用します。

In<Hoge> in;
Out<Foo> out;

@Override
protected void describe() {
    CoreOperatorFactory core = new CoreOperatorFactory();
    Extend<Foo> op = core.extend(in, Foo.class);
    out.add(op);
}

上記の例では、 Hoge が持つすべてのプロパティを Foo も持っていなければなりません。 そうでない場合、コンパイル時にエラーとなります。

射影演算子

レコードから不要なプロパティを除去した別の型に変換する演算子です。 計算のために一時的に導入していたプロパティなどを除去したり、出力前に適切な型に変換することを想定としています。

射影演算子の概要
項目 説明
分類 コア
導入 0.2
メソッド project
性能特性 Extract
入力数 1
出力数 1
射影演算子の入出力
分類 名前 単位 備考
入力 in レコード 任意  
出力 out レコード 任意 入出力の型に制約あり

Attention

射影演算子を利用する場合、変換前の型には変換後のレコードにある全てのプロパティが定義されている必要があります。 つまり、この演算子は「プロパティを減らす」場合のみに利用できます。

射影演算子の実装

射影演算子はコア演算子に分類されるため、Operator DSLでの実装はありません。 Flow DSLからは次のように利用します。

In<Foo> in;
Out<Hoge> out;

@Override
protected void describe() {
    CoreOperatorFactory core = new CoreOperatorFactory();
    Project<Hoge> op = core.project(in, Hoge.class);
    out.add(op);
}

上記の例では、 Hoge が持つすべてのプロパティを Foo も持っていなければなりません。 そうでない場合、コンパイル時にエラーとなります。

再構築演算子

レコードの内容を別の型に移し替える演算子です。 元の型と移し替える先の型のうち、両者に共通するプロパティのみをコピーします。

再構築演算子の概要
項目 説明
分類 コア
導入 0.2.1
メソッド restructure
性能特性 Extract
入力数 1
出力数 1
再構築演算子の入出力
分類 名前 単位 備考
入力 in レコード 任意  
出力 out レコード 任意  

Hint

再構築演算子は、 拡張演算子射影演算子 の制約を緩めたものです。 これらの演算子が利用できる場面では通常再構築演算子も利用できますが、データ構造がむやみに変更された際にコンパイラによるチェックが甘くなります。 拡張演算子や射影演算子で十分である場合、できるだけそちらを利用することを推奨します。

再構築演算子の実装

再構築演算子はコア演算子に分類されるため、Operator DSLでの実装はありません。 Flow DSLからは次のように利用します。

In<Foo> in;
Out<Hoge> out;

@Override
protected void describe() {
    CoreOperatorFactory core = new CoreOperatorFactory();
    Restructure<Hoge> op = core.restructure(in, Hoge.class);
    out.add(op);
}

上記の例では、 HogeFoo に共通するプロパティのみが、 Hoge ( in ) から Foo にコピーされます。

抽出演算子

レコードに含まれるデータを抽出して、複数のレコードを生成する演算子です。 主に「レコードを分解して別のレコードを作成する」という目的で利用します。

抽出演算子の概要
項目 説明
分類 ユーザー
導入 0.2.1
演算子注釈 Extract [14]
本体の実装 必要
性能特性 Extract
入力数 1
出力数 任意
ビュー引数 指定可能
値引数 指定可能
型引数 指定可能
抽出演算子の入出力
分類 名前 単位 備考
入力 in レコード 任意  
出力 (任意) レコード 任意 任意個数を指定可
[14]com.asakusafw.vocabulary.operator.Extract

抽出演算子の実装

抽出演算子の演算子メソッドには次のような情報を指定します。

抽出演算子の実装
分類 対応 キー 備考
返戻 出力 void 不可  
引数1 入力 モデル 不可  
ビュー引数 入力 ビュー 任意  
以降の引数 各出力 結果 不可 任意の個数
値引数 なし プリミティブ 不可  

この演算子は、入力されたデータから任意のデータを抽出し、それぞれ出力に流します。

一つのデータモデルオブジェクト型の引数と、 複数の結果オブジェクト型の引数を取り、引数から抽出した任意のデータモデルオブジェクトを結果オブジェクトに出力を行うプログラムを記述します。

出力は任意個の結果で、メソッド内で同じ結果に対して複数回の結果を指定することも可能です。

引数には同メソッドで宣言した型変数を利用できますが、全ての結果オブジェクト型の出力に型変数を含める場合には、入力に同様の型変数を指定してある必要があります。

抽出演算子の演算子メソッドは、一般的な演算子メソッドの要件の他に、 下記の要件をすべて満たす必要があります。

  • 返戻型にvoidを指定する
  • 以下の引数を宣言する
    • データモデルオブジェクト型の引数
    • 一つ以上の結果型の引数
  • 以下の修飾子を付与する
    • (特になし)
  • 以下の修飾子は付与しない
    • abstract

以下は実装例です。

// スレッド安全なので抽出結果のオブジェクトは再利用可能
private final A a = new A();
private final B b = new B();

/**
 * レコードに含まれるそれぞれのフィールドを抽出し、出力する。
 * @param hoge 抽出対象のデータモデル
 * @param aResult aの抽出結果
 * @param bResult bの抽出結果
 */
@Extract
public void extractFields(
        Hoge hoge,
        Result<A> aResult,
        Result<B> bResult) {
    a.setValue(hoge.getA());
    aResult.add(a);
    b.setValue(hoge.getB0());
    bResult.add(b);
    b.setValue(hoge.getB1());
    bResult.add(b);
}

結合演算子

結合系の演算子は、複数のレコードを突き合わせたり結合したりするための演算子です。

マスタ確認演算子

レコードと同様のキーを持つレコードを別の入力から探し、存在する場合としない場合で出力を振り分ける演算子です。

マスタ確認演算子の概要
項目 説明
分類 ユーザー
導入 0.1
演算子注釈 MasterCheck [15]
本体の実装 不要
性能特性 Join
入力数 2
出力数 2
ビュー引数 指定可能
値引数 指定可能
型引数 指定可能
備考 マスタ選択を利用可能
マスタ確認演算子の入出力
分類 名前 単位 備考
入力 master グループ 任意 グループ化を指定
入力 tx レコード 任意 グループ化を指定
出力 found レコード txと同様 マスタが見つかったもの
出力 missed レコード txと同様 マスタが見つからなかったもの
[15]com.asakusafw.vocabulary.operator.MasterCheck

マスタ確認演算子の実装

マスタ確認演算子の演算子メソッドには次のような情報を指定します。

マスタ確認演算子の実装
分類 対応 キー 備考
返戻 出力 boolean 不可  
引数1 入力 モデル 必須 マスタデータの入力
引数2 入力 モデル 必須  
ビュー引数 入力 ビュー 任意  
値引数 なし プリミティブ 不可  

この演算子は、トランザクションデータに対応するマスタデータを引き当てて確認し、マスタデータを発見できたものと発見できなかったものに分けて出力に流します。

このメソッドには本体を指定せず、抽象メソッドとして宣言します。

対象のメソッドは結合対象の二つのデータモデルオブジェクト型の引数を取ります。 このとき最初の引数は、マスタデータなど結合条件に対してユニークであるようなデータモデルオブジェクトである必要があります。

戻り値型にはboolean型を指定します。マスタデータを発見できた場合は ture 、 発見できなかった場合は false を返却します。

データモデルオブジェクト型の引数にはそれぞれ Key 注釈を指定し、 group でグループ化のためのプロパティ名を指定します。 それぞれのプロパティ列が完全に一致するものが結合対象になります。 整列のためのプロパティ名および整列方向に関する動作は規定されません。

引数には同メソッドで宣言した型変数を利用できます。

マスタ確認演算子の演算子メソッドは、一般的な演算子メソッドの要件の他に、 下記の要件をすべて満たす必要があります。

  • 返戻型にboolean型を指定する
  • 以下の引数を宣言する
    • 結合対象のデータモデルオブジェクト型の引数 (マスタデータ)、さらに Key 注釈でグループ化のための情報を指定する
    • 結合対象のデータモデルオブジェクト型の引数、さらに Key 注釈でグループ化のための情報を指定する
  • 以下の修飾子を付与する
    • abstract
  • 以下の修飾子は付与しない
    • (特になし)

以下は実装例です。

/**
 * レコードHogeTrnに対するHogeMstが存在する場合に{@code true}を返す。
 * @param master マスタデータ
 * @param tx トランザクションデータ
 * @return HogeMstが存在する場合のみtrue
 */
@MasterCheck
public abstract boolean exists(
        @Key(group = "id") HogeMst master,
        @Key(group = "masterId") HogeTrn tx);

また、この演算子注釈に selection を指定することで、非等価結合条件を記述することも可能です。 詳しくは マスタ選択 を参照して下さい。

マスタ結合演算子

レコードと同様のキーを持つレコードを別の入力から探し、それらを結合したレコードを出力する演算子です。 この演算子は、結合モデル [16] のレコードを構築します。

入力はそれぞれ結合モデルの元になったデータモデルを指定し、結合に成功した場合に結合モデルが出力され、失敗した場合には元になったレコードが出力されます。

また、結合条件や結合方法は結合モデルに指定したものを利用します。

マスタ結合演算子の概要
項目 説明
分類 ユーザー
導入 0.1
演算子注釈 MasterJoin [17]
本体の実装 不要
性能特性 Join
入力数 2
出力数 2
ビュー引数 指定可能
値引数 指定可能
型引数 指定不可
備考 マスタ選択を利用可能
マスタ結合演算子の入出力
分類 名前 単位 備考
入力 master グループ 任意  
入力 tx レコード 任意  
出力 joined レコード 任意 結合結果、結合モデルを指定
出力 missed レコード txと同様 マスタが見つからなかったもの
[16]結合モデルについては DMDLユーザーガイド を参照してください。
[17]com.asakusafw.vocabulary.operator.MasterJoin

マスタ結合演算子の実装

マスタ結合演算子の演算子メソッドには次のような情報を指定します。

マスタ結合演算子の実装
分類 対応 キー 備考
返戻 出力 モデル 不可 結合モデルのみ
引数1 入力 モデル 不可 マスタデータの入力
引数2 入力 モデル 不可  
ビュー引数 入力 ビュー 任意  
値引数 なし プリミティブ 不可  

この演算子は、トランザクションデータに対して対応するマスタデータを結合し、結合結果のレコードを出力に流します。

このメソッドには本体を指定せず、抽象メソッドとして宣言します。

対象のメソッドは、結合対象の二つのデータモデルオブジェクト型の引数を取ります。 このとき最初の引数は、マスタデータなど結合条件に対してユニークであるようなデータモデルオブジェクトである必要があります。

戻り値型には結合結果を表す結合モデルの型を指定します。 結合モデルの型は、必ず結合対象の二つのデータモデルオブジェクトを結合したものである必要があります。

この演算子の結合条件や結合方法は、結合モデル型の注釈 [18] に全て埋め込まれています。 そのため、他のマスタ操作系の演算子とは異なり、 Key の指定は不要です。

この演算子メソッドには型引数を定義できません。

マスタ結合演算子の演算子メソッドは、一般的な演算子メソッドの要件の他に、 下記の要件をすべて満たす必要があります。

  • 返戻型に結合結果となるモデル型を指定する
  • 以下の引数を宣言する
    • 結合対象のデータモデルオブジェクト型の引数 (マスタデータ)
    • 結合対象のデータモデルオブジェクト型の引数
  • 以下の修飾子を付与する
    • abstract
  • 以下の修飾子は付与しない
    • (特になし)

以下は実装例です。

/**
 * レコードHogeMstとHogeTrnを結合し、結合結果のHogeを返す。
 * @param master マスタデータ
 * @param tx トランザクションデータ
 * @return 結合結果
 */
@MasterJoin
public abstract Hoge join(HogeMst master, HogeTrn tx);

また、この演算子注釈に selection を指定することで、非等価結合条件を記述することも可能です。 詳しくは マスタ選択 を参照して下さい。

[18]com.asakusafw.vocabulary.model.Joined

マスタ分岐演算子

レコードと同様のキーを持つレコードを別の入力から探し、両方の情報を元にそれぞれの出力にレコードを振り分ける演算子です。 この演算子は、マスタを引き当てつつ 分岐演算子 と同等の処理を行います。

マスタ分岐演算子の概要
項目 説明
分類 ユーザー
導入 0.1
演算子注釈 MasterBranch [19]
本体の実装 必要
性能特性 Join
入力数 2
出力数 任意
ビュー引数 指定可能
値引数 指定可能
型引数 指定可能
備考 マスタ選択を利用可能
マスタ分岐の入出力
分類 名前 単位 備考
入力 master グループ 任意 グループ化を指定
入力 tx レコード 任意 グループ化を指定
出力 (任意) レコード txと同様 任意の個数を指定可
[19]com.asakusafw.vocabulary.operator.MasterBranch

マスタ分岐演算子の実装

マスタ分岐演算子の演算子メソッドには次のような情報を指定します。

マスタ分岐演算子の実装
分類 対応 キー 備考
返戻 全出力 列挙型 不可 列挙定数ごとに出力
引数1 入力 モデル 必須 マスタデータの入力
引数2 入力 モデル 必須  
ビュー引数 入力 ビュー 任意  
値引数 なし プリミティブ 不可  

この演算子は、トランザクションデータに対応するマスタデータを引き当て、それらの内容に応じてトランザクションデータをそれぞれの出力に振り分けます。

対象のメソッドは結合対象の二つのデータモデルオブジェクト型の引数を取ります。 このとき最初の引数は、マスタデータなど結合条件に対してユニークであるようなデータモデルオブジェクトである必要があります。

戻り値型には、分岐先を表現する列挙定数を返します。この列挙型は、分岐先の出力名を表しています。 メソッドから列挙定数を返すと、その時点の引数に渡された入力が、返した列挙定数に対応する出力に渡されます。

データモデルオブジェクト型の引数にはそれぞれ Key 注釈を指定し、 group でグループ化のためのプロパティ名を指定します。 それぞれのプロパティ列が完全に一致するものが結合対象になります。 整列のためのプロパティ名および整列方向に関する動作は規定されません。

引数には同メソッドで宣言した型変数を利用できます。

マスタ分岐演算子の演算子メソッドは、一般的な演算子メソッドの要件の他に、 下記の要件をすべて満たす必要があります。

  • 返戻型には分岐先を表現する列挙型を指定する
    • その列挙型は、public として宣言されている
    • その列挙型は、一つ以上の列挙定数を持つ
  • 以下の引数を宣言する
    • 結合対象のデータモデルオブジェクト型の引数 (マスタデータ)、さらに Key 注釈でグループ化のための情報を指定する
    • 結合対象のデータモデルオブジェクト型の引数、さらに Key 注釈でグループ化のための情報を指定する
  • 以下の修飾子を付与する
    • (特になし)
  • 以下の修飾子は付与しない
    • abstract

Attention

マスタ分岐演算子の内部では、入力の内容を変更しないようにしてください。 そのような動作を期待する場合、 マスタつき更新演算子分岐演算子 を組み合わせて利用するようにしてください。

Attention

この演算子の引数1 (マスタデータの入力) には、引き当てるマスタが見つからなかった場合に null が渡されます。 これは他のマスタ系の演算子とは異なる動作ですので、注意が必要です。

以下は実装例です。

public abstract class OperatorClass {
    ...

    /**
     * レコードの状態ごとに処理を分岐する。
     * @param master マスタデータ、存在しない場合は{@code null}
     * @param tx トランザクションデータ
     * @return 分岐先を表すオブジェクト
     */
    @MasterBranch
    public Status branchWithJoin(
            @Key(group = "id") ItemMst master,
            @Key(group = "itemId") HogeTrn tx) {
        if (master == null) {
            return Status.ERROR;
        }
        int price = master.getPrice();
        if (price < 0) {
            return Status.ERROR;
        }
        if (price >= 1000000) {
            return Status.EXPENSIVE;
        }
        return Status.CHEAP;
    }

    /**
     * 値段に関するレコードの状態。
     */
    public enum Status {
        /**
         * 高い。
         */
        EXPENSIVE,

        /**
         * 安い。
         */
        CHEAP,

        /**
         * エラー。
         */
        ERROR,
    }

    ...
}

また、この演算子注釈に selection を指定することで、非等価結合条件を記述することも可能です。 詳しくは マスタ選択 を参照して下さい。

マスタつき更新演算子

レコードと同様のキーを持つレコードを別の入力から探し、両方の情報を元に片方のレコードの内容を更新する演算子です。 この演算子は、マスタを引き当てつつ 更新演算子 と同等の処理を行います。

マスタつき更新演算子の概要
項目 説明
分類 ユーザー
導入 0.1
演算子注釈 MasterJoinUpdate [20]
本体の実装 必要
性能特性 Join
入力数 2
出力数 2
ビュー引数 指定可能
値引数 指定可能
型引数 指定可能
備考 マスタ選択を利用可能
マスタつき更新演算子の入出力
分類 名前 単位 備考
入力 master グループ 任意 グループ化を指定
入力 tx レコード 任意 グループ化を指定
出力 updated レコード txと同様 マスタが見つかったもの
出力 missed レコード txと同様 マスタが見つからなかったもの
[20]com.asakusafw.vocabulary.operator.MasterJoinUpdate

マスタつき更新演算子の実装

マスタつき更新演算子の演算子メソッドには次のような情報を指定します。

マスタつき更新演算子の実装
分類 対応 キー 備考
返戻 出力 void 不可  
引数1 入力 モデル 必須 マスタデータの入力
引数2 入力 モデル 必須 変更対象のデータ
ビュー引数 入力 ビュー 任意  
値引数 なし プリミティブ 不可  

この演算子は、トランザクションデータに対応するマスタデータを引き当てたのち、マスタデータの情報を利用してトランザクションデータの任意の項目を変更し、出力に流します。

対象のメソッドは結合対象の二つのデータモデルオブジェクト型の引数を取ります。 このとき最初の引数は、マスタデータなど結合条件に対してユニークであるようなデータモデルオブジェクトである必要があります。

データモデルオブジェクト型の引数にはそれぞれ Key 注釈を指定し、 group でグループ化のためのプロパティ名を指定します。 それぞれのプロパティ列が完全に一致するものが結合対象になります。 整列のためのプロパティ名および整列方向に関する動作は規定されません。

メソッドの本体では、引数のトランザクションデータの内容を変更するプログラムを記述します。 マスタデータの内容を変更した際の動作は規定されません。

引数には同メソッドで宣言した型変数を利用できますが、全ての結果オブジェクト型の出力に型変数を含める場合には、いずれかの入力に同様の型変数を指定してある必要があります。

マスタつき更新演算子の演算子メソッドは、一般的な演算子メソッドの要件の他に、 下記の要件をすべて満たす必要があります。

  • 返戻型にvoidを指定する
  • 以下の引数を宣言する
    • 結合対象のデータモデルオブジェクト型の引数 (マスタデータ)、さらに Key 注釈でグループ化のための情報を指定する
    • 結合対象のデータモデルオブジェクト型の引数、さらに Key 注釈でグループ化のための情報を指定する
  • 以下の修飾子を付与する
    • (特になし)
  • 以下の修飾子は付与しない
    • abstract

以下は実装例です。

/**
 * マスタの価格をトランザクションデータに設定する。
 * @param master マスタデータ
 * @param tx 変更するトランザクションデータ
 */
@MasterJoinUpdate
public void updateWithMaster(
        @Key(group = "id") ItemMst master,
        @Key(group = "itemId") HogeTrn tx) {
    tx.setPrice(master.getPrice());
}

また、この演算子注釈に selection を指定することで、非等価結合条件を記述することも可能です。 詳しくは マスタ選択 を参照して下さい。

グループ結合演算子

複数の入力をキーでグループ化し、キーが一致する入力ごとのグループをまとめて操作する演算子です。 非常に複雑な操作を表現できますが、コンパイラの最適化を適用しにくかったり、グループごとの大きさに制限があるなどの問題もあります。

グループ結合演算子の概要
項目 説明
分類 ユーザー
導入 0.1
演算子注釈 CoGroup [21]
本体の実装 必要
性能特性 CoGroup
入力数 任意
出力数 任意
ビュー引数 指定可能
値引数 指定可能
型引数 指定可能
備考  
グループ結合演算子の入出力
分類 名前 単位 備考
入力 (任意) グループ 任意 任意の個数、グループ化を指定
出力 (任意) レコード 任意 任意の個数
[21]com.asakusafw.vocabulary.operator.CoGroup

グループ結合演算子の実装

グループ結合演算子の演算子メソッドには次のような情報を指定します。

グループ結合演算子の実装
分類 対応 キー 備考
返戻 出力 void 不可  
引数1~ 各入力 リスト 必須 任意の個数
ビュー引数 入力 ビュー 任意  
以降の引数 各出力 結果 不可 任意の個数
値引数 なし プリミティブ 不可  

この演算子は、2種類以上のデータをそれぞれ条件に応じてグループ化してリストを作成し、 それらのリストを処理した結果を出力します。

入力は任意個のリストで、それぞれに Key 注釈のグループ化条件 group でプロパティの一覧を指定し、プロパティ列が完全に一致するものごとにメソッド内の処理を行います。 いくつかのグループに要素が存在しない場合、対応する引数には要素数0のリストが渡されます。

なお、 Key 注釈の整列条件 order でプロパティの一覧を指定すると、対象のリストの各要素は指定されたプロパティの内容で整列されます。

出力は任意個の結果で、メソッド内で同じ結果に対して複数回の結果を指定することも可能です。 結果の要素型には型引数の指定が可能ですが、その型引数は入力でも利用されている必要があります。

グループ結合演算子の演算子メソッドは、一般的な演算子メソッドの要件の他に、 下記の要件をすべて満たす必要があります。

  • 返戻型にvoidを指定する
  • 以下の引数を宣言する
    • 一つ以上のデータモデルオブジェクトを要素に取るリスト型の引数、 さらにそれぞれ Key 注釈でグループ化と整列のための情報を指定する
    • 一つ以上の結果型の引数
  • 以下の修飾子を付与する
    • (特になし)
  • 以下の修飾子は付与しない
    • abstract

以下は実装例です。

/**
 * HogeとFooをHogeのIDでグループ化し、重複なしで突合できたもののみを結果として出力する。
 * それ以外の値はエラーとして出力する。
 * @param hogeList Hogeのグループごとのリスト
 * @param fooList Fooのグループごとのリスト
 * @param hogeResult 成功したHoge
 * @param fooResult 成功したFoo
 * @param hogeError 失敗したHoge
 * @param fooError 失敗したFoo
 */
@CoGroup
public void checkUp(
        @Key(group = "id") List<Hoge> hogeList,
        @Key(group = "hogeId") List<Foo> fooList,
        Result<Hoge> hogeResult,
        Result<Foo> fooResult,
        Result<Hoge> hogeError,
        Result<Foo> fooError) {
    // いずれも存在+重複なしで突合成功
    if (hogeList.size() == 1 && fooList.size() == 1) {
        hogeResult.add(hogeList.get(0));
        fooResult.add(fooList.get(0));
    }
    // それ以外はエラー
    else {
        for (Hoge hoge : hogeList) {
            hogeError.add(hoge);
        }
        for (Foo foo : fooList) {
            fooError.add(foo);
        }
    }
}

巨大な入力グループへの対応

グループ結合演算子の実装 において、演算子の入力には List を指定しています。 この演算子は基本的に小さなグループごとに処理することを想定しており、大きなグループを処理する場合に List 内の要素が多くなりすぎて、メモリが不足してしまう場合があります。

これを回避するために、演算子メソッドの各入力の引数に @Once注釈 、または @Spill注釈 を指定することができます。

Attention

Asakusa on MapReduce では @Once 注釈 および @Spill 注釈を利用できません。 Asakusa on MapReduce では後述の InputBuffer.ESCAPE に記載の方法を利用してください。

@Once注釈

@Once [22] 注釈を演算子の入力に指定すると、メモリ消費を抑え大きな入力グループを安全に取り扱うことができます。 ただし、入力には以下の制約が課せられます。

  • 引数の型は Iterable<...> でなければならない (通常は List<...> )
  • 各要素の内容は一度だけしか読み出せない

以下は @Once 注釈を使用するグループ結合演算子メソッドの例です。 演算子メソッドの各入力に @Once 注釈を付与し、引数の型を List から Iterable に変更しています。

@CoGroup
public void cogroupWithOnce(
        @Key(group = "hogeCode") @Once Iterable<Hoge> hogeList,
        @Key(group = "hogeId") @Once Iterable<Foo> fooList,
        Result<Hoge> hogeResult,
        Result<Foo> fooResult
        ) {
    for (Hoge hoge : hogeList) {
        ...
    }
    for (Foo foo : fooList) {
        ...
    }
}
[22]com.asakusafw.vocabulary.model.Once
@Spill注釈

@Spill [23] 注釈を演算子の入力に指定すると、演算子メソッドの引数に指定したリストはメモリ外のストレージを一時的に利用します。 Java VMのヒープ上に配置されるオブジェクトは全体の一部で、残りはファイルシステム上などの領域に保存します。

これにより List を利用しつつ巨大な入力データを取り扱えるようになります。 また、 @Once 注釈では制約のある、リストに対する複数回アクセスやランダムアクセスが可能です。

Attention

@Spill 注釈を利用するとほとんどの場合に著しくパフォーマンスが低下します。 また、一時領域のストレージ構成や空き領域の確保といった、環境面での考慮も必要になります。

このため、通常は @Once 注釈の利用を推奨します。 演算子メソッド実装の都合上 @Once 注釈の制約が許容できない場合にのみ、 @Spill 注釈の利用を検討してください。

@Spill 注釈を指定した入力の List には以下に示す多大な制約がかかります。

  • それぞれの List からはひとつずつしかオブジェクトを取り出せなくなる。
  • 2つ以上オブジェクトを取り出した場合、最後に取り出したオブジェクト以外はまったく別の内容に変更されている可能性がある。
  • リストから取り出したオブジェクトを変更しても、リストの別の要素にアクセスしただけで変更したオブジェクトの内容が失われる可能性がある。

つまり、次のようなプログラムを書いた場合の動作は保証されません。

@CoGroup
public void invalid(@Key(group = "id") @Spill List<Hoge> list, Result<Hoge> result) {
    // 二つ取り出すとaの内容が保証されない
    Hoge a = list.get(0);
    Hoge b = list.get(1);

    // 内容を変更しても、別の要素を参照しただけでオブジェクトの内容が変わる場合がある
    b.setValue(100);
    list.get(2);
}

上記のようなプログラムを書きたい場合、かならずオブジェクトのコピーを作成してください。

Hoge a = new Hoge();
Hoge b = new Hoge();

@CoGroup
public void valid(@Key(group = "id") @Spill List<Hoge> list, Result<Hoge> result) {
    a.copyFrom(list.get(0));
    b.copyFrom(list.get(1));
    b.setValue(100);
    list.get(2);
    ...
}

なお、下記のようにひとつずつ取り出して使う場合、オブジェクトをコピーする必要はありません(ただし、このケースでは @Once で代替可能です)。

@CoGroup
public void valid(@Key(group = "id") @Spill List<Hoge> list, Result<Hoge> result) {
    for (Hoge hoge : list) {
        hoge.setValue(100);
        result.add(hoge);
    }
}
[23]com.asakusafw.vocabulary.model.Spill
InputBuffer.ESCAPE

Attention

バージョン 0.10.4 において、 InputBuffer.ESCAPE を指定する方法は過去バージョンとの互換性維持のため提供していますが、将来のバージョンでは非推奨となる予定です。 Asakusa on Spark、および Asakusa on M3BP ではこの機能の代わりに @Once注釈 および @Spill注釈 の利用を推奨します。

グループ結合演算子の実装 において、演算子の入力には List を指定しています。 この演算子は基本的に小さなグループごとに処理することを想定しており、大きなグループを処理する場合に List 内の要素が多くなりすぎて、メモリが不足してしまう場合があります。

これを回避するには、演算子注釈の要素 inputBufferInputBuffer.ESCAPE [24] を指定します。 何も指定しない場合は、ヒープ上に全てのデータを保持する InputBuffer.EXPAND が利用されます。

InputBuffer.ESCAPE を指定した場合、巨大な入力データを取り扱えるようになる代わりに、演算子メソッドの引数に指定した List に以下に示す多大な制約がかかります。

  • それぞれの List からはひとつずつしかオブジェクトを取り出せなくなる。
  • 2つ以上オブジェクトを取り出した場合、最後に取り出したオブジェクト以外はまったく別の内容に変更されている可能性がある。
  • リストから取り出したオブジェクトを変更しても、リストの別の要素にアクセスしただけで変更したオブジェクトの内容が失われる可能性がある。

Warning

ESCAPE を指定した場合、メモリ外のストレージを一時的に利用します。 そのため、ほとんどの場合に著しくパフォーマンスが低下します。

Note

ESCAPE を指定すると、演算子メソッドの引数に指定したリストは 内部的に「スワップ領域」を裏側に持ちます。 Java VMのヒープ上に配置されるオブジェクトは全体の一部で、残りはファイルシステム上などの領域に保存します。 ヒープ上には常に同じオブジェクトを利用して、スワップから復帰するときはそれらのオブジェクトを再利用しています。 この制約は、今後解消されるかもしれません。

つまり、次のようなプログラムを書いた場合の動作は保証されません。

@CoGroup(inputBuffer = InputBuffer.ESCAPE)
public void invalid(@Key(group = "id") List<Hoge> list, Result<Hoge> result) {
    // 二つ取り出すとaの内容が保証されない
    Hoge a = list.get(0);
    Hoge b = list.get(1);

    // 内容を変更しても、別の要素を参照しただけでオブジェクトの内容が変わる場合がある
    b.setValue(100);
    list.get(2);
}

上記のようなプログラムを書きたい場合、かならずオブジェクトのコピーを作成してください。

Hoge a = new Hoge();
Hoge b = new Hoge();

@CoGroup(inputBuffer = InputBuffer.ESCAPE)
public void valid(@Key(group = "id") List<Hoge> list, Result<Hoge> result) {
    a.copyFrom(list.get(0));
    b.copyFrom(list.get(1));
    b.setValue(100);
    list.get(2);
    ...
}

なお、下記のようにひとつずつ取り出して使う場合、オブジェクトをコピーする必要はありません。

@CoGroup(inputBuffer = InputBuffer.ESCAPE)
public void valid(List<Hoge> list, Result<Hoge> result) {
    for (Hoge hoge : list) {
        hoge.setValue(100);
        result.add(hoge);
    }
}
[24]com.asakusafw.vocabulary.flow.processor.InputBuffer

分割演算子

結合モデルから結合元のレコードを抽出してそれぞれ出力する演算子です。 この演算子への入力は、結合モデルである必要があります。

分割演算子の概要
項目 説明
分類 ユーザー
導入 0.1
演算子注釈 Split [25]
本体の実装 不要
性能特性 Extract
入力数 1
出力数 2
ビュー引数 指定不可
値引数 指定不可
型引数 指定不可
備考  
分割演算子の入出力
分類 名前 単位 備考
入力 in レコード 任意 結合モデルのみ
出力 left レコード 特殊 結合モデルの左項の型
出力 right レコード 特殊 結合モデルの右項の型
[25]com.asakusafw.vocabulary.operator.Split

分割演算子の実装

分割演算子の演算子メソッドには次のような情報を指定します。

分割演算子の実装
分類 対応 キー 備考
返戻 なし void 不可  
引数1 入力 モデル 不可 結合モデル
引数2 出力 結果 不可 結合モデルの元になったモデル
引数3 出力 結果 不可 結合モデルの元になったモデル

この演算子は、結合済みのデータを入力に取り、結合前のデータに分割してそれぞれ出力します。

このメソッドには本体を指定せず、抽象メソッドとして宣言します。

対象のメソッドは一つのデータモデルオブジェクト型の引数と、二つの結果オブジェクトの引数を取ります。 このメソッドは結合データモデルオブジェクトの結合情報を元に、結合前のデータモデルオブジェクトをそれぞれ返すようなプログラムを自動的に生成します。

引数1には分割したい対象の結合モデルの型を指定します。 以降の引数には、分割結果を表す結果型を指定します。 この分割結果は、分割対象の結合モデルの元になったデータモデル型である必要があります。

この演算子メソッドには型引数を定義できません。

分割演算子の演算子メソッドは、一般的な演算子メソッドの要件の他に、 下記の要件をすべて満たす必要があります。

  • 返戻型にvoidを指定する
  • 以下の引数を宣言する
    • 結合済みのデータモデルオブジェクト型の引数
    • Result 型の型引数に、一つ目の分割先のデータモデルオブジェクト型を指定した引数
    • Result 型の型引数に、二つ目の分割先のデータモデルオブジェクト型を指定した引数
  • 以下の修飾子を付与する
    • abstract
  • 以下の修飾子は付与しない
    • (特になし)

以下は実装例です。

/**
 * レコードHogeFooをHogeとFooに分割する。
 * @param joined 分割するレコード
 * @param hoge 分割後のHoge
 * @param foo 分割後のFoo
 */
@Split
public abstract void split(
        HogeFoo joined,
        Result<Hoge> hoge,
        Result<Foo> foo);

集計演算子

集計系の演算子は、主にグループ化したレコード内での計算を行うための演算子です。

単純集計演算子

レコードをキーでグループ化し、グループ内で集計した結果を出力する演算子です。 この演算子は、集計モデル [26] のレコードを構築します。入力は集計モデルの元になったデータモデルを指定し、集計結果の集計モデルが出力されます。 また、グループ化条件や集計方法は集計モデルに指定したものを利用します。

単純集計演算子の概要
項目 説明
分類 ユーザー
導入 0.1
演算子注釈 Summarize [27]
本体の実装 不要
性能特性 Fold
入力数 1
出力数 1
ビュー引数 指定不可
値引数 指定不可
型引数 指定不可
備考  
単純集計演算子の入出力
分類 名前 単位 備考
入力 in グループ 任意 集計モデルの元になった型
出力 out レコード 任意 集計結果、集計モデルの型
[26]集計モデルについては DMDLユーザーガイド を参照してください。
[27]com.asakusafw.vocabulary.operator.Summarize

NULL値に対する集約関数の動作

単純集計演算子を利用して集約するフィールドに null が含まれている場合、それぞれ以下のように動作します。

nullに対する集約関数の動作
集約関数 NULL値が含まれる場合の動作
any NULL値も他の値と同様に取り扱う
sum NullPointerException をスローする
max NullPointerException をスローする
min NullPointerException をスローする
count NULL値も他の値と同様に取り扱う

単純集計演算子の実装

単純集計演算子の演算子メソッドには次のような情報を指定します。

単純集計演算子の実装
分類 対応 キー 備考
返戻 出力 モデル 不可 集計モデルのみ
引数1 入力 モデル 不可 集計モデルの元

この演算子は、単一の入力を特定の項目でグループ化し、グループ内で集計した結果を出力します。

このメソッドには本体を指定せず、抽象メソッドとして宣言します。

対象のメソッドは、集計対象のデータモデルオブジェクト型の引数を取ります。 返戻型には集計結果を表す集計モデルの型を指定します。

この演算子のグループ化条件や集計方法は、集計モデル型の注釈 [28] に全て埋め込まれているため、ここでは特に指定しません。

この演算子メソッドには型引数を定義できません。

単純集計演算子の演算子メソッドは、一般的な演算子メソッドの要件の他に、 下記の要件をすべて満たす必要があります。

  • 返戻型に集計結果となる集計モデル型を指定する
  • 以下の引数を宣言する
    • 集計対象のデータモデルオブジェクト型の引数
  • 以下の修飾子を付与する
    • abstract
  • 以下の修飾子は付与しない
    • (特になし)

以下は実装例です。

/**
 * レコードHogeをHogeTotalに集計する。
 * @param hoge 集計対象
 * @return 集計結果
 */
@Summarize
public abstract HogeTotal summarize(Hoge hoge);
[28]com.asakusafw.vocabulary.model.Summarized

部分集約

単純集計演算子では、演算子注釈の partialAggregation を指定することで部分集約の設定を行えます。 この要素には PartialAggregation [29] を指定でき、指定した値ごとに次のような動作をします。

部分集約の設定
指定する値 動作
TOTAL 部分集約を行わない
PARTIAL 常に部分集約を行う
DEFAULT コンパイラオプションの設定に従う [30]

部分集約を行う場合、この演算子はグループの計算が完了する前にグループごとに集計の計算を始め、データのコピーや転送を削減しようとします。 単純集計演算子では部分集約可能な計算しか行いませんので、このオプションによって動作が変化することは基本的にありません。

Attention

基本的に、単純集計演算子では部分集約を行うべきです。 初期値は PARTIAL になっています。

[29]com.asakusafw.vocabulary.flow.processor.PartialAggregation
[30]

コンパイラオプションの設定については、以下の各コンパイラリファレンスを参照してください

畳み込み演算子

レコードをキーでグループ化し、グループ内のレコードを単一のレコードに畳み込む演算子です。 畳み込みの前後でレコードの型は一致していなければならず、また畳み込みの順序は規定されません。

畳み込み演算子の概要
項目 説明
分類 ユーザー
導入 0.1
演算子注釈 Fold [31]
本体の実装 必要
性能特性 Fold
入力数 1
出力数 1
ビュー引数 指定可能 [32]
値引数 指定可能
型引数 指定可能
備考  
畳み込み演算子の入出力
分類 名前 単位 備考
入力 in グループ 任意 グループ化を指定
出力 out レコード inと同様 畳みこみ結果
[31]com.asakusafw.vocabulary.operator.Fold
[32]ただし、 部分集約PARTIAL を指定している場合はビュー引数を指定できません。

畳み込み演算子の実装

畳み込み演算子の演算子メソッドには次のような情報を指定します。

畳み込み演算子の実装
分類 対応 キー 備考
返戻 出力 void 不可  
引数1 入出力 モデル 必須 畳み込み結果
引数2 入力 モデル 不可 引数1と同じ型を指定
ビュー引数 入力 ビュー 任意 部分集約PARTIAL を指定している場合は使用不可
値引数 なし プリミティブ 不可  

この演算子は、単一の入力を特定の項目でグループ化し、グループ内で畳みこんだ結果を出力します。

同じモデル型の二つの引数を取り、メソッドの本体で第一引数の内容を変更するプログラムを記述します。 第一引数には Key 注釈を指定し、group でグループ化のためのプロパティ名を指定する必要があります。 なお、整列のためのプロパティ名および整列方向は無視されます。

この演算子は次のように動作します。

  1. 引数1の Key 注釈に指定したグループ化条件で入力をグループ化
  2. グループごとにそれぞれ以下の処理
  1. グループ内の要素数が1になったら終了
  2. そうでなければ、グループから要素を2つ取り除いて演算子メソッドを起動
  3. 演算子メソッドの引数1に指定したモデルをグループに書き戻す
  4. グループ内の処理を繰り返す

グループ内の折りたたみは、引数2を元に引数1を破壊的に変更します。 最後まで残った引数1の結果が、演算子の出力になります。

引数には同メソッドで宣言した型変数を利用できます。

畳み込み演算子の演算子メソッドは、一般的な演算子メソッドの要件の他に、 下記の要件をすべて満たす必要があります。

  • 返戻型にvoidを指定する
  • 以下の引数を宣言する
    • ここまでの畳み込みの結果を表すデータモデルオブジェクト型の引数、 さらに Key 注釈でグループ化のための情報を指定する
    • 畳み込み対象のデータモデルオブジェクト型の引数
  • 以下の修飾子を付与する
    • (特になし)
  • 以下の修飾子は付与しない
    • abstract

以下は実装例です。

/**
 * レコードHogeを畳み込む。
 * @param left ここまでの畳み込みの結果
 * @param right 畳み込む対象
 */
@Fold
public void fold(@Key(group = "name") Hoge left, Hoge right) {
    // @Summarizeを手動で行うイメージで、leftに次々とrightを加える
    left.setValue(left.getValue() + right.getValue());
}

畳み込み演算子でも 部分集約 の指定が可能です。 集約の指定方法は 単純集計演算子 と同様です。

Warning

畳み込み演算子で部分集約を利用する場合、演算子メソッドの本体でフレームワークAPIを利用できなくなります。 これはAsakusa Frameworkの実装上の制約で、今後解消されるかもしれません。

グループ整列演算子

レコードをキーでグループ化し、さらにグループを特定の条件で整列させて操作する演算子です。 この演算子は、 グループ結合演算子 を単一の入力に対して行うものです。

グループ整列演算子の概要
項目 説明
分類 ユーザー
導入 0.1
演算子注釈 GroupSort [33]
本体の実装 必要
性能特性 CoGroup
入力数 1
出力数 任意
ビュー引数 指定可能
値引数 指定可能
型引数 指定可能
備考  
グループ整列演算子の入出力
分類 名前 単位 備考
入力 in グループ 任意 グループ化を指定
出力 (任意) レコード 任意 任意個数を指定可
[33]com.asakusafw.vocabulary.operator.GroupSort

グループ整列演算子の実装

グループ整列演算子の演算子メソッドには次のような情報を指定します。

グループ整列演算子の実装
分類 対応 キー 備考
返戻 出力 void 不可  
引数1 入力 リスト 必須  
ビュー引数 入力 ビュー 任意  
以降の引数 各出力 結果 不可 任意の個数
値引数 なし プリミティブ 不可  

この演算子は、単一の入力をグループ化し、グループ内で整列したリストとして処理した結果を出力します。

一つのデータモデルオブジェクトを要素に取るリスト型の引数と、複数の結果オブジェクト型の引数を取り、リストの任意の要素について加工を行った後に、結果オブジェクトに出力を行うプログラムを記述します。 リスト型の引数には Key 注釈を指定し、グループ化のためのプロパティ名と整列のためのプロパティ名および整列方向を指定する必要があります。

引数には同メソッドで宣言した型変数を利用できますが、全ての結果オブジェクト型の出力に型変数を含める場合には、いずれかの入力に同様の型変数を指定してある必要があります。

グループ整列演算子の演算子メソッドは、一般的な演算子メソッドの要件の他に、 下記の要件をすべて満たす必要があります。

  • 返戻型にvoidを指定する
  • 以下の引数を宣言する
    • データモデルオブジェクトを要素に取るリスト型の引数、 さらに Key 注釈でグループ化と整列のための情報を指定する
    • 一つ以上の結果型の引数
  • 以下の修飾子を付与する
    • (特になし)
  • 以下の修飾子は付与しない
    • abstract

グループ整列演算子は、入力の個数が1つに制限されているという点を除き、 グループ結合演算子 と同じ方法で記述できます。

以下は実装例です。

/**
 * レコードHogeを名前ごとに年齢の若い順に並べ、先頭と末尾だけをそれぞれ結果に流す。
 * @param hogeList グループごとのリスト
 * @param first グループごとの先頭要素
 * @param last グループごとの末尾要素
 */
@GroupSort
public void firstLast(
        @Key(group = "name", order = "+age") List<Hoge> hogeList,
        Result<Hoge> first,
        Result<Hoge> last) {
    first.add(hogeList.get(0));
    last.add(hogeList.get(hogeList.size() - 1));
}

Result インターフェースには複数件の結果を追加することもできます。

/**
 * レコードHogeを名前ごとに年齢の若い順に並べ、先頭の3件を結果に流す
 * @param hogeList グループごとのリスト
 * @param top3 グループごとの先頭3件の要素
 */
@GroupSort
public void topThree(
        @Key(group = "name", order = "+age") List<Hoge> hogeList,
        Result<Hoge> top3) {
    for (int i = 0; i < 3; i++) {
        top3.add(hogeList.get(i));
    }
}

なお、グループ整列演算子で巨大な入力グループを取り扱いたい場合、 グループ結合演算子 と同様に @Once@Spill 注釈を指定します。 詳しくは 巨大な入力グループへの対応 を参照してください。

特殊演算子

特殊系の演算子は、ここまでに紹介した分類に属さない特殊な演算子です。

フロー演算子

Flow DSLで定義したフロー部品を演算子として利用します。 この演算子の入出力は、元となったフロー部品の入出力と一致します。

フロー演算子の概要
項目 説明
分類 特殊
導入 0.1
入力数 任意
出力数 任意
値引数 指定可
型引数 指定可
備考  

フロー演算子の実装

フロー演算子はフロー部品を定義することで自動的に作成されます。 フロー部品の定義方法は Asakusa DSLユーザーガイド を参照して下さい。

チェックポイント演算子

再試行がサポートされている実行エンジンで、再試行の開始ポイントのヒントを指定するための演算子です。

Attention

チェックポイント演算子は、ジョブフローのトランザクションとは無関係です。 通常は明示的に指定する必要はありません。

チェックポイント演算子の概要
項目 説明
分類 コア
導入 0.1
メソッド checkpoint
性能特性 Extract
入力数 1
出力数 1
チェックポイント演算子の入出力
分類 名前 単位 備考
入力 in レコード 任意  
出力 out レコード inと同様  

チェックポイント演算子の実装

チェックポイント演算子はコア演算子に分類されるため、Operator DSLでの実装はありません。 Flow DSLからは次のように利用します。

In<Hoge> in;
Out<Hoge> out;

@Override
protected void describe() {
    CoreOperatorFactory core = new CoreOperatorFactory();
    Checkpoint<Hoge> op = core.checkpoint(in);
    out.add(op);
}

ロギング演算子

通過したデータごとにアプリケーションログを出力する演算子です。 ログには以下のレベルがあります。

ログのレベル
レベル 概要
ERROR 重大な不具合
WARN 注意を要する不具合
INFO 分析のための情報
DEBUG デバッグのための情報

このうち、 DEBUG はコンパイラの設定で有効または無効を切り替えられます。

ロギング演算子の概要
項目 説明
分類 ユーザー
導入 0.1
演算子注釈 Logging [34]
本体の実装 必要
性能特性 Extract
入力数 1
出力数 1
ビュー引数 指定可能
値引数 指定可能
型引数 指定可能
備考  
ロギング演算子の入出力
分類 名前 単位 備考
入力 in レコード 任意  
出力 out レコード inと同様  
[34]com.asakusafw.vocabulary.operator.Logging

ロギング演算子の実装

ロギング演算子の演算子メソッドには次のような情報を指定します。

ロギング演算子の実装
分類 対応 キー 備考
返戻 なし String 不可  
引数1 入出力 モデル 不可  
ビュー引数 入力 ビュー 任意  
値引数 なし プリミティブ 不可  

この演算子は、入力されたデータをそのまま出力しますが、その際にロギングを行います。

メソッドの戻り値で返した文字列がログとして出力されます。 また、ログはシステムに規定された方法で処理されます [35] 。 なお、引数のオブジェクトの内容を変更してはいけません。

ロギング演算子の演算子注釈は、 Logging.Level [36] を指定することでログのレベルを指定できます。 この属性を指定しない場合は INFO レベルが使用されます。 レベルについては ロギング演算子 を参照して下さい。

この演算子をフロー部品やジョブフローで使用する際に、出力 out は他の演算子等と結線されていなくてもエラーにならない、という特性を持ちます。

引数には同メソッドで宣言した型変数を利用できます。 例えば上限境界の無い型引数を定義して、引数の型として利用すると、 すべてのデータを受け取れるようなロギング演算子を定義することができます。

ロギング演算子の演算子メソッドは、一般的な演算子メソッドの要件の他に、 下記の要件をすべて満たす必要があります。

  • 返戻型にStringを指定する
  • 以下の引数を宣言する
    • データモデルオブジェクト型の引数
  • 以下の修飾子を付与する
    • (特になし)
  • 以下の修飾子は付与しない
    • abstract

以下は実装例です。

/**
 * エラーログを出力する。
 * @param hoge 更新するレコード
 */
@Logging(Logging.Level.ERROR)
public String error(Hoge hoge) {
    return MessageFormat.format("hoge = {0}", hoge.getValueOption());
}
[35]ログの処理方法は、内部的には レポートAPI に処理を移譲しています。
[36]com.asakusafw.vocabulary.operator.Logging.Level

空演算子

「データを流さない入力」を表す演算子です。 フロー演算子 の利用しない入力に接続することを想定しています。

空演算子の概要
項目 説明
分類 コア
導入 0.1
メソッド empty
性能特性 N/A
入力数 0
出力数 1
空演算子の入出力
分類 名前 単位 備考
出力 out レコード 任意  

空演算子の実装

空演算子はコア演算子に分類されるため、Operator DSLでの実装はありません。 Flow DSLからは次のように利用します。

@Override
protected void describe() {
    CoreOperatorFactory core = new CoreOperatorFactory();
    HogeOperatorFactory hoge = new HogeOperatorFactory();
    ...
    Empty<Hoge> op = core.empty(Hoge.class);
    Something something = hoge.something(op);
    ...
}

停止演算子

「データを流さない出力」を表す演算子です。 各種演算子の利用しない出力に接続することを想定しています。

停止演算子の概要
項目 説明
分類 コア
導入 0.1
メソッド stop
性能特性 N/A
入力数 1
出力数 0
停止演算子の入出力
分類 名前 単位 備考
入力 in レコード 任意  

Note

Flow DSLではすべての演算子の出力が何らかに接続されていなければなりません。 これは接続漏れなどによる実装バグなどを検出するための措置です。

停止演算子の実装

停止演算子はコア演算子に分類されるため、Operator DSLでの実装はありません。 Flow DSLからは次のように利用します。

In<Hoge> in;

@Override
protected void describe() {
    CoreOperatorFactory core = new CoreOperatorFactory();
    HogeOperatorFactory hoge = new HogeOperatorFactory();
    Something something = hoge.something(in);
    core.stop(something.unnecessary);
}

補助演算子

補助演算子は単体で演算子としては機能せず、他の演算子と組み合わせて利用する注釈です。

マスタ選択

マスタ選択は、以下の演算子において非等価結合を実現するための補助演算子です。

それぞれの演算子注釈には共通して selection という注釈要素を指定可能です。 この要素にメソッド名を指定し、同じ演算子クラス内に指定したメソッド名で、注釈 MasterSelection [37] を付与したパブリックメソッドを宣言します。

このメソッドは次のように宣言します。

マスタ選択の実装
分類 対応 キー 備考
返戻 入力 モデル 不可 選択結果のマスタデータ
引数1 入力 リスト 不可 選択対象のマスタ一覧
引数2 入力 モデル 不可  
ビュー引数 入力 ビュー 不可  
値引数 なし プリミティブ 不可  

この演算子は、トランザクションデータに対応する複数のマスタデータを引き当てたのち、実際に利用するマスタデータを選択します。 つまり、等価結合のみしか行えない環境において、重複するマスタデータから複雑な条件でマスタデータを選択するために利用することができます。

対象のメソッドは、マスタデータを表すデータモデルオブジェクトを要素に取るリスト型の引数と、トランザクションデータを表すデータモデルオブジェクト型の引数を順に取ります。 いずれも Key 注釈は不要です。

メソッドの本体ではマスタデータを選択し、一つだけ選んで戻り値として返します。 戻り値に null を返した場合にはマスタの引当に失敗した扱いになります。 なお、各引数の内容を変更した際の動作は規定されません。

返戻値の型と、引数1の要素型はマスタ選択演算子を利用する演算子の引数1と同じ型である必要があります。 また、引数2以降はそれぞれマスタ選択演算子を利用する演算子メソッドの引数と同じ型である必要があります。 なお、引数2以降は省略可能です。

マスタ選択演算子を指定した演算子メソッドが実行されると、その演算子の処理が実行される前に、マスタ選択演算子のメソッドが起動されます。 その際、マスタデータが指定したグループ化条件に従ってリストに詰められて、マスタ選択演算子メソッドの引数として与えられます。 そして、マスタ選択演算子メソッドの戻り値を引数として、元の演算子メソッドが実行されます。

この注釈を付与するメソッドは、下記の要件を満たす必要があります。

  • 返戻型に結合対象のデータモデルオブジェクト型(マスタデータ)を指定する
  • 以下の引数を宣言する
    • 結合対象のデータモデルオブジェクト型の引数 (マスタデータ)
    • 結合対象のデータモデルオブジェクト型の引数
  • 以下の修飾子を付与する
    • (特になし)
  • 以下の修飾子は付与しない
    • abstract

以下は実装例です。

/**
 * 有効なマスタを選択する。
 * @param masters 選択対象のマスタデータ一覧
 * @param tx トランザクションデータ
 * @return 実際に利用するマスタデータ、利用可能なものがない場合はnull
 */
@MasterSelection
public ItemMst selectItemMst(List<ItemMst> masters, HogeTrn tx) {
    for (ItemMst mst : masters) {
        if (mst.getStart() <= tx.getDate() &&
                tx.getDate() <= mst.getEnd()) {
            return mst;
        }
    }
    return null;
}

マスタ選択演算子を利用する演算子は、かならず同じクラス内に宣言する必要があります。 また、その演算子は同一種類のマスタおよびトランザクションデータを取り扱う必要があります。

以下は、マスタ選択演算子を使用する演算子メソッドの実装例です。

/**
 * マスタの価格をトランザクションデータに設定する。
 * @param master マスタデータ
 * @param tx 変更するトランザクションデータ
 */
@MasterJoinUpdate(selection = "selectItemMst")
public void updateWithMaster(
        @Key(group = "id") ItemMst master,
        @Key(group = "itemId") HogeTrn tx) {
    tx.setPrice(master.getPrice());
}
[37]com.asakusafw.vocabulary.operator.MasterSelection

多重化抑制

多重化抑制は演算子メソッドに追加で指定する注釈で、コンパイラの多重化に関する最適化を抑止します。 コンパイラは最適化の過程で、単一の演算子を複数個に分解して並列性を確保します。 このため、同じデータに対して処理が複数回実行される場合があり、毎回異なる結果を出力するような演算子では期待した結果が得られない場合があります。

多重化を抑制する場合には、次のように注釈 Volatile [38] を演算子メソッドに指定します。

/**
 * ランダムに分岐する。
 * @param hoge 対象のレコード
 * @return 分岐先を表すオブジェクト
 */
@Volatile
@Branch
public Status select(Hoge hoge) {
    if (Math.random() < 0.5) {
        return Status.SMALL;
    } else {
        return Status.BIG;
    }
}

上記の場合、レコードはそれぞれ SMALLBIG のいずれかのみに出力されるのが通常です。 しかし、多重化抑制の指定がない場合には、この演算子はレコードを両方に出力する場合や、いずれにも出力しない場合など予期せぬ動作をする場合があります。

その他、以下のケースなどでは多重化抑止が有効です。

  • ユニークな値を採番する
  • 実行時の時刻などを利用する
  • 入力の個数を計測する
[38]com.asakusafw.vocabulary.operator.Volatile

除去抑制

除去抑制は演算子メソッドに追加で指定する注釈で、コンパイラの除去に関する最適化を抑止します。 コンパイラは最適化の過程で、最終的なジョブフローの出力に到達しない演算子の処理をすべて除去します。 このため、副作用のみを期待するような演算子を配置しても、期待した動作を行いません。

除去を抑制する場合には、次のように注釈 Sticky [39] を演算子メソッドに指定します。

/**
 * 例外をスローする。
 * @param hoge 対象のレコード
 */
@Sticky
@Update
public void raise(Hoge hoge) {
    throw new IllegalStateException();
}

上記の更新演算子は直後に 停止演算子 によって出力を抑制され、ジョブフローの出力に接続されていないものとします。 除去抑制の指定がない場合、この演算子はコンパイラによって「不要な演算子」と判断され、例外がスローされることはありません。

上記のように除去抑制が指定されている場合にはこの演算子は消去されず、この演算子の入力にデータが流れた瞬間に例外がスローされます。

[39]com.asakusafw.vocabulary.operator.Sticky