Azureの小ネタ (改)

~Azureネタを中心に、色々とその他の技術的なことなどを~

C#でMap Reduce。

JAZUG 3周年のセッションでも少ししゃべらしてもらったのですが、あまり時間もなく、ブログでフォローしようと思いつつ時間がたってしまいましたが、少しブログでもまとめておこうかと思います。

.NET SDK For Hadoop

C#で、M/Rを書くための.NET向け SDKCodePlexから配布されています。

ライブラリ自身は、NuGetから取得できるので、ここから何かダウンロードする必要はありませんが、ドキュメントは参考になるかと思います、

実行方法など

プログラムを紹介する前に、実行方法について。以下の3種類の実行方法があります。

  1. ローカル実行
  2. ローカルのHDInsightによる実行
  3. Azure上のHDInsightによる実行

1.はStreamingUnitクラスによるお手軽実行です。ローカルのHadoop環境すら不要なので、とりあえず動かしてみたり、挙動を確認したりするのに適しています。 2.は、前記事で説明したローカル環境にインストールしたHadoopで実行、3.はAzure上に構築したHadoop環境での実行になります。

サンプル

ここでは、簡単なM/RとしてWordカウントサンプルを作成し、StreamingUnitクラスによる実行を紹介します。

準備

まずは、VSでコンソールプロジェクトを作成します。後に補足しますが、単独実行可能なようにexeのプロジェクトです。

f:id:StateMachine:20131129215416p:plain

NuGetコンソールから、Hadoopクライアントライブラリをインストールします。Hive等は使わなければインストールしなくても構わないでしょう。

install-package Microsoft.Hadoop.MapReduce  
install-package Microsoft.Hadoop.Hive 
install-package Microsoft.Hadoop.WebClient 
install-package Microsoft.Hadoop.Avro 

Mapper

Mapperは、MapperBaseクラスを継承し、Mapメソッドをオーバーライドします。ビッグデータ(笑)が適宜分割されて投げられますので、ここではライン毎にワード分割をし、それらをキーバリュー形式でコンテキストオブジェクトに設定します。ここでは、キーをワード、バリューには適当に、"1"を設定しておきます。

    public class Mapper : MapperBase
    { 
        private readonly char[] _delimiterChars = { ' ', ',', '.', ':', ';', '\'', '\t' };

        public override void Map(string inputLine, MapperContext context)
        {
            var words = inputLine.Split(_delimiterChars);
            foreach (var word in words)
            {
                if (!string.IsNullOrEmpty(word))
                {
                    context.EmitKeyValue(word, "1");
                }
            }
        }
    }

Reducer

後処理となるReducerは、ReducerCombineBaseクラスを継承し、Reduceメソッドをオーボーライドします。キーとバリューが渡されます。Mapperでは、ワードカウント毎に、"1"を足していたので、その数を数えればワードをカウントできるということです。ワードをキーに、カウント数をバリューに設定します。

    public class Reducer : ReducerCombinerBase
    {
        public override void Reduce(string key, IEnumerable<string> values,
                                    ReducerCombinerContext context)
        {
            context.EmitKeyValue(key, values.Count().ToString());
        }
    }

ローカル実行

StreamingUnitクラスに、Mapper、Reducerを指定し、Executeメソッドを呼び出します。引数は、ワードカウントするファイルを一行ずつ読み込んだ配列です。

            string name = @"hoge.txt";
            StreamingUnitOutput outputData = StreamingUnit.Execute<Mapper, Reducer>(File.ReadAllLines(name));

            foreach (var r in outputData.Result)
            {
                Console.WriteLine(r);
            }

            Console.WriteLine("Hit any key.");
            Console.ReadLine();

結果はStreamingUnitOutputオブジェクトが返ってくるので、とりあえず表示さしてみるとよいでしょう。

まとめ

StreamingUnit クラスを使うとお手軽に実行して、デバッグできたりするのでGJですね。