Asakusa on MapReduce DSLの可視化

この文書では、Asakusa DSLの分析を行うにあたって、Asakusa on MapReudceが提供するDSLの可視化の仕組みについて解説します。

Attention

本書で説明する機能はMapReduce DSLコンパイラでのみ使用可能です。

Asakusa DSLの分析用ファイル

Asakusa DSLをバッチコンパイルして生成したバッチアプリケーションアーカイブファイル [1] には、Asakusa DSLの分析用ファイルが含まれています。 この分析用ファイルは、バッチアプリケーションの構造を把握したり、アプリケーション実行時に発生した問題箇所の特定を行うことを補助します。

分析用ファイルは、バッチアプリケーションアーカイブファイル内の <バッチID>/opt/dsl-analysis ディレクトリ配下に配置されています [2] 。 各分析用ファイルの説明を以下に示します。 なお、以下に示すファイルのうち、dotファイルについては後述の Graphvizによるグラフの生成 を参照してグラフ形式として出力することも可能です。

dotスクリプトファイル一覧
ファイル名 説明
batch/compiled-structure.txt バッチコンパイルした結果のバッチ構造を示すテキストファイル
batch/compiled-structure.dot バッチコンパイルした結果のバッチ構造を示すdotファイル
batch/compiled-merged-structure.dot バッチコンパイルした結果のバッチ構造を示すdotファイル。同一の演算子を単一のノードとして表現する。
batch/original-structure.txt バッチコンパイル前のバッチ構造を示すテキストファイル
batch/original-structure.dot バッチコンパイル前のバッチ構造を示すdotファイル
batch/original-merged-structure.txt バッチコンパイル前のバッチ構造を示すテキストファイル。同一の演算子を単一のノードとして表現する。
jobflow/<フローID>/flowgraph.dot フローの入出力を示すdotファイル
jobflow/<フローID>/stagegraph.dot ステージ全体の構造を示すdotファイル
jobflow/<フローID>/stageblock-XX.dot 各ステージ単位の構造を示すdotファイル
[1]バッチアプリケーションアーカイブファイルを生成する方法については、 Asakusa Gradle Plugin ユーザーガイド を参照してください。
[2]バッチアプリケーションアーカイブファイルから分析用ファイルを取り出すには、jarコマンド等を使用してアーカイブファイルから分析用ファイルを抽出してください。 なお、プロジェクトをバッチコンパイルした環境では、プロジェクトのビルドディレクトリ配下の batchc/<バッチID>/opt/dsl-analysis ディレクトリに分析用ファイルが出力されています。

Graphvizによるグラフの生成

グラフ生成ツールである Graphviz [3] を使用して、dotファイルからグラフファイルを生成する方法を説明します。

[3]https://www.graphviz.org/

Graphvizのインストール

開発環境にGraphvizをインストールします。UbuntuにGraphvizをインストールする例を以下に示します。

sudo apt-get install graphviz

Graphvizの詳細やインストール方法は上記のGraphvizのサイト等を参照して下さい。

dotスクリプトからグラフファイルを作成する

Graphvizを使って、dotファイルからPDF形式 [4] でグラフを作成する例を以下に示します。

# バッチアプリケーションアーカイブファイルを解凍する
jar -xf example-app-batchapps-1.0-SNAPSHOT.jar
# バッチアプリケーションアーカイブに含まれるdotファイルをPDFに変換する
cd example.summarizeSales/opt/dsl-analysis/jobflow/byCategory
dot -Tpdf -o stagegraph.pdf stagegraph.dot
[4]GraphvizではPDF形式の他に、 PNGやJPEG形式など様々な形式でグラフを出力することができます。詳しくは Graphviz のマニュアルなどを参照してください。

グラフの出力例

分析用ファイルから生成することができるグラフの出力例を紹介します。

ステージグラフ

jobflow/<フローID>/stagegraph.dot は、ジョブフローが持つステージ [5] 全体の構造を示すグラフを提供します。

../_images/stagegraph.png

ステージ全体の構造のうち、特定のステージのみのグラフを参照したい場合は、 jobflow/<フローID>/stageblock-XX.dot を参照します。

[5]ステージとはAsakusa DSLをバッチコンパイルした結果生成されるバッチアプリケーションに含まれるMapReduceジョブの単位です。 詳しくは Asakusa DSLユーザーガイド - Batch DSLコンパイラが生成するバッチアプリケーション などを参照してください。

フローグラフ

jobflow/<フローID>/flowgraph.dot は、ジョブフローの入出力、及びジョブフローに含まれる演算子間の入出力の関係を示すグラフを提供します。

../_images/flowgraph.png

バッチ構造を示すテキストファイルの出力例

分析用ファイルに含まれるバッチ構造を示すテキストファイルの例を紹介します。

バッチコンパイル前のバッチ構造

batch/original-structure.txt はバッチコンパイル前のバッチ構造を示します [6]

batch: example.summarizeSales
flow: byCategory
    input:
        salesDetail (hoge.jobflow.SalesDetailFromCsv)
        itemInfo (hoge.jobflow.ItemInfoFromCsv)
        storeInfo (hoge.jobflow.StoreInfoFromCsv)
    output:
        categorySummary (hoge.jobflow.CategorySummaryToCsv)
        errorRecord (hoge.jobflow.ErrorRecordToCsv)
    flow: hoge.jobflow.CategorySummaryJob
        operator: hoge.operator.CategorySummaryOperator#setErrorMessage([class hoge.modelgen.dmdl.model.ErrorRecord, class java.lang.String])[message[class java.lang.String]=店舗不明]
        input: InputDescription{name=itemInfo, type=class hoge.modelgen.dmdl.model.ItemInfo}
        output: OutputDescription{name=errorRecord, type=class hoge.modelgen.dmdl.model.ErrorRecord}
        input: InputDescription{name=salesDetail, type=class hoge.modelgen.dmdl.model.SalesDetail}
        output: OutputDescription{name=categorySummary, type=class hoge.modelgen.dmdl.model.CategorySummary}
        input: InputDescription{name=storeInfo, type=class hoge.modelgen.dmdl.model.StoreInfo}
        operator: com.asakusafw.vocabulary.flow.util.CoreOperatorFactory$Restructure#toString([])[]
        operator: com.asakusafw.vocabulary.flow.util.CoreOperatorFactory$Restructure#toString([])[]
        operator: hoge.operator.CategorySummaryOperator#summarizeByCategory([class hoge.modelgen.dmdl.model.JoinedSalesInfo])[]
        operator: hoge.operator.CategorySummaryOperator#checkStore([class hoge.modelgen.dmdl.model.StoreInfo, class hoge.modelgen.dmdl.model.SalesDetail])[]
...
[6]バッチコンパイル前のバッチ構造はdotファイルによるグラフ形式も利用することができますが、テキストファイル形式のほうがより詳細な情報が含まれています。

バッチコンパイル後のバッチ構造

batch/compiled-structure.txt はバッチコンパイル後のバッチ構造を示します [7]

batch: example.summarizeSales
flow: byCategory
    input:
        salesDetail (hoge.jobflow.SalesDetailFromCsv)
        itemInfo (hoge.jobflow.ItemInfoFromCsv)
        storeInfo (hoge.jobflow.StoreInfoFromCsv)
    output:
        categorySummary (hoge.jobflow.CategorySummaryToCsv)
        errorRecord (hoge.jobflow.ErrorRecordToCsv)
    stages:
        prologue:
        main:
            stage: hoge.batchapp.example.summarizeSales.byCategory.stage0001.StageClient
                mapper: hoge.batchapp.example.summarizeSales.byCategory.stage0001.StageMapper1
                    fragment: hoge.batchapp.example.summarizeSales.byCategory.stage0001.MapFragment1
                mapper: hoge.batchapp.example.summarizeSales.byCategory.stage0001.StageMapper2
                    fragment: hoge.batchapp.example.summarizeSales.byCategory.stage0001.MapFragment2
                        operator: hoge.operator.CategorySummaryOperator#checkStore([class hoge.modelgen.dmdl.model.StoreInfo, class hoge.modelgen.dmdl.model.SalesDetail])[]
                            side-data: storeInfo (hoge.jobflow.StoreInfoFromCsv)
                reducer: hoge.batchapp.example.summarizeSales.byCategory.stage0001.StageReducer
                    fragment: hoge.batchapp.example.summarizeSales.byCategory.stage0001.ReduceFragment4
                        operator: hoge.operator.CategorySummaryOperator#joinItemInfo([class hoge.modelgen.dmdl.model.ItemInfo, class hoge.modelgen.dmdl.model.SalesDetail])[]
                    fragment: hoge.batchapp.example.summarizeSales.byCategory.stage0001.MapFragment3
                        operator: com.asakusafw.vocabulary.flow.util.CoreOperatorFactory$Restructure#toString([])[]
                        operator: hoge.operator.CategorySummaryOperator#setErrorMessage([class hoge.modelgen.dmdl.model.ErrorRecord, class java.lang.String])[message[class java.lang.String]=商品不明]
            stage: hoge.batchapp.example.summarizeSales.byCategory.stage0002.StageClient
                mapper: hoge.batchapp.example.summarizeSales.byCategory.stage0002.StageMapper1
                    fragment: hoge.batchapp.example.summarizeSales.byCategory.stage0002.MapFragment1
                        operator: hoge.operator.CategorySummaryOperator#checkStore([class hoge.modelgen.dmdl.model.StoreInfo, class hoge.modelgen.dmdl.model.SalesDetail])[]
                            side-data: storeInfo (hoge.jobflow.StoreInfoFromCsv)
                    fragment: hoge.batchapp.example.summarizeSales.byCategory.stage0002.MapFragment2
                        operator: com.asakusafw.vocabulary.flow.util.CoreOperatorFactory$Restructure#toString([])[]
                        operator: hoge.operator.CategorySummaryOperator#setErrorMessage([class hoge.modelgen.dmdl.model.ErrorRecord, class java.lang.String])[message[class java.lang.String]=店舗不明]
            stage: hoge.batchapp.example.summarizeSales.byCategory.stage0003.StageClient
                mapper: hoge.batchapp.example.summarizeSales.byCategory.stage0003.StageMapper1
...
[7]バッチコンパイル後のバッチ構造はdotファイルによるグラフ形式も利用することができますが、テキストファイル形式のほうがより詳細な情報が含まれています。