はじめに

この記事はJavaバッチフレームワークのAsakusa Frameworkで簡単なバッチアプリケーションを作成する方法を共有します。
公式にはAsakusa Framework チュートリアルが存在しますが、本記事では手軽にAsakusaの開発や運用について概要を理解して雰囲気をつかんでもらえることを目的としています。

動作環境

以下の環境で動作確認をしています。

  • Windows 10 (64bit)
  • JDK 1.8.0_161
  • Gradle 4.5

(以下の手順を試す前に、JDKとGradleのインストールを済ませておいてください。)

やりたいこと

紹介するサンプルアプリケーションは、入力ファイル(内容はHelloだけ)を読み込んで、内容をHello, World!に更新してファイルを出力する簡単なものです。
DFDの形式にすると以下のようなものになります。
helloworld_dfd.png

開発環境の準備

以下のフォルダを作成して、サンプルアプリケーションのプロジェクト用フォルダとします。

C:¥asakusa-develop¥helloworld

作成したプロジェクト用フォルダの配下にGradleのビルドスクリプトファイル(build.gradle)を作成します。
今回のサンプルアプリケーションはWindowsのJVM上で実行させるため、Asakusa Vanillaを構成しています。
ここの設定を変えることでHadoopやM3BP用のアプリケーションを生成することも可能です。
作成したGradleスクリプトの詳細については、Asakusa Gradle Plugin リファレンスを参照してください。

build.gradle
group 'com.example'

buildscript {
    repositories {
        maven { url 'http://asakusafw.s3.amazonaws.com/maven/releases' }
        maven { url 'http://asakusafw.s3.amazonaws.com/maven/snapshots' }
    }
    dependencies {
        classpath group: 'com.asakusafw.gradle', name: 'asakusa-distribution', version: '0.10.0'
    }
}

apply plugin: 'asakusafw-sdk'
apply plugin: 'asakusafw-organizer'
apply plugin: 'asakusafw-vanilla'
apply plugin: 'eclipse'

asakusafwOrganizer {
    vanilla.enabled true
    profiles.prod {
        hadoop.embed true
    }
}

以下のGradleコマンドを実行するとEclipseのプロジェクトとしてインポート可能な構成ファイルが生成されます。(プロジェクトフォルダの下で実行してください)

C:¥asakusa-develop¥helloworld>gradle eclipse

IntelliJ IDEAを利用したい場合は、公式のIntelliJ IDEAの利用を参照してください。
なお、Eclipseを使うのであれば、Shafu(Asakusa開発用のEclipseプラグイン)の利用を検討してください。

データモデルクラスの生成

データモデルを定義するDMDL(Data Model Definition Language)スクリプトファイルを作成します。
以下のスクリプトでは、入力モデルと出力モデルはそれぞれinputoutputという名前で、Direct I/O CSVで入出力を行う設定になっています。
以下のフォルダを作成してその配下にスクリプトファイル(models.dmdl)を作成します。

C:¥asakusa-develop¥helloworld¥src¥main¥dmdl
models.dmdl
@directio.csv
input = {
  value : TEXT;
};

@directio.csv
output = {
  value : TEXT;
};

以下のGradleコマンドを実行すると、作成したスクリプトファイルを元にAsakusa Frameworkで利用可能なデータモデルクラスが生成されます。(プロジェクトフォルダの下で実行してください)

C:¥asakusa-develop¥helloworld>gradle compileDMDL

演算子クラスの作成

以下のフォルダを作成してその配下にcom.example.operator.HelloWorldOperatorクラスを作成します。
実装する演算子の処理は入力ファイルのvalueに値(, World!)を追加する処理なので、@Update演算子を実装します。
演算子に関する詳細については、Asakusa DSL演算子リファレンスを参照してください。
com.example.modelgen.dmdl.model.Inputクラスは先ほどのDMDLから自動生成されたクラスです。

C:¥asakusa-develop¥helloworld¥src¥main¥java
com.example.operator.HelloWorldOperator
package com.example.operator;

import com.asakusafw.vocabulary.operator.Update;
import com.example.modelgen.dmdl.model.Input;

public abstract class HelloWorldOperator {

    @Update
    public void appendMessage(Input input) {
        input.setValueAsString(input.getValueAsString() + ", World!");
    }
}

入出力定義クラスの作成

入力定義クラスと出力定義クラスを作成します。それぞれ、AbstractInputCsvInputDescriptionAbstractOutputCsvOutputDescriptionを継承して実装しています。これらのクラスもDMDLから自動生成されています。
ファイル入出力クラスの詳細については、Direct I/O ユーザーガイド - ファイルの入出力を参照するとよいでしょう。

入力定義クラスの作成

com.example.jobflow.InputFile
package com.example.jobflow;

import com.example.modelgen.dmdl.csv.AbstractInputCsvInputDescription;

public class InputFile extends AbstractInputCsvInputDescription {

    @Override
    public String getBasePath() {
        return "input";
    }

    @Override
    public String getResourcePattern() {
        return "hello.csv";
    }
}

出力定義クラスの作成

com.example.jobflow.OutputFile
package com.example.jobflow;

import com.example.modelgen.dmdl.csv.AbstractOutputCsvOutputDescription;

public class OutputFile extends AbstractOutputCsvOutputDescription {

    @Override
    public String getBasePath() {
        return "output";
    }

    @Override
    public String getResourcePattern() {
        return "helloworld.csv";
    }

}

ジョブフロークラスの作成

以下のジョブフロークラスでは、コンストラクタでデータフローのImportに入力定義クラス(InputFile)を設定し、Exportに出力定義クラス(OutputFile)を設定しています。
describeメソッドにデータフローを記述します。サンプルでは、入力モデル(input)から更新演算子(appendMessage)へ結線してその結果を出力モデル(output)へ出力しています。
詳細については、Asakusa DSLユーザーガイド - Flow DSL を参照してください。

com.example.jobflow.HelloWorldJob
package com.example.jobflow;

import com.asakusafw.vocabulary.flow.Export;
import com.asakusafw.vocabulary.flow.FlowDescription;
import com.asakusafw.vocabulary.flow.Import;
import com.asakusafw.vocabulary.flow.In;
import com.asakusafw.vocabulary.flow.JobFlow;
import com.asakusafw.vocabulary.flow.Out;
import com.asakusafw.vocabulary.flow.util.CoreOperatorFactory;
import com.example.modelgen.dmdl.model.Input;
import com.example.modelgen.dmdl.model.Output;
import com.example.operator.HelloWorldOperatorFactory;
import com.example.operator.HelloWorldOperatorFactory.AppendMessage;

@JobFlow(name = "helloWorldJob")
public class HelloWorldJob extends FlowDescription {

    final In<Input> input;
    final Out<Output> output;

    public HelloWorldJob(
            @Import(name = "input", description = InputFile.class)
            In<Input> input,
            @Export(name = "output", description = OutputFile.class)
            Out<Output> output) {
        this.input = input;
        this.output = output;
    }

    @Override
    protected void describe() {
        CoreOperatorFactory core = new CoreOperatorFactory();
        HelloWorldOperatorFactory operator = new HelloWorldOperatorFactory();
        AppendMessage appendedMessage = operator.appendMessage(input);
        output.add(core.restructure(appendedMessage.out, Output.class));
    }
}

バッチクラスの作成

以下のバッチクラスは、ジョブフロークラス(HelloWorldJob)を実行するだけです。
バッチクラスについては、Asakusa DSLユーザーガイド - Batch DSLを参照してください。

com.example.batch.HelloWorldBatch
package com.example.batch;

import com.asakusafw.vocabulary.batch.Batch;
import com.asakusafw.vocabulary.batch.BatchDescription;
import com.example.jobflow.HelloWorldJob;

@Batch(name = "example.helloWorld")
public class HelloWorldBatch extends BatchDescription {

    @Override
    protected void describe() {
        run(HelloWorldJob.class).soon();
    }
}

ここまでで、ソースフォルダの配下は次のような構成になっていると思います。
source_folder.png

アプリケーションのビルド

次のGradleコマンドでサンプルアプリケーションのデプロイメントアーカイブファイルを生成します。(プロジェクトフォルダの下で実行してください)

C:¥asakusa-develop¥helloworld>gradle assemble

実行に成功するとbuildフォルダの配下にデプロイメントアーカイブファイルが作成されています。

C:¥asakusa-develop¥helloworld¥build¥asakusafw-helloworld.tar.gz

アプリケーションのデプロイ

今回はWindows上にデプロイするので(商用などの場合はHadoopやM3BP環境へデプロイするのですが。。)Windows環境変数にASAKUSA_HOMEを追加します。

変数
ASAKUSA_HOME C:¥asakusa-develop¥asakusa

生成したデプロイメントアーカイブファイル(asakusafw-helloworld.tar.gz)をASAKUSA_HOMEの配下に展開します。
ASAKUSA_HOMEの下で以下のコマンドを実行します。

C:¥asakusa-develop¥asakusa>java -jar tools¥bin¥setup.jar
setup: C:¥asakusa-develop¥asakusa
framework version: 0.10.0
installation path is not a POSIX file system: C:¥asakusa-develop¥asakusa

アプリケーションの実行

入力ファイルの配備

バッチの入力ファイルを以下のフォルダへ配備します。デフォルトではユーザーホームディレクトリ以下のtarget¥testing¥directioフォルダの配下に配備します。
入力定義クラスで設定したbasePathgetBasePathメソッドの返り値)とresourcePatterngetResourcePatternメソッドの返り値)に一致するようにします。

C:¥...<ユーザーホームディレクトリ>...¥target¥testing¥directio¥input¥
hello.csv
Hello

Asakusa CLIで実行する

このサンプルでは、Asakusa CLIを利用するため(商用では、YAESSで実行することになります)、WindowsのPATH環境変数に以下の値を追加します。

%ASAKUSA_HOME%¥bin

以下のコマンドでバッチアプリケーションを実行します。

asakusa run vanilla.example.helloWorld

実行結果として以下のファイルが出力されていることを確認します。

C:¥...<ユーザーホームディレクトリ>...¥target¥testing¥directio¥output¥
helloworld.csv
"Hello, World!"

最後に

Asakusa Frameworkのversionも0.10.0になって開発や運用の敷居が下がってきているので、このタイミングでまとめてみようと思い立ちこの記事を書いてみましたが如何だったでしょうか?まだ書き足りないことも多いのですが、また次回の記事で紹介していければと思います。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.