blog.katsuma.tv
楽天テクノロジーでLT&デモをしてきました
少し前の情報になるのですが、楽天テクノロジーカンファレンスでTokyo-JoggingネタのLT&デモを行ってきました。

当日は、WiiリモコンだけじゃなくてバランスWiiボードと、最近対応したヌンチャクのデモも行いました。やや古いネタではあるものの、大勢の方に実際に体験いただいて、アドバイスや意見などいただけて楽しい時間を過ごすことができました。
ただ1つ残念だったのはデモブースに常駐してないとダメだったので、他の方の発表がまったく聞けなかったこと。。楽しそうな話いっぱいあったのでそこが残念でした。と、思ったら発表内容はUstreamで残っているみたいなので、あとで確認したいとおもいます。
また、ありがたいことにデモ投票では3位(!)の結果をいただけることになりました。LTでは時間切れになっちゃって消化不良だったわけですが、デモで実際に体験いただけたのがよかったのかなとおもいます。
最後に、貴重な場所と機会を提供いただいた楽天株式会社 開発部の方々、どうもありがとうございました!
Hive QL(HQL)でORDER BYするときの注意点
HiveでのSQLことHQLの小ネタ。HQLでは基本的にSQLはほぼ完璧に利用できますが、たまにハマりポイントもあります。その1つが並び替えのORDER BY。
ORDER BYとSORT BY
HQLの文法的にORDER BYは有効ですが、実際は並び替えは行われません。(無視されているような感じ)Hiveでは代わりに「SORT BY [column]」を利用することになります。
ただし、ここでも罠があって、SORT BYは結果がreducerの数に依存します。(各reducerがsort処理をしたものがマージされるものになるので、全体としてはおかしな結果を得ることになります) 通常、reducerは複数走っているはずなので、結局SORT BYを利用してもORDER BYと同等の結果を得ることができません。
では、どうするか?と言うと明示的にreducerの数を1に指定してからSORT BYを実行すればOKです。
set mapred.reduce.tasks=1; SELECT key, value FROM table_name SORT BY key;
また、Hiveシェルを使わない場合は1ライナーで。
hive -e 'set mapred.reduce.tasks=1;SELECT key, value FROM table_name SORT BY key;'
HQL最適化
ただ、これだとreducerの数がボトルネックになって、SORT BYと条件文などが組合わさると途端に処理が遅くなることがあります。
なので、このような条件文付きSORT BYを実行するときは、
- 複数のreducerが条件文つきHQLでデータを整形し、中間テーブルAを作成
- 1つのreducerが、中間テーブルAを対象にSORT BYし、条件文は付けない
な、方針でHQLを分割して実行すると、高速に動作できるかと思います。
ちなみに、このテーブルを分ける(カラムを厳選した中間テーブルを作成する)のはHQLの最適化でかなり有効で、SORT BY以外でもかなり有効なケースが多くあります。このあたりの最適化の話は、また別途まとめたいと思います。
HiveのmetastoreをMySQLを使ってLocal Metastore形式で利用する
前回、紹介したHiveについての続き。
Hiveは内部で扱うメタデータを「metastore」というデータで保持しています。テーブルやパーティションなどの情報、またレコードが実際に保持されてある場所などのメタデータは全部このmetastoreにまとまっています。このmetastoreは、次の3種類の方法で保存することができます。
- Embeded metastore
- Local Metastore
- Remote Metastore
Embeded metastore
Embeded metastoreは主にテスト用途に利用されます。テスト用途なので、単一プロセスからの接続しか許可されていません。 そのため、コンソールを複数起動して、それぞれのコンソールから別のMap&Reduceを走らせる...なんてことができません。ただし、Hiveは初期設定がこのEmbededモードになっているので、特に設定することなくすぐに利用するメリットはあります。
また、metastoreはmetastoreディレクトリ(hive-default.xmlのhive.metastore.urisセクションに記述されています)内の 単一のファイルに保存されることになります。メタデータのバックアップをとりたいときは、このファイルをバックアップ対象にすればOKです。
Remote Metastore
1つ飛ばして、Remote Metastoreについて。Remote Metastoreはネットワーク越しにmetastoreを扱いたい場合における設定方法です。Hiveクライアントとデータを保存するMySQLの間にThriftサーバをproxyのような形で挟むことで実現しています。Thriftプロトコルを実現できていれば通信が可能なので、実際はJavaのHiveクライアントだけではなく、異なる言語によるクライアントからも接続が可能です。たとえばPHPでの例があるみたいです。
Local Metastore
Local Metastoreは、上で述べた2つの形式の間の位置づけのものです。 metastoreを単一ファイルで扱わずに、Remote Metastoreの形式にようにMySQLに保存することで、同一ホスト内から同時に複数のセッションを張ることができます。 このLocal Metastoreは簡単に実現できる割にすごく便利なので、紹介しておきます。
DBの設定
まず、MySQLでmetastoreを保存する適当なDB、およびその接続ユーザを定義します。たとえばrootで接続し、次のように定義します。
create database hive; grant all privileges on hive.* to user_hive@localhost identified by 'hive_password'; flush privileges;
この設定をHiveに反映させるために設定用xmlを編集します。
hive-site.xmlの編集
Hiveの初期設定はhive-default.xmlにまとまっていますが、この設定はhive-site.xmlという名前のファイルを同一ディレクトリに用意してあげることで上書きできます。 上記設定は次の項目を編集、または追加してあげることで反映されます。
<property> <name>hive.metastore.local</name> <value>true</value> <description>controls whether to connect to remove metastore server or open a new metastore server in Hive Client JVM</description> </property> <property> <name>javax.jdo.option.ConnectionURL</name> <value>jdbc:mysql://localhost/hive?createDatabaseIfNotExist=true</value> <description>JDBC connect string for a JDBC metastore</description> </property> <property> <name>javax.jdo.option.ConnectionDriverName</name> <value>com.mysql.jdbc.Driver</value> <description>Driver class name for a JDBC metastore</description> </property> <property> <name>javax.jdo.option.ConnectionUserName</name> <value>hive_user</value> <description>metastore mysql user</description> </property> <property> <name>javax.jdo.option.ConnectionPassword</name> <value>hive_password</value> <description>metastore mysql password</description> </property> <property> <name>hive.metastore.warehouse.dir</name> <value>/user/hive/warehouse</value> <description>location of default database for the warehouse</description> </property>
どのプロパティ名も名前からどんなものかは凡そ予想はつくと思います。 ちなみにhive.metastore.warehouse.dirはHDFS上でのファイルパスになるので、ここだけ要注意です。
xmlを編集したら、hiveクライアントのシェルを立ち上げ直します。 シェル自体はEmbeded Metastoreのときとメッセージ形式も変わらないですが、同時に複数のHQLを実行することができるので、格段に使いやすくなります。 Hiveの利用を考える場合は、Local Metastoreの利用は検討してみる価値はあるのかな、と思います。
まとめ
Hiveのmetastoreの保存形式について、また、Local Metastoreの形式について、その設定方法をまとめてみました。これらの保存方式については、公式サイトにもまとまっている資料があるので、一度目を通してみるとコンポーネント間の関係が理解しやすいかと思います。
Tokyo-JoggingをSnow Leopardに対応させました
- 2009-10-05 (月)
- tokyo-jogging
はてなブックマーク ( 0 )
delicious ( 0 )
Livedoor Clip ( 0 )
1年ぶりにTokyo-Joggingをupdateさせました。
さぼってたわけではないのですが、抜本的に通信方法を変更しようとあれこれ試行錯誤していた割に根本的に解決できない問題にぶちあたって途方に暮れていたので、路線変更で小さなバグfixとヌンチャク対応したものを一気にまとめあげてリリースしました。
Snow Leopard対応
Tokyo-Joggingでは内部でBluetoothの信号を扱うためにBlueCoveというライブラリを利用しているのですが、どうもこれがSnow Leopardではうまく動かない模様。原因を探っているとSnow Leopardでは64bit版のJavaがデフォルトで起動するのに対して、BlueCoveのバイナリが32bit用にビルドされていることが原因みたい。インストールされてあるJavaの設定を変更してもいのですが、プログラム単位で対応するためには起動オプションに
-d32
を追加すればいいみたいです。
また、BlueCoveを2.1.0にバージョン上げたら「java.lang.IllegalArgumentException: PCM values restricted by JAR82 to minimum 4097」な例外が出て、落ちてしまってたので、これも対応。起動オプションに
-Dbluecove.jsr82.psm_minimum_off=true
を付けてあげればいいみたいです。
これらの起動オプションは付属のstart-jogging.shに反映させてあるので、最新版にupdateした上で
./start-jogging.sh
で、起動することでSnow Leopard対応したオプション付きで起動できます。
Eclipseから起動する場合は、上記の2つのオプションをRun Configurationsの"VM arguments"に追記してあげればOKです。
ヌンチャク対応
地味なupdateですが、ヌンチャクを利用できるようにしました。Wiimoteを認識させた後にヌンチャクを接続するとアナログスティックで方向を変えることができます。(ヌンチャクを接続させたままWiimoteを認識させてもヌンチャクが認識されないので注意)
これで、左手にヌンチャク、右手にWiimoteなスタイルでスムーズに方向を変えつつどこでも走ることができますね!
今後はどうするの?
結構、作りっぱなしで放置しているように見られがちですが、実際はジョギング自身でやりたいことはもちろん、派生系でもまだまだやりたいことはあって、ゆっくりながらもupdateしていく予定です。あと、ここへきて外でしゃべらさせていただく機会も増えそうなので、そういうタイミングにあわせてupdateしていく予定です。(今回のupdateも実はその流れ)
SQL感覚でMap Reduce処理できるHiveについて

前回、JavaScriptでMap Reduceのコードが書けるHadoop Streamingについて紹介しました。 標準入出力さえサポートされてあれば、任意のコードでMap Reduuceの処理が書ける、というものでしたが、エンジニアはそもそも面倒くさがり。コードも書くのも面倒です。 と、いうわけで、今回はもうコードすら書かずにSQLライクでMap ReduceできるHiveというプロダクトについて、まとめたいと思います。
Hive
Hiveとは、簡単に言うとHadoop上で動作するRDBのようなものです。 HDFSなどの分散ファイルシステム上に存在するデータに対して、HiveQLというSQLライクな言語で操作できます。 で、面白いのがHiveQLの操作は基本的にMap Reduceのラッパーになっていること。 要するに、SELECT文実行すると裏でMap&Reduceのタスクが走り出して、分散処理されて結果を得ることができます。
そんなHiveは、もともとFacebookが開発を始めたものでした。2008年12月に、正式にHadoopプロジェクトにcontributeされて、いまはHiveの公式サイトもHadoopのサイト内でホスティングされてあります。
では、さっそく導入方法について確認してみます。
ビルド
Hiveのビルドに先立って、Hadoopをインストールしておきます。Hadoopのインストール方法は前回のエントリにも書いてある通りです。
Hiveのビルド自体は、Subevrsionからcheckoutして、antのタスクでビルドできる簡単なものです。1ヶ月ほど前のHiveは、patchを当てないとHadoop 0.20.0用にビルドできなかったのですが、最近のtrunkのものは特に何もせずにビルドできるようです。
svn co http://svn.apache.org/repos/asf/hadoop/hive/trunk hive cd hive ant -Dhadoop.version="0.20.0" package
ビルドできたらbuild/distを環境変数$HIVE_HOMEとでも設定しておきます。また、あわせて$HADOOP_HOMEも設定しておきましょう。
セットアップ
ビルドが成功したら、Hive用のデータ保存領域のセットアップをHDFS上で行います。Hadoopを起動した状態で次のようにセットアップします。
$HADOOP_HOME/bin/hadoop fs -mkdir /tmp $HADOOP_HOME/bin/hadoop fs -mkdir /user/hive/warehouse $HADOOP_HOME/bin/hadoop fs -chmod g+w /tmp $HADOOP_HOME/bin/hadoop fs -chmod g+w /user/hive/warehouse
すると、次のコマンドでHiveが起動されます。
$HIVE_HOME/bin/hive
テーブルの作成
では、早速Hiveで扱うテーブルを作成します。 テーブルの作成方法はMySQLなんかの一般的なRDBMSのそれとほぼ同等です。 たとえば、ユーザのアクセスログをまとめたログがあると仮定します。このログを保存するテーブルは最低限、ユーザIDとそのアクセス時間が保存されればOKなので、次のように定義できます。
CREATE TABLE user_logs(id INT, created_at STRING);
構文については見たまんまなので。理解しやすいかと思います。ちなみに、昔のバージョンだとカラムにDATETIMEなんかの型が定義できたようですが、現在はDATETIME型はなくなっているようです。(Hive/LanguageManual/DDL)
また、CSVなどの形式ですでに既存のログファイルがある場合、便利な機能があります。 Hiveではテーブル定義時に(CSVなどの)ある形式のデータを扱うことをあらかじめ指定しておくと、 CSV形式のログデータをそっくりそのままHiveのテーブルのレコードとしてロードさせることが可能です。
たとえばCSV形式のファイルを扱う場合、このような定義方法になります。
CREATE TABLE user_logs(id INT, created_at STRING) row format delimited fields terminated by ',' lines terminated by '\n';
この上で、次のようなコマンドで既存のログデータをロードできます。
LOAD DATA LOCAL INPATH '/path/to/log_20090907.csv' OVERWRITE INTO TABLE user_logs;
これで、CSVデータをHiveQLで扱えるようになりました。この時点でHDFS上にlog_20090907.csvは保存されています。/user/hive/warehouse/以下にテーブル名である「user_logs」ディレクトリが作成されてあり、該当ファイルが保存されてあります。
$ $HADOOP_HOME/bin/hadoop fs -ls /user/hive/warehouse/user_logs/ Found 1 items -rw-r--r-- 1 katsuma supergroup 17800731 2009-09-06 11:01 /user/hive/warehouse/user_logs/20090907.csv
では、ここで早速HiveQLを実行してみましょう。全件取得するときは一般的なSELECT文が利用できます。
SELECT * from user_logs;
ただし、このままだとローカルからデータをロードするだけで、ただのCSVのSQLラッパーでしかありません。 HiveQLが真価を発揮するのはいろいろ条件付けたSQLを発行してから。
ユニークユーザ数をHiveQLで算出
ここで、ユニークユーザ数(UU)を算出してみます。普通のMap Reduceの処理だと、IDごとのHashMapを作成してそのサイズからUUを算出することになりますが、HiveはSQLライクに算出することができます。つまり、こういうかんじ。
select count(distinct id) from user_logs;
すると、いきなりここからMap&Reduce処理が走り出します。 この、「SQL実行でMap&Reduceが実行される」という様子があまりにすごいので、最初これ見たときはかなりウケました。
Total MapReduce jobs = 1 Number of reduce tasks determined at compile time: 1 In order to change the average load for a reducer (in bytes): set hive.exec.reducers.bytes.per.reducer=In order to limit the maximum number of reducers: set hive.exec.reducers.max= In order to set a constant number of reducers: set mapred.reduce.tasks= Starting Job = job_200909061015_0001, Tracking URL = http://hdp-01:50030/jobdetails.jsp?jobid=job_200909061015_0001 Kill Command = /home/katsuma/hadoop/latest/bin/../bin/hadoop job -Dmapred.job.tracker=hdp-01:9001 -kill job_200909061015_0001 2009-09-06 10:41:27,049 map = 0%, reduce = 0% 2009-09-06 10:42:27,520 map = 5%, reduce = 0% 2009-09-06 10:42:28,540 map = 50%, reduce = 0% 2009-09-06 10:42:33,594 map = 69%, reduce = 0% 2009-09-06 10:42:34,610 map = 100%, reduce = 0% 2009-09-06 10:42:55,748 map = 100%, reduce = 100% Ended Job = job_200909061015_0001 OK 21509 Time taken: 105.58 seconds
すると、結果が取得できました。上記例だと21509ユーザという結果を取得できていますね。あまりに簡単すぎてウケます。
ちなみにHiveのコンソールはサイレントモードが用意されてあって、Hiveのコンソールを起動させることなく、普段のシェルからも実行させることができます。サイレンとモードは-Sオプションをつけて実行すればよく、
$HIVE_HOME/bin/hive -S -e 'select count(distinct id) from user_logs'
と、すれば、途中経過をすっとばして結果だけ取得できます。もちろんこれはバッチ処理など、Hiveコンソールを利用せずにいろんな値を取得させたいときに利用すればよさそうですね。
Partitionを設定
Hiveの特徴的な機能としてPartitionというものがあります。 これはテーブル自体にバージョン管理の概念を持たせるもので、ログ管理にすごく便利そうなものです。
たとえばデイリーのログファイルをHiveで管理したいと思ったときに、 毎日HDFS上にログファイルを転送することになるかと思いますが、Partitionを利用することで、 ログを追記でテーブルに書き込む(=ファイルにappendする)のではなく、 日付ごとに独立したファイルのままHDFSに保存することができます。 なので、「やっぱりHiveより素のMqp&Reduce書くようなフローに戻そう」と 思ったときに、Partitionを利用してロードしておいたほうが後々都合がよいかと思います。(あと、初期のHadoopはファイルのappendができない、という制約があったので、Hive側はこの制約を回避するために、このような概念を持たせて独立したファイルを透過的に見せるような仕様で実装したんじゃないかな?と推測しています)
Partition自身は、ふだんのテーブルにおけるカラムのように扱えるので、実際は特別に何か意識する必要はありません。Partition付きテーブルはこのように定義できます。
CREATE TABLE user_logs(id INT, created_at STRING) partitioned by(dt STRING) row format delimited fields terminated by ',' lines terminated by '\n';
この場合だと、dailyの情報をpartitionに持たせるために「dt」という名前のpartitionに設定させています。その上で、このテーブルにデータをロードする場合は次のようになります。
LOAD DATA LOCAL INPATH '/path/to/20090907.csv' OVERWRITE INTO TABLE user_logs partition (dt='20090907'); LOAD DATA LOCAL INPATH '/path/to/20090908.csv' OVERWRITE INTO TABLE user_logs partition (dt='20090908');
すると、HDFS上ではバージョン情報をもったまま保存されていることが確認できます。
$ $HADOOP_HOME/bin/hadoop fs -ls /user/hive/warehouse/user_logs/ Found 2 items drwxr-xr-x - katsuma supergroup 0 2009-09-06 11:18 /user/hive/warehouse/user_logs/dt=20090907 drwxr-xr-x - katsuma supergroup 0 2009-09-06 11:17 /user/hive/warehouse/user_logs/dt=20090908
これらのPartitionの情報は、もちろんHiveQL上で扱うことができて、たとえば上記例だと9月8日のUUを算出したい場合は
select count(distinct id) from user_logs where dt='20090908';
で、算出できます。また、9月7日以降のUUを算出したい場合だと
select count(distinct id) from user_logs where dt>='20090907';
な、風に書けます。直感的で便利ですよね。(この比較式はたぶん、JavaのString#compareToに従ってるんじゃないか、と推測)
まとめ
Hiveはまだ立ち上がったばっかりの若いプロジェクトですが、基本的なログ解析をするくらいの分には、かなり使えそうな印象です。上記例のように、基本的に元ファイルはそのままHDFS上に保存されているので、Hiveの不具合で何かおきた場合も自前のMap&Reduce処理に戻すことができるのも安心ですね。
今回は、あまり細かな説明までしませんでしたが、HiveQLはJoinやUnionなど割と複雑なテーブル間処理も行うことができます。このあたりも興味ある方は一度、オフィシャルのマニュアルに目を通してみてはいかがでしょうか?
Hadoop Streamingを利用してJavaScriptでMap Reduce
- 2009-08-02 (日)
- Java | Javascript
はてなブックマーク ( 26 )
delicious ( 14 )
Livedoor Clip ( 5 )
久々のBlog更新、というわけでリハビリがてらJavaScriptで軽く遊んでみたいと思います。
いま、巷で流行ってるMapReduceのオープンソース実装Hadoopは「Hadoop Streaming」という標準入出力でデータのやりとりができる仕組みを使って、 Hadoopの実装言語であるJavaにとらわれず、RubyやPerlなど他の言語でもMap+Reduceの処理ができることが1つのウリになっています。 で、僕たちwebエンジニアはみんなJavaScript大好きなので、「JavaScriptでもMap Reduceやりたい!」という流れになるのは必然です。 そこで、試行錯誤でいろいろ試してみると割とさっくり出来たのでそのメモを残しておきたいと思います。
環境の整備
Mac OSX上のVMWare FusionにCentOSの仮想マシンを2台立ち上げて、環境セットアップしました。以下のような手順で環境整備しました。
仮想HWの設定
仮想マシンのイメージファイルですが、僕は毎回thoughtpoliceのサイトのものを利用しています。ここからCentOS 5.3のイメージを落としてFusionでロード。
1つハマったのが、同じイメージをコピーして複数台起動すると、MACアドレスがかぶって同時に複数台の仮想マシンがNWに接続できない点。なので、仮想マシンを最初に起動させる前にMACアドレスの設定をしておくことをおすすめします。
MACアドレスは、vmxファイルのuuid.bios値をもとに自動生成されるようで、この値を最初から全仮想マシンでバラバラにしておけばOKです。と、いっても有効な値の範囲があるので、最後の1byte値だけズラしておけばOKだと思います。たとえば、上記サイトからイメージを取得した場合、uuid.bios値の最後は「7d」になっているので、僕はこの値を「7c」「7b」なんかにズラしておきました。(Fusion上から正規の方法?で、マシンをクローンする方法がよくわからなかったので、こういう強引な方法を取っています。綺麗な方法をご存知の方いらしたらぜひ教えてください!)
ネットワーク設定
/etc/hostsを設定して2台のマシンの名前解決。細かな話ですけど、ホスト名には「_(アンダーバー)」は使えないのに要注意。最初「hdp_01」みたいなホスト名にしていて、実行時エラーが出てドはまってたときに全然気づかなかった。
- 192.168.1.15 hdp-01
- 192.168.1.16 hdp-02
SSHの設定
マシンはそれぞれ自分自身(localhopst)に対して、パスフレーズなしでSSHでログインできるように公開鍵を設定しておきます。
- ssh-keygen -t rsa -P ""
- cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
- chmod 600 ~/.ssh/authorized_keys
また、MasterのマシンからSlaveのマシンに対しても同様の設定をしておきます。今回はMasterはhdp-01, Slaveはhdp-02という設定です。hdp-01上で、次の設定をします。
- cp ~/.ssh/id_rsa.pub ~/.ssh/id_rsa_master.pub
- scp ~/.ssh/id_rsa_master.pub hdp-02:/home/katsuma/.ssh/
- chmod 600 ~/.ssh/authorized_keys
また、hdp-02上で、次の設定をします。
- cat ~/.ssh/id_rsa_master.pub >> ~/.ssh/authorized_keys
これで、Masterからlocalhost, およびSlaveに対してパスフレーズなしでログインできることを確認しておきます。
セキュリティの設定
後でハマるのが面倒なので、iptablesやSELinuxは切っておきます。必要であれば適宜設定してください。
- sudo /etc/init.d/iptables off
- sudo /etc/sysconfig iptables off
- sudo vi /etc/sysconfig/selinux
- SELINUX=disabled に変更
Shellの設定
.bashrcなんかに以下の設定をしておくと便利です。僕はzsh派なので、.zshrcに記述しました。
# hadoop alias cdh='cd /home/katsuma/hadoop/latest/' alias dls='/home/katsuma/hadoop/latest/bin/hadoop dfs -ls' # ls alias drm='/home/katsuma/hadoop/latest/bin/hadoop dfs -rm' # rm alias dcat='/home/katsuma/hadoop/latest/bin/hadoop dfs -cat' # cat alias drmr='/home/katsuma/hadoop/latest/bin/hadoop dfs -rmr' # rm -r alias dmkdir='/home/katsuma/hadoop/latest/bin/hadoop dfs -mkdir' # mkdir alias dput='/home/katsuma/hadoop/latest/bin/hadoop dfs -put' # HDFS に転送 alias dget='/home/katsuma/hadoop/latest/bin/hadoop dfs -get' # HDFS から転送 alias dcpfl='/home/katsuma/hadoop/latest/bin/hadoop dfs -copyFromLocal' alias dcptl='/home/katsuma/hadoop/latest/bin/hadoop dfs -copyToLocal'
Javaのインストール
Sunのサイトに行き、 「Java SE Development Kit (JDK)」を選択して、インストーラをダウンロード。その後、以下の手順でインストールできます。
chmod +x jdk-6u7-linux-i586-rpm.bin sudo ./jdk-6u7-linux-i586-rpm.bin
Hadoopの整備
Hadoopのインストール
Hadoopは今日時点で最新の0.20.0を利用しました。インストール場所はどこでもいいのですが、僕はホームディレクトリ直下に専用のディレクトリ掘って、いろんなバージョン試せるようにこんな感じで設置してます。ここから最新版をDLが可能です。
- cd path/to/hadoop-0.20.0.tar.gz
- tar zxvf hadoop-0.20.0.tar.gz
- mv hadoop-0.20.0 ~/hadoop/
- ln -s hadoop-0.20.0 latest
他のバージョンを試したくなったら~/hadoop/以下に展開して、シンボリックリンクを付け直すとOKですね。
Hadoopの設定
特に凝ったことはしていません。全ノードともに同じ設定である必要があるので、Masterで設定しちゃって、それをrsyncで他のSlaveと同期をとるのがよいと思います。
conf/hadoop-env.sh
export JAVA_HOME=/usr/java/latest
conf/core-site.xml
<configuration>
<property>
<name>hadoop.tmp.dir</name>
<value>/home/${user.name}/hadoop/latest/tmp</value>
</property>
<property>
<name>fs.default.name</name>
<value>hdfs://hdp-01:9000</value>
</property>
</configuration>
conf/hdfs-site.xml
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>
conf/mapred-site.xml
<configuration>
<property>
<name>mapred.job.tracker</name>
<value>hdp-01:9001</value>
</property>
</configuration>
conf/masters
hdp-01
conf/slaves
hdp-02
ここまで設定できたら、masterのイメージをrsyncしておきましょう。
cd ~/hadoop/ rsync -r hadoop-0.20.0/ hdp-02:/home/katsuma/hadoop/hadoop-0.20.0
SpiderMonkeyの導入
さて、やっとHadoopの設定が終わったので、次にJavaScriptの処理系の導入です。 Hadoop Streamingは前述の通り、標準入出力の仕掛けを使って実現されているので、さすがにブラウザの処理系をそのまま利用することができません。
そこで、FirefoxのJavaScriptのエンジンであるSpiderMonkeyを利用することにします。 SpiderMonkeyはファイルを入力としても処理できるし、irbのように対話型シェルとしても利用できるJavaScriptの処理系です。また、ブラウザを利用しないので、標準出力関数print、標準入力関数readlineが実装されてあるので、今回はこれを利用すればうまくいきそうです。
では、SpiderMonkeyを各ノードに導入します。これも最新版を導入します。あらかじめ、make, gccあたりをyumで入れておきましょう。
- wget http://ftp.mozilla.org/pub/mozilla.org/js/js-1.8.0-rc1.tar.gz
- tar zxf js-1.8.0-rc1.tar.gz
- cd js/src
- BUILD_OPT=1 make -f Makefile.ref
- sudo install -m 755 Linux_All_OPT.OBJ/js /usr/local/bin
Map, Reduce処理のJavaScriptを記述する。
では、Map, Reduceそれぞれの処理をJavaScriptで書きます。今回はサンプルとしてよくある、ワードカウントの処理を行ってみます。
map.js
map.jsは標準入力された文章を半角スペースごとに分けて、CSVの形式に整形します。JavaScript1.7相当の機能が利用できるので、Array.prototype.forEachが利用できることもポイントです。
#!/usr/local/bin/js
var line="";
while ((line = readline())!= null){
var words = line.split(" ");
words.forEach(function(w){
print(w + "," + 1);
});
}
reduce.js
reduce.jsは、map処理されたCSV形式の入力に対して、counterオブジェクトで各単語をカウントしていきます。
#!/usr/local/bin/js
var counter = {};
var line = "";
while ((line = readline()) != null) {
var words = line.split(",");
var word = words[0]
if(!counter[word]) counter[word] = 1;
else counter[word]++;
}
for(var k in counter){
print(k + ":" + counter[k]);
}