2014年4月30日水曜日

備忘) Pythonで書くMap Reduce on Hadoop


ここ最近の授業でもPythonのMulti processingのモジュールを使って、Mapper, Partitioner, Reducerを組み合わせて、いろいろ集計したり、回帰分析のプログラムを書いたりしています。 徐々にですが、Map Reduceがどういうもので、どこをパラレルに計算させて、集計とるかみたいな勘がわかってきました。


で、今日は、1ヶ月くらい前にHadoopのセットアップをやりましたが、その後ほったらかしていたので、授業で勉強したことを活かすべく(?)、Hadoopの擬似分散モード上で動くPythonのM/Rのプログラムを書いてみようと思います。

参考にしたブログはこちら。


  • http://www.michael-noll.com/tutorials/writing-an-hadoop-mapreduce-program-in-python/
  • http://blog.matthewrathbone.com/2013/11/17/python-map-reduce-on-hadoop---a-beginners-tutorial.html


まず下準備です。


1. 使用するデータを用意する


こちらのデータは、1行目から順に、ID, 性別, 年齢, 身長(インチ), 体重(ポンド), 自分の体重をどう思うか?(1=太っている、2=痩せている、3=普通), 体重を変えようとしているか?(1=太ろうとしている, 2=痩せようとしている, 3 = 維持しようとしている) というデータです(元データはこちら
:ftp://ftp.cdc.gov/pub/Health_Statistics/NCHS/nhanes/nhanes3/1A/adult.dat)。

このデータを、adult_data.csvと呼びます。
'00003', 1, 21, 72, 180, 3, 1
'00004', 2, 32, 63, 135, 1, 2
'00009', 2, 48, 61, 147, 1, 2
'00010', 1, 35, 70, 205, 1, 2
'00011', 1, 48, 67, 170, 3, 3
'00019', 1, 44, 70, 187, 3, 3
'00034', 2, 42, 63, 128, 1, 2
'00040', 2, 17, 60, 100, 3, 3
'00044', 2, 24, 66, 125, 3, 2
'00045', 2, 67, 64, 147, 3, 3
'00048', 2, 56, 68, 231, 1, 2
'00049', 2, 82, 73, 97, 2, 1
'00051', 1, 44, 71, 300, 1, 2


2. 使用するデータをローカルからHDFS上にアップする

#まずは、testフォルダを作ります
$ hadoop fs -mkdir /user/<your username>/test
#そんでもって、putでデータをローカルからHDFS上にコピーします
$ hadoop fs -put adult_data.csv /user/<your username>/test/adult_data.csv

3. PythonでMapperとReducerを書きます

今回は、性別ごとの平均年齢を出してみます。
まずは、Mapperから。

どうやら、Hadoopのstreaming-jarというもので、データを一行ずつPythonのプログラムに標準入力できるようです。なので、テキストとして読み込んだ一行ずつのデータをstripとsplit(",")でパースしています。例えば、最初の行は、以下のような配列になります。

"'00003', 1, 21, 72, 180, 3, 1" ->['00003', "1", "21", "72", "180", "3", "1"]

そして、1つめの要素(性別)と2つめの要素をピックして、標準出力していきます。 Key Valueのペアは、ただのタブ区切りのテキストとして出力されるというわけです。

Mapper.py
#!/usr/bin/python

import sys

# input comes from STDIN (standard input)
for line in sys.stdin:
    line = line.strip()
    line = line.split(",")

    if len(line) >=2:
        sex = line[1]
        age = line[2]

        print '%s\t%s' % (sex, age)

続いて、Reducerです。 Reducer.pyには、PartitionerとReducerがセットになっています。 Mapperから吐き出されるKey Valueペアのテキストをパースして、辞書にValueを格納、最後に集計というのが大雑把な流れです。

Reducer.py
#!/usr/bin/python
#Reducer.py
import sys

sex_age = {}

#Partitoner
for line in sys.stdin:
    line = line.strip()
    sex, age = line.split('\t')

    if sex in sex_age:
        sex_age[sex].append(int(age))
    else:
        sex_age[sex] = []
        sex_age[sex].append(int(age))

#Reducer
for sex in sex_age.keys():
    ave_age = sum(sex_age[sex])*1.0 / len(sex_age[sex])
    print '%s\t%s'% (sex, ave_age)

3. Pythonのプログラムの権限変更

作ったプログラムに実行権限を追加します。
$ chmod +x mapper.py
$ chmod +x reducer.py

4. テストしてみる

これって、ただのテキストを吐き出して、Mapperで読み込んで、また吐き出して、Reducerでも読み込んで吐き出しているだけなので、ターミナル上でテストできます。例えば、こんな感じで。
$ cat adult_data.csv | python mapper.py | python reducer.py
1 47.597301855
2 47.2906009245


5. 最後にMap Reduce on Hadoop!

ここで、hadoop-streaming.jarというJavaのプログラムをhadoop jarで実行します(参考にしたブログに書いてあった、hadoop-streaming.jarがあるディレクトリと私のディレクトリが違ったので、cdhのバージョ等ンに寄って違うのかもしれませんので、検索して確認したほうが良いかもしれません)。

mapper.pyとreducer.pyのあるディレクトリで以下を実行すると、Map Reduceが始まります(見やすくするために、複数行で書いていますが、実際にやるときは一行で書いてください)。
$hadoop jar /usr/lib/hadoop-mapreduce/hadoop-streaming.jar 
 -mapper mapper.py 
 -reducer reducer.py 
 -input /user/<your username>/test/adult_data.csv 
 -output ave_age 
 -file mapper.py 
 -file reducer.py


6. めでたく結果をゲット

(よくわからないんですが)outputで指定したフォルダに、part-00000というテキストファイルが作られていて、そこに結果が入っています。
$hadoop fs -cat /user/<your username>/ave_age/part-00000 
1 47.597301855
2 47.2906009245

2014年3月24日月曜日

CDH4を使ってのHadoop + HIVE インストール備忘録(Ubuntu 12.10)

新しいモジュールでDistributed Computingの授業があるので、UbuntuにHadoopとHiveを入れておこうと思って始めたのですが、不慣れでかなり手間取ってしまい、丸一日潰してしまいました。。。こういうインフラ系のことって本当に難しいんですね・・・

また同じことはできないと思うので、忘れないように残しておきます。

参考にしたブログや記事です。本当に助かりました。ありがとうございます。


  • https://gist.github.com/YoshihitoAso/9444292
  • http://kakakikikeke.blogspot.jp/search?q=hive



上記を見ながら、「動かない!!なぜだ!??」と試行錯誤しながら、ようやく動くまでに至った経緯です。正直、Hadoopがどうやって動いているのか、hiveがどうして動いているのかわかっていませんが、自分がやったことは以下のとおりです。


まず、インストールするOSですが、Ubuntu12.10の64bitです。

Javaのインストール
$ sudo add-apt-repository ppa:webupd8team/java
$ sudo apt-get update
$ sudo apt-get install oracle-java7-installer
インストールが済んだら、以下のコマンドを叩いてバージョンを確認します。
$ java -version
java version "1.7.0_51"
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode)
続いて、JAVA_HOMEを設定します。homeにある隠しファイル「.bashrc」を開いて、以下をファイルの末尾に入力し保存します。
export JAVA_HOME=/usr/lib/jvm/java-7-oracle
export PATH=$PATH:$JAVA_HOME/bin
これをやったら、一度ログアウトして、JAVA_HOMEの変更を反映させるのを忘れないように!(それをやらずに、この後のCDHをインストールしたところ、エラー!って怒られました・・・)

CDH4をインストールします。
$ sudo dpkg -i cdh4-repository_1.0_all.deb
$ curl -s http://archive.cloudera.com/cdh4/ubuntu/precise/amd64/cdh/archive.key | sudo apt-key add -
$ sudo apt-get update
$ sudo apt-get install hadoop-conf-pseudo
どうやら、インストールしたときに、hdfsユーザーというものが作られているようです。そこで、ここからはhdfsユーザーで作業をします。
$ sudo su hdfs
コマンドラインが、「hdfs@」で始まるようになります。
そして、以下のコマンドを叩いて、Namenodeをフォーマットします。
$hdfs namenode -format
そしたら、コマンドラインに「exit」と入力してhdfsユーザーから抜けます。
続いて、以下のコマンドをターミナルに入力して、HDFSを起動します。ちなみに止めるときはstartの代わりにstopです。
for service in /etc/init.d/hadoop-hdfs-*
do
sudo $service start (止めるときは、ここのstartをstopに変える)
done
startingほにゃららみたいなメッセージが何回か現れると思います。 それを見届けてから、何も考えずに以下を打ち込みます。
$ sudo su - hdfs
$ hadoop fs -mkdir /tmp 
$ hadoop fs -chmod -R 1777 /tmp
$ hadoop fs -mkdir /var/log/hadoop-yarn
$ hadoop fs -chown yarn:mapred /var/log/hadoop-yarn
$ hadoop fs -mkdir /tmp/hadoop-yarn/staging
$ hadoop fs -chmod -R 1777 /tmp/hadoop-yarn/staging
$ hadoop fs -mkdir /tmp/hadoop-yarn/staging/history/done_intermediate
$ hadoop fs -chmod -R 1777 /tmp/hadoop-yarn/staging/history/done_intermediate
$ hadoop fs -mkdir /user/$USER
$ hadoop fs -chown hdfs /user/$USER
そして、HIVEを使うために、/userの権限を変更します。(これをやらなかったために、HIVEを起動して、テーブル作ったときに、Permission Deniedのエラーが出てハマりました。。。。)
$sudo -u hdfs hadoop dfs -chmod 777 /user
上記がうまくの権限変更がうまく行っているか、確認します。
$sudo su hdfs (改めてhdfsでログイン)
$ hadoop fs -ls /
Found 3 items
drwxrwxrwt   - hdfs supergroup          0 2014-03-23 22:13 /tmp
drwxrwxrwx   - hdfs supergroup          0 2014-03-23 22:02 /user
drwxr-xr-x   - hdfs supergroup          0 2014-03-23 18:26 /var
続いて、YARNを起動してみます。
sudo service hadoop-yarn-resourcemanager start
sudo service hadoop-yarn-nodemanager start
sudo service hadoop-mapreduce-historyserver start

そして、HIVEをインストールします。
※これはhdfsユーザーではなくrootユーザーでやります。
$ wget http://mirror.tcpdiag.net/apache/hive/stable/hive-0.11.0.tar.gz
$ tar xzf hive-0.11.0.tar.gz
$ mkdir /usr/local/hive
そしたら、hive-0.11.0の中身を新しく作った/usr/local/hiveに移します。
次に、環境変数を設定します。また、homeにある隠しファイル「.bashrc」を開いて以下をファイルの末尾に追加して保存します。
export HIVE_HOME=/usr/local/hive
export PATH=$HIVE_HOME/bin:$PATH
また、一度ログアウトし、再度ログイン。ターミナルで、$echo $HIVE_HOMEを叩いて、ちゃんと反映されているか確認。続いて、/hive/confに入っている各種テンプレートを本番用に変更します。
$cd $HIVE_HOME
$mkdir logs
$cd /usr/local/hive/conf
$mv hive-log4j.properties.template log4j.properties
$mv hive-env.sh.template hive-env.sh
$chmod 755 hive-env.sh
$mv hive-exec-log4j.properties.template hive-exec-log4j.properties
$mv hive-default.xml.template hive-site.xml
これで、最後にhiveが動くかどうか・・・・
$hive (これはrootユーザーです)
それで、hive>となったら、まずはshow databases;を叩いてみます。

hive> show databases;
OK
default
test
Time taken: 3.108 seconds, Fetched: 2 row(s)
で、create tableなど試してみて、きちんと動いているようであれば、無事インストール終了です。

2014年3月23日日曜日

サンフランシスコの花粉症

花粉症って日本だけだと思っていたら、アメリカにもあるんですね・・・。ゴールデンゲートパークの近くに住んでいるか、くしゃみが止まらない・・・

日本にいるときは、必ずマスクをして外出していたのですが、サンフランシスコではマスクをしている人を見かけないので、ちょっとマスクして出かけにくいなぁと。結構、バス乗っていても、くしゃみしたり、鼻すすっている人多いんですが、マスクはしていないんですよね。。。友達にこのこと言ったら、「怪しまれるからマスクはしない方がいい」って言われたので、しばらく我慢します。

うーん、早く花粉症の季節が終わらないかなぁ。