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';
簡単ですねっ!