レースクイーン情報
レースクイーンを各種ブログ(Blog)から一括検索します。
トップ > images > images - 人気ブログ(Blog)検索結果詳細 (2008年12月1日 9時)
テスト
[synergy]synergyインストールメモ
synergyは、一つのマウスとキーボードで複数のマシンを操作できるようにしてくれる。
自分は、MacBookAirとwindowsXPのノートPCとLinuxのデスクトップを持っている。
これらすべてをMacBookAirのキーボードとタッチパッドで操作する。
ここでsynergyでは、
MacBookAirをサーバ、
windowsXPとLinuxをクライアントとしている。
Leopardに対してのパッチを当ててコンパイル
http://d.hatena.ne.jp/zariganitosh/20080318/1205813394
こちらによると、Leopardでは、サーバーが起動してからしばらくして落ちてしまうらしい。
実際にこれを確認して悩んでた。
上記のURLの通り、パッチを当ててコンパイル。
$ cd ./synergy-1.3.1
$ patch -p0 < ~/Downloads/synergy.patch
$ patch lib/platform/COSXKeyState.cpp < ~/Downloads/OSX_BusError.patch
$ ./configure
$ make
$ sudo make install
サーバーの設定
synergy.confを設定する。
設定に使うマシン名は、それぞれに設定されているホスト名が使われる。
- MacBookAir(hato-no-macbook-air.local)
- WindowsXP(HATONOTEPC)
- LINUX(localhost.localdomain)
まず、どんなマシンがあるのかを設定する。
例として、moe、larry、curlyみたいな設定がされているがこれは消す。
section: screens
hato-no-macbook-air.local:
HATONOTEPC:
localhost.localdomain:
end
次に上記で設定したマシンに関係を設定していく。
今回行なったのは、
- macの画面左端がlinux
- macの画面右端がWindowsXP
という設定。設定ファイルには次のように記述する。
section: links
hato-no-macbook-air.local:
left = localhost.localdomain
right = HATONOTEPC
これに伴い、
- linuxの画面右端がmac
- WindowsXPの画面左端がmac
という設定にする。
HATONOTEPC:
left = hato-no-macbook-air.local
localhost.localdomain:
right = hato-no-macbook-air.local
end
これで、Macの画面左端にポインタを持っていけば、Linuxの右端にポインタが現れ、
Macの画面右端にポインタを持っていけば、Windowsの左端にポインタが現れるような設定になった。
この設定ファイルを「/etc」ディレクトリに入れて、サーバを起動する。
$ /usr/local/bin/synergys --config /etc/synergy.conf
# 動作確認をするときのコマンド
$ /usr/local/bin/synergys -f --config /etc/synergy.conf
Linuxでのクライアントの起動と停止
Linuxでもソースをコンパイルしてインストール。
クライアントの場合は、設定は特にいらない。
下記のコマンドで、クライアントを起動。
$ /usr/local/bin/synergyc hato-no-macbook-air.local
これでクライアントは起動する。
停止はkillで行なう。
$ ps -x | grep synergy # pidを確認
$ kill <pid>
Windowsのクライアント
Windowsのクライアントはバイナリでインストールした。
サーバのIPもしくはホスト名を指定して起動。
ログイン時にサーバー起動
http://taishizi.blog105.fc2.com/blog-entry-133.html
自動起動に関してはこちらを参考にさせていただきました。
今回はapple scriptを利用してシェルスクリプトをログイン時に起動するように設定した。
まず
「アプリケーション>AppleScript>スクリプトエディタ」
で、エディタを起動して、下記のスクリプトを記述。
do shell script "/usr/local/bin/synergys --config /ect/synergy.conf"
このapple scriptでsynergyサーバーを起動する。
このスクリプトを適当なファイル名で保存する。
ログイン時にこのスクリプトを起動させる設定は
システム環境設定>アカウント>(自分のアカウント)>「ログイン項目」
で、保存したファイルを指定する。
これにより、ログイン時に起動するようになった。
日本語入力
http://wiki.nothing.sh/page/memo/Synergy
日本語に関してのパッチはこちらを参考にしました。
http://www.h5.dion.ne.jp/~pollux/
切り替えに関してはこちらの「CmdSpace」をインストールして対応しました。
作者:hato_mune
更新日:2008年11月22日 20時49分
[Hadoop][MapReduce]HadoopによるAnalog2
まず最初に、下記のコードの様に、パッケージの宣言とインポートを行なう。Analogは、Sampleパッケージに所属する。(適切なパッケーイ名の付け方ってあるのかな)
package Sample; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configured; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapred.FileInputFormat; import org.apache.hadoop.mapred.FileOutputFormat; import org.apache.hadoop.mapred.JobClient; import org.apache.hadoop.mapred.JobConf; import org.apache.hadoop.mapred.MapReduceBase; import org.apache.hadoop.mapred.Mapper; import org.apache.hadoop.mapred.OutputCollector; import org.apache.hadoop.mapred.Reducer; import org.apache.hadoop.mapred.Reporter; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner;
はじめのインポートブロック部分は、Javaの標準のクラスを読み込んでいて、次のインポートブロックでは、MapReduceに関するクラスを読み込んでいる。
Analogクラスは、org.apache.hadoop.conf.Configuredを継承し、org.apache.hadoop.util.Toolインタフェースを実装する事から始める。
public class Analog extends Configured implements Tool { ... code ... }
Configuredクラスは、特定のXMLファイルから設定パラメータを読み込む役割を担っている。getconf()メソッドを呼び出すと、読み込みが完了する。このメソッドは、org.apache.hadoop.conf.Configurationのインスタンスを返す。このインスタンスは、XMLデータにあるname-valueのペアとして設定されたリソースを持っている。各リソースは、文字列またはorg.apache.hadoop.fs.Pathのインスタンスにより名付けられている。デフォルトでは、クラスパスから順に読み込まれるXMLファイルは下記の2つである。
- hadoop-default.xml
- このファイルは、Hadoopのデフォルト設定を含んでいる。例えば全体的な設定、ログ、I/O、ファイルシステムなどのプロパティなど。もしこれらの値を変えたいときは、Hadoop-site.xmlで設定を上書きする。
- hadoop-site.xml
- このファイルの設定により、値を設定できる。
リリースは、好きなだけ追加できる。追加していったものは、順に読み込まれる。Hadoop API documentationにaddResource()とaddFinalResourse()が紹介されている。addFinalResource()は、変更できないようなリソースを設定する関数である。
Analogは、toolインタフェースを実装している。このインタフェースは、コマンドラインからのオプション指定を扱う様々なメソッドをサポートしている。このインタフェースを使うと、run()メソッドを書く必要がある。このメソッドは、パラメータとして文字列の並びを引数として取り、Intを返す。Intは、実行が成功したかどうかを表わしている。
run()メソッドを書けば、mainメソッドでは、次のように書ける。
public static void main(String[] args) throws Exception { int res = ToolRunner.run(new Configuration(), new Analog(), args); System.exit(res); }
org.apache.hadoop.util.ToolRunnerクラスは、Analog内で定義したrun()メソッドを起動する。ToolRunnerは、Toolインタフェースを実装しているクラスを走らすために使われる。このような仕組みによって、様々な入力オプションを取り扱うカスタムハンドラを書かなくて済む。
次にMapとreduceの記述部分。Analogでは内部で二つのクラスを書いた。下記の二つである。
- Map
- キーと値のペアを受け取り、キーと値のペアを1つ以上出力する機能を含む。
- Reduce
- 複数のMapから出力結果を集めて、集めたデータを出力する機能を含む。
AnalogのMapは下記のようになっている。
public static class MapClass extends MapReduceBase implements Mapper<LongWritable, Text, Text, IntWritable> { public void map(LongWritable key, Text value, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { String line = value.toString(); StringTokenizer itr = new StringTokenizer(line); String tokens[] = new String[9]; for (int i = 0; i <= 8 && itr.hasMoreTokens(); i++) { tokens[i] = itr.nextToken(); } if (tokens[8] != null) { word.set(tokens[8]); output.collect(word, one); } } }
mapはkey-valueペアを受け取る。keyはログファイル名、valueはログファイルの一行が入っている。文字列をスペース区切りでトークンに分け、9番目のトークン(ステータスコード)を取り出す。そして、keyをステータスコード、valueを1としたkey-valueのペアを作成する。OutputCollectorのインスタンスを用いて、作成したkey-valueペアをemitする。
次にReduce。Reduceは下記のようになっている。
public static class Reduce extends MapReduceBase implements Reducer<Text, IntWritable, Text, IntWritable> { public void reduce(Text key, Iterator<IntWritable> values, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { int sum = 0; while (values.hasNext()) { sum += values.next().get(); } output.collect(key, new IntWritable(sum)); } }
最後に、設定したパラメータを読み込む。このパラメータは、MapReduceフレームワークに、key-valueがそれぞれどのような型になっているのか、MapとReduceすの名前は何か、をフレームワークに知らせる。これは下記のようにrun()メソッドで行なう。
public int run(String[] args) throws Exception { JobConf conf = new JobConf(getConf(), Analog.class); conf.setJobName("Analog");
まずorg.apache.hadoop.mapred.JobConfのインスタンスを作成する。このインスタンスは、設定を行なうものであり、Configureクラスを継承している。JobConfは、Hadoopフレームワークに実装したMapとReduceを転送する重要な役割を担っている。JobConfに適切な値を渡した後、runJob()メソッドを起動する。これは重要なメソッドでorg.apache.hadoop.mapred.JobTrackerクラスにある。JobClientは内部でorg.apache.hadoop.mapred.JobTrackerクラスとやり取りをしており、進行の追跡、ログのアクセス、クラスタのステータスの取得などの機能を使用できるようにしている。
このような形でAnalogをMapReduceアプリケーションとして作成した。
参考サイト
MapReduce programming with Apache Hadoop - このメモを書く際に「Writing a Hadoop MapReduce application」を参考にしました。
作者:hato_mune
更新日:2008年11月20日 23時0分
[Hadoop][MapReduce]HadoopによるAnalog
http://d.hatena.ne.jp/naoya/20080511/1210506301
こちらのMapReduce::LiteのサンプルプログラムであるAnalogを、
javaで書いてHadoopで実行させてみた。
下記がjavaのソース。力業感たっぷり。
package Sample; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configured; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapred.FileInputFormat; import org.apache.hadoop.mapred.FileOutputFormat; import org.apache.hadoop.mapred.JobClient; import org.apache.hadoop.mapred.JobConf; import org.apache.hadoop.mapred.MapReduceBase; import org.apache.hadoop.mapred.Mapper; import org.apache.hadoop.mapred.OutputCollector; import org.apache.hadoop.mapred.Reducer; import org.apache.hadoop.mapred.Reporter; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner; public class Analog extends Configured implements Tool { public static class MapClass extends MapReduceBase implements Mapper<LongWritable, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(1); private Text word = new Text(); public void map(LongWritable key, Text value, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { String line = value.toString(); StringTokenizer itr = new StringTokenizer(line); String tokens[] = new String[9]; for (int i = 0; i <= 8 && itr.hasMoreTokens(); i++) { tokens[i] = itr.nextToken(); } if (tokens[8] != null) { word.set(tokens[8]); output.collect(word, one); } } } public static class Reduce extends MapReduceBase implements Reducer<Text, IntWritable, Text, IntWritable> { public void reduce(Text key, Iterator<IntWritable> values, OutputCollector<Text,IntWritable> output, Reporter reporter) throws IOException { int sum = 0; while (values.hasNext()) { sum += values.next().get(); } output.collect(key, new IntWritable(sum)); } } static int printUsage() { System.out.println("Analog [-m <maps>] [-r <reduces>] <input> <output>"); ToolRunner.printGenericCommandUsage(System.out); return -1; } public int run (String[] args) throws Exception { JobConf conf = new JobConf(getConf(), Analog.class); conf.setJobName("Analog"); conf.setOutputKeyClass(Text.class); conf.setOutputValueClass(IntWritable.class); conf.setMapperClass(MapClass.class); conf.setCombinerClass(Reduce.class); conf.setReducerClass(Reduce.class); List<String> other_args = new ArrayList<String>(); for (int i = 0; i < args.length; ++i) { try { if ("-m".equals(args[i])) { conf.setNumMapTasks(Integer.parseInt(args[++i])); } else if ("-r".equals(args[i])) { conf.setNumReduceTasks(Integer.parseInt(args[++i])); } else { other_args.add(args[i]); } } catch (NumberFormatException except) { System.out.println("ERROR: Integer expected instead of " + args[i]); return printUsage(); } catch (ArrayIndexOutOfBoundsException except) { System.out.println("ERROR: Required parameter missing from " + args[i-1]); return printUsage(); } } if (other_args.size() != 2) { System.out.println("ERROR: Wrong number of parameters: " + other_args.size() + " instead of 2."); return printUsage(); } FileInputFormat.setInputPaths(conf, other_args.get(0)); FileOutputFormat.setOutputPath(conf, new Path(other_args.get(1))); JobClient.runJob(conf); return 0; } public static void main (String[] args) throws Exception { int res = ToolRunner.run(new Configuration(), new Analog(), args); System.exit(res); } }
「Sample」ディレクトリを作って、上記のソースを「Analog.java」でそこに保存。
下記の要領で、コンパイルし、解析対象ファイルである「access_log」をHDFSに上げ、
プログラム実行して、結果確認を行なった。
$ javac -cp hadoop-0.17.2.1-core.jar Sample/*.java # コンパイル $ jar cvf Analog.jar Sample/*.class # jarファイル作成 $ bin/hadoop dfs -copyFromLocal access_log access_log # HDFSに転送 $ ./bin/hadoop jar Analog.jar Sample.Analog access_log result # Analogを実行 $ ./bin/hadoop dfs -cat result/part-00000 # 処理結果を確認 200 163 301 2 302 1 404 28 500 2
プログラムの詳細メモはまた明日。
参考サイト
MapReduceのJava実装 Apache Hadoopを使ってみた - コンパイル手順を参考にさせていただきました。
作者:hato_mune
更新日:2008年11月20日 1時24分
[Hadoop][MapReduce]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
作者:hato_mune
更新日:2008年11月19日 0時13分
テスト
[synergy]synergyインストールメモ
synergyは、一つのマウスとキーボードで複数のマシンを操作できるようにしてくれる。
自分は、MacBookAirとwindowsXPのノートPCとLinuxのデスクトップを持っている。
これらすべてをMacBookAirのキーボードとタッチパッドで操作する。
ここでsynergyでは、
MacBookAirをサーバ、
windowsXPとLinuxをクライアントとしている。
Leopardに対してのパッチを当ててコンパイル
http://d.hatena.ne.jp/zariganitosh/20080318/1205813394
こちらによると、Leopardでは、サーバーが起動してからしばらくして落ちてしまうらしい。
実際にこれを確認して悩んでた。
上記のURLの通り、パッチを当ててコンパイル。
$ cd ./synergy-1.3.1
$ patch -p0 < ~/Downloads/synergy.patch
$ patch lib/platform/COSXKeyState.cpp < ~/Downloads/OSX_BusError.patch
$ ./configure
$ make
$ sudo make install
サーバーの設定
synergy.confを設定する。
設定に使うマシン名は、それぞれに設定されているホスト名が使われる。
- MacBookAir(hato-no-macbook-air.local)
- WindowsXP(HATONOTEPC)
- LINUX(localhost.localdomain)
まず、どんなマシンがあるのかを設定する。
例として、moe、larry、curlyみたいな設定がされているがこれは消す。
section: screens
hato-no-macbook-air.local:
HATONOTEPC:
localhost.localdomain:
end
次に上記で設定したマシンに関係を設定していく。
今回行なったのは、
- macの画面左端がlinux
- macの画面右端がWindowsXP
という設定。設定ファイルには次のように記述する。
section: links
hato-no-macbook-air.local:
left = localhost.localdomain
right = HATONOTEPC
これに伴い、
- linuxの画面右端がmac
- WindowsXPの画面左端がmac
という設定にする。
HATONOTEPC:
left = hato-no-macbook-air.local
localhost.localdomain:
right = hato-no-macbook-air.local
end
これで、Macの画面左端にポインタを持っていけば、Linuxの右端にポインタが現れ、
Macの画面右端にポインタを持っていけば、Windowsの左端にポインタが現れるような設定になった。
この設定ファイルを「/etc」ディレクトリに入れて、サーバを起動する。
$ /usr/local/bin/synergys --config /etc/synergy.conf
# 動作確認をするときのコマンド
$ /usr/local/bin/synergys -f --config /etc/synergy.conf
Linuxでのクライアントの起動と停止
Linuxでもソースをコンパイルしてインストール。
クライアントの場合は、設定は特にいらない。
下記のコマンドで、クライアントを起動。
$ /usr/local/bin/synergyc hato-no-macbook-air.local
これでクライアントは起動する。
停止はkillで行なう。
$ ps -x | grep synergy # pidを確認
$ kill <pid>
Windowsのクライアント
Windowsのクライアントはバイナリでインストールした。
サーバのIPもしくはホスト名を指定して起動。
ログイン時にサーバー起動
http://taishizi.blog105.fc2.com/blog-entry-133.html
自動起動に関してはこちらを参考にさせていただきました。
今回はapple scriptを利用してシェルスクリプトをログイン時に起動するように設定した。
まず
「アプリケーション>AppleScript>スクリプトエディタ」
で、エディタを起動して、下記のスクリプトを記述。
do shell script "/usr/local/bin/synergys --config /ect/synergy.conf"
このapple scriptでsynergyサーバーを起動する。
このスクリプトを適当なファイル名で保存する。
ログイン時にこのスクリプトを起動させる設定は
システム環境設定>アカウント>(自分のアカウント)>「ログイン項目」
で、保存したファイルを指定する。
これにより、ログイン時に起動するようになった。
日本語入力
http://wiki.nothing.sh/page/memo/Synergy
日本語に関してのパッチはこちらを参考にしました。
http://www.h5.dion.ne.jp/~pollux/
切り替えに関してはこちらの「CmdSpace」をインストールして対応しました。
作者:hato_mune
更新日:2008年11月22日 11時49分
[Hadoop][MapReduce]HadoopによるAnalog2
まず最初に、下記のコードの様に、パッケージの宣言とインポートを行なう。Analogは、Sampleパッケージに所属する。(適切なパッケーイ名の付け方ってあるのかな)
package Sample; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configured; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapred.FileInputFormat; import org.apache.hadoop.mapred.FileOutputFormat; import org.apache.hadoop.mapred.JobClient; import org.apache.hadoop.mapred.JobConf; import org.apache.hadoop.mapred.MapReduceBase; import org.apache.hadoop.mapred.Mapper; import org.apache.hadoop.mapred.OutputCollector; import org.apache.hadoop.mapred.Reducer; import org.apache.hadoop.mapred.Reporter; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner;
はじめのインポートブロック部分は、Javaの標準のクラスを読み込んでいて、次のインポートブロックでは、MapReduceに関するクラスを読み込んでいる。
Analogクラスは、org.apache.hadoop.conf.Configuredを継承し、org.apache.hadoop.util.Toolインタフェースを実装する事から始める。
public class Analog extends Configured implements Tool { ... code ... }
Configuredクラスは、特定のXMLファイルから設定パラメータを読み込む役割を担っている。getconf()メソッドを呼び出すと、読み込みが完了する。このメソッドは、org.apache.hadoop.conf.Configurationのインスタンスを返す。このインスタンスは、XMLデータにあるname-valueのペアとして設定されたリソースを持っている。各リソースは、文字列またはorg.apache.hadoop.fs.Pathのインスタンスにより名付けられている。デフォルトでは、クラスパスから順に読み込まれるXMLファイルは下記の2つである。
- hadoop-default.xml
- このファイルは、Hadoopのデフォルト設定を含んでいる。例えば全体的な設定、ログ、I/O、ファイルシステムなどのプロパティなど。もしこれらの値を変えたいときは、Hadoop-site.xmlで設定を上書きする。
- hadoop-site.xml
- このファイルの設定により、値を設定できる。
リリースは、好きなだけ追加できる。追加していったものは、順に読み込まれる。Hadoop API documentationにaddResource()とaddFinalResourse()が紹介されている。addFinalResource()は、変更できないようなリソースを設定する関数である。
Analogは、toolインタフェースを実装している。このインタフェースは、コマンドラインからのオプション指定を扱う様々なメソッドをサポートしている。このインタフェースを使うと、run()メソッドを書く必要がある。このメソッドは、パラメータとして文字列の並びを引数として取り、Intを返す。Intは、実行が成功したかどうかを表わしている。
run()メソッドを書けば、mainメソッドでは、次のように書ける。
public static void main(String[] args) throws Exception { int res = ToolRunner.run(new Configuration(), new Analog(), args); System.exit(res); }
org.apache.hadoop.util.ToolRunnerクラスは、Analog内で定義したrun()メソッドを起動する。ToolRunnerは、Toolインタフェースを実装しているクラスを走らすために使われる。このような仕組みによって、様々な入力オプションを取り扱うカスタムハンドラを書かなくて済む。
次にMapとreduceの記述部分。Analogでは内部で二つのクラスを書いた。下記の二つである。
- Map
- キーと値のペアを受け取り、キーと値のペアを1つ以上出力する機能を含む。
- Reduce
- 複数のMapから出力結果を集めて、集めたデータを出力する機能を含む。
AnalogのMapは下記のようになっている。
public static class MapClass extends MapReduceBase implements Mapper<LongWritable, Text, Text, IntWritable> { public void map(LongWritable key, Text value, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { String line = value.toString(); StringTokenizer itr = new StringTokenizer(line); String tokens[] = new String[9]; for (int i = 0; i <= 8 && itr.hasMoreTokens(); i++) { tokens[i] = itr.nextToken(); } if (tokens[8] != null) { word.set(tokens[8]); output.collect(word, one); } } }
mapはkey-valueペアを受け取る。keyはログファイル名、valueはログファイルの一行が入っている。文字列をスペース区切りでトークンに分け、9番目のトークン(ステータスコード)を取り出す。そして、keyをステータスコード、valueを1としたkey-valueのペアを作成する。OutputCollectorのインスタンスを用いて、作成したkey-valueペアをemitする。
次にReduce。Reduceは下記のようになっている。
public static class Reduce extends MapReduceBase implements Reducer<Text, IntWritable, Text, IntWritable> { public void reduce(Text key, Iterator<IntWritable> values, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { int sum = 0; while (values.hasNext()) { sum += values.next().get(); } output.collect(key, new IntWritable(sum)); } }
最後に、設定したパラメータを読み込む。このパラメータは、MapReduceフレームワークに、key-valueがそれぞれどのような型になっているのか、MapとReduceすの名前は何か、をフレームワークに知らせる。これは下記のようにrun()メソッドで行なう。
public int run(String[] args) throws Exception { JobConf conf = new JobConf(getConf(), Analog.class); conf.setJobName("Analog");
まずorg.apache.hadoop.mapred.JobConfのインスタンスを作成する。このインスタンスは、設定を行なうものであり、Configureクラスを継承している。JobConfは、Hadoopフレームワークに実装したMapとReduceを転送する重要な役割を担っている。JobConfに適切な値を渡した後、runJob()メソッドを起動する。これは重要なメソッドでorg.apache.hadoop.mapred.JobTrackerクラスにある。JobClientは内部でorg.apache.hadoop.mapred.JobTrackerクラスとやり取りをしており、進行の追跡、ログのアクセス、クラスタのステータスの取得などの機能を使用できるようにしている。
このような形でAnalogをMapReduceアプリケーションとして作成した。
参考サイト
MapReduce programming with Apache Hadoop - このメモを書く際に「Writing a Hadoop MapReduce application」を参考にしました。
作者:hato_mune
更新日:2008年11月20日 14時0分
[Hadoop][MapReduce]HadoopによるAnalog
http://d.hatena.ne.jp/naoya/20080511/1210506301
こちらのMapReduce::LiteのサンプルプログラムであるAnalogを、
javaで書いてHadoopで実行させてみた。
下記がjavaのソース。力業感たっぷり。
package Sample; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configured; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapred.FileInputFormat; import org.apache.hadoop.mapred.FileOutputFormat; import org.apache.hadoop.mapred.JobClient; import org.apache.hadoop.mapred.JobConf; import org.apache.hadoop.mapred.MapReduceBase; import org.apache.hadoop.mapred.Mapper; import org.apache.hadoop.mapred.OutputCollector; import org.apache.hadoop.mapred.Reducer; import org.apache.hadoop.mapred.Reporter; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner; public class Analog extends Configured implements Tool { public static class MapClass extends MapReduceBase implements Mapper<LongWritable, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(1); private Text word = new Text(); public void map(LongWritable key, Text value, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { String line = value.toString(); StringTokenizer itr = new StringTokenizer(line); String tokens[] = new String[9]; for (int i = 0; i <= 8 && itr.hasMoreTokens(); i++) { tokens[i] = itr.nextToken(); } if (tokens[8] != null) { word.set(tokens[8]); output.collect(word, one); } } } public static class Reduce extends MapReduceBase implements Reducer<Text, IntWritable, Text, IntWritable> { public void reduce(Text key, Iterator<IntWritable> values, OutputCollector<Text,IntWritable> output, Reporter reporter) throws IOException { int sum = 0; while (values.hasNext()) { sum += values.next().get(); } output.collect(key, new IntWritable(sum)); } } static int printUsage() { System.out.println("Analog [-m <maps>] [-r <reduces>] <input> <output>"); ToolRunner.printGenericCommandUsage(System.out); return -1; } public int run (String[] args) throws Exception { JobConf conf = new JobConf(getConf(), Analog.class); conf.setJobName("Analog"); conf.setOutputKeyClass(Text.class); conf.setOutputValueClass(IntWritable.class); conf.setMapperClass(MapClass.class); conf.setCombinerClass(Reduce.class); conf.setReducerClass(Reduce.class); List<String> other_args = new ArrayList<String>(); for (int i = 0; i < args.length; ++i) { try { if ("-m".equals(args[i])) { conf.setNumMapTasks(Integer.parseInt(args[++i])); } else if ("-r".equals(args[i])) { conf.setNumReduceTasks(Integer.parseInt(args[++i])); } else { other_args.add(args[i]); } } catch (NumberFormatException except) { System.out.println("ERROR: Integer expected instead of " + args[i]); return printUsage(); } catch (ArrayIndexOutOfBoundsException except) { System.out.println("ERROR: Required parameter missing from " + args[i-1]); return printUsage(); } } if (other_args.size() != 2) { System.out.println("ERROR: Wrong number of parameters: " + other_args.size() + " instead of 2."); return printUsage(); } FileInputFormat.setInputPaths(conf, other_args.get(0)); FileOutputFormat.setOutputPath(conf, new Path(other_args.get(1))); JobClient.runJob(conf); return 0; } public static void main (String[] args) throws Exception { int res = ToolRunner.run(new Configuration(), new Analog(), args); System.exit(res); } }
「Sample」ディレクトリを作って、上記のソースを「Analog.java」でそこに保存。
下記の要領で、コンパイルし、解析対象ファイルである「access_log」をHDFSに上げ、
プログラム実行して、結果確認を行なった。
$ javac -cp hadoop-0.17.2.1-core.jar Sample/*.java # コンパイル $ jar cvf Analog.jar Sample/*.class # jarファイル作成 $ bin/hadoop dfs -copyFromLocal access_log access_log # HDFSに転送 $ ./bin/hadoop jar Analog.jar Sample.Analog access_log result # Analogを実行 $ ./bin/hadoop dfs -cat result/part-00000 # 処理結果を確認 200 163 301 2 302 1 404 28 500 2
プログラムの詳細メモはまた明日。
参考サイト
MapReduceのJava実装 Apache Hadoopを使ってみた - コンパイル手順を参考にさせていただきました。
作者:hato_mune
更新日:2008年11月19日 16時24分
[Hadoop][MapReduce]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
作者:hato_mune
更新日:2008年11月18日 15時13分