Hadoop始めたいけどJavaで書くのめんどくさい… という人のためのチュートリアル.
HadoopはJavaで記述されているため基本的にはMapper/ReducerもJavaで記述するが,HadoopにはHadoop Streamingという機能があり,Unixの標準入出力を介してデータの受け渡しをすることができる.
これを用いてPythonでMapper/Reducerを書いてみた.もちろんHadoop Streamingを利用すればPython以外の言語でも書ける.今回はUbuntu上に擬似分散環境を構築してみた.
Ubuntu12.04 + Haadoop2.4.1
Hadoopの環境構築
Javaがない場合はインストール
$ sudo apt-get update
$ sudo apt-get install openjdk-7-jdk
Hadoopをダウンロード
$ wget http://mirror.nexcess.net/apache/hadoop/common/hadoop-2.4.1/hadoop-2.4.1.tar.gz
$ tar zxvf hadoop-2.4.1.tar.gz
$ mv hadoop-2.4.1.tar.gz hadoop
$ rm hadoop-2.4.1.tar.gz
$ sudo mv hadoop /usr/local
$ cd /usr/local/hadoop
$ export PATH=$PATH:/usr/local/hadoop/bin #.zshrcに書いておくとよい
以下の4つのファイルを編集
$ vim etc/hadoop/core-site.xml
...
<configuration>
<property>
<name>fs.default.name</name>
<value>hdfs://localhost:9000</value>
</property>
</configuration>
$ vim etc/hadoop/hdfs-site.xml
...
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>
$ mv etc/hadoop/mapred-site.xml.template etc/hadoop/mapred-site.xml
$ vim etc/hadoop/mapred-site.xml
...
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>
$ vim etc/hadoop/hadoop-env.xml
...
export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64
export HADOOP_INSTALL=/usr/local/hadoop
export PATH=$PATH:$HADOOP_INSTALL/bin
export PATH=$PATH:$HADOOP_INSTALL/sbin
export HADOOP_MAPRED_HOME=$HADOOP_INSTALL
export HADOOP_COMMON_HOME=$HADOOP_INSTALL
export HADOOP_HDFS_HOME=$HADOOP_INSTALL
export YARN_HOME=$HADOOP_INSTALL
export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_INSTALL/lib/native
export HADOOP_OPTS="-Djava.library.path=$HADOOP_INSTALL/lib"
...
鍵がない場合は追加する
$ ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa
$ cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys
最後にnamenodeを初期化し,Hadoopを起動する
$ hdfs namenode -format
$ sbin/start-dfs.sh
PythonによるMapper/Reducerの記述
今回は,HadoopのサンプルコードであるWordCountをPythonで記述する
まず,入力ファイルを用意する
$ mkdir inputs
$ echo "a b b c c c" > inputs/input.txt
Mapper
$ vim mapper.py
#!/usr/bin/env python
import sys
for l in sys.stdin:
for word in l.strip().split(): print '{0}\t1'.format(word)
Mapperは以下のようなものを出力する
a 1
b 1
b 1
c 1
c 1
c 1
Reducer
$ vim reducer.py
#!/usr/bin/env python
from collections import defaultdict
from operator import itemgetter
import sys
wordcount_dict = defaultdict(int)
for l in sys.stdin:
word, count = line.strip().split('\t')
wordcount_dict[word] += int(count)
for word, count in sorted(wordcount_dict.items(), key=itemgetter(0)):
print '{0}\t{1}'.format(word, count)
ReducerはMapperで出力されたそれぞれのwordを数え上げ,以下のようなものを出力する
a 1
b 2
c 3
Hadoop Streamingによる実行
いよいよ上記のMapper/ReducerをHadoop上で実行する
まず.Hadoop Streamingのためのjarファイルをダウンロードする
$ wget http://repo1.maven.org/maven2/org/apache/hadoop/hadoop-streaming/2.4.1/hadoop-streaming-2.4.1.jar
HDFS上にディレクトリを作成し,入力ファイルをのせる
(ローカル上のファイルととHDFS上のファイルがこっちゃにならないように注意)
$ hdfs dfs -mkdir /user
$ hdfs dfs -mkdir /user/vagrant
$ hdfs dfs -put inputs/input.txt /user/vagrant
実行すると指定した出力ディレクトリに結果が格納される
$ hadoop jar hadoop-streaming-2.4.1.jar -mapper mapper.py -reducer reducer.py -input /user/vagrant/input.txt -output outputs
$ hdfs dfs -cat /user/vagrant/outputs/part-00000
a 1
b 2
c 3