Pigでの"正しい"繰り返し処理の書き方

最近Pigで変態的な使い方をしていますが今回もそんな話です。

Pigでも稀にfor文みたいなものが使えれれば便利なことがあります。(FOREACHじゃないよ!)
そんな場合は今までPigを生成するためのスクリプトを作成し、それを実行して生成されたPigを実行していたんですが、よく考えたらPigのスクリプト内で全てが完結できるんですよね!

例えば、data/1, …, data/i, …, data/5 というデータソースに対して、1つにデータをまとめたいんだけど、どのデータソースなのか識別したいからデータソースの番号をカラムに追加するといった処理があるかと思います。

Shell Scriptの例

loop_shell.pig

%declare PIG `echo "$(for i in $(seq 1 5); do echo "
data\$i = LOAD 'data/\$i' AS (
        id   :int,
        name :chararray
);
data\$i = FOREACH data\$i GENERATE \$i AS data_id, *;
"
alias=$([ -z "\$alias" ] && echo data\$i || echo "\$alias, data\$i")
done;

echo "
ret = UNION \$alias;
STORE ret INTO 'output';
"
)"`


$PIG

※Macで実行しようと思うと seq がないんで何も出力されません(jot か gseq で書き換えてください)

Perlの例

loop_perl.pig

%declare PIG `echo "$(perl -e "for (\\$i = 1; \\$i <= 5; \\$i++) { print <<PIG;
data\\$i = LOAD 'data/\\$i' AS (
        id   :int,
        name :chararray
);
data\\$i = FOREACH data\\$i GENERATE \\$i AS data_id, *;

PIG
\\$alias .= defined \\$alias ? \", data\\$i\" : \"data\\$i\";
}

print <<PIG;
ret = UNION \\$alias;
STORE ret INTO 'output';
PIG
")"`

$PIG

ポイントは

%declare PIG `echo "$(処理)"`
$PIG

みたいに echo の結果を受け取ることと、変数名をバックスラッシュでエスケープする必要があることですかね。ただし echo の結果を受け取るようにすると処理途中にエラーが出ていても全くわからないんですけど!

あ、ちなみに Shell Script の方で dryrun を実行した結果は次のようになります。




data1 = LOAD 'data/1' AS (
        id   :int,
        name :chararray
);
data1 = FOREACH data1 GENERATE 1 AS data_id, *;


data2 = LOAD 'data/2' AS (
        id   :int,
        name :chararray
);
data2 = FOREACH data2 GENERATE 2 AS data_id, *;


data3 = LOAD 'data/3' AS (
        id   :int,
        name :chararray
);
data3 = FOREACH data3 GENERATE 3 AS data_id, *;


data4 = LOAD 'data/4' AS (
        id   :int,
        name :chararray
);
data4 = FOREACH data4 GENERATE 4 AS data_id, *;


data5 = LOAD 'data/5' AS (
        id   :int,
        name :chararray
);
data5 = FOREACH data5 GENERATE 5 AS data_id, *;


ret = UNION data1, data2, data3, data4, data5;
STORE ret INTO 'output';

簡単ですねっ!