R&Dトレンドレポート

第13回 Hadoopおまけ編─“Jadoop”作ってみました

この記事を読むのに必要な時間:およそ 4 分

処理の流れと実装

以下はワードカウントのためのJadoopの実装となります。

入力データ

1, wakimoto takeshi
2, wakimoto hajime 
3, beat takeshi
4, neet kiyoshi

キーは行番号,バリューは行の文字列データとします。最終的に以下のような結果を期待します。

出力データ

hajime,1
kiyoshi,1
takeshi,2
beet,1
neet,1
wakimoto,2

それぞれの単語と単語の出現個数がキーとバリューで表現されています。

コンストラクタ

今回はJadoop.jsというjsを作成し,jqueryと組み合わせて動作させるようにしてみました。コンストラクタではサーバサイドの各種CGIを定義し,Jadoopオブジェクトを生成します。

 26   var j = new Jadoop("wordcount",  //このクライアントで処理したい種別
 34       "http://localhost/test-cgi/jadoop/cgi/mapGet.cgi", // mapするデータの取得
 35       "http://localhost/test-cgi/jadoop/cgi/mapPost.cgi", // map関数の戻り値をポストする
 36       "http://localhost/test-cgi/jadoop/cgi/redGet.cgi", // reduceするデータの取得
 37       "http://localhost/test-cgi/jadoop/cgi/redPost.cgi",  // reduce関数の戻り値をポストする
 38       "http://localhost/test-cgi/jadoop/cgi/getTask.cgi" // 種別ごとのred, mapするタスクのIDを取得
 39       );
 40 

ここではwordcoutという種別で各種入出力のためのCGIを定義しています。

Map関数

コンストラクタで定義したmapするデータの取得CGIで得られるデータのキーとバリューのペアごとに呼び出される関数です。この例では,キーに行番号,バリューに文字列が与えられます。

 42   // map関数
 43   var wordcoundMap = function(key, val)
 44   {
 45     var res = new Array();
 46 
 47     // 分かち書きライブラリ
 48     var segmenter = new TinySegmenter();         // インスタンス生成
 49     var segs = segmenter.segment(val);
 50 
 51     $.each(segs, function(i, a){
 52         res.push([a,1]);
 53         });
 54 
 55     if ( segs.length == 0 )
 56     {
 57       res.push(["",1]);
 58     }
 59 
 60     return res;
 61   }

ここではTynySegmenterという分かち書きのjsライブラリを使用しています。与えた文字列をこのライブラリで分かち書きし,[単語, 1]という配列を配列にpushしています(2重配列を生成している⁠⁠。ここでは行番号をキーとして渡していますが,今回の処理では不要ですので無視しています。

1行目を例にすると,

  • [[wakimoto,1],[takeshi, 1]]

という配列を生成していることになります。

mapするデータ全てに処理を適用後,2重配列はマージされサーバに転送されます(Map関数の戻り値をポストするCGIを使用する⁠⁠。これがMap処理で分割されたデータすべてにMap処理が実行されます。

Reduce関数

Reduce関数はMap処理が全て済んでから呼び出されます。(サーバサイドで全てのMap処理が終わった事を検知してReduce用のデータをダウンロードさせる)

reduceするデータの取得で得られたデータはキーごとにグルーピングされ,バリューのリストを生成しています。この例ではキーtakeshiに関しては,以下のようなデータが与えられます。

  • [takeshi, [1,1]]
 63   // reduce関数
 64   function wordcoundRed(key, val)
 65   {
 66     var res = new Array();
 67 
 68     var vals = val.length;
 69 
 70     return [key, vals];
 71   }

この処理ではキーごとの出現回数をカウントするだけなので単純にvalのlengthを取得し,単語と件数の配列を返しています。

全てのreduceするデータの処理が終わった後,サーバに転送され結果として保存されます。

Jadoopへのセットと実行

Jadoopオブジェクトにmapper, reducerとして登録し,定期的に実行させます。

 74   j.setMap(wordcoundMap);
 75   j.setRed(wordcoundRed);

 80   setInterval('j.doMapRed()', 10000);

この例では10秒ごとにmapデータのダウンロード,reduceデータのダウンロードを行い,データがあればwordcountMap(), wordcountRed()が実行され,結果をサーバに返すようになっています。

このようなjsを自分のWebページに仕込むことで,不特定多数のクライアントPCに対して分散処理を行わせることが可能となります。

著者プロフィール

脇本武士(わきもとたけし)

都内中小IT企業(メイサンソフト(株))に所属。某大手自動車会社でのシステム開発,運用を経て,現在は研究開発部署に席をお借りしています。DB周りの保守サポート,ウェブ技術開発を主に手がけてきました。現在は大規模計算フレームワークの活用とKVSに注目しています。普段はOS Xを使用していますが一番よく使うアプリはTerminalです(笑)。

R&Dトレンドレポート(てくらぼ)