S-JIS[2011-08-31/2011-09-28] 変更履歴

Pig Latin「group」

Pig Latinの「group」のメモ。


概要

「group」は、指定されたキーでデータを分ける命令。
SQLの「group by」の様なものだが、キー毎にデータの一覧(リスト)を作成する。

group 入力元エイリアス by キー
group 入力元エイリアス by (キー,…)
group 入力元エイリアス by 計算式

1項目の集約の例

キーが1項目である単純な例。

データ(/cygwin/tmp/data.txt):

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)

複数項目の集約の例

複数の項目をキーとして集約する例。

データ(/cygwin/tmp/data2.txt):

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つのキーの下に集まる。


Pig Latinへ戻る / Pig目次へ戻る / 技術メモへ戻る
メールの送信先:ひしだま