Pig Latinの「group」のメモ。
|
「group」は、指定されたキーでデータを分ける命令。
SQLの「group by」の様なものだが、キー毎にデータの一覧(リスト)を作成する。
group 入力元エイリアス by キー group 入力元エイリアス by (キー,…) group 入力元エイリアス by 計算式
キーが1項目である単純な例。
key1,aaa key2,bbb key1,ccc key3,ddd key1,eee key2,fff
grunt> a = load '/cygwin/tmp/data.txt' using PigStorage(',') as (key:chararray, data:chararray); grunt> b = group a by key;
grunt> describe b b: {group: chararray,a: {key: chararray,data: chararray}}
describeで項目名を確認すると、キー項目は「group」という名前で、データ項目は入力元エイリアスと同じ名前(この例では「a」)が付けられているのが分かる。
grunt> dump b 〜 (key1,{(key1,aaa),(key1,ccc),(key1,eee)}) (key2,{(key2,bbb),(key2,fff)}) (key3,{(key3,ddd)})
dumpで実行結果を見てみると、指定したキー毎にデータが分けられてデータ一覧(リスト構造。Pigではバッグ(bag)と呼ぶ)が作られているのが分かる。
groupで一覧化したデータは、foreachで集約系の関数を使って処理することが出来る。
grunt> c = foreach b generate group as key, MIN(a.data) as mn, MAX(a.data) as mx, COUNT(a) as cnt; grunt> describe c c: {key: chararray,mn: chararray,mx: chararray,cnt: long} grunt> dump c 〜 (key1,aaa,eee,3) (key2,bbb,fff,2) (key3,ddd,ddd,1)
一覧化されたデータは、flattenを使って複数行に出力することが出来る。(結果として元に戻る)
grunt> d = foreach b generate group as key2, flatten(a.data) as data2; grunt> describe d d: {key2: chararray,data2: chararray} grunt> dump d 〜 (key1,aaa) (key1,ccc) (key1,eee) (key2,bbb) (key2,fff) (key3,ddd)
複数の項目をキーとして集約する例。
key1,keyA,aaa,123 key1,keyB,bbb,234 key1,keyC,ccc,345 key2,keyA,ddd,456 key1,keyA,eee,567 key1,keyA,fff,678 key2,keyA,ggg,789
grunt> aa = load '/cygwin/tmp/data2.txt' using PigStorage(',') as (k1:chararray, k2:chararray, ds:chararray, dn:int);
複数の項目をキーとする場合、byの後ろのキー項目を括弧で囲む。
grunt> bb = group aa by (k1, k2);
※「括弧でくくって複数の項目を指定する」と言うより、「タプルを定義している」と言う方が正しそう。byの後ろには式(演算)を書くことも出来るから。
grunt> describe bb bb: {group: (k1: chararray,k2: chararray),aa: {k1: chararray,k2: chararray,ds: chararray,dn: int}}
describeで変数名の定義を見てみると、キーである「group」のデータ型が丸括弧で囲まれている(=タプルである)ことが分かる。
grunt> dump bb 〜 ((key1,keyA),{(key1,keyA,aaa,123),(key1,keyA,eee,567),(key1,keyA,fff,678)}) ((key1,keyB),{(key1,keyB,bbb,234)}) ((key1,keyC),{(key1,keyC,ccc,345)}) ((key2,keyA),{(key2,keyA,ddd,456),(key2,keyA,ggg,789)})
dumpで実行結果を見ると、キーの値もちゃんとタプルになっている。
foreachを使って集計してみる。
grunt> cc = foreach bb generate group as ks, SUM(aa.dn) as sum; grunt> describe cc cc: {ks: (k1: chararray,k2: chararray),sum: long} grunt> dump cc 〜 ((key1,keyA),1368) ((key1,keyB),234) ((key1,keyC),345) ((key2,keyA),1245)
キーがタプルのままなので、後続処理で扱いにくそう。
別のforeachでタプルから項目を取り出すことが出来る。
grunt> cc2 = foreach cc generate ks.k1 as k1, ks.k2 as k2, sum; grunt> describe cc2 cc2: {k1: chararray,k2: chararray,sum: long}
もしくは、flattenでタプルを解除できる。同時に名前を付けることも出来る。
grunt> dd = foreach bb generate flatten(group) as (k1,k2), SUM(aa.dn) as sum; grunt> describe dd dd: {k1: chararray,k2: chararray,sum: long} grunt> dump dd 〜 (key1,keyA,1368) (key1,keyB,234) (key1,keyC,345) (key2,keyA,1245)
全項目をキーとする(つまり集約しない)場合は、allを使う。[2011-09-28]
全レコードを対象とした集計を行いたい場合に利用できる。(完全に一致している行があっても別レコードとして扱われる)
/* 全データの件数を数える例(select COUNT(*) from テーブル) */ b = group a all; c = foreach b generate COUNT(a);
/* 特定項目の全合計を算出する例(select SUM(col) as total from テーブル) */ b = group a all; c = foreach b generate SUM(a.col) as total;
grunt> dump b (all, {(〜),…}
「all」という1つの値をキーにして集約している。つまり全データが1つのキーの下に集まる。