MapReduce::LiteによるWordCount

http://codezine.jp/article/detail/2485
こちらのサイトで紹介されているHadoopのサンプルプログラム
WordCount(WordCount.java)と同じ事を行なうものを、
MapReduce::Liteで書いてみた。
WordCountはスペース区切りで並べられた単語を数えるプログラムである。

入力データ:
hoge hoge hoge fuga fuga hoge uho
 

出力データ:
uho => 1
fuga => 2
hoge => 4

まずマップを記述する。

package WordCount::Mapper;
use Moose;
with 'MapReduce::Lite::Mapper';

sub map {
    my ($self, $key, $value) = @_;
    my @elements = split /\s+/, $value;
    for my $element (@elements) {
         $self->emit($element, 1);
    }
}

MapReduce::Lite::Mapperを継承し、新たにWordCount::Mapperを作成する。
map関数をオーバライドして、スペース区切りのデータを切り分け、
それぞれの単語を「<単語, 1>」の形でemitするようにする。
この後、reducerに渡される前にシャッフルという段階があり、処理される。
この処理が行なわれた後、リストは各単語毎に「<単語, (1, 1, ...)>」という形になる。
次にこのリストを受け取るReducerを作成する。

package WordCount::Reducer;
use Moose;
with 'MapReduce::Lite::Reducer';

sub reduce { 
    my ($self, $key, $value) = @_;
    $self->emit($key, $value->size);
}

MapReduce::Lite::Reducerを継承し、新たにWordCount::Reducerを作成する。
reduce関数をオーバライドして、「<単語、(1, 1, ....)>」の形で渡ってくるリストを受け取り、
(1, 1, ...)の部分の長さを求めるようにする。
実質、(1, 1, ...)の長さは、単語の出現回数となる。

これらのMapReduceを実行するプログラムは下記の通り。
 

package main;
use FindBin::lib;
use MapReduce::Lite;

my $spec = MapReduce::Lite::Spec->new(intermidate_dir => "./tmp");

for (@ARGV) {
    my $in = $spec->create_input;
    $in->file($_);
    $in->mapper('WordCount::Mapper');
}

$spec->out->reducer('WordCount::Reducer');
$spec->out->num_tasks(1);

mapreduce($spec);

 
中間ファイルを置くディレクトリ「tmp」を作成し、単語リストが書かれたファイル「./inputs/file1」を読み込ませて、プログラムを実行。

$ mkdir tmp
$ ./WordCount.pl ./inputs/file1
uho => 1
fuga => 2
hoge => 4