どらちゃんのポッケ

R・統計・技術メモなど勉強ログ置き場

hortonworksのhadoopを触る2 (チュートリアル2:pig)

pigの使い方(ちょっと実践)

データの準備

  • 元データをここからダウンロード

  • データの内容は下記の通り

    • 野球のデータっぽい

            playerID,yearID,stint,teamID,lgID,G,G_batting,AB,R,H,2B,3B,HR,RBI,SB,CS,BB,SO,IBB,HBP,SH,SF,GIDP,G_old
            aardsda01,2004,1,SFN,NL,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11
            aardsda01,2006,1,CHN,NL,45,43,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,45
            aardsda01,2007,1,CHA,AL,25,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2
            aardsda01,2008,1,BOS,AL,47,5,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,5
            aardsda01,2009,1,SEA,AL,73,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      

PigStorage

batting = load 'Batting.csv' using PigStorage(',');

  • Batting.csvを読み込んで、カンマ区切りで分割する

FOREACH/GENERATE

runs = FOREACH batting GENERATE $0 as playerID, $1 as year, $8 as runs;

  • 「foreach」は、入力データを1レコードずつ処理していく命令
  • GENERATE はデータの列を処理するために使う
  • 1列目をplayerID、2行目をyear、9行目をrunとする(射影).
  • 下記のようなテーブルになる。
    • playerID year runs
      aardsda01 2004 10

GROUP

grp_data = GROUP runs by (year);

  • 特定の値ごとにグループを生成する
  • 年度ごとの全選手の値がグループ化された

    (1871,{(selmafr01,1871,14),(flowedi01,1871,39),・・・)}) (1872,{(burdoja01,1872,26),(allenha01,1872,8),・・・)})

MAX

max_runs = FOREACH grp_data GENERATE group as grp,MAX(runs.runs) as max_runs;

  • グループ内で最大の値を返す
  • nullがある場合、無視される

・・・ここで、エラーが発生!!

  • チュートリアル通りに行ったが、ここでエラーが発生した・・・。
    • Error executing an algebraic function
  • 公式ドキュメントにあったが、どうやらrunのカラムにnumeric型以外のものが認識されていることによっておこっているらしい
    • http://hortonworks.com/community/forums/topic/tutorial-2-error-2106-error-executing-an-algebraic-function/
    • 明示的に型を指定することでエラーの回避ができる

        batting = load 'Batting.csv' using PigStorage(',');
        runs = FOREACH batting GENERATE
        (chararray)$0 AS playerID,
        (int)$1 AS year,
        (int)$8 AS runs;
        -- DESCRIBE runs;
      
        grp_data = GROUP runs BY (year);
        max_runs = FOREACH grp_data GENERATE
        group AS grp, MAX(runs.runs) AS max_runs;
        -- DESCRIBE max_runs;
      
    • 修正後、結果は下記のようになる

        (1871,66)
        (1872,94)
        (1873,125)
        (1874,91)
      
    • この問題は、実際に行うときにもハマりそうだな・・・

    • 年度ごとにrunが最も大きい値が抽出された

JOIN

join_max_run = JOIN max_runs by ($0, max_runs), runs by (year,runs);

  • max_runsの1列目(year)とmax_runs と runsのyearとruns を複合キーとしてinnerjoinしている
    • 年度ごとにもっともrunが大きい値の選手の情報を追加
  • 結果は下記の通り

      (1871,66,barnero01,1871,66)
      (1872,94,eggleda01,1872,94)
      (1873,125,barnero01,1873,125)
      (1874,91,mcveyca01,1874,91)
      (1875,115,barnero01,1875,115)
      (1876,126,barnero01,1876,126)
      (1877,68,orourji01,1877,68)
    

join_data = FOREACH join_max_run GENERATE $0 as year, $2 as playerID, $1 as runs;

  • データを整形

      (1871,barnero01,66)
      (1872,eggleda01,94)
      (1873,barnero01,125)
      (1874,mcveyca01,91)
      (1875,barnero01,115)
    

DUMP

dump join_data;

  • 格納されているデータを確認
  • 特定のカラムだけの抽出はできない

最終的なスクリプト

    batting = load 'Batting.csv' using PigStorage(',');
    runs = FOREACH batting GENERATE
    (chararray)$0 AS playerID,
    (int)$1 AS year,
    (int)$8 AS runs;
    -- DESCRIBE runs;

    grp_data = GROUP runs BY (year);
    max_runs = FOREACH grp_data GENERATE
    group AS grp, MAX(runs.runs) AS max_runs;
    -- DESCRIBE max_runs;

    join_max_run = JOIN
    max_runs BY (grp, max_runs),
    runs by (year, runs);
    -- DESCRIBE join_max_run;

    join_data = FOREACH join_max_run GENERATE
    $0 as year,
    $2 as playerID,
    $1 as runs;
    DESCRIBE join_data;
    STORE join_data INTO 'baseball1';
    dump join_data;
  • 以上、pigの使い方でした
  • んー。DSLに慣れないな・・・
  • 1回の実行に時間がかかるので、デバッグに時間がかかる。なにか良い方法はないのだろうか・・・