Apache Pig による基本的な文法 (1)

## Pig を使う

[昨日](http://qiita.com/ynakayama/items/8f334b3314561c5d48af)は主に Apache Pig を使うまでの準備について書きました。今日から Pig のスクリプトを記述して実際にデータを分析していくところを説明していきます。

### インタラクティブシェルを起動する

Ruby で言う irb や pry 、 Python で言う ipython のように、 Pig でもインタラクティブシェルを起動して挙動を確認することができます。

```bash
pig -x local
```

このようにインタラクティブシェルを起動して挙動を確認するのはインタプリタ言語の基本ですね。 C-r がうまく機能しないなど若干足りない面もありますがひとまずこれで Pig を対話的に動かすことができます。

### データの形式を定義して読み込む

次のようなデータを考えます。

```
20140312        XXXXXXF6XXXX    Shop7   1394560015      2014-03-12 02:46:55 +0900       0
20140312        XXXXXXC2XXXX    Shop1   1394560104      2014-03-12 02:48:24 +0900       0
20140312        XXXXXXF6XXXX    Shop8   1394559936      2014-03-12 02:45:36 +0900       0
20140312        XXXXXXF6XXXX    Shop8   1394560009      2014-03-12 02:46:49 +0900       73
20140312        XXXXXXF6XXXX    Shop8   1394560050      2014-03-12 02:47:30 +0900       41
20140312        XXXXXXF6XXXX    Shop3   1394560111      2014-03-12 02:48:31 +0900       61
20140312        XXXXXXF6XXXX    Shop8   1394560199      2014-03-12 02:49:59 +0900       88
20140312        XXXXXX56XXXX    Shop16  1394560009      2014-03-12 02:46:49 +0900       0
20140312        XXXXXXAEXXXX    Shop16  1394559933      2014-03-12 02:45:33 +0900       0
20140312        XXXXXXAEXXXX    Shop16  1394559996      2014-03-12 02:46:36 +0900       63
```

R でも python (pandas) でもカンマあるいはタブ区切りのデータを読み込むためには専用の関数が用意されていました。 Pig でも同じでまずはデータを読み込んで利用可能にします。

```
raw = LOAD 'input.txt' USING PigStorage('\t') AS (date: chararray, key: chararray, shop: chararray, unixtime: int, humantime: chararray, times: int);
```

int, long, float, double といったお馴染みの数値型、文字型については chararray が使えます。

### データを参照する

データの中身は dump で参照できます。インタラクティブシェルで最も頻繁に使う命令かもしれません。

```
dump raw;
```

### データを集約する

特定の条件でデータをまとめるには GROUP を使います。たとえば上の例のデータをキー毎にまとめてみます。

```
grouped = GROUP raw BY key;
```

```
XXXXXX00XXXX    {(20140312,XXXXXX00XXXX,Shop12,1394560172,2014-03-12 02:49:32 +0900,0),(20140312,XXXXXX00XXXX,Shop10,1394560123,2014-03-12 02:48:43 +0900,8),(20140312,XXXXXX00XXXX,Shop11,1394560134,2014-03-12 02:48:54 +0900,11),(20140312,XXXXXX00XXXX,Shop11,1394560136,2014-03-12 02:48:56 +0900,2),(20140312,XXXXXX00XXXX,Shop10,1394560154,2014-03-12 02:49:14 +0900,18),(20140312,XXXXXX00XXXX,Shop11,1394560172,2014-03-12 02:49:32 +0900,18),(20140312,XXXXXX00XXXX,Shop8,1394560016,2014-03-12 02:46:56 +0900,0),(20140312,XXXXXX00XXXX,Shop11,1394560111,2014-03-12 02:48:31 +0900,0),(20140312,XXXXXX00XXXX,Shop12,1394560115,2014-03-12 02:48:35 +0900,4),(20140312,XXXXXX00XXXX,Shop8,1394560076,2014-03-12 02:47:56 +0900,60),(20140312,XXXXXX00XXXX,Shop8,1394560136,2014-03-12 02:48:56 +0900,60),(20140312,XXXXXX00XXXX,Shop1,1394560196,2014-03-12 02:49:56 +0900,60)}
XXXXXX01XXXX    {(20140312,XXXXXX01XXXX,Shop13,1394559983,2014-03-12 02:46:23 +0900,0),(20140312,XXXXXX01XXXX,Shop14,1394559986,2014-03-12 02:46:26 +0900,3),(20140312,XXXXXX01XXXX,Shop12,1394559983,2014-03-12 02:46:23 +0900,0)}
...
```

### データを数える

上の出力結果のタプルとなったデータをカウントしてみます。これは先程とは逆で、まとめたデータを展開する形になります。

```
counted = FOREACH grouped GENERATE flatten($1);
```

```
(20140312,XXXXXX00XXXX,Shop12,1394560172,2014-03-12 02:49:32 +0900,0)
(20140312,XXXXXX00XXXX,Shop10,1394560123,2014-03-12 02:48:43 +0900,8)
(20140312,XXXXXX00XXXX,Shop11,1394560134,2014-03-12 02:48:54 +0900,11)
(20140312,XXXXXX00XXXX,Shop11,1394560136,2014-03-12 02:48:56 +0900,2)
(20140312,XXXXXX00XXXX,Shop10,1394560154,2014-03-12 02:49:14 +0900,18)
(20140312,XXXXXX00XXXX,Shop11,1394560172,2014-03-12 02:49:32 +0900,18)
(20140312,XXXXXX00XXXX,Shop8,1394560016,2014-03-12 02:46:56 +0900,0)
(20140312,XXXXXX00XXXX,Shop11,1394560111,2014-03-12 02:48:31 +0900,0)
(20140312,XXXXXX00XXXX,Shop12,1394560115,2014-03-12 02:48:35 +0900,4)
(20140312,XXXXXX00XXXX,Shop8,1394560076,2014-03-12 02:47:56 +0900,60)
(20140312,XXXXXX00XXXX,Shop8,1394560136,2014-03-12 02:48:56 +0900,60)
(20140312,XXXXXX00XXXX,Shop1,1394560196,2014-03-12 02:49:56 +0900,60)
(20140312,XXXXXX01XXXX,Shop13,1394559983,2014-03-12 02:46:23 +0900,0)
...
```

### データを取り除く

今度は times が 60 以下のデータを取り除いてみましょう。このように特定のデータを除外する場合は FILTER が使えます。

```
filtered = FILTER raw BY times > 60;
```

```
(20140312,XXXXXXF6XXXX,Shop8,1394560009,2014-03-12 02:46:49 +0900,73)
(20140312,XXXXXXF6XXXX,Shop3,1394560111,2014-03-12 02:48:31 +0900,61)
(20140312,XXXXXXF6XXXX,Shop8,1394560199,2014-03-12 02:49:59 +0900,88)
(20140312,XXXXXXAEXXXX,Shop16,1394559996,2014-03-12 02:46:36 +0900,63)
(20140312,XXXXXXAEXXXX,Shop16,1394560059,2014-03-12 02:47:39 +0900,63)
(20140312,XXXXXXAEXXXX,Shop16,1394560122,2014-03-12 02:48:42 +0900,63)
(20140312,XXXXXXAEXXXX,Shop16,1394560185,2014-03-12 02:49:45 +0900,63)
(20140312,XXXXXXA7XXXX,Shop2,1394560042,2014-03-12 02:47:22 +0900,67)
(20140312,XXXXXX72XXXX,Shop16,1394560005,2014-03-12 02:46:45 +0900,66)
(20140312,XXXXXX72XXXX,Shop16,1394560073,2014-03-12 02:47:53 +0900,68)
(20140312,XXXXXX72XXXX,Shop16,1394560139,2014-03-12 02:48:59 +0900,66)
...
```

どうやら無事に抽出できたようですね。

### データをファイルに出力する

ファイルに出力するには STORE を使います。

```
STORE filtered INTO 'result' USING PigStorage();
```

## まとめ

今回は対話的に Pig のシェルを操作して最も基本的なデータのハンドリングを試してみました。