Y's note

Web技術・プロダクトマネジメント・そして経営について

本ブログの更新を停止しており、今後は下記Noteに記載していきます。
https://note.com/yutakikuchi/

10分でHadoop-Pigの基本文法を理解する

Hadoop MapReduce デザインパターン ―MapReduceによる大規模テキストデータ処理

Hadoop MapReduce デザインパターン ―MapReduceによる大規模テキストデータ処理

はじめに

年末から使い続けているPigについて勉強した事をまとめていきます。主に以下のDocumentを参照しています。PigのDocumentでLatinを日本語で詳しく紹介しているものが見当たらなかったので、そういった目的でこの記事を参照されている方のお役に立てれば光栄です。

Pig Tutorial

tutorial.tar.gzのdownloadとscriptの実行

tutorialのサンプルファイルが入っているtutorial.tar.gzをdownloadして解凍します。解凍したら作成されるディレクトリに移動します。試しにlocalmodeでscript1-local.pigを実行してみます。実行すると結果のディレクトリがlocalに作成されて中身を確認する事ができます。実行したサンプルはexecite-small.logという検索Queryログをtab区切りでparseして、Queryのngramを抽出します。抽出したngramの頻度に対してscoreを付けて、頻度の高いngramを出力しています。では以下では文法を確認して行きます。

$ wget -O  tutorial.tar.gz "https://cwiki.apache.org/confluence/download/attachments/27822259/pigtutorial.tar.gz?version=1&modificationDate=1311188529000"
$ tar xzf  tutorial.tar.gz
$ cd pigtmp
$ ls 
-rw-r--r--. 1 yuta yuta 204K  7月 21 04:01 2011 excite-small.log
-rw-r--r--. 1 yuta yuta  10M  7月 21 04:01 2011 excite.log.bz2
-rw-r--r--. 1 yuta yuta  11M  7月 21 04:01 2011 pig.jar
-rw-r--r--. 1 yuta yuta 3.8K  7月 21 04:01 2011 script1-hadoop.pig
-rw-r--r--. 1 yuta yuta 3.8K  7月 21 04:01 2011 script1-local.pig
-rw-r--r--. 1 yuta yuta 3.5K  7月 21 04:01 2011 script2-hadoop.pig
-rw-r--r--. 1 yuta yuta 3.4K  7月 21 04:01 2011 script2-local.pig
-rw-r--r--. 1 yuta yuta  11K  7月 21 04:01 2011 tutorial.jar
$ pig -x local script1-local.pig
2013-01-05 03:32:08,341 [main] INFO  org.apache.pig.Main - Logging error messages to: /home/yuta/scripts/pigtmp/pig_1357324328284.log
2013-01-05 03:32:08,621 [main] INFO  org.apache.pig.backend.hadoop.executionengine.HExecutionEngine - Connecting to hadoop file system at: file:///
2013-01-05 03:32:09,203 [main] WARN  org.apache.pig.PigServer - Encountered Warning USING_OVERLOADED_FUNCTION 3 time(s).
2013-01-05 03:32:09,205 [main] INFO  org.apache.pig.tools.pigstats.ScriptState - Pig features used in the script: GROUP_BY,ORDER_BY,DISTINCT,FILTER
(略)

$ cat script1-local-results/part-r-00000 
07	new	2.4494897427831788	2	1.1428571428571426
08	pictures	2.04939015319192	3	1.4999999999999998
08	computer	2.4494897427831788	2	1.1428571428571426
08	s	2.545584412271571	3	1.3636363636363635
10	free	2.2657896674010605	4	1.923076923076923
10	to	2.6457513110645903	2	1.125
10	pics	2.794002794004192	3	1.3076923076923075
10	school	2.828427124746189	2	1.1111111111111114
11	pictures	2.04939015319192	3	1.4999999999999998
11	in	2.1572774865200244	3	1.4285714285714284
13	the	3.1309398305840723	6	1.9375
14	music	2.1105794120443453	4	1.6666666666666667
14	city	2.2360679774997902	2	1.1666666666666665
14	university	2.412090756622109	3	1.4000000000000001
15	adult	2.8284271247461903	2	1.1111111111111112
17	chat	2.9104275004359965	3	1.2857142857142854
19	in	2.1572774865200244	3	1.4285714285714284
19	car	2.23606797749979	3	1.3333333333333333
データ型について

Pig Latin Basics はてなブックマーク - Pig Latin Basics
Pigで扱うデータ型をLOAD時(後で説明)に定義する事ができます。以下はPigのデータ型ですので、よく覚えておくと良いと思います。
Simple Types

データ型 意味
int 符号付き32Bit整数 10
long 符号付き64Bit整数 Data:10L or 10l Display:10L
float 32bit浮動小数点型 Data:10.5F or 10.5f or 10.5e2f or 10.5E2F Display: 10.5F or 1050.0F
double 64bit浮動小数点型 Data:10.5 or 10.5e2 or 10.5E2 Display: 10.5 or 1050.0
chararray UTF-8形式のstring(character array) hello world
bytearray blob型のデータ binary
boolean boolean true / false

Complex Types

データ型 意味
tuple データ項目の組み合わせ (19,2)
bag tupleの組み合わせ {(19,2), (18,1)}
map 辞書データ。key/value [open#apache]

※ tuple,bag,fieldという単語が良く出てきますが、関係はbag > tuple > fieldというものになっている事をイメージしてもらえれば問題ないと思います。

PigScriptからUDFを使うためにはREGISTERで登録する

PigScriptからorg.apache.pig.tutorial.NonURLDetector(query)のような不要なqueryを除外するような独自に定義した関数郡のjarファイルを登録するためにはREGISTERを使います。ちなみにtutorial.jarにはNonURLDetector以外にも以下のようなclassファイルが含まれています。またソースコードhadoop-pigパッケージに含まれているので確認することができます。

REGISTER ./tutorial.jar;
raw = LOAD 'excite-small.log' USING PigStorage('\t') AS (user, time, query);
clean1 = FILTER raw BY org.apache.pig.tutorial.NonURLDetector(query);
$ zipinfo tutorial.jar 
Archive:  tutorial.jar
Zip file size: 10725 bytes, number of entries: 13
drwxr-xr-x  2.0 unx        0 bx stor 11-Jul-20 12:01 META-INF/
-rw-r--r--  2.0 unx      107 b- defN 11-Jul-20 12:01 META-INF/MANIFEST.MF
drwxr-xr-x  2.0 unx        0 b- stor 11-Jul-20 12:01 org/
drwxr-xr-x  2.0 unx        0 b- stor 11-Jul-20 12:01 org/apache/
drwxr-xr-x  2.0 unx        0 b- stor 11-Jul-20 12:01 org/apache/pig/
drwxr-xr-x  2.0 unx        0 b- stor 11-Jul-20 12:01 org/apache/pig/tutorial/
-rw-r--r--  2.0 unx     2201 b- defN 11-Jul-20 12:01 org/apache/pig/tutorial/ExtractHour.class
-rw-r--r--  2.0 unx     3283 b- defN 11-Jul-20 12:01 org/apache/pig/tutorial/NGramGenerator.class
-rw-r--r--  2.0 unx     2302 b- defN 11-Jul-20 12:01 org/apache/pig/tutorial/NonURLDetector.class
-rw-r--r--  2.0 unx     3728 b- defN 11-Jul-20 12:01 org/apache/pig/tutorial/ScoreGenerator.class
-rw-r--r--  2.0 unx     2163 b- defN 11-Jul-20 12:01 org/apache/pig/tutorial/ToLower.class
-rw-r--r--  2.0 unx     4044 b- defN 11-Jul-20 12:01 org/apache/pig/tutorial/TutorialTest.class
-rw-r--r--  2.0 unx     1114 b- defN 11-Jul-20 12:01 org/apache/pig/tutorial/TutorialUtil.class
13 files, 18942 bytes uncompressed, 8953 bytes compressed:  52.7%
$ repoquery -l hadoop-pig | grep NonURLDetector                                               
/usr/share/doc/pig-0.8.1+28.39/examples/src/org/apache/pig/tutorial/NonURLDetector.java
$ cat /usr/share/doc/pig-0.8.1+28.39/examples/src/org/apache/pig/tutorial/NonURLDetector.java
package org.apache.pig.tutorial;

import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.List;
import java.util.ArrayList;

import org.apache.pig.FilterFunc;
import org.apache.pig.FuncSpec;
import org.apache.pig.data.Tuple;
import org.apache.pig.impl.logicalLayer.schema.Schema;
import org.apache.pig.data.DataType;
import org.apache.pig.impl.logicalLayer.FrontendException;

/**
 * This function removes search queries that are URLs (as defined by _urlPattern).
 * This function also removes empty queries.
 */
public class NonURLDetector extends FilterFunc {

  private Pattern _urlPattern = Pattern.compile("^[\"]?(http[:|;])|(https[:|;])|(www\\.)");
  
  public Boolean exec(Tuple arg0) throws IOException {
      if (arg0 == null || arg0.size() == 0)
          return false;

    String query; 
    try{
        query = (String)arg0.get(0);
        if(query == null)
            return false;
        query = query.trim();
    }catch(Exception e){
        System.err.println("NonURLDetector: failed to process input; error - " + e.getMessage());
        return false;
    }

    if (query.equals("")) {
      return false;
    }
    Matcher m = _urlPattern.matcher(query);
    if (m.find()) {
      return false;
    }
    return true;
  }
  
  /* (non-Javadoc)
   * @see org.apache.pig.EvalFunc#getArgToFuncMapping()
   * This is needed to make sure that both bytearrays and chararrays can be passed as arguments
   */
  @Override
  public List<FuncSpec> getArgToFuncMapping() throws FrontendException {
      List<FuncSpec> funcList = new ArrayList<FuncSpec>();
      funcList.add(new FuncSpec(this.getClass().getName(), new Schema(new Schema.FieldSchema(null, DataType.CHARARRAY))));

      return funcList;
  }

}
LOADでデータの読み込み、USINGでデータParserを指定、ASで変数としてのデータをaliasで定義

今回Queryの元データ集計を行うためのファイルは以下のようなタブ区切りでデータが保存されています。まずはデータを読み込むためにLOAD 'ファイル名'でデータを呼び出します。呼び出したデータをパースしてカラム変数に格納するためにUSINGASを使います。PigStorage関数の引数にparseするためのdelimiterを入れます。tutorialの例では'\t'と入れていますが、defaultは'\t'なので入れなくても動きます。PigStorageClassについては以下のリンク先を参照すると良いと思います。PigStorage (Pig 0.10.0 API) はてなブックマーク - PigStorage (Pig 0.10.0 API) ASはdelimiterによって分離されたデータ項目をカラム順に格納します。ASを使わないということも出来ます。カラムのaliasを持たない場合は$0,$1,$2のように$とカラム番号名で参照することになります。ASの中ではデータ型の定義が可能です。user:chararrayのように指定します。chararrayは上で説明した文字列型の事です。

2A9EABFB35F5B954    970916105432    +md foods +proteins
BED75271605EBD0C    970916001949    yahoo chat
BED75271605EBD0C    970916001954    yahoo chat
BED75271605EBD0C    970916003523    yahoo chat
BED75271605EBD0C    970916011322    yahoo search
BED75271605EBD0C    970916011404    yahoo chat
BED75271605EBD0C    970916011422    yahoo chat
BED75271605EBD0C    970916012756    yahoo caht
raw = LOAD 'excite-small.log' USING PigStorage('\t') AS (user, time, query);
raw = LOAD 'excite-small.log' USING PigStorage('\t') -- カラム名を指定しないので参照する時は$0,$1,$2
raw = LOAD 'excite-small.log' USING PigStorage('\t') AS (user: chararray, time: chararray, query: chararray); -- データ型を指定
格納されているデータを確認する場合はDUMPを利用する

格納されている変数のデータを確認するにはDUMPを利用します。単純にDUMP 変数名;として指定するだけです。DUMPはLOADFILTERFOREACHなどによって生成された結果の変数に対してはデータの出力が可能ですが、DUMP 変数名.ASカラム名;といった指定で特定のカラムのみを出力することができません。

DUMP raw;
-- DUMP raw.user -- 失敗する例
(0158F8ACC570947D,970916162130,wu tang clan)
(0158F8ACC570947D,970916162623,doggumentary)
(0158F8ACC570947D,970916163639,control machete)
(06878125BE78B42C,970916183900,how to make ecstacy)
(06878125BE78B42C,970916184804,jdun@scuc.edu.au)
(06878125BE78B42C,970916185100,tborges@inetminas.estaminas.com.br)
(B0C1B6DC7370F24B,970916090623,hhtp://www.yale.edu/opa.)
(1432F28A749F7BE6,970916220548,nesticle 0.40 download)
(1432F28A749F7BE6,970916221400,nes rom)
(1432F28A749F7BE6,970916221804,double dragon 3 rom)
(1432F28A749F7BE6,970916221859,emuland)
(98F5BBD3754D292F,970916082614,powwow.com)
(98F5BBD3754D292F,970916082616,powwow.com)
(98F5BBD3754D292F,970916082713,powwow.com tribal )
(C5D01E05FF9CA265,970916155706,mary lou allgood)
(C5D01E05FF9CA265,970916155729,mary lou allgood)
(DB38E7AF26F3AD9A,970916114356,microsoft excel)
不要なデータを削除するためにはFILTERを使う

条件を指定して不要なデータ行を削除するためにFILTERを利用します。下のサンプルではUDFで定義されたorg.apache.pig.tutorial.NonURLDetector(query)を利用してqueryが空またはURL形式で無い場合は変数に格納するという処理をしています。UDFの中では単純にTrue/Falseをreturnするだけです。もっと簡単な例だと空かどうかの判定だけであればquery != ''のように指定することもできます。文字列比較ではeqという演算子で一致を確認することができます。eqは==と等価です。しかし不一致のneは使えません。またFILTERは数値演算も可能です。BY score > 2.0のように指定するとできます。更に便利なことにFILTERには正規表現も使え、指定にはMATCHESを利用します。

clean1 = FILTER raw BY org.apache.pig.tutorial.NonURLDetector(query);
clean2 = FILTER raw BY query != '';
clean2 = FILTER raw BY query eq '';
clean2 = FILTER raw BY query == '';
-- clean2 = FILTER raw BY query eq ''; -- 指定できない
clean2 = FILTER raw BY query MATCHES '.*university.*';
filtered_uniq_frequency = FILTER uniq_frequency3 BY score > 2.0;
カラムデータに対して繰り返し処理を加えたい場合はFOREACHを利用する

抽出された行のカラムに対して特定の処理を繰り返し加えたい場合はFOREACH 変数名 GENERATEを利用します。下ではURLや空をFILTERした行に対して、queryを小文字に変換し、timeを検索時間に変換し、ngramに分割したデータがタプル形式になっているので、それをフラット化するためにFLATTENを使っています。tutorialの例ではFOREACHを3行使っていて面倒なので、1行にまとめてしまうことも出来ます。

clean1 = FILTER raw BY org.apache.pig.tutorial.NonURLDetector(query);
clean2 = FOREACH clean1 GENERATE user, time, org.apache.pig.tutorial.ToLower(query) AS query;
houred = FOREACH clean2 GENERATE user, org.apache.pig.tutorial.ExtractHour(time) AS hour, query;
ngramed1 = FOREACH houred GENERATE user, hour, FLATTEN(org.apache.pig.tutorial.NGramGenerator(query)) AS ngram;
DUMP ngramed1;

-- 上のFOREACHを1行でまとめる
ngramed1 = FOREACH clean1 GENERATE user, org.apache.pig.tutorial.ExtractHour( time ) AS hour, FLATTEN( org.apache.pig.tutorial.NGramGenerator( org.apache.pig.tutorial.ToLower( query ) ) ) AS ngram;
-- フラット化されたデータ
(C5D01E05FF9CA265,15,allgood)
(C5D01E05FF9CA265,15,lou allgood)
(C5D01E05FF9CA265,15,lou)
(C5D01E05FF9CA265,15,mary)
(C5D01E05FF9CA265,15,mary lou)
(C5D01E05FF9CA265,15,allgood)
(C5D01E05FF9CA265,15,lou allgood)
(C5D01E05FF9CA265,15,lou)
(C5D01E05FF9CA265,15,mary)
(C5D01E05FF9CA265,15,mary lou)
(DB38E7AF26F3AD9A,11,excel)
(DB38E7AF26F3AD9A,11,microsoft excel)
(DB38E7AF26F3AD9A,11,microsoft)

-- フラット化されていないデータ
(98F5BBD3754D292F,08,{(com),(powwow com),(powwow)})
(98F5BBD3754D292F,08,{(com),(powwow com),(powwow)})
(98F5BBD3754D292F,08,{(com),(powwow com),(tribal),(powwow),(com tribal)})
(C5D01E05FF9CA265,15,{(allgood),(lou allgood),(lou),(mary),(mary lou)})
(C5D01E05FF9CA265,15,{(allgood),(lou allgood),(lou),(mary),(mary lou)})
(DB38E7AF26F3AD9A,11,{(excel),(microsoft excel),(microsoft)})
重複された行を削除しUniqしたい場合はDISTINCTを使う

重複された行を削除したい場合はDISTINCTを利用します。RDBMSを使っている人なら馴染みある機能だと思います。

ngramed2 = DISTINCT ngramed1;
DUMP ngramed2;
(FFA4F354D3948CFB,05,big cocks)
(FFA4F354D3948CFB,06,big)
(FFA4F354D3948CFB,06,cocks)
(FFA4F354D3948CFB,06,big cocks)
(FFCA848089F3BA8C,10,manson)
(FFCA848089F3BA8C,10,marilyn)
(FFCA848089F3BA8C,10,marilyn manson)
データのグループ化をしたい場合はGROUPを使う

特定の条件でデータのグループ化をしたい場合はGROUPを利用します。下の例では検索時間,ngramの二つでuserのListをGROUPとして1行で出力しています。

hour_frequency1 = GROUP ngramed2 BY (ngram, hour);
DUMP hour_frequency1;
((university,11),{(752FE259E734662C,11,university),(1C29DA34960DE1A9,11,university)})
((university,13),{(0E10DD8EB5EEB192,13,university),(C983FC6A580A67D4,13,university)})
((university,14),{(0D49AC0B76523A18,14,university),(6946DDFE6F9050F5,14,university),(C983FC6A580A67D4,14,university)})
データの個数をカウントする場合はCOUNTを使う

データの個数をカウントするにはCOUNTを利用します。下の例では上でGROUP化されたデータのタプル数をカウントする例になります。(ngram,hour)のカラムが$0、GROUP化された(user,hour,ngram)カラムが$1に相当し、COUNT($1)の式によって((university,14),{(0D49AC0B76523A18,14,university),(6946DDFE6F9050F5,14,university),(C983FC6A580A67D4,14,university)})が(university,14,3)として3つカウントされます。

hour_frequency2 = FOREACH hour_frequency1 GENERATE flatten($0), COUNT($1) as count;
DUMP hour_frequency2;
(universita,09,1)
(university,01,1)
(university,06,1)
(university,09,1)
(university,10,1)
(university,11,2)
(university,13,2)
(university,14,3)
(university,15,1)
(university,19,1)
(university,21,1)
(univiristy,06,1)
一つの項目だけでグループ化

ここもGROUPの使い方の説明です。事前にグループ化されたデータをngramだけで再度グループ化しています。よくやってしまう間違いとしてBY ngram;と指定しまうことです。hour_frequency2にはngramという項目がありません。hour_frequency1でgroupされたngramが存在しているだけなので、group::ngramと指定します。

uniq_frequency1 = GROUP hour_frequency2 BY group::ngram;
-- uniq_frequency1 = GROUP hour_frequency2 BY group::ngram; -- 良くやる間違い
DUMP uniq_frequency1;
(universita,{(universita,09,1)})
(university,{(university,14,3),(university,01,1),(university,06,1),(university,09,1),(university,10,1),(university,11,2),(university,13,2),(university,15,1),(university,19,1),(university,21,1)})
(univiristy,{(univiristy,06,1)})
指定したカラムでソートしたい場合はORDERを使う

特定のカラムでデータをソートしたい場合はORDERを利用します。DISTINCTと同様にRDBMSにもある機能ですね。下の例ではngramのscore化されたデータをFILTERにてscore > 2.0の行を抽出し、hour/scoreの項目でソートをした結果を格納しています。ORDER BYはASCで昇順、DESCで降順にソートすることができます。

uniq_frequency3 = FOREACH uniq_frequency2 GENERATE $1 as hour, $0 as ngram, $2 as score, $3 as count, $4 as mean;
filtered_uniq_frequency = FILTER uniq_frequency3 BY score > 2.0;
ordered_uniq_frequency = ORDER filtered_uniq_frequency BY hour, score; -- 昇順ソート
ordered_uniq_frequency = ORDER filtered_uniq_frequency BY hour DESC; -- 降順ソート
-- DESC
(19,in,2.1572774865200244,3,1.4285714285714284)
(19,car,2.23606797749979,3,1.3333333333333333)
(17,chat,2.9104275004359965,3,1.2857142857142854)
(15,adult,2.8284271247461903,2,1.1111111111111112)
(14,music,2.1105794120443453,4,1.6666666666666667)
(14,city,2.2360679774997902,2,1.1666666666666665)
(14,university,2.412090756622109,3,1.4000000000000001)
(13,the,3.1309398305840723,6,1.9375)
(11,in,2.1572774865200244,3,1.4285714285714284)
(11,pictures,2.04939015319192,3,1.4999999999999998)
(10,free,2.2657896674010605,4,1.923076923076923)
(10,to,2.6457513110645903,2,1.125)
(10,pics,2.794002794004192,3,1.3076923076923075)
(10,school,2.828427124746189,2,1.1111111111111114)
(08,computer,2.4494897427831788,2,1.1428571428571426)
(08,pictures,2.04939015319192,3,1.4999999999999998)
(08,s,2.545584412271571,3,1.3636363636363635)
(07,new,2.4494897427831788,2,1.1428571428571426)
データの結合にはJOINを使う

二つの変数間のデータを結合するにはJOINを利用します。JOINには内部結合(INNER)と外部結合等(LEFT,RIGHT,FULL)の種類があり、何も指定しない場合は内部結合になります。

same = JOIN hour00 BY $0, hour12 BY $0; -- 内部結合
same = JOIN hour00 BY $0 LEFT, hour12 BY $0; -- 左外部結合
same = JOIN hour00 BY $0 RIGHT, hour12 BY $0; -- 右外部結合
same = JOIN hour00 BY $0 FULL, hour12 BY $0; -- 全外部結合
-- JOIN RIGHT
(,,,applied technologies,12,1)
(,,,horoscope benmcnenly,12,1)
(,,,providers california,12,1)
(,,,snowboarding kirkwood,12,1)
(,,,snowboarding kurkwood,12,1)
(,,,instrument instruments,12,1)
(,,,vietnam telecommunications,12,1)
データを保存したい場合はSTOREを使う

Pigで実行したデータをファイルに保存したい場合はSTOREを利用します。STOREもLOADと同様にUSINGでデータのparserを指定することが出来ます。下の例ではPigStorageを指定しているのでtab区切りのデータ保存になります。INTOで指定するのは結果を保存するディレクトリです。ディレクトリの中にpart-r-00000というファイルができるので、それが出力結果になります。結果は一番上で実行したスクリプトの結果になります。

STORE ordered_uniq_frequency INTO 'script1-local-results' USING PigStorage();

Advanced

以下ではtutorialに載っていない更なる応用例を記載します。入力サンプルのデータを変更して以下のタブ区切りで定義されているstudentデータを使います。データを変えたのは以下のページと結果を比較しやすくするためです。すいません。Pig Latin Basics はてなブックマーク - Pig Latin Basics

John  18 4.0F
Mary  19 3.8F
Bill  20 3.9F
Joe   18 3.8F
変数のデータ型を調べる時はDESCRIBEを使う

DESCRIBEは変数のデータ型を出力します。FLATTEN等の処理を入れる時にデータ型を確認するために利用すると便利です。

raw1 = LOAD 'student' USING PigStorage() AS (name:chararray, age:int, gpa:float);
DESCRIBE raw1;
raw: {name: chararray,age: int,gpa: float}
2つ以上の変数をグループ化する時はCOGROUPを使う

2つ以上の変数をグループ化したい時はCOGROUPを利用します。データや使い方の形式はGROUPと同じです。下では3つの変数をCOGROUPしています。

raw1 = LOAD 'student' USING PigStorage() AS (name:chararray, age:int, gpa:float);
raw2 = LOAD 'student' USING PigStorage() AS (name:chararray, age:int, gpa:float);
raw3 = LOAD 'student' USING PigStorage() AS (name:chararray, age:int, gpa:float);
filter_raw2 = FILTER raw2 BY age == 18;
co_data = COGROUP raw1 BY age, filter_raw2 BY age, raw3 BY age;
DUMP co_data; 
(18,{(John,18,4.0),(Joe,18,3.8)},{(John,18,4.0),(Joe,18,3.8)},{(John,18,4.0),(Joe,18,3.8)})
(19,{(Mary,19,3.8)},{},{(Mary,19,3.8)})
(20,{(Bill,20,3.9)},{},{(Bill,20,3.9)})
データの組み合わせを全て取得する時はCROSSを使う

2つ以上の変数の組み合わせを全て取得したい時はCROSSを利用します。全ての組み合わせを作るので処理が凄く重くなるようなので注意して使うといいと思います。

raw1 = LOAD 'student' USING PigStorage() AS (name:chararray, age:int, gpa:float);
raw2 = LOAD 'student' USING PigStorage() AS (name:chararray, age:int, gpa:float);
filter_raw2 = FILTER raw2 BY age == 18;
cross_data = CROSS raw1, filter_raw2;
DUMP cross_data; 
(John,18,4.0,Joe,18,3.8)
(John,18,4.0,John,18,4.0)
(Mary,19,3.8,Joe,18,3.8)
(Mary,19,3.8,John,18,4.0)
(Joe,18,3.8,Joe,18,3.8)
(Joe,18,3.8,John,18,4.0)
(Bill,20,3.9,Joe,18,3.8)
(Bill,20,3.9,John,18,4.0)
2つのデータの統合はUNIONを使う

2つ以上の変数を統合したい場合はUNIONを利用します。CROSSと違いUNIOは単純なデータの追加になります。

raw1 = LOAD 'student' USING PigStorage() AS (name:chararray, age:int, gpa:float);
raw2 = LOAD 'student' USING PigStorage() AS (name:chararray, age:int, gpa:float);
filter_raw2 = FILTER raw2 BY age == 18;
union_data = UNION raw1, filter_raw2;
DUMP union_data;
(John,18,4.0)
(Mary,19,3.8)
(Bill,20,3.9)
(Joe,18,3.8)
(John,18,4.0)
(Joe,18,3.8)
結果の個数を絞りたい時はLIMITを使う

ORDER BYとの組み合わせで取得したい結果を絞りたい時はLIMITを利用します。単純に変数に対して個数を設定するだけです。

raw1 = LOAD 'student' USING PigStorage() AS (name:chararray, age:int, gpa:float);
raw2 = LOAD 'student' USING PigStorage() AS (name:chararray, age:int, gpa:float);
filter_raw2 = FILTER raw2 BY age == 18;
union_data = UNION raw1, filter_raw2;
order_data = ORDER union_data by age DESC;
limit_data = LIMIT order_data 2;
DUMP limit_data;
(Bill,20,3.9)
(Mary,19,3.8)
ランダムサンプリングを取得したい時はSAMPLEを使う

取得したいランダムサンプルの割合をSAMPLEで指定します。指定方法はSAMPLE 変数名 割合実数です。

raw1 = LOAD 'student' USING PigStorage() AS (name:chararray, age:int, gpa:float);
raw2 = LOAD 'student' USING PigStorage() AS (name:chararray, age:int, gpa:float);
filter_raw2 = FILTER raw2 BY age == 18;
union_data = UNION raw1, filter_raw2;
sample_data = SAMPLE union_data 0.1;
DUMP sample_data;
(John,18,4.0)
データを条件で分割したい場合はSPLITを使う

データを特定の条件で複数の変数に分割したい場合はSPLITを利用します。SPLITは複数の変数における条件を1行で表現できますが、動作内容としてはFILTERと同様でFILTERでも表記することが出来ます。

raw1 = LOAD 'student' USING PigStorage() AS (name:chararray, age:int, gpa:float);
raw2 = LOAD 'student' USING PigStorage() AS (name:chararray, age:int, gpa:float);
filter_raw2 = FILTER raw2 BY age == 18;
union_data = UNION raw1, filter_raw2;
SPLIT union_data INTO x_data IF age > 19, y_data IF age == 19, z_data IF age < 19;
DUMP y_data;
(Mary,19,3.8)
NativeのMapReduceを実行するにはMAPREDUCEを使う

こちら実行を試していませんが、NativeのMapReduceを実行したい時にはMAPREDUCEを利用します。以下のスクリプトにinputDir,outputDirを指定して実行します。

A = LOAD 'WordcountInput.txt';
B = MAPREDUCE 'wordcount.jar' STORE A INTO 'inputDir' LOAD 'outputDir' AS (word:chararray, count: int) `org.myorg.WordCount inputDir outputDir`;
データを外部スクリプトに渡すにはSTREAMを使う

こちらは実行していませんが、外部のスクリプトにデータを渡したい場合はSTREAMを使います。

A = LOAD 'data';
B = GROUP A BY $1;
C = FOREACH B FLATTEN(A);
D = STREAM C THROUGH `stream.pl`;