Stellaqua - TOMの技術日記 このページをアンテナに追加 RSSフィード

2010年08月08日

[]Amazon EC2上のHadoopMeCabを使えるようにしてみた…い

最近すっかり"Webサービスを作ってみた"系の記事ばっかりでしたが、今回は久々にEC2上でのHadoopのお話。

以前の記事EC2上でHadoopを動かした時は、MeCabデフォルトで入っていなかったので、事前に自宅サーバ上で分かち書きしたデータを使っていました。

ただ、日本語処理するならMeCabはほぼ必須だろうし、せっかくならMeCabが使える状態でMapReduceしたいのが人情ってもんです。

という訳で、EC2上のHadoopを使って、MeCabを利用した日本語文章の単語カウントMapReduceに挑戦してみました。

基本的な方向性としては以下の通りです。

  1. EC2上でインスタンス起動。
  2. 起動したインスタンスMeCabインストール
  3. AMIとして保存。
  4. Hadoopを起動する時にこのAMIが使われるようにする。

で、実際にやってみた訳なんですが、結論から言うとうまくいきませんでした…。

AMIを保存して、そのAMIが使われるようにするところまではできたんですが、そのインスタンスログインできない状態になってしまって、実際にMeCabを利用したMapReduceを動かすところまでできていません。

という事で途中までではありますが、やってみた手順を書き残しておきたいと思います。

以下、"[local]$"がローカルのサーバ上、"[ec2]$"がEC2上でのプロンプトを表す事とします。

EC2上でHadoopを起動してログインする

まずはEC2上にインスタンスを1つ起動させてログインします。

[local]$ hadoop-ec2 launch-master hadoop-test 1
[local]$ scp -i stellaqua.id *.pem root@ec2-XXX-XXX-XXX-XXX.compute-1.amazonaws.com:/mnt
[local]$ hadoop-ec2 login hadoop-test

タイムゾーンを変更する

今回(というか毎度)参考にさせて頂いているid:rx7さんの記事によるとタイムゾーンの設定をしておいた方がよいとの事なので、ついでにここでタイムゾーンの変更をしておきます。

[ec2]$ cp /usr/share/zoneinfo/Japan /etc/localtime
cp: `/etc/localtime' を上書きしてもよろしいですか(yes/no)? y

MeCabインストールする

続いて本命のMeCabインストールします。

[ec2]$ yum -y update
[ec2]$ yum -y install mecab mecab-devel mecab-ipadic
[ec2]$ echo 'こんにちは' | mecab
こんにちは      感動詞,*,*,*,*,*,こんにちは,コンニチハ,コンニチワ
EOS

ちゃんとMeCabが使えるようになりましたね!

EC2root権限が与えられるので、yumで必要なものをガシガシ入れてしまうとよいですね。

AMIを作成してS3にアップロードする

AMI作成の手順については、毎度お世話になっているid:rx7さんの記事を参考にさせて頂きました。

Amazon EC2/S3を使ってみた - 3.EC2起動後〜AMI作成 - 元RX-7乗りの適当な日々

[ec2]$ cd /mnt/
[ec2]$ ec2-bundle-vol -d /mnt --privatekey pk-XXXX.pem --cert cert-XXXX.pem --user XXXX-XXXX-XXXX -p hadoop-0.17.0-i386 -r i386
[ec2]$ ec2-upload-bundle --bucket stellaqua/ec2_images/hadoop_mecab --manifest hadoop-0.17.0-i386.manifest.xml --access-key XXXX --secret-key XXXX
[ec2]$ exit
[local]$ hadoop-ec2 terminate-cluster hadoop-test
[local]$ ec2-register stellaqua/ec2_images/hadoop_mecab/hadoop-0.17.0-i386.manifest.xml
IMAGE   ami-XXXX
[local]$ vi hadoop-ec2-env.sh
→"S3_BUCKET=hadoop-ec2-images"となっているところを、上記で指定したバケットに変える

ポイントは、manifestファイルをHadoopのバージョンとアーキテクチャの名前を付けて保存する事と、設定ファイルでAMIを保存したバケットを設定しておく事ですね。

これで、hadoop-ec2コマンドでHadoopを起動する時に、登録したAMIが使われるようになるはずです。

早速、クラスタを起動してログインしてみます。

[local]$ hadoop-ec2 launch-cluster hadoop-test 1
[local]$ hadoop-ec2 login hadoop-test

これでログインできるはずなんですが、なぜかログインしに行ったままウンともスンとも言わない状態になってしまいます。

"Permission denied"とも言われないし、netstatで見るとESTABLISHEDにはなっているので、接続自体はできているとは思うのですが…。その後も色々試してはみたんですが、現時点でお手上げ状態になっています…。

また折を見て試してみて、うまくいったら記事にしようかなと思います。

2010年04月04日

[][]Amazon Elastic MapReduceHadoop Streamingする時にライブラリをrequireする方法

ちょっと元データの件数が大量にある処理をしたいという要件があって、普通に逐次処理していくと恐ろしく時間が掛かるので、「こんな時こそHadoop!」って事で、久々にHadoopをいじくっていました。

ただ、自宅サーバでやろうとすると、いくら分散処理できるとは言っても結局処理するのは物理的には1台な訳で、メモリを使い切ってスワップしまくってウンともスンとも言わなくなってしまうという、とっても悲しい状況になってしまいました。

「そんな時はAmazon先生にお願い!」って事で、Amazon Elastic MapReduceを試していたんですが、ちょっとハマってしまったところがあったので、備忘録がてら記事にしようかと思います。

Mapper/Reducer以外のファイルが使えない!

以前にAmazon Elastic MapReduceを試した時は、MapperとReducerが1ファイルだけの簡単な処理でやってみただけでした。

ただ、今回はもうちょっと処理が複雑で、Mapperから別ファイルをrequireしたり、serializeしてファイルに書き出しておいたデータを使ったりするものでした。

CLIでAmazon Elastic MapReduceを実行する場合、一番簡単な書き方で以下のような形になります。

$ elastic-mapreduce --create --stream \
--input s3n://stellaqua/mapreduce/inputs \
--output s3n://stellaqua/mapreduce/outputs \
--mapper s3n://stellaqua/mapreduce/map.php \
--reducer s3n://stellaqua/mapreduce/reduce.php

Mapper/ReducerはS3に置いたものを指定する事ができて、初期化時に勝手にS3から読み込んできてHadoopの実行ノードに転送して実行してくれます。

しかし、Mapper/Reducer以外のファイルは例えS3上に置いておいても、勝手に読み込んだりはしれくれないので、Mapperとかでrequireしようとしても、読み込む事ができません。

で、どうすればいいか途方に暮れつつ調べていたら、以下のサイトさんで解決方法を見い出す事ができました。

Soffritto::Journal

"--cache-archive"というオプションを使う事で、Hadoop初期化時に各ノードに転送する事ができるようです。

まずMapper/Reducer以外の、ライブラリなどのファイルを一つのディレクトリにまとめておいて、jarコマンドでアーカイブします。

$ jar cvf lib.jar -C lib/ .

Mapper/Reducerでrequireしたりする時は、相対パスで書いておきます。

<?php
require 'lib/Hogeclass.php';
?>

後はElastic MapReduceを実行する時に、"--cache-archive"オプションを使ってjarファイルを指定してやればオッケーです。

$ elastic-mapreduce --create --stream \
--input s3n://stellaqua/inputs/input.dat \
--output s3n://stellaqua/outputs \
--mapper s3n://stellaqua/map.php \
--reducer s3n://stellaqua/reduce.php \
--cache-archive s3n://stellaqua/lib.jar#lib \
--num-instances 4 \
--log-uri s3n://stellaqua/logs

ついでながら、上記では、起動インスタンス数とログ出力先の指定もしています。

うまく使えば、ローカルにPEARを展開したものをアーカイブして、Hadoop Streamingから利用するとかできそうですね。

という訳で実際にElastic MapReduce上で処理させてみたんですが、またしても問題が…。

処理が成功しようが失敗しようが料金が掛かる
1回分の料金が安いとは言え、何度も失敗しているとその分料金がかさんでいくのは微妙に痛いです…。
どこまで処理が進んだか分かりづらい
一応、AWS Management Console上にデバッグコンソールというのもあってsyslogが見れるんですが、ちゃんと処理が進んでいるのかどうか微妙に分かりづらいです…。

…という事で、何回もの失敗を乗り越えてやっとまともに動くようになったので、1時間ほど動かしてみたんですが、ちゃんと処理が進んでいるのかどうかよく分からなかったので止めてしまいました。Elastic MapReduceを使いこなすには、もうちょっと研究が必要そうですね…。

2009年04月04日

[]Amazon Elastic MapReducePHPも使えるか試してみた

AmazonがEC2上でHadoopによるMapReduceを実行できるサービスを出してきたようですね。

Amazon EMR ? Amazon Web Services

no title

前回の記事では、EC2上でHadoop用のインスタンスを自分で動作させて、ファイルの転送も事前にやって…と色々下準備が必要だったんですが、このサービスを使えばローカルの環境からいきなりコマンド一発でMapReduceを実行する事ができるようになりました。

そんなのを聞いたらやってみたくなるよね、という事で、PHPのMapper/Reducerが使えるか試してみたかったので、早速使ってみる事にしました。

多段階のMapReduceは面倒なので、今回は以前の記事で使った単語カウントのMapper/Reducerを使う事にします。

事前準備

ほとんど準備は必要ないとはいえ、以下のような準備はしておく必要があります。

  • S3のSignUp
  • EC2のSignUp
  • ElasticMapReduceのSignUp
  • S3への必要なファイル(入力ファイル/Mapper/Reducer)のアップロード

この辺の手順については割愛させて頂きます。

実行するには、Webベースのコンソールから実行する方法もあるんですが、今回はコマンドベースのものを使用しました。コマンドラインツールとして、Rubyのクライアントが用意されていて、以下のURLからダウンロードできます。

404 Not Found

ダウンロードしたZIPファイルを展開して、展開したディレクトリにパスを通せばOK!

ちなみに、"credentials.json"というファイルを作ってアクセスキーなどの設定を書いておけば、コマンド実行時にいちいちアクセスキーとかの設定を書かなくて済むようになるようですね。

れっつMapReduce!

ちょっと試行錯誤はあったんですが、結果的に以下のコマンドでいけました。

$ elastic-mapreduce --create --stream \
--input s3n://stellaqua/mapreduce/inputs \
--output s3n://stellaqua/mapreduce/outputs \
--mapper s3n://stellaqua/mapreduce/map.php \
--reducer s3n://stellaqua/mapreduce/reduce.php

アウトプットのディレクトリは自動で作られるようなので、事前に作っておかない状態で実行しました。inputsは事前に作って、中に空白区切りのテキストファイルを放り込んでおきました。

実行すると、"Created job flow j-1NID8F5O07YPY"というような簡素な1行だけの出力がされて、ジョブの実行が開始されます。ジョブの状態を確認するには以下のコマンドを実行します。

$ elastic-mapreduce --list

もっと詳細を確認したい場合は、以下のようにジョブIDを指定してdescribeオプションでコマンドを実行します。

$ elastic-mapreduce --describe --jobflow j-1NID8F5O07YPY

実行結果は、outputsで指定したS3のバケットに入るので、後は適当なS3クライアントでダウンロードしてくればOKですね。

ざっと見てみた感じでは、問題なく単語カウントができていたようでした。

感想

感覚としては、やっぱりどうしても起動のオーバーヘッドが大きいな〜、と思ってしまいますね。まぁ、実際の処理が一瞬で終わるようなものをわざわざMapReduceを使ってやっているからそう感じてしまうだけで、元から数時間掛かるような処理だったら、たかだか数分ぐらいの起動時間なんて大したことないんでしょうけどね。

使用感という意味では、前回やったようなEC2インスタンスの起動・停止さえやらなくてよくて、ほとんどコマンド一発叩くだけ、という感じなのでものすごいお手軽ですね。

ちょっと複雑な事をやろうと思うとそれなりに知識が必要で難しいんですが、例えば単純なアクセスログ解析とか、簡単な処理でもデータ量が膨大になるような時にはかなり有用かもしれませんね。

2009年03月27日

[][]Amazon EC2上でHadoop Streamingによる分散処理をPHPでやってみた

あいかわらずHadoopStreamingが楽しくてやっているんですが、そろそろ自宅サーバ1台だけで処理するのは限界っぽいので、AmazonEC2上でHadoopStreamingにチャレンジしてみました。

AmazonEC2の導入に関しては、以下のまとめ記事からのリンクを参照しまくりさせてもらいました。多謝。m(_ _)m

Amazon EC2/S3を使ってみた - まとめ (Amazon Web Services関連エントリ目次) - 元RX-7乗りの適当な日々

そして、AmazonEC2上でのHadoopStreamingの動かし方に関しては、以下の記事を参考にさせてもらいました。

hadoop-ec2でアクセス解析してみたよ! - soffritto::journal

階層的クラスタリングをEC2上で動かしてみる

とりあえずテストという事で、前回の記事で作成した階層的クラスタリングのMapReduceを、EC2上で動かしてみようと思います。

EC2のセットアップに関しては上で紹介した記事が非常によくまとまっているので、ここでは手順等は省略。

今回はEC2への接続周りはセットアップ済みという前提で、自宅のサーバ上からどうやってEC2上のHadoopを動かすかという辺りの手順を書いてみたいと思います。ただ、やっている事は上で紹介したもう一つの記事とほとんど同じなので、手順もほとんど同じになっています。

Hadoop用のマシンイメージにPHPが含まれているか心配だったんですが、ちゃんと入っていました。*1

以下、"[local]$"のプロンプトは自宅サーバ上、"[EC2]$"のプロンプトはEC2上でのコマンドを表します。

EC2上でHadoopを起動する

[local]$ hadoop-ec2 launch-cluster hadoop-test 2

これだけです…。たったこれだけで、EC2上に仮想のマシンが用意されて、Hadoopが使えるようになります。素晴らしい〜。

EC2上に必要なファイルをアップロードする

[local]$ hadoop-ec2 push hadoop-test reduce.php
[local]$ hadoop-ec2 push hadoop-test reduce2.php
[local]$ hadoop-ec2 push hadoop-test Reducer.php
[local]$ hadoop-ec2 push hadoop-test Iterator.php
[local]$ hadoop-ec2 push hadoop-test words.txt
[local]$ hadoop-ec2 push hadoop-test hcluster.sh

前回はMapperで形態素解析して入力データを作っていたんですが、残念ながらEC2上のマシンイメージにMeCabが入ってなかったので、今回は事前にMapper処理済みのデータを用意する事にしました。

あと、拙作のPHP-Hadoop-Streaming-Frontendディレクトリ階層を付けずにフラットな状態でアップロードするようにしました。ファイルアップした後にディレクトリ階層化してもいいんですが、面倒なので…。

れっつ HadoopStreaming on EC2!

これで準備OK! 早速動かしてみましょう。

[local]$ hadoop-ec2 login hadoop-test
[EC2]$ mkdir inputs
[EC2]$ mkdir outputs
[EC2]$ cp -i words.txt inputs
[EC2]$ ./hcluster.sh

非常にサクサク動きますねぇ。処理時間はだいたい30分ぐらいでした。今回のお題はデータ量も計算量もそんなに大きくないので、自宅サーバでやった場合とあんまり違いは出なかったですね。(^^;ゞ

EC2上のインスタンスを停止する

最後に忘れずにEC2上のインスタンスを停止しておきます。これを忘れると、延々と課金され続けてしまうので注意…。

[EC2]$ exit
[local]$ hadoop-ec2 terminate-cluster hadoop-test

感想

実はやってみるまでは「EC2って面白そうだけどお金も掛かるし、何か設定とか面倒臭そうだよなぁ…。」と思っていたんですが、正直なところそこまで面倒でもないし、何より安い!

1台/h=0.10$≒9.88337616円(執筆時点)なので、1台を24時間ずっと使っていたとしても1日240円もしないという…。今、利用状況を見てみたら、何だかんだで色々遊ぶのに使って6h…その他、データ転送代などがちょこちょこ入って、占めて0.65$=63.8695097円也…。

膨大な量のデータを処理したい時は、事前にMapReduceを作っておいて、EC2上で計算させる…っていう使い方をすれば、そんなにコストも掛からないし、かなり使えそうです。

問題は、いかにデータ処理の計算をMapReduceできる形に落とすか…ですね…。この辺り、自分自身は専門分野ではないし、ネット上でもなかなか情報がなくてつらいところなんですが…やっていて楽しいところではあるので、集合知プログラミングシリーズの記事の中で、また少しずつやっていこうと思っています。

*1:バージョンは確認し忘れた…。

2009年03月17日

[][]何番煎じか分からないけど集合知プログラミングをPHPでやってみた その7「階層的クラスタリングによりグループを見つけ出す」

前回は話だけで終わってしまったので、今回はソースコード中心です。

アイテム同士の距離の計算に必要な情報を出力するReducerを実装する

という訳で早速ですが、前回延々と話をしていた事をReducerに実装します。

#!/usr/bin/php
<?php
require_once(dirname(dirname(__FILE__)).'/lib/HadoopStreaming/Reducer.php');

class Reducer extends HadoopStreaming_Reducer
{
    public function reduce ( $key, $values )
    {
        $wordcount = array();
        while ( $values->has_next_value ) {
            list($id, $count) = explode(':', $values->current_value);
            $wordcount[$id]++;
            $entrycount[$id] = $count > 0 ? $count : 1;
            $values->next();
        }
        if ( count($wordcount) >= 2 ) {
            $keys = array_keys($wordcount);
            for ( $id1=0; $id1<count($keys)-1; $id1++ ) {
                for ( $id2=$id1+1; $id2<count($keys); $id2++ ) {
                    $emitkey = $keys[$id1].':'.$keys[$id2];
                    $wc1 = $wordcount[$keys[$id1]] / $entrycount[$keys[$id1]];
                    $wc2 = $wordcount[$keys[$id2]] / $entrycount[$keys[$id2]];
                    $sum1 = $wc1;
                    $sum2 = $wc2;
                    $pow1 = pow($wc1, 2);
                    $pow2 = pow($wc2, 2);
                    $mul = $wc1 * $wc2;
                    $this->emit($emitkey, "sum1:${sum1}");
                    $this->emit($emitkey, "sum2:${sum2}");
                    $this->emit($emitkey, "pow1:${pow1}");
                    $this->emit($emitkey, "pow2:${pow2}");
                    $this->emit($emitkey, "mul:${mul}");
                    $this->emit($emitkey, "count:1");
                }
            }
        }
    }
}

$reducer = new Reducer();
$reducer->run();
?>

Reducerには、"単語=>[エントリID,エントリID,…]"という形でデータが渡ってくるので、一旦、$wordcountという配列でエントリID毎に出現単語数を集計しています。

これで$wordcountのキーには、この単語が現れるエントリのIDが並ぶので、このエントリID同士の総当りをループさせて、必要な情報を計算していきます。

なお、"クラスタ化した時は各アイテムの中間の位置を新しいクラスタの位置にする"という処理を実現する為に、各クラスタに含まれるエントリの数が入力データに含まれるようにしていて、各エントリの単語数($wc1,$wc2)は各クラスタ内のエントリ数($entrycount)で割った値になるようにしています。

計算した値は、後でもう1回Reducerを掛けて集計するので、ここではkeyを付けてどんどんemitしていくだけにします。

このReducerを掛けると、以下のように、2つのエントリ同士の計算に必要な情報がバラバラと出力されます。

:
0:13	count:1
0:13	count:1
0:13	mul:1
0:13	mul:10
0:13	pow1:1
0:13	pow1:4
0:13	pow2:1
0:13	pow2:25
0:13	sum1:1
0:13	sum1:2
0:13	sum2:1
0:13	sum2:5
:

アイテム同士の距離を計算して出力するReducerを実装する

続いて、先ほど得られた出力を使って、各アイテム同士の距離を計算して出力するReducerを実装します。

#!/usr/bin/php
<?php
require_once(dirname(dirname(__FILE__)).'/lib/HadoopStreaming/Reducer.php');

class Reducer extends HadoopStreaming_Reducer
{
    public function reduce ( $key, $values )
    {
        $wc = array();
        while ( $values->has_next_value ) {
            list($target, $value) = explode(':', $values->current_value);
            $wc[$target] += $value;
            $values->next();
        }
        $num = $wc['mul'] - ( $wc['sum1'] * $wc['sum2'] / $wc['count'] );
        $den = sqrt( ($wc['pow1'] - pow($wc['sum1'], 2) / $wc['count'])
                    * ($wc['pow2'] - pow($wc['sum2'], 2) / $wc['count']) );
        $result = ( $den === 0.0 ) ? 0.0 : ( 1.0 - $num / $den );
        $this->emit($key, $result);
    }
}

$reducer = new Reducer();
$reducer->run();
?>

これで、はてブのHotEntryから取得したデータを使って、どのエントリ同士が似ているかを計算する事ができるようになりました。

似たアイテム同士をクラスタにして後は同じ事の繰返し

ここまで来たら次は、一番距離が近かったエントリ同士を1つのクラスタとしてくっつけて、後はクラスタが1つになるまで繰返しMapReduceを掛けていけば、階層的クラスタリングの完成です。

…となるんですが、HadoopStreamingを使って複数のMapper/Reducerを組み合わせて処理させる方法が分からなかったので、仕方なくシェルスクリプトで適宜中間ファイルを処理しながら、MapReduceを繰り返して実行するようにしました。

という事で、かなり無理矢理感はあるんですが…結果的に、全体の処理をループする部分は、次のようなスクリプトになりました。

#!/bin/sh
dfs='/home/hadoop/hadoop-0.18.3/bin/hadoop dfs'
hadoop='/home/hadoop/hadoop-0.18.3/bin/hadoop jar /home/hadoop/hadoop-0.18.3/contrib/streaming/hadoop-0.18.3-streaming.jar'

$dfs -rmr outputs
$dfs -rm inputs/hotentry_descriptions.txt
$dfs -put ~/inputs/hotentry_descriptions.txt inputs
$hadoop -input inputs/hotentry_descriptions.txt -output outputs -mapper ~/bin/mapreduce/php/hcluster/map.php
rm -f ~/outputs/part-*
$dfs -get outputs/part-* ~/outputs
cat ~/outputs/part-* >~/inputs/words.txt
$dfs -rm inputs/words.txt
$dfs -put ~/inputs/words.txt inputs/words.txt

cid=1
>~/outputs/clusters.txt
cc=`cut -f 2 ~/inputs/words.txt | cut -d ':' -f 1 | sort | uniq | wc -l`

while [ $cc -gt 1 ];
do
    $dfs -rmr outputs
    $hadoop -input inputs/words.txt -output outputs -mapper cat -reducer ~/bin/mapreduce/php/hcluster/reduce.php
    $dfs -rm inputs/part-*
    $dfs -mv outputs/part-* inputs
    $dfs -rmr outputs
    $hadoop -input inputs/part-* -output outputs -mapper cat -reducer ~/bin/mapreduce/php/hcluster/reduce2.php

    closest=`$dfs -cat outputs/part-* | sort -nk 2 | head -1 | cut -f 1`
    id1=`echo $closest | cut -d ':' -f 1`
    id2=`echo $closest | cut -d ':' -f 2`
    if [ $id1 -lt 0 ]; then
        c1=`cut -f 2 ~/inputs/words.txt|grep '\'$id1|head -1|cut -d ':' -f 2`
    else
        c1=1
    fi
    if [ $id2 -lt 0 ]; then
        c2=`cut -f 2 ~/inputs/words.txt|grep '\'$id2|head -1|cut -d ':' -f 2`
    else
        c2=1
    fi
    ec=`expr $c1 + $c2`
    echo "-$cid     $closest">>~/outputs/clusters.txt
    sed 's/\t'$id1'\(:.*$\|$\)/\t-'$cid':'$ec'/' ~/inputs/words.txt | sed 's/\t'$id2'\(:.*$\|$\)/\t-'$cid':'$ec'/' >~/inputs/words.txt_tmp
    mv -f ~/inputs/words.txt_tmp ~/inputs/words.txt
    $dfs -rm inputs/words.txt
    $dfs -put ~/inputs/words.txt inputs/words.txt
    cid=`expr $cid + 1`
    cc=`cut -f 2 ~/inputs/words.txt | cut -d ':' -f 1 | sort | uniq | wc -l`
    echo 'クラスタ数:'$cc
done

最初に1回Mapperを使って単語リストを作成した後に、クラスタの数が1つになるまでループしながら繰返し2種類のReducerを実行するようにしています。

結果発表

実行結果はテキストとして出力しているので、このままだとどんな結果なのかよく分かりません。

元書では、ノードをピラミッドの形で並べて表示する"デンドログラム"というグラフの形式で結果を確認するようになっていて、グラフィックとして出力するプログラムも作っているんですが、そんなのまで作るのは面倒なので、今回はGraphvizを使ってグラフを生成するようにしました。

得られた結果をdot形式に直して、最初に取得したタイトルを埋め込んで、デンドログラムっぽい形で出力させてみました。

f:id:stellaqua:20090317220147p:image:w450

今回は、HotEntryの最初のページ(30件)が対象で、なおかつRSSの概要から単語を拾っているだけなので、正直なところあんまりそれっぽい結果とは言えないかもしれないですね。

まぁ、今回の一番の目的は、"いかにMapReduce的に実装するか"だったので、自分的にその目的は果たす事ができたのでよしとしたいと思います。

次回は?

次回は、別のアルゴリズム(K平均法)によるクラスタリングを、またMapReduceを使って挑戦していきたいと思います。