改良版gruntで豚さんともっと対話して仲良くなろう!

「PigかわいいよPig!」と自分に言い聞かせながらHiveへの浮気心を抑えている今日この頃です。(いや、Hiveも勉強しないとなんですが・・・)
Hiveで便利なのはSQLライクに使えることも然ることながら、一度テーブルを作成してしまえば読み込み(select)の際にスキーマを定義しなくていいことじゃないかと思います。
Pigでデータ読み込む際に毎回同じ記述をしなければならないとか不毛な作業!
ちょっとしたデータだと読み込む際にスキーマ定義するのが面倒で列番号を指定して処理したりしますが、所望のフィールドが何番目か数えるのもこれまた不毛!

長い前置きになりましたが、今回はPigをgruntでサクッと使えるようにするためのちょっとした工夫をご紹介します。

gruntの改良

1. rlwrapをインストール

rlwrapはreadlineが使えない場合に導入することでかなりの恩恵を受けることができるわけですが、gruntはC-dが効かなかったりC-rでインクリメンタルサーチができなかったりと不便なので導入します。

$ wget http://utopia.knoware.nl/~hlub/rlwrap/rlwrap-0.37.tar.gz
$ tar xvf rlwrap-0.37.tar.gz
$ cd rlwrap-0.37
$ ./configure --prefix=$HOME/local  # prefixは好みに応じて調整(指定しなくていいと思う)
$ make
$ make check
$ make install

2. grunt用のrlwrap補完候補リストを作成

rlwrapの-cオプションで指定するリストです

$ mkdir ~/.grunt

このファイルのような補完候補リストを作成し、~/.grunt/completions という名前で保存します。

3. 環境変数GRUNT_HOMEを導入

何かと便利なので環境変数を導入します

$ echo 'export GRUNT_HOME=$HOME/.grunt' >> ~/.bashrc

4. gruntコマンド作成

次の内容のgruntコマンドを作成します。

cd $GRUNT_HOME/scripts && rlwrap -b "'"'(){}[],+=&^%$#@`";|\' -f $GRUNT_HOME/completions -ca pig

次のように実行すれば作成できます。(どのみちコピペするなら上の内容をコピーした方がいいような・・・)

$ echo 'cd $GRUNT_HOME/scripts && rlwrap -b "'"'"'"'"'"'(){}[],+=&^%$#@`";|\'"'"' -f $GRUNT_HOME/completions -ca pig' > ~/local/bin/grunt
$ chmod +x ~/local/bin/grunt

※コマンド作成場所は適当に変えてください(/usr/local/binとか)

5. よく読み込むデータのロードを行うスクリプトの作成

HiveのCREATE TABLEに相当する作業です

$ mkdir ~/.grunt/scripts

例えばhogeというデータを読み込むのに次のようなファイルを作成しておきます。
~/.grunt/scripts/hoge

hoge = LOAD '/hoge/hogehoge/hoge' AS (
        id   :int,
        name :chararray
);        

さらに、例えば日付ごとにデータが存在するfugaというデータを読み込むのに次のようなファイルを作成しておきます。
~/.grunt/scripts/fuga

fuga = LOAD 'fuga/fugafuga/fuga/$d' AS (
        id   :int,
        name :chararray
);

6. 使ってみる

$ grunt
grunt> run hoge
grunt> hoge = LOAD '/hoge/hogehoge/hoge' AS (
>>         id   :int,
>>         name :chararray
>> );        
grunt>
grunt> describe hoge
hoge: {id: int,name: chararray}
grunt> run -param d=2011-10-27 fuga
grunt> fuga = LOAD 'fuga/fugafuga/fuga/2011-10-27' AS (
>>         id   :int,
>>         name :chararray
>> );
grunt> 
grunt> describe fuga
fuga: {id: int,name: chararray}
grunt>

これで普通にhogeやfugaに対して処理が施せます!
しかもrlwrapの-cオプションにより~/.grunt/scripts以下にあるファイル名はタブ補完できるので、長いデータ名でも安心ですね!
さらにはgruntではC-dで<DEL>にならなかったり、C-rでインクリメンタルサーチができなかったりと不便ですが、それもrlwrapによって解消できてます!!
さらにさらに、本来ならrunを実行すると実行したスクリプトの内容が履歴に残ってカオスですが、rlwrapを使用しているので入力したコマンドしか履歴に残りません!!!
あとあと、~/.grunt/completionsをいじれば好きに補完候補を追加・削除できちゃいます!!!!
超便利!!!!!

応用

先日ご紹介したマクロもどきを実現するスクリプトを改変して組み合わせるといいかもしれません!
指定されたファイルが存在しない場合に$GRUNT_HOME/scriptsを探すように変更します。

import_pig

#!/bin/sh

pig_script=$1
[ -f "$pig_script" ] || pig_script=$GRUNT_HOME/scripts/$pig_script; [ -f "$pig_script" ] || exit 1

cat <<EOF
"eval \\\\"cat <<CMD
\\\\\\\\\\\$(paste -d\\\\\\\\\\\\\\\\0 /dev/null $pig_script | sed 's/\\\\\\\\\\\\\\$\\\\([0-9]\\\\)/\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\$\\\\1/g')
CMD\\\\""
EOF

こうすることで、次のようなファイルを実行してみると

$ cat load_fuga.pig
%declare fuga `import_pig fuga`
%declare load_fuga `exec_pig_macro $fuga d=2011-10-27`
$load_fuga

$ pig -r load_fuga.pig
$ cat load_fuga.pig.substituted


fuga = LOAD 'fuga/fugafuga/fuga/2011-10-27' AS (
	id   :int,
	name :chararray
);

ってな感じで、gruntのために作成したかのように見えたロード系のスクリプトがマクロもどきとして機能するわけです!
3行記述しないといけないのがあれですが、スキーマを全部記述するよりはだいぶましなんじゃないでしょうか。

PigかわいいよPig!!