soturon miyoshi 2014 - kochi uhonda/studentarc/13_miyoshi.pdf · hadoop distributed file...
TRANSCRIPT
2013年度 卒業論文
時系列画像に対する汎用分散
データマイニングシステムの基礎検討
提出日 2014年 2月 10日
高知大学理学部応用理学科
情報科学コース 本田研究室
B103K299T 三好智也
要旨
近年,情報通信技術の進展により時間とともに蓄積されるビッグデータの利用に対して
期待が高まっている。ビッグデータの分析には,大量のファイルを扱うためコモディティ
な複数の計算機の分散処理の解析が有用と考えられる。このような分散処理を用いたビッ
グデータの解析は,画像などのマルチメディアデータに対しては検討が始まった状況にあ
る。このようなマルチメディアデータは,監視カメラ映像やリモートセンシングなどの分
野で大量の時空間データとして保存されている。大量の時系列画像として構成されている
時空間データに対して時間,空間などの任意の断面で柔軟に抽出して解析を行うことで時
空間の変動パターンを発見することが期待できる。本研究では,様々な時系列画像から異
なる断面での効率的なパターン発見を支援できる汎用分散型時空間データマイニングシス
テムを検討した。分散処理のフレームワークは,Hadoop,MapReduce を用いることにし
た。
システムのパフォーマンスを評価するために,1152×1152 pixel の南米の植生指標画像
から同一座標の時系列抽出と統計量の計算処理を行い,スレーブ数を変化させた時の計算
時間のスケーラビリティで評価した。評価を行った結果,Map-Reduce 間のデータの流れ
が飽和するというボトルネックが発生することでスケーラビリティを確保出来なかった。
そこで分散の単位として画素ではなくブロックを扱い,Map-Reduce 間のデータ圧縮を行
うことで計算速度を向上させ,スケーラビリティを確保することができることが分かった。
更に,Reduce処理の実装の仕方によってデータ量を考慮しなければ計算時間が膨大に増加
することも分かった。また,実データへの適用例として気象衛星画像に対して期間毎の平
均値,分散を求める前処理を行った。
今後の課題としてシステムのインタフェースの開発と異なる時空間断面を扱う問題を拡
張し,システムの完成を目指す。
目次
1. はじめに .................................................................................................................. 1
2. 研究背景 .................................................................................................................. 2
2.1. Hadoopの概要 ..................................................................................................... 2
2.2. HDFS ................................................................................................................... 2
2.3. Hadoop MapReduce ......................................................................................... 2
2.4. Hadoopクラスタの構成 ...................................................................................... 3
3. 本研究でのシステム構成 ......................................................................................... 4
3.1. 想定するシステム ................................................................................................. 4
3.2. プロトタイプシステムの構成 ............................................................................... 4
3.3. 時空間データ ........................................................................................................ 5
3.4. 時系列データの抽出の流れ .................................................................................. 5
3.5. プロトタイプシステムで使用するデータ ............................................................. 6
4. 実験 –プロトタイプシステム- .............................................................................. 7
4.1. 実験環境 ............................................................................................................... 7
4.2. 実験条件 ............................................................................................................... 8
4.3. 予備実験 ............................................................................................................... 8
4.4. Mapから Reduceに送るデータ量の削減 .......................................................... 10
4.4.1. データ型の変更 ............................................................................................... 10
4.4.2. Combinerの実装 ............................................................................................ 12
4.4.3. 入力ファイル数の削減 .................................................................................... 14
4.4.4. サンプリングによるデータの間引き .............................................................. 15
4.4.5. 画素のブロック分散とブロックデータのベクトル化(2次元配列) ................. 17
4.4.6. 画素のブロック分散とブロックデータのベクトル化(1次元配列) ................. 19
4.4.7. Map-Reduce間のデータ圧縮 ......................................................................... 21
4.4.8. 実験のまとめ .................................................................................................. 26
5. 実データへの適用 .................................................................................................. 27
5.1. 手法 .................................................................................................................... 27
5.2. 実験データと実験環境 ....................................................................................... 27
5.3. 実験結果と考察 .................................................................................................. 27
6. おわりに ................................................................................................................ 32
謝辞 参考文献
1
1. はじめに 近年,情報通信技術の進展により時間とともに蓄積されるビッグデータの利用に対して
期待が高まっている。ビッグデータの分析には,コモディティな複数の計算機で分散処理
を行う分散型システムの活用が有用と考えられる。このような分散処理システムを用いた
ビッグデータの解析は,画像などのマルチメディアデータに対しては,検討が始まった状
況にある。このようなマルチメディアデータは,監視カメラ映像やリモートセンシングな
ど様々な分野で大量の時空間データとして蓄積されている。時空間データは,大量の時系
列画像として構成されている。このようなデータに対して時間,空間などの任意の断面で
柔軟に抽出して解析を行うことで時空間の変動パターンを発見することが期待できる。 時空間データに対して解析を行った先行研究では,気象観測衛星ひまわり 6 号
(MTSAT1-R)の時系列気象画像を用いて,データマイニングの観点からユーザが対話的に時空間変動の相関性や特徴的なパターン発見を支援するシステムを構築した研究がある(坂口,2010)[1]。また,GIMMS NDVIの南米データを時系列ファイルに変換し,最尤法によるロジスティクス関数の計算を高速化するためにHadoopで実現した研究がある(西前,2012)[2]。 そこで本研究では,様々な時空間データに対して異なる断面での知識発見を支援できる
汎用型時空間データマイニングシステムの研究を検討した。本システムでは,ユーザがリ
モート環境からネットワーク経由で対話的に知識発見を行う事ができるような分散処理シ
ステムを想定する。分散計算環境のフレームワークとしては,Apache Hadoop,Gfarm,Xgrid等があるが,本研究では,Hadoopを採用した。Hadoopを採用した理由には,分散ファイルシステム Hadoop Distributed File System(HDFS)と分散処理のフレームワークである Hadoop MapReduceを備え,システムの耐障害性に配慮した機能や機械学習を行うためのライブラリ Apache Mahoutがあるからである。 本論文では,3章では分散計算環境の Hadoopについて,4章では,時空間データに対し
ての試用実験について,5章では,実際にリアルタイムデータでのデータマイニングについて,6章では,本論文をまとめについて述べていく。
2
2. 研究背景 2.1. Hadoopの概要 Apache Hadoop Projectは,信頼性の高いスケーラブルな分散コンピューティングのためのオープンソースソフトウェアとして開発されている。Hadoopは Google社の Google File System(GFS)とMapReduceを参考に開発された[3]。 Apache Hadoopは,いくつかのプロジェクトで構成されており,コアプロジェクトとしてコモディティな計算機で構成される大規模クラスタ上の分散ファイルシステムである
Hadoop Distributed File System(HDFS),大規模な計算ノード・クラスタ上において膨大なデータを高速で並列処理するためのプログラミングモデル Hadoop MapReduce がある[3]。 以下に,Hadoopを構成している HDFSとMapReduceについて述べる。 2.2. HDFS HDFS は,ストリーミング型のデータアクセスパターンによって,非常に大きなファイルを保存するために設計されたファイルシステムでコモディティハードウェアによって構
成されるクラスタで動作する。HDFS では,書き込みを 1 度だけおこない,読み出しを何度も行う設計で作られている。書き込み際にファイルを一定サイズ(デフォルト値:64MB)のブロックに分割し,複数の計算機にブロックを複製(デフォルト値:3)して分散して保存することで耐障害生を高めている。 また,HDFSを実行するためには,NameNode(マスター)と DataNode(スレーブ)が必要である。NameNode では,ファイルやディレクトリのメタ情報の管理を行い,DataNodeでは,分散されたデータブロックの読み書きを行う動作をしている。 2.3. Hadoop MapReduce MapReduce は,処理を Map フェーズと Shffle&Sort フェーズと Reduce フェーズという 3 つのフェーズに分割して行う。Map フェーズでは,情報の分解・抽出を行い,Shffle&Sortフェーズでは,情報の整理・集約を行い,最後に Reduceフェーズで情報の計算を行う。各フェーズでは,データの入出力を Key-Value というペアの集合として扱う。図 1 に Map-Reduce のイメージ図を示す。また,Map-Reduce を実行するために,JobTracker(マスター)と TaskTracker(スレーブ)が動作している。JobTracker では,TaskTracker郡で実行されるタスクのスケジューリングを行うことで管理し,TaskTrackerでは,各ジョブの管理を行う動作をしている。
Mapフェーズは,HDFSに分散されたデータをKey-Valueというペア構造に分解を行い,引数として Map が受け取る。受け取った引数を Map の内部で処理を行い,出力結果を新たな Key-Valueとして出力される。
3
Shuffle&Sortフェーズでは,Mapフェーズで出力された Key-Valueのデータを Reduceに対応するパーティションにデータを分割する。各パーティション内では,Keyによる Sortが行われている。分割されたデータは,マージされた後 Reduceにコピーされる。すべてのMapの出力が Reduceにコピーされた後,同じ Keyを持つデータでマージされる。
Reduce フェーズでは,Shffle&Sort フェーズで出力された Key-Value ペアを一つずつReduceの内部で処理を行い,出力結果を新たな Key-Valueペアとして出力される。Reduceの出力結果は,HDFS上に書き込まれる。複製の一つは,ローカルに書き込まれる。
図 1 MapReduceのイメージ図
2.4. Hadoopクラスタの構成 まず,図 2に Hadoopのクラスタ構成のイメージ図を示す。Hadoopクラスタを構成する成分としてマスター(親)とスレーブ(子)という親子関係がある。マスターは,HDFDのファイルやディレクトリのメタ情報の管理を行う NameNode と NameNode のデータのバックアップをとる SecondaryNameNodeと MapReduceで実行されるタスクのスケジューリングを行うことで管理する JobTrackerで構成されている。また,スレーブは,分散されたデータブロックの読み書きを行う DataNodeと各ジョブの管理を行う JobTrackeで構成されている。Hadoopの設定は,付録 Aに示す。
図 2 Hadoopのクラスタ構成
4
3. 本研究でのシステム構成 3.1. 想定するシステム 時系列画像から異なる断面での効率的なパターン発見を支援することのできる汎用的な
クラウド型時空間データマイニングシステムを想定する。Hadoopを用いることでユーザがリモート環境から対話的にデータマイニングができるシステムを実現する。本研究では,
想定するシステムのプロトタイプシステムとして Hadoop を用いて実装し,時系列画像に対して基本的なタスクとして最大値,最小値,平均値などの簡単な統計量の計算を行い,
システムのパフォーマンスを調査した。
3.2. プロトタイプシステムの構成 プロトタイプシステムの構成を図 3 に示す。プロトタイプシステムでは,数台のマスターと数十台のスレーブで Hadoop での分散処理環境を構築する。マスターの JobTracker,NameNode,SecondaryNameNodeは,物理的に 1台にまとめることができる。しかし,スレーブを増やすことで物理的メモリが足らなくなる恐れがあるので本研究では,それぞ
れの Nodeを分けることにする。
図 3 プロトタイプシステムの構成
5
3.3. 時空間データ 時間の経過と共に変動する空間のデータを時空間データと呼ぶ。そのような時空間デー
タは,大量の時系列画像(空間データ)として保存されていることが多い。そのようなデータに対して幾つかの解析方法がある。以下に,解析方法を示す[4]。 l 抽出(Extraction)
時系列から目的に応じて必要な信号や情報を取り出すこと l 記述(Description)
時系列を図示することや基本的な記述統計量を用いて時系列の特徴を簡潔に表現す
ること l モデリング(Modeling)
与えられた時空間に対し,その変動の仕方を表現する時空間モデルを構成し,時系
列の確率的構造を解析する l 予測(Prediction)
時系列が互いに相関を持つことを利用して変動を予測すること また,時空間データに対しては,同一座標の時系列,同一時間の空間断面,時空間の中
の小領域などの異なる断面での解析ができる。本研究では,システムのパフォーマンスを
評価するために同一座標に対する時系列データ抽出と統計量による記述に限定する。
3.4. 時系列データの抽出の流れ ここでは,MapReduce 間の時系列画像からの時系列データの抽出の流れを図 4 に示す。
時刻𝑡に対する画像の座標(x! , 𝑦!)の階調値を I(𝑥! , 𝑦!,𝑡)とおく。MapReduceで時系列画像に対して解析を行う際,Key と Value を柔軟に設定しなければならない。ここでは,時系列画像から座標ごとの最大値,最小値,平均値を求める単純な実装例を示す。まず,データ構
造に空間座標(x! , 𝑦!)を key,時刻𝑡,階調値 I(𝑥! , 𝑦!,𝑡)を valueとして割り当てる。Mapフェーズでは,分割されたデータを key-Valueに分解する。次に,Shuffle&Sortフェーズで分散された同じ Key を各スレーブに振り分ける。最後に,Reduce フェーズで同じ Key を持つ時系列でまとめられたデータから最大値,最小値,平均値を計算し,key を座標,valueを最大値,最小値,平均値の統計量として出力する。
6
図 4 Map-Reduceでの時系列データ抽出の流れ
3.5. プロトタイプシステムで使用するデータ 本研究での対象データは,地球観測衛星 NOAA衛星に搭載されたセンサーの観測データから合成されたGIMMS NDVI(植物の量や活性度合を表す指標)の南米のデータを使用する。イメージ図を図 5に示す。取得期間は,1981年から 2004年までの 25年間,画像サイズは,1152×1152 pixel である。データの取得周期は,月 2回,画像解像度は 1 pixel あたり 8km,観測地域の範囲は北緯 31°~南緯 55°,西経 100°~120°である。画像は,1 pixel あたり 2バイト,1枚あたりのサイズが 2.7MBのデータを 25年間,1年あたり 24年/枚を 2倍に複製した合計 1200枚の約 3.2GBのデータを使用する。
図 5 GIMMS NDVI,南米データの例
7
4. 実験 –プロトタイプシステム- 4.1. 実験環境 実験では,高知大学情報科学教室演習室の iMac53台(マスター3台,スレーブ 50台)を利
用する。実験で使用する計算機の性能を表 1に示す。マスター,スレーブの計算機は全てMac OS X 10.6.8をネットブートで起動する設定になっている。Hadoopのユーザを LDAPで作成し,システムデータをNFSに格納することでユーザの管理を簡易化している。また,各計算機の未使用のローカルストレージ(1台約 455GB)を HDFSの領域に使用することで約 23TBのデータ領域を確保した。
表 1 実験で使用する計算機の性能
メモリ 4GB HDD 500GB
HDFS用 HDD容量 455GB(全システムで 23TB)
OS Mac OS X 10.6.8
Hadoop version 1.0.3
Java version 1.6.0
ネットワーク 1000baseT
実験環境に用いたシステムのネットワーク構成を図 6 に示す。ネットワークの接続形態は,2台の L2スイッチによるスター型になっている。スイッチ間は,10GBpsでそれ以外では 1GBpsで接続されている。
図 6 実験に用いたシステムのネットワーク構成
8
4.2. 実験条件 本章の実験条件を表 2に示す。実験では,1152×1152 pixel の植生指標画像を 1200枚使用し,同一地点の時系列での統計量を求める計算をスレーブのノード数 1台から 50台に変化させた時の分散処理のスケーラビリティを評価した。実験の際には,単純化のために 1スレーブ 1 コアを使用し,ブロック数の分散数とスレーブ数は同じとする。スケーラビリティの評価するために計算速度向上比を定義する。計算速度向上比の式は以下に示す。
計算速度向上比 =1スレーブ 1コアでの実行時間
各条件での実行時間 (4-1)
表 2 実験条件
条件 値
入力
植生指標画像(GIMMS) 南米領域
・1152×1152
・1200 枚
出力 同一地点の時系列の統計量(最大値,最小値,平均値)
ノード数 1,10,20,30,40,50
コア数 1
レプリケーション 3
4.3. 予備実験 単純化のために表 3のような実装形式で,スレーブ数 1台から 50台までに変化させた時のスケーラビリティを評価した。Text形式のプログラムは,付録 B-1に示す。
表 3 Textでの実装形式
データ形式 データ内容
Key Value Key Value
Map
入
力 NULL
Writable BytesWritable ― 階調値
出
力 Text Text
2次元座標 (X:0-1152,Y:0-1152)
時刻,階調値
Reduce
入
力 Text Text
2次元座標 (X:0-1152,Y:0-1152)
時刻,階調値
出
力 Text Text
2次元座標 (X:0-1152,Y:0-1152)
最大値,最小値,
平均値,時刻
9
各フェーズのスレーブ数による計算時間の変化を図 7,スケーラビリティの変化を図 8に示す。Reduce フェーズと全体フェーズのスレーブ数に対するスケーラビリティの変化は,ほぼ同じものなので以後,グラフではMapフェーズと全体フェーズのスケーラビリティの変化を示す。全体フェーズの計算速度向上比がスレーブ数 10台程度で頭打ちが起きた。理想的な計算速度向上は,右上がりの直線になる。このことからMapフェーズでは,スレーブ数に比例して計算速度向上が上がるという理想的な形になっているのに対し,Reduceフェーズは 10 台で頭打ちが起きていることから Map から Reduce に送られるデータ量がボトルネックになっていることが考えられる。
図 7 スレーブ数による計算時間の変化
図 8 スレーブ数による計算速度向上比の変化
0
1000
2000
3000
4000
5000
6000
7000
8000
9000
0 10 20 30 40 50
計算時間(秒)
スレーブ数
Mapフェーズ
全体フェーズ
0
10
20
30
40
50
60
0 10 20 30 40 50
計算速度向上比
スレーブ数
Mapフェーズ
全体フェーズ
理想的性能
10
4.4. Mapから Reduceに送るデータ量の削減 Mapから Reduceに送るデータ量を削減することで,Reduceの頭打ちをなくすことでス
ケーラビリティが回復することが期待できる。そこで,以下の手法での性能比較を検討し
た。 ① データ型の変更 ② Combinerの実装 ③ 入力ファイル数の削減 ④ サンプリングによるデータの間引き ⑤ 画素のブロック分散とブロックデータのベクトル化(2次元配列) ⑥ 画素のブロック分散とブロックデータのベクトル化(1次元配列) ⑦ Map-Reduce間のデータ圧縮
4.4.1. データ型の変更 ここではMapの出力形式と Reduceの入力形式を見直すことでMap-Reduce間のデータ
型を削減するのが目的である。Map-Reduce間のデータ形式(Key-Value)を Text-Text,Int-Int,Text-Byte,Byte-Byte,VInt-VInt形式のケースでスレーブ数 50台,計算時間の比較のため,植生指標画像の陸のみの同一地点の時系列の統計量の計算時間とMapから Reduceに流れるデータ量の比較を行った。データ形式の比較を行った結果を図 9に示す。 最も効果があったデータ形式は,Hadoopで用いることができる可変長の Int形式であるVInt形式となった。そこで VInt形式を用いて Text形式と同じ実験を行った。VInt形式のプログラムは,付録 B-2に示す。
図 9 データ形式の比較
0 100 200 300 400 500 600 700 800 900
0.00 1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00
Text-Text Int-Int Text-Byte Byte-Byte Vint-Vint
計算時間
(秒)
データサイズ
(MB)
出力形式
Map出力のデータサイズ
計算時間
11
VInt形式のスレーブ数によるMapフェーズと全体フェーズの計算時間の変化を図 10,計算速度向上比の変化を図 11に示す。計算時間は,Text形式と比べて約 1.3倍速くなったが,計算速度向上比では,Text形式と同様にスレーブ数 10台の所で頭打ちが起きてしまった。しかし,計算時間には効果があったので以後 VInt(VIntWritable,VIntArrayWritable)形式を用いる。
図 10 スレーブ数による計算時間の変化
図 11 スレーブ数による計算速度向上比の変化
0
5000
10000
15000
20000
25000
0 10 20 30 40 50
計算時間(秒
)
スレーブ数
Mapフェーズ
全体フェーズ
0
10
20
30
40
50
60
0 10 20 30 40 50
計算速度向上比
スレーブ数
Mapフェーズ
全体フェーズ
12
4.4.2. Combinerの実装 ここでは,Combiner を実装して実験を行う。Combiner とは,Shffle&Sort フェーズの
前にローカルで Reduceのような集約計算を行う機能である[5]。Combinerを実装することで Map-Reduce間のデータ量を削減し,Reduceに送るデータ量を削減できる。Combinerを実装した時の実装形式を表 4に示す。Combinerを実装したプログラムは,付録 B-3に示す。
表 4 Combinerの実装形式
データ形式 データ内容
Key Value Key Value
Map 入力
Null Writable
Bytes Writable
階調値
出力 VInt
Writable VIntArray Writable
1次元座標 (0-1327104)
最大値,最小値,
時刻,総数,個数
Combiner
入力 VInt
Writable VIntArray Writable
1次元座標 (0-1327104)
最大値,最小値,
時刻,総数,個数
出力 VInt
Writable VIntArray Writable
1次元座標 (0-1327104)
最大値,最小値,
時刻,総数,個数
Reduce 入力
VInt Writable
VIntArray Writable
1次元座標 (0-1327104)
最大値,最小値,
時刻,総数,個数
出力 Text
Writable Text
Writable 2次元座標
(X:0-1152,Y:0-1152) 最大値,最小値,
平均値,時刻
13
スレーブ数によるMapフェーズと全体フェーズの計算時間と計算速度向上比の変化を図12,図 13 に示す。計算速度向上比は,全体フェーズでスレーブ数 10 台の所で頭打ちが起きていることから Combiner を実装することでスケーラビティを回復することはできなかった。また,計算時間が増加した理由は Combiner を実装することでプログラムの実装形式を変更したことによるデータ量の増加が考えられる。
図 12 スレーブ数による計算時間の変化
図 13 スレーブ数による計算速度向上比の変化
0
5000
10000
15000
20000
25000
30000
0 10 20 30 40 50
計算時間(秒)
スレーブ数
Mapフェーズ
全体フェーズ
0
10
20
30
40
50
60
0 10 20 30 40 50
計算速度向上比
スレーブ数
Mapフェーズ
全体フェーズ
14
4.4.3. 入力ファイル数の削減 ここでは,入力ファイル数を削減することでMap-Reduce間のデータ量を直接減らすこ
とでスケーラビリティを確保できると考えた。実験では,300枚,600枚,1200枚とファイル数を削減しながら VInt形式で実験を行ったときの計算時間の変化を図 14,計算速度向上比の変化を図 15に示す。入力ファイル数を変化させた時の全体フェーズの計算時間は,スレーブ数 1台のときに変化はあるが,スレーブ数を増やすと変化があまりない。また,計算速度向上比は,スレーブ数 10台辺りで頭打ちが起きスケーラビリティを確保することはできなかった。
図 14 入力ファイル数を変化させた時の計算時間の変化
図 15 入力ファイル数を変化させた時の計算速度向上比の変化
0
5000
10000
15000
20000
25000
0 10 20 30 40 50
計算時間
(秒)
スレーブ数
入力ファイル数300枚
入力ファイル数600枚
入力ファイル数1200枚
0
2
4
6
8
10
12
14
16
18
0 10 20 30 40 50
計算速度向上比
スレーブ数
入力ファイル数300枚入力ファイル数600枚入力ファイル数1200枚
15
4.4.4. サンプリングによるデータの間引き ここでは,植生指標画像に対してサンプリングによるデータの間引きを行うことで Map
から Reduceへ送るデータ量を減らすことでスケーラビリティの確保を検討した。実験では,全点から 1/2,1/4,1/8の間引きによって送るデータを削減しながら行った。スレーブ数による全体フェーズの計算時間と計算速度向上比の変化を図 16,図 17に示す。計算速度向上比では,1/2,1/4の間引きの場合では,全点と同じくスレーブ数 10台辺りで頭打ちが起きてしまった。1/8 の間引きの場合は,スレーブ数 20 台の所で頭打ちが起きてしまい間引きによるスケーラビリティの確保はできなかった。
図 16 スレーブ数による計算時間の変化
図 17 スレーブ数による計算速度向上比の変化
0
5000
10000
15000
20000
25000
0 10 20 30 40 50
計算時間
(秒)
スレーブ数
Vint 全点Vint 1/2間引きVint 1/4間引きVint 1/8間引き
0
2
4
6
8
10
12
14
16
0 10 20 30 40 50
計算速度向上比
スレーブ数
Vint 全点Vint 1/2間引きVint 1/4間引きVint 1/8間引き
16
次に,入力データ数を減らすために植生指標画像の陸のみで同じ実験を行った。スレー
ブ数による全体フェーズの計算時間と計算速度向上比の変化を図 18,図 19に示す。計算速度向上比は,1/2 の間引きでは,スケーラビリティを確保出来なかったが,1/4 点 1/8 点の間引きを行った場合,スケーラビリティの確保ができた。しかし,サンプリングによる計
算回数の間引きを行った数だけ計算回数を繰り返さないといけない問題がある。
図 18 スレーブ数による計算時間の変化
図 19 スレーブ数による計算速度向上比の変化
0
2000
4000
6000
8000
10000
12000
0 10 20 30 40 50
計算時間
(秒)
スレーブ数
Vint 全点
Vint 1/2間引き
Vint 1/4間引き
Vint 1/8間引き
0
5
10
15
20
25
30
35
40
45
0 10 20 30 40 50
計算速度向上比
スレーブ数
Vint 全点Vint 1/2間引きVint 1/4間引きVint 1/8間引き
17
次に,スレーブ数 50台で植生指標画像の陸のみで行った時の計算時間に間引きを行った数だけ繰り返した計算時間を比較したものを図 20に示す。間引きを行った数だけ計算を繰り返すことで,間引きを行わないケースより計算時間が増大する結果になった。このこと
からサンプリングによるデータの間引きは,スケーラビリティの確保は可能だが計算時間
が遅くなるということが分かった。
図 20 間引きを繰り返した計算時間の比較
4.4.5. 画素のブロック分散とブロックデータのベクトル化(2次元配列) Key を 2 次元座標にすることで分散単位を独立した画素として扱うことでデータを送る毎に,座標や時間などの情報を送るので Map-Reduce 間のデータ量が増加してしまう。そこで,画像の画素の並びの規則性を利用することで分散単位を画素のブロックとして送る
手法を検討した。以後この手法を画素のブロック分散と呼ぶ。 画素のブロック分散の実装形式を表 5 に示す。データ構造は,画像をブロック化として
分割を行いその領域の IDiを Keyに割り当てる。さらに Valueのデータ形式を 2次元配列として実装する。データ内容は,ブロック化された画像の取得したデータの Indexjを 2 次元配列の 1 次元目に割り当て,そのデータに対しての取得時刻tと座標(x! , 𝑦! )と階調値I(𝑥! , 𝑦!,𝑡)を 2 次元目の要素に割り当てることで階調値をベクトル化して Value に割り当てることができる。また,今回の実験では,ブロックの分散数とスレーブ数を一致させて,
Partitioner で各ブロックを異なるスレーブに送ることで分散化の効率を制御して実験を行った。画素のブロック分散(2次元配列)のプログラムは,付録 B-4に示す。
0:00:00
0:05:00
0:10:00
0:15:00
0:20:00
0:25:00
全点 1/2間引き 1/4間引き 1/8間引き
計算時間
(秒)
計算ケース
18
表 5 画素のブロック分散とブロックデータのベクトル化の実装形式 データ形式 データ内容
Key Value Key Value
Map
入
力 NULL
Writable BytesWritable ― 画像のデータ
出
力 VInt
Writable VIntTwoDArray
Writable 画像を分割した
時の領域 ID
1次元目:データの Index 2次元目:階調値,時刻,
座標
Reduce
入
力 VInt
Writable VIntTwoDArray
Writable 画像を分割した
時の領域 ID
1次元目:データの Index 2次元目:階調値,時刻,
座標
出
力 NULL
Writable TextWritable
Windowの順番の ID
最大値,最小値,平均値,
時刻
画素のブロック分散(2 次元配列)と VInt 形式による座標毎の分散のケースでのスレーブ
数による全体フェーズの計算時間と計算速度向上比の変化を図 21,図 22に示す。計算速度向上比は,座標毎の分散と比べて頭打ちする所が 20台までスケーラビリティが回復したが,理想的なスケーラビリティを確保することはできなかった。また,スレーブ数 20台の所で計算速度向上比が向上しているのは,スレーブ数 1 台の時の計算時間が膨大に増大しているからである。計算時間が膨大しているのは,Reduceに対して膨大なデータ量の負荷が掛かっているからと考えられる。
図 21 スレーブ数による計算時間の変化
0
10000
20000
30000
40000
50000
60000
70000
80000
90000
0 10 20 30 40 50
計算時間
(秒)
スレーブ数
画素のブロック分散(2次元配列)
座標毎の分散
19
図 22 スレーブ数による計算速度向上比の変化
4.4.6. 画素のブロック分散とブロックデータのベクトル化(1次元配列) 画素のブロック分散(2 次元配列)の手法では,分散単位を画素のブロックとして扱ってい
たが,画素ごとに時刻や座標などの情報を送っていた。そこで画像の画素が規則的な配列
で並んでいることを利用して冗長な情報を削減する方法を検討した。この手法を以後,画
素のブロック分散(1次元配列)と呼ぶことにする。画素のブロック分散(1次元配列)の実装形式を表 6に示す。この手法は,画素のブロック分散(2 次元配列)の手法とデータ形式は,基本同じであるが Value に関しての実装形式を変更する。Value でのデータ形式を 1 次元配列で実装する。データ内容は,ブロック化された領域の画像の取得時刻𝓉と先頭座標(x! , 𝑦!),
さらにベクトル化して取り出した階調値{I(𝑥! , 𝑦!𝑡), I(𝑥! + 1, 𝑦! , 𝑡),… }とする。また,今回の実
験では,スレーブ数 1台,10台の場合に計算時間が膨大に大きくなるためブロック数を 20として,各ブロックとノードの対応付けの制御は行わないことにした。画素のブロック分
散(1次元配列)のプログラムは,付録 B-5に示す。
0
5
10
15
20
25
30
35
40
45
0 10 20 30 40 50
計算速度向上比
スレーブ数
画素のブロック分散(2次元配列) 座標毎の分散
20
表 6 実装形式
データ形式 データ内容
Key Value Key Value
Map
入
力 Key Value
画像のデータ
出
力
NULL Writable
Bytes Writable
画像を分割した時の
領域 ID
1:画像の取得時刻 2:領域の始点座標 3-:画像の階調値
Reduce 入
力 VIntWritable
VIntArray Writable
画像を分割した時の
領域 ID
1:画像の取得時刻 2:領域の始点座標 3-:画像の階調値
出
力 VIntWritable
VIntArray Writable
Windowの順番のID
最大値,最小値,平均値,
時刻 次に,スレーブ数による全体フェーズの計算時間と計算速度向上比の変化を図 23,図 24
に示す。画素のブロック分散(2次元配列)を画素のブロック分散(1次元配列)の計算時間を比べると画素のブロック分散(1次元配列)の方が速くなったことが分かる。しかし,計算速度向上比はスレーブ数 20台の所で頭打ちが起きてしまった。
図 23 スレーブ数による計算時間の変化
0
10000
20000
30000
40000
50000
60000
70000
80000
90000
0 10 20 30 40 50
計算時間
(秒)
スレーブ数
画素のブロック分散(1次元配列)
画素のブロック分散(2次元配列)
座標毎の分散
21
図 24 スレーブ数による計算速度向比の変化
4.4.7. Map-Reduce間のデータ圧縮 Map-Reduce 間のデータ量を削減するためにデータ量の圧縮を検討した。以下に検討した圧縮ライブラリを表 7 に示す。圧縮ライブラリでは,Linux のためのビルド済みのネイティブの実装と Hadoopに組み込み済みの Javaでの実装の 2種類存在する。今回使用する実験環境では,ネイティブの実装とコーデックという圧縮/解凍アルゴリズムの実装ができないことからHadoopの標準アルゴリズムDEFLATEアルゴリズムを用いて圧縮を行った。圧縮の実装は,計算時間や Key1つあたりのデータサイズを考慮した結果,ブロック分散(1次元配列)と手法で圧縮を行った。また今回の実験でも,スレーブ数 1台,10台ではブロック数を一律 20で行う。
表 7 圧縮ライブラリのリスト 圧縮
フォーマット ツール アルゴリズム
ファイル名の 拡張子
Javaの実装
ネイティブの 実装
DEFLATE なし DEFLATE .deflate ○ ○ gzip Gzip DEFLATE .gz ○ ○
bzip2 bzip2 bzip2 .bz2 ○ ✕ LZO Lzop LZO .lzo ✕ ○ LZ4 なし LZ4 .lz4 ✕ ○
Snappy なし Snappy .snappy ✕ ○
0
5
10
15
20
25
30
35
40
45
0 10 20 30 40 50
計算速度向上比
スレーブ数
画素のブロック分散(1次元配列)
画素のブロック分散(2次元配列)
座標毎の分散
22
座標毎の分散と画素のブロック分散(圧縮なし)と画素のブロック(圧縮あり)のケースでのスレーブ数による全体フェーズの計算時間と計算速度向上比の変化を図 25,図 26に示す。圧縮を実装することによって計算速度向上比を確保することができた。計算速度向上比は
スレーブ数が増加することで計算速度向上比の増加が下がる傾向にある。その理由は,ス
レーブ数が増加することで分散数が増え,1台に対する圧縮効果が下がるからと考えられる。また,スレーブ数 50 台での各ケースでの計算時間を比較すると座標毎の分散では,2311秒,画素のブロック分散では 478 秒,圧縮を行った方は,126 秒となった。座標毎の分散と画素のブロック分散(圧縮あり)のケースでの計算時間を比較することで 18 分の1の計算時間に削減することができた。
図 25 スレーブ数による計算時間の変化
図 26 スレーブ数による計算速度向上比の変化
100
1000
10000
100000
0 10 20 30 40 50
計算時間
(秒)
スレーブ数
画素のブロック分散(圧縮あり) 画素のブロック分散(圧縮なし) 座標毎の分散
0 5
10 15 20 25 30 35 40 45 50
0 10 20 30 40 50
計算速度向上比
スレーブ数
画素のブロック分散(圧縮あり) 画素のブロック分散(圧縮なし) 座標毎の分散
23
次に,各ケースでの Map-Reduce 間のデータ量を比較した結果を表 8 に示す。画素のブロック分散のケースと座標毎の分散(圧縮なし)のケースを比べると約 5分の 1のデータ量削減となった。また,圧縮することで約 7 分の 1 程度のデータ量削減に成功した。座標毎の分散ケースと画素のブロック分散(圧縮あり)のケースを比較すると約 35 分の 1 のデータ量削減となった。
表 8 Map-Reduce間のデータ量の平均の比較
ケース Map-reduce間のデータ量
(MB) 1:画素のブロック分散(圧縮あり) 683 2:画素のブロック分散(圧縮なし) 4552 3:座標毎の分散 23736
次に,データ量を変化させて分散数を変化させたときの計算時間の比較を行った。比較
のため画像枚数を 1200 枚(3.2GB),2400 枚(6.4GB),3600 枚(9.6GB),4800 枚(12.8GB)と変化させながら画素のブロック分散(圧縮有り)のスレーブ数 50台でブロックの分散数 50,100,150,200,250 として変化させた時の各ケースの Map-Reduce 間の平均データ量を表 9,計算時間を図 27に示す。画像枚数 1200枚,2400枚では,スレーブ数と分散数が同じ数の時に計算時間が最も速いのに対し,画像枚数 3600 枚,4800 枚では,ブロックの分散数がスレーブ数を多いケースで計算時間が最も速くなる結果になった。
表 9 Map-Reduce間の平均データ量の比較
画像枚数 Map-Reduce間の平均データ量
(MB) 1200 717 2400 1435 3600 2152 4800 2869
24
図 27 ブロックの分散数による計算時間の変化
そこで,Reduceの過程が分散数とスレーブ数での計算時間に影響があると考え,画像枚数 4800枚で Reduceプロセス抜きと Reduce処理ありの 2つのケースで実験を行ったときのブロックの分散数と計算時間の変化を図 28に示す。Reduceプロセス抜きのケースでは,分散数とスレーブ数が一致するときに計算時間が最も速くなった。この結果から Reduceの処理が計算時間に影響を与えていることが分かる。
図 28 Reduceプロセス抜きでのブロックの分散数による計算時間の変化
0
200
400
600
800
1000
1200
1400
1600
0 50 100 150 200 250
計算時間
(秒)
分散数
1200枚
2400枚
3600枚
4800枚
0
200
400
600
800
1000
1200
1400
1600
0 50 100 150 200 250
計算時間
(秒)
分散数
4800枚
4800枚(reduce処理なし)
25
次に,分散数 1つあたりのMap-Reduce間のデータ量を比較したものを図 29に示す。データ量を比較した結果,分散数 1つあたりのMap-Reduce間のデータ量が 30MB を超えると Reduceの処理が飽和していることが分かる。しかし,Map-Reduce間のデータ量は圧縮を実装しているため,ケース毎に圧縮率が異なるので Reduceの過程で飽和が起きるデータ量の閾値を求めるのは,困難である。そこで,各ケースの圧縮解凍後の分散数 1 つあたりのMap-Reduce間のデータ量を比較したものを図 30に示す。データ量を比較した結果,分散数 1つあたりの入力データ量が 200MBを超えると Reduceの処理が飽和していることが考えられる。このことから入力データ量を考慮して分散数を変更しなければならないケー
スがあることが分かった。
図 29 分散数 1つあたりのMap-Reduce間のデータ量の変化
0
10
20
30
40
50
60
0 50 100 150 200 250
Map
-Red
uce間のデータ量
(MB)
分散数
1200枚2400枚3600枚4800枚
26
図 30 分散数 1つあたりの入力データ量の変化(圧縮解凍後)
4.4.8. 実験のまとめ 基礎実験からシステムの評価を行った。計算速度向上比を確保するためには,分散単位
を画素から画素のブロックとして扱い,Map-Reduce 間のデータ量に対して圧縮を行うことで理想的なスケーラビリティを確保できることが分かった。また,Map-Reduce 間のデータ量が分散数1つあたり 200MB を超えることで Reduce の処理が飽和してしまうため,入力データ量の上限を考慮しながら分散数を増やす必要があることも分かった。 次の章の実データに対する実験では,実験環境での最大スレーブ数 50台と画素のブロッ
ク分散(圧縮あり)のケースで実験を行う。
0
50
100
150
200
250
300
350
400
0 50 100 150 200 250
入力データ量
(MB)
分散数
1200枚
2400枚
3600枚
4800枚
27
5. 実データへの適用 5.1. 手法 構築したシステムの実データへの適用例として,気象衛星画像の時空間変動マイニング
に対する前処理として気象衛星画像からある時系列での同一地点の統計値を求めることを
実施する。前処理をすることで気象衛星画像に対する興味深い地点を探し,その後の知識
発見に役立てるのが目的である。実データへの適用のプログラムは,付録 Cに示す。
5.2. 実験データと実験環境 実験で用いたデータは,高知大学気象衛星情報頁[6]で保存されている気象衛星気象衛星
MTSAT-1,2 が撮影したものを緯度(北緯 70 度~南緯 70 度)・経度(東経 70 度~西経 150 度)座標にマッピングしたものである。MTSAT-1は,東経 140度,MTSAT-2は,東経 145度の赤道上の静止軌道に投入され,1時間毎に 5つのチャンネル(VIS,赤外線 4バンド)で観測されている。雲の消長の時空間の変動パターンを求めるため,赤外線バンド IR1(10.3~11.3µm)を選択した。画像サイズは,560×560 pixel ,空間解像度 0.25°/ pixel である 2012年の 1 月初めから 12 月末までのデータ(8734 枚)計約 2.6GB のデータを実験で用いることにした。実験環境は,前章の表 2 と同じである。今回の実験のタスクとしては,雲の動きの激しい所を探すために 2週間のウィンドウでの同一地点の平均値,分散を 12時間間隔ずらしで計算をノード数 50台で行うものとする。
5.3. 実験結果と考察 春,夏,秋,冬季節ごとの分散と平均値の空間分布を図 31,図 32 に示す。左上が冬(1月 1日から 14日),右上が春(4月 1日から 14日),左下が夏(7月 1日から 14日),右下が秋(10月 1日から 14日)の分散と平均値の空間分布図を表している。値が高いほど黒→紫→赤→黄と色が変化させている。 分散の結果から,赤道付近で雲の動きが激しいことが分かる。また,春と夏では,北半
球のほうが雲の動きが激しく,逆に秋と冬では,南半球のほうが雲の動きが激しいことが
分かる。
28
図 31 季節の分散(左上:冬(1月 1日から 14日),右上:春(4月 1日から 14日),左下:夏(7月 1日から 14日),右下:秋(10月 1日から 14日))
29
図 34 各季節での平均値
。
図 32 季節の平均値(左上:冬(1月 1日から 14日),右上:春(4月 1日から 14日),左下:夏(7月 1日から 14日),右下:秋(10月 1日から 14日))
30
また,今回のケースでも,データ量に対して分散数を変化させたときの計算時間の比較
を行った。画像枚数を 1 年分(8734 枚(2.6GB)),2 年分(17444 枚(6.4GB)),3 年分(26155枚(7.8GB)),4 年分(34877 枚(10.4GB))と変化させながら画素のブロック分散(圧縮有り)のスレーブ数 50台でブロックの分散数 50,100,150,200,250として変化させた時の各ケースのMap-Reduce間の平均データ量の平均を比較したものを表 10,計算時間の変化を図33 に示す。1 年分と 2 年分のケースでは,分散数とスレーブ数が一致するときに計算時間が最も速くなった。3年分と4年分のケースでは,分散数がスレーブ数より多いケースで計算時間が最も速くなった。また,4年分のケースでは,分散数がスレーブ数と一致するときに入力データ数が多くて処理ができなった。
表 10 Map-Reduce間の平均データの比較
ケース Map-Reduce間の平均データ量
(MB) 1年分 2472 2年分 4940 3年分 7427 4年分 10056
図 33 ブロックの分散数による計算時間の変化
0
2000
4000
6000
8000
10000
12000
14000
16000
18000
0 50 100 150 200 250
計算時間
(秒)
分散数
1年分
2年分
3年分
4年分
31
次に,各ケースの分散数 1つあたりのMap-Reduce間のデータ量を比較したものを図 34,に示す。分散数 1つあたりのMap-Reduce間のデータ量の結果では,100MBを超えた時にReduceの処理が飽和していることが考えられる。植生指標画像のケースの時と閾値が異なるのは,データでの圧縮効率が異なるからであると考えられる。分散数1つあたりの圧縮
解凍後の入力データ量の変化を図 35 で比較すると,植生指標画像のケースと同じ 200MBを超えると Reduceのデータ量が飽和していることが分かる。このことからこの値は,前章で求められた閾値と整合的であることが分かる。また,4年分のデータで Reduceの飽和が起きているのは,入力データ数が多いことが問題と考えられる。このことから入力データ
量,数に応じて分散数をスレーブ数より大きく設定しなければならないケースがあること
が分かり,これは使用するマシンの性能によって変わると考えられる。
図 34 分散数 1つあたりのMap-Reduce間のデータ量の変化
図 35 分散数 1つあたりの入力データ量の変化(圧縮解凍後)
0 20 40 60 80
100 120 140 160 180 200
0 50 100 150 200 250
Map-Redeuce間のデータ量(MB)
分散数
1年分2年分3年分4年分
0 50
100 150 200 250 300 350 400
0 50 100 150 200 250
入力データ量(MB)
分散数
1年分2年分3年分4年分
32
6. おわりに 本研究では,分散処理のフレームワークである Hadoop,MapReduceを用いて時系列画像に対する汎用分散データマイニングシステムの構築を目指した。実験環境のパフォーマ
ンスを評価するために 1152×1152 pixel の植生指標画像から同一地点の時系列データの抽出と統計量の計算を実装し,スレーブ数を増やした時のスケーラビリティでパフォーマン
スを評価した。 評価の結果,Map-Reduce 間のデータの流れが飽和するという現象が発生し,スケーラ
ビリティの確保が出来なかった。分散の単位を独立した画素として扱ってしまうことで,
座標や時間などのデータを何度も送ってしまい,Map-Reduce 間のデータ量を増加させていたと考えられる。そこでボトルネックを解消するために,扱う分散の単位を画素から画
像の並びの規則性を利用して,画素のブロックとして扱うことにした。分散の単位を画素
のブロックに変更することで Map-Reduce 間のデータ量を削減させた。また,更なるデータ量削減のために Map-Reduce 間のデータ量に対して圧縮を実装した。2 つの手段を実装することでスケーラビリティを確保できることが分かった。 しかし,スレーブ数に対して同じ分散数で実験を行った結果,スレーブ数 1,10台では,
計算時間が急激に増加した。そこでスレーブ数 50台でデータ量を変化させながら,分散数を変化させた時の計算時間を比較した。入力データ量を増やすことでスレーブ数と分散数
が同じときに計算時間が急激に増加する問題が生じた。そこで問題に対して Map-Reduce間のデータ量が影響しているかを確認するために Reduceプロセス抜きで,問題が起きた同じ条件で実験を行った結果,計算時間が急激に増加する問題は起きなかった。また,今回
の実験環境では,問題が起こるのはブロックあたりの圧縮解凍後のデータ量 200MBを超えるあたりであった。このことから Reduceの処理に応じて入力データ量の上限を考慮する必要があることが分かった。 また,実データへの適用例として気象衛星画像を用いて雲量変化が激しい所を探す前処
理を行ったところ,いくつか特徴的な所を発見することができた。今後は,汎用分散デー
タマイニングシステムのインタフェースの開発や異なる時空間断面を扱う問題を拡張しな
がらシステムを完成していく必要がある。
33
謝辞 本研究を進めるにあたり,ご指導を頂いた理学部数理情報科学科本田理恵准教授に深く
感謝します。共同研究者である,高知大学総合人間自然科学研究科修士過程の西前光先輩
には,細部にわたるご指導を頂き,感謝します。また,同研究室の方々には限られた時間
でしたが,常に刺激的な議論をさせて頂き,有意義な時間を過ごせました。ここに感謝の
意を表します。
34
参考文献 [1] 坂口祥太,時系列気象画像からの時空間相関性発見支援システムの構築, [2] 西前光,Hadoop による分散データマイニング ‐植生指標の時空間変動モデリングへ
の適用-,卒業論文 高知大学,2012 [3] Tom White,Hadoop,O’REILLY,2013 [4] 北川源四郎,時系列解析入門,岩波書店,2005 [5] 中野猛ほか,HADOOP HACKS,O’REILLY,2012 [6] 高知大学気象情報頁,http://weather.is.kochi-u.ac.jp
付録目次
A Hadoopの環境設定 .............................................................................................. A-1
A-1 hadoop-env.sh .................................................................................................. A-1
A-2 hdfs-site.xml ..................................................................................................... A-2
A-3 mapred-site.xml ............................................................................................... A-3
A-4 core-site.xml ..................................................................................................... A-5
B 植生指標画像から同一座標の最大値,最小値,平均値と時間を求めるプログラム
B-1
B-1 Text形式 .............................................................................................................. B-1
B-1-1 Text.java ........................................................................................................... B-1
B-1-2 TextMapper.java .............................................................................................. B-3
B-1-3 TextReducer.java ............................................................................................. B-4
B-1-4 WholeFileInputFormat.java ............................................................................ B-5
B-1-5 WholeFileRecordReader.java .......................................................................... B-6
B-2 VInt形式 .............................................................................................................. B-8
B-2-1 VInt.Java .......................................................................................................... B-8
B-2-2 VIntMapper.java ............................................................................................ B-10
B-2-3 VIntReducer.java ........................................................................................... B-11
B-2-4 VIntArrayWritable.java ................................................................................. B-13
B-3 Combinerの実装 ................................................................................................ B-14
B-3-1 Combiner_VInt.java ....................................................................................... B-14
B-3-2 Combiner_VInt_Mapper.java ........................................................................ B-16
B-3-3 Combiner_VInt_Reducer.java ....................................................................... B-17
B-3-4 Combine.java .................................................................................................. B-18
B-3-5 VIntArrayWritable.java ................................................................................. B-19
B-4 画素のブロック分散とブロックデータのベクトル化(2次元配列) ..................... B-20
B-4-1 groukey.java ................................................................................................... B-20
B-4-2 groupkeymapper.java .................................................................................... B-22
B-4-3 groupkeyreducer.java ..................................................................................... B-24
B-4-4 groupkeypartioner.java .................................................................................. B-26
B-4-5 VIntTwoDArrayWritable.java ....................................................................... B-27
B-5 画素のブロック分散とブロックデータのベクトル化(1次元配列) ..................... B-28
B-5-1 grouupkey.java ............................................................................................... B-28
B-5-2 groupkeymapper.java .................................................................................... B-30
B-5-3 groupkeyreducer.java ..................................................................................... B-32
B-5-4 KeyPartioner.java .......................................................................................... B-34
B-5-5 VIntArrayWritable.java ................................................................................. B-35
C 気象衛星画像から期間毎の同一地点の平均値と分散を求めるプログラム .......... C-1
C-1 MeteorologicalDriver.java ................................................................................... C-1
C-2 MeteoroloicalMapper.java ................................................................................... C-2
C-3 MeteorologicalReducer.java ................................................................................ C-4
C-4 KeyPartioner.java ............................................................................................... C-7
C-5 VIntArrayWritable.java ...................................................................................... C-8
A-1
A Hadoopの環境設定 A-1 hadoop-env.sh 1 # Set Hadoop-specific environment variables here. 2 3 # The only required environment variable is JAVA_HOME. All others are 4 # optional. When running a distributed configuration it is best to 5 # set JAVA_HOME in this file, so that it is correctly defined on 6 # remote nodes. 7 8 # The java implementation to use. Required. 9 # export JAVA_HOME=/usr/lib/j2sdk1.5-sun 10 #export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home 11 #export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home 12 export JAVA_HOME=/home/hadoop/java_old/Home//Javaのディレクトリ設定 13 14 # Extra Java CLASSPATH elements. Optional. 15 # export HADOOP_CLASSPATH= 16 17 # The maximum amount of heap to use, in MB. Default is 1000. 18 export HADOOP_HEAPSIZE=8192//Hadoop 一律のヒープサイズの設定 19 20 # Extra Java runtime options. Empty by default. 21 # export HADOOP_OPTS=-server 22 #export HADOOP_OPTS="-Djava.security.krb5.realm=OX.AC.UK -Djava.security.krb5.kdc=kdc0.ox.ac.uk:kdc1.ox.ac.uk" 23 export HADOOP_OPTS="-Djava.security.krb5.realm= -Djava.security.krb.kdc=" 24 25 # Command specific options appended to HADOOP_OPTS when specified 26 export HADOOP_NAMENODE_OPTS= "-javaagent:/home/hadoop/Halook/HalookJavelin_NN/lib/halookJavelin.jar-Dcom.sun.management.jmxremote $HADOOP_NAMENODE_OPTS"//NameNodeのデーモン 27 export HADOOP_SECONDARYNAMENODE_OPTS= "-Dcom.sun.management.jmxremote $HADOOP_SECONDARYNAMENODE_OPTS"//SecondaryNameNodeのデーモン 28 export HADOOP_DATANODE_OPTS="-Dcom.sun.management.jmxremote $HADOOP_DATANODE_OPTS"//DataNodeのデーモン 29 export HADOOP_BALANCER_OPTS="-Dcom.sun.management.jmxremote $HADOOP_BALANCER_OPTS"//Balanacerのデーモン 30 export HADOOP_JOBTRACKER_OPTS="-javaagent:/home/hadoop/Halook/HalookJavelin_JT/lib/halookJavelin.jar -Dcom.sun.management.jmxremote $HADOOP_JOBTRACKER_OPTS"//JobTrackerのデーモン 31 # export HADOOP_TASKTRACKER_OPTS= 32 # The following applies to multiple commands (fs, dfs, fsck, distcp etc) 33 # export HADOOP_CLIENT_OPTS 34 35 # Extra ssh options. Empty by default. 36 # export HADOOP_SSH_OPTS="-o ConnectTimeout=1 -o SendEnv=HADOOP_CONF_DIR" 37 38 # Where log files are stored. $HADOOP_HOME/logs by default. 39 # export HADOOP_LOG_DIR=${HADOOP_HOME}/logs 40 export HADOOP_LOG_DIR=/private/var/netboot/Users/Shared/hadoop
A-2
41 42 # File naming remote スレーブ hosts. $HADOOP_HOME/conf/スレーブ s by default. 43 # export HADOOP_スレーブ S=${HADOOP_HOME}/conf/スレーブ s 44 45 # host:path where hadoop code should be rsync'd from. Unset by default. 46 # export HADOOP_マスター=マスター:/home/$USER/src/hadoop 47 48 # Seconds to sleep between スレーブ commands. Unset by default. This 49 # can be useful in large clusters, where, e.g., スレーブ rsyncs can 50 # otherwise arrive faster than the マスター can service them. 51 # export HADOOP_スレーブ_SLEEP=0.1 52 53 # The directory where pid files are stored. /tmp by default. 54 # export HADOOP_PID_DIR=/var/hadoop/pids 55 56 # A string representing this instance of hadoop. $USER by default. 57 # export HADOOP_IDENT_STRING=$USER 58 59 # The scheduling priority for daemon processes. See 'man nice'. 60 # export HADOOP_NICENESS=10 61 export HADOOP_HOME_WARN_SUPPRESS="TRUE" 62 export JAVA_OPTS="-Dfile.encoding=UTF-8 -Djava.awt.headless=true" A-2 hdfs-site.xml 1 <?xml version="1.0"?> 2 <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> 3 4 <!-- Put site-specific property overrides in this file. --> 5 6 <configuration> 7 //レプリケーションの数 8 <property> 9 <name>dfs.replication</name> 10 <value>3</value> 11 </property> 12 //NameNodeがメタデータに保存するディレクトリのリスト 13 <property> 14 <name>dfs.name.dir</name> 15 <value>/private/var/netboot/Users/Shared/hadoop/name</value> 16 </property> 17 //DataNodeがブロックを保存するディレクトリのリスト 18 <property> 19 <name>dfs.data.dir</name> 20 <value>/private/var/netboot/Users/Shared/hadoop/data</value> 21 </property> 22 //ブロックのサイズ 23 <property> 24 <name>dfs.block.size</name> 25 <value>33554432</value> 26 </property> 27 </configuration>
A-3
A-3 mapred-site.xml 1 <?xml version="1.0"?> 2 <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> 3 4 <!-- Put site-specific property overrides in this file. --> 5 6 <configuration> 7 //jobtrackerの RPCサーバが動作するホスト名とポート 8 <property> 9 <name>mapred.job.tracker</name> 10 <value>pcv1-59:9001</value> 11 </property> 12 //Map-Reduceのシステムファイルが格納される場所 13 <property> 14 <name>mapred.system.dir</name> 15 <value>/private/var/netboot/Users/Shared/hadoop/system</value> 16 </property> 17 //tasktrackerにおいて同時に実行される最大タスク数 18 <property> 19 <name>mapred.tasktracker.map.tasks.maximum</name> 20 <value>1</value> 21 </property> 22 //tasktrackerにおいて同時に実行される最大タスク数 23 <property> 24 <name>mapred.tasktracker.reduce.tasks.maximum</name> 25 <value>1</value> 26 </property> 27 //クラスタ全体で使用されるタスク数 28 <property> 29 <name>mapred.map.tasks</name> 30 <value>50</value> 31 </property> 32 //クラスタ全体で使用されるタスク数 33 <property> 34 <name>mapred.reduce.tasks</name> 35 <value>50</value> 36 </property> 37 //タスクを実行する tasktrackerの子プロセスを起動するために使われる JVMのメモリ 38 <property> 39 <name>mapred.child.java.opts</name> 40 <value>-Xmx8192m</value> 41 </property> 42 //圧縮の有無 43 <property> 44 <name>mapred.compress.map.output</name> 45 <value>true</value> 46 </property> 47 //タスクのタイムアウト 48 <property> 49 <name>mapred.task.timeout</name> 50 <value>14400000</value> 51 <description>The number of milliseconds before a task will be 52 53
A-4
54 </description> 55 </property> 56 </configuration>
A-5
A-4 core-site.xml 1 <?xml version="1.0"?> 2 <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> 3 4 <!-- Put site-specific property overrides in this file. --> 5 6 <configuration> 7 //hadoop関連ファイルの位置 8 <property> 9 <name>hadoop.tmp.dir</name> 10 <value>/private/var/netboot/Users/Shared/hadoop/tmp/hadoop-${user.name}</value> 11 </property> 12 //チェックポイントの保存するディレクトリのリスト 13 <property> 14 <name>fs.checkpoint.dir</name> 15 <value>/private/var/netboot/Users/Shared/hadoop/checkpoint</value> 16 </property> 17 //デフォルトのファイルシステム 18 <property> 19 <name>fs.default.name</name> 20 <value>hdfs://pcv1-60:9000</value> 21 </property> 22 //ネイティブの実装の有無 23 <property> 24 <name>hadoop.native.lib</name> 25 <value>false</value> 26 </property> 27 //バッファサイズの設定 28 <property> 29 <name>io.file.buffer.size</name> 30 <value>4096</value> 31 <description> 32 33 34 </description> 35 </property> 36 </configuration>
B-1
B 植生指標画像から同一座標の最大値,最小値,平均値と時間を求めるプログラム
B-1 Text形式 WholeFileRecordReader.java, WholeFileInputFormat.javaのプログラムは以後,共通なので省略する。 B-1-1 Text.java 1 import java.lang.String; 2 import java.util.Date; 3 import java.util.Formatter; 4 import org.apache.hadoop.conf.Configuration; 5 import org.apache.hadoop.conf.Configured; 6 import org.apache.hadoop.fs.Path; 7 import org.apache.hadoop.io.*; 8 import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; 9 import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; 10 import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat; 11 import org.apache.hadoop.mapreduce.Job; 12 import org.apache.hadoop.util.GenericOptionsParser; 13 import org.apache.hadoop.util.Tool; 14 import org.apache.hadoop.util.ToolRunner; 15 16 public class kadai1 extends Configured implements Tool{ 17 18 19 20 21 @Override 22 public int run(String args[]) throws Exception{ 23 Configuration conf = getConf(); 24 if (conf == null) { 25 26 } 27 28 String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs(); 29 30 Job job = new Job(conf, "Kadai1"); 31 //実装するクラスの設定 32 job.setJarByClass(kadai1.class); 33 job.setMapperClass(Kadai1Mapper.class); 34 job.setReducerClass(Kadai1Reducer.class); 35 job.setInputFormatClass(WholeFileInputFormat.class); 36 job.setOutputFormatClass(TextOutputFormat.class); 37 job.setNumReduceTasks(Integer.parseInt(args[2])); 38 job.setMapOutputKeyClass(Text.class); 39 job.setOutputKeyClass(Text.class); 40 job.setOutputValueClass(Text.class); 41 42 FileInputFormat.addInputPath(job, new Path(otherArgs[0])); 43 Formatter formatter = new Formatter(); 44 //出力ファイル 45 String outpath = "Out" 46
B-2
47 FileOutputFormat.setOutputPath(job, new Path(outpath)); 48 49 50 return job.waitForCompletion(true) ? 0 : 1; 51 } 52 53 public static void main(String[] args) throws Exception { 54 int exitCode = ToolRunner.run(new kadai1(), args); 55 System.exit(exitCode); 56 } 57 58 59 }
B-3
B-1-2 TextMapper.java 1 import java.io.IOException; 2 import org.apache.hadoop.conf.Configuration; 3 import org.apache.hadoop.io.BytesWritable; 4 import org.apache.hadoop.io.NullWritable; 5 import org.apache.hadoop.io.Text; 6 import org.apache.hadoop.mapreduce.Mapper; 7 8 public class Kadai1Mapper extends Mapper<NullWritable, BytesWritable, Text, Text>{ 9 public static final int OFFSET=8; 10 public static final int XAXIS=1152; 11 public static final int YAXIS=1152; 12 13 14 public void map(NullWritable key, BytesWritable value, Context context) 15 throws IOException, InterruptedException { 16 17 int i,j,k; 18 Configuration conf = context.getConfiguration(); 19 //分割ファイルからのファイルの時間取得 20 String filename =conf.get("map.input.file"); 21 String[] url=filename.split("/"); 22 String[] kariname=url[url.length-1].split("_"); 23 24 //階調値取得 25 byte[] data = value.getBytes(); 26 BytesWritable bw =new BytesWritable(); 27 for(i=0;i<XAXIS;i+=100){ 28 for(j=0;j<YAXIS;j+=100){ 29 k=2*XAXIS*j+2*i+OFFSET; 30 bw.set(data,k,2); 31 byte[] bws=bw.getBytes(); 32 int vi=(bws[1]<<8)+(bws[0]&0xFF); 33 String Info= String.valueOf(vi)+','+kariname[0]; //輝度と名前 34 String key2=(i+","+j); 35 //Reduceにデータ出力 36 context.write(new Text(key2), new Text (Info)); 37 } 38 } 39 } 40 41 }
B-4
B-1-3 TextReducer.java 1 import java.io.IOException; 2 import org.apache.hadoop.io.IntWritable; 3 import org.apache.hadoop.io.Text; 4 import org.apache.hadoop.mapreduce.Reducer; 5 6 public class TextReducer 7 extends Reducer<Text, Text, Text, Text> { 8 9 @Override 10 public void reduce(Text key, Iterable<Text> values, 11 Context context) 12 throws IOException, Interrupted Exception { 13 String s; 14 String str; 15 int[] max=new int[2]; 16 int[] min=new int[2]; 17 int count=0; 18 double sum=0.0; 19 min[0]=10000; 20 //階調値の比較 21 for(Text value:values){ 22 s=value.toString(); 23 String[] tmp=s.split(","); 24 int kari=Integer.valueOf(tmp[0]); 25 //最大値比較 26 if(max[0]<kari){ 27 max[0]=kari; 28 max[1]=Integer.valueOf(tmp[1]); 29 } 30 //最小値比較 31 if(min[0]>kari){ 32 min[0]=kari; 33 min[1]=Integer.ValueOf(tmp[1]); 34 } 35 sum+=kari; 36 count++; 37 } 38 str="最大値"+max[0]+"最大値時間"+max[1]+"最小値"+min[0]+"最小値時間"+min[1]+"平均値"+(sum/count); 39 //出力データ 40 context.write(key, new Text(str)); 41 42 } 43 44 }
B-5
B-1-4 WholeFileInputFormat.java 1 import java.io.IOException; 2 import org.apache.hadoop.fs.*; 3 import org.apache.hadoop.io.*; 4 import org.apache.hadoop.mapreduce.InputSplit; 5 import org.apache.hadoop.mapreduce.*; 6 import org.apache.hadoop.mapreduce.JobContext; 7 import org.apache.hadoop.mapreduce.RecordReader; 8 import org.apache.hadoop.mapreduce.lib.input.*; 9 //1つのファイル全体を1レコードとして読み込む mapperのための InputFormat 10 public class WholeFileInputFormat extends FileInputFormat<NullWritable, BytesWritable> { 11 12 public RecordReader<NullWritable, BytesWritable> createRecordReader( 13 14 15 16 return new WholeFileRecordReader(split, context); 17 } 18 19 protected boolean isSplitable(JobContext context, Path filename) { 20 return false; 21 } 22 23 24 }
B-6
B-1-5 WholeFileRecordReader.java 1 import java.io.IOException; 2 import org.apache.hadoop.conf.Configuration; 3 import org.apache.hadoop.fs.*; 4 import org.apache.hadoop.io.*; 5 import org.apache.hadoop.mapreduce.*; 6 import org.apache.hadoop.mapreduce.lib.input.*; 7 //WholeFileInputFormatがファイル全体を1レコードとして読み込むために使う RecordReader 8 public class WholeFileRecordReader 9 extends RecordReader<NullWritable, BytesWritable> { 10 11 private FileSplit fileSplit; 12 private Configuration conf; 13 private boolean processed = false; 14 15 private BytesWritable value = new BytesWritable(); 16 17 18 public WholeFileRecordReader(InputSplit inputSplit, TaskAttemptContext context) 19 throws IOException, InterruptedException { 20 21 initialize(inputSplit, context); 22 } 23 24 public void initialize(InputSplit inputSplit, TaskAttemptContext context) 25 throws IOException, InterruptedException { 26 27 this.fileSplit = (FileSplit)inputSplit; 28 this.conf = context.getConfiguration(); 29 } 30 31 public NullWritable getCurrentKey() 32 throws IOException, InterruptedException { 33 34 return NullWritable.get(); 35 } 36 37 public BytesWritable getCurrentValue() 38 throws IOException, InterruptedException { 39 40 return value; 41 } 42 43 public float getProgress() 44 throws IOException, InterruptedException { 45 46 return processed ? 1.0f : 0.0f; 47 } 48 49 public boolean nextKeyValue() 50 throws IOException, InterruptedException { 51 52 if (!processed) { 53 byte[] contents = new byte[(int) fileSplit.getLength()];
B-7
54 Path file = fileSplit.getPath(); 55 FileSystem fs = file.getFileSystem(conf); 56 FSDataInputStream in = null; 57 try { 58 59 60 61 62 } finally { 63 64 } 65 66 processed = true; 67 return true; 68 } 69 return false; 70 } 71 72 public void close() throws IOException { 73 74 } 75 } 76
B-8
B-2 VInt形式
B-2-1 VInt.Java 1 import java.lang.String; 2 import java.util.Date; 3 import java.util.Formatter; 4 import org.apache.hadoop.conf.Configuration; 5 import org.apache.hadoop.conf.Configured; 6 import org.apache.hadoop.fs.Path; 7 import org.apache.hadoop.io.*; 8 import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; 9 import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; 10 import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat; 11 import org.apache.hadoop.mapreduce.Job; 12 import org.apache.hadoop.util.GenericOptionsParser; 13 import org.apache.hadoop.util.Tool; 14 import org.apache.hadoop.util.ToolRunner; 15 16 public class kadai1 extends Configured implements Tool{ 17 18 @Override 19 public int run(String args[]) throws Exception{ 20 Configuration conf = getConf(); 21 if (conf == null) { 22 23 } 24 25 String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs(); 26 27 Job job = new Job(conf, "Kadai1"); 28 //実装するクラスの設定 29 job.setJarByClass(kadai1.class); 30 job.setMapperClass(Kadai1Mapper.class); 31 job.setReducerClass(Kadai1Reducer.class); 32 job.setInputFormatClass(WholeFileInputFormat.class); 33 job.setOutputFormatClass(TextOutputFormat.class); 34 job.setNumReduceTasks(Integer.parseInt(args[2])); 35 job.setMapOutputKeyClass(VIntWritable.class); 36 job.setMapOutputValueClass(VIntArrayWritable.class); 37 job.setOutputKeyClass(Text.class); 38 job.setOutputValueClass(Text.class); 39 40 FileInputFormat.addInputPath(job, new Path(otherArgs[0])); 41 Formatter formatter = new Formatter(); 42 //出力データ 43 String outpath = "Out" 44 45 FileOutputFormat.setOutputPath(job, new Path(outpath)); 46 47 48 return job.waitForCompletion(true) ? 0 : 1; 49 } 50 51 public static void main(String[] args) throws Exception {
B-9
52 int exitCode = ToolRunner.run(new kadai1(), args); 53 System.exit(exitCode); 54 } 55 56 57 }
B-10
B-2-2 VIntMapper.java 1 import java.io.IOException; 2 import org.apache.hadoop.conf.Configuration; 3 import org.apache.hadoop.io.BytesWritable; 4 import org.apache.hadoop.io.NullWritable; 5 import org.apache.hadoop.io.VIntWritable; 6 import org.apache.hadoop.mapreduce.Mapper; 7 8 public class Kadai1Mapper extends Mapper<NullWritable, BytesWritable, VIntWritable, VIntArrayWritable>{ 9 //画像のサイズとオフセット値(ヘッダ) 10 public static final int OFFSET=8; 11 public static final int XAXIS=1152; 12 public static final int YAXIS=1152; 13 14 15 public void map(NullWritable key, BytesWritable value, Context context) 16 throws IOException, InterruptedException { 17 18 int i,j,k; 19 20 VIntWritable[] vintvalue=new VIntWritable[2]; 21 //ファイルから時間取得 22 Configuration conf = context.getConfiguration(); 23 String filename =conf.get("map.input.file"); 24 String[] url=filename.split("/"); 25 String[] kariname=url[url.length-1].split("_"); 26 vintvalue[0]=new VIntWritable(Integer.valueOf(kariname[0]));//日時 27 //ファイルから階調値取得 28 byte[] data = value.getBytes(); 29 BytesWritable bw =new BytesWritable(); 30 for(i=0;i<XAXIS;i+=1){ 31 for(j=0;j<YAXIS;j+=1){ 32 k=2*XAXIS*j+2*i+OFFSET; 33 bw.set(data,k,2); 34 byte[] bws=bw.getBytes(); 35 int vi=(bws[1]<<8)+(bws[0]&0xFF);//階調値 36 vintvalue[1]=new VIntWritable(vi); 37 int context_key=(j*1152+i);//座標 38 //Reduceへ出力 39 context.write(new VIntWritable(context_key), new VIntArrayWritable(vintvalue)); 40 } 41 } 42 } 43 44 }
B-11
B-2-3 VIntReducer.java 1 import java.io.IOException; 2 import org.apache.hadoop.io.Text; 3 import org.apache.hadoop.io.Writable; 4 import org.apache.hadoop.mapreduce.Reducer; 5 import org.apache.hadoop.io.VIntWritable; 6 7 public class Kadai1Reducer 8 extends Reducer<VIntWritable, VIntArrayWritable, Text, Text> { 9 10 @Override 11 public void reduce(VIntWritable key, Iterable<VIntArrayWritable> values, 12 Context context) 13 14 15 16 int x=0,y=0; 17 final int gazou_size=1152; 18 String str; 19 int[] max=new int[2]; 20 int[] min=new int[2]; 21 int count=0; 22 double sum=0.0; 23 min[0]=10000; 24 //階調値比較 25 for(VIntArrayWritable value:values){ 26 Writable[] tmp=value.get(); 27 int vi=((VIntWritable)tmp[1]).get(); 28 //最大値比較 29 if(max[0]<vi){ 30 31 32 33 } 34 //最小値比較 35 if(min[0]>vi){ 36 37 38 } 39 sum+=vi; 40 count++; 41 42 } 43 44 int zahyou=key.get();//座標 45 46 x=(zahyou/gazou_size); 47 y=zahyou-((zahyou/gazou_size)*gazou_size); 48 49 str="最大の輝度"+max[0]+"日時"+max[1]+"最小の輝度"+min[0]+"日時"+min[1]+"平均値"+(sum/count); 50 //出力 51 context.write(new Text(x+","+y),new Text(str)); 52
B-12
53 } 54 55 }
B-13
B-2-4 VIntArrayWritable.java 1 import org.apache.hadoop.io.ArrayWritable; 2 import org.apache.hadoop.io.VIntWritable; 3 //VIntArratWritableを使用するためのクラス作成 4 public class VIntArrayWritable extends ArrayWritable{ 5 public VIntArrayWritable(){ 6 super(VIntWritable.class); 7 } 8 public VIntArrayWritable(VIntWritable[] colArr){ 9 super(VIntArrayWritable.class,colArr); 10 } 11 }
B-14
B-3 Combinerの実装 B-3-1 Combiner_VInt.java 1 import java.lang.String; 2 import java.util.Date; 3 import java.util.Formatter; 4 import org.apache.hadoop.conf.Configuration; 5 import org.apache.hadoop.conf.Configured; 6 import org.apache.hadoop.fs.Path; 7 import org.apache.hadoop.io.*; 8 import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; 9 import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; 10 import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat; 11 import org.apache.hadoop.mapreduce.Job; 12 import org.apache.hadoop.util.GenericOptionsParser; 13 import org.apache.hadoop.util.Tool; 14 import org.apache.hadoop.util.ToolRunner; 15 16 public class kadai1 extends Configured implements Tool{ 17 18 @Override 19 public int run(String args[]) throws Exception{ 20 Configuration conf = getConf(); 21 if (conf == null) { 22 return -1; 23 } 24 25 String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs(); 26 27 Job job = new Job(conf, "Kadai1"); 28 //実装するクラスの設定 29 job.setJarByClass(kadai1.class); 30 job.setMapperClass(Kadai1Mapper.class); 31 job.setReducerClass(Kadai1Reducer.class); 32 job.setInputFormatClass(WholeFileInputFormat.class); 33 job.setOutputFormatClass(TextOutputFormat.class); 34 job.setNumReduceTasks(Integer.parseInt(args[2])); 35 job.setMapOutputKeyClass(VIntWritable.class); 36 job.setMapOutputValueClass(VIntArrayWritable.class); 37 job.setOutputKeyClass(Text.class); 38 job.setOutputValueClass(Text.class); 39 job.setCombinerClass(Combine.class); 40 41 FileInputFormat.addInputPath(job, new Path(otherArgs[0])); 42 Formatter formatter = new Formatter(); 43 //出力データ 44 String outpath = "Out" 45 + formatter.format("%1$tm%1$td%1$tH%1$tM%1$tS", new Date()); 46 FileOutputFormat.setOutputPath(job, new Path(outpath)); 47 48 49 return job.waitForCompletion(true) ? 0 : 1; 50 }
B-15
51 52 public static void main(String[] args) throws Exception { 53 int exitCode = ToolRunner.run(new kadai1(), args); 54 System.exit(exitCode); 55 } 56 57 58 }
B-16
B-3-2 Combiner_VInt_Mapper.java 1 import java.io.IOException; 2 import org.apache.hadoop.conf.Configuration; 3 import org.apache.hadoop.io.BytesWritable; 4 import org.apache.hadoop.io.NullWritable; 5 import org.apache.hadoop.io.VIntWritable; 6 import org.apache.hadoop.mapreduce.Mapper; 7 8 public class Kadai1Mapper extends Mapper<NullWritable, BytesWritable, VIntWritable, VIntArrayWritable>{ 9 public static final int OFFSET=8; 10 public static final int XAXIS=1152; 11 public static final int YAXIS=1152; 12 13 public void map(NullWritable key, BytesWritable value, Context context) 14 throws IOException, InterruptedException { 15 16 int i,j,k; 17 VIntWritable[] vintvalue=new VIntWritable[2]; 18 //時間取得 19 Configuration conf = context.getConfiguration(); 20 String filename =conf.get("map.input.file"); 21 String[] url=filename.split("/"); 22 String[] kariname=url[url.length-1].split("_"); 23 vintvalue[0]=new VIntWritable(Integer.valueOf(kariname[0]));//時間 24 25 byte[] data = value.getBytes(); 26 BytesWritable bw =new BytesWritable(); 27 //階調値取得 28 for(i=0;i<XAXIS;i+=2){ 29 for(j=0;j<YAXIS;j+=2){ 30 k=2*XAXIS*j+2*i+OFFSET; 31 bw.set(data,k,2); 32 byte[] bws=bw.getBytes(); 33 int vi=(bws[1]<<8)+(bws[0]&0xFF); 34 vintvalue[1]=new VIntWritable(vi); 35 int context_key=j*1152+i; 36 //Reduceへの出力データ 37 context.write(new VIntWritable(context_key), new VIntArrayWritable(vintvalue)); 38 } 39 } 40 } 41 } 42 43 }
B-17
B-3-3 Combiner_VInt_Reducer.java 1 import java.io.IOException; 2 import org.apache.hadoop.io.Text; 3 import org.apache.hadoop.io.Writable; 4 import org.apache.hadoop.mapreduce.Reducer; 5 import org.apache.hadoop.io.VIntWritable; 6 7 public class Kadai1Reducer 8 extends Reducer<VIntWritable, VIntArrayWritable, Text, Text> { 9 10 @Override 11 public void reduce(VIntWritable key, Iterable<VIntArrayWritable> values, 12 Context context) 13 throws IOException, Interrupted Exception { 14 15 int x=0,y=0; 16 String str; 17 int[] max=new int[2]; 18 int[] min=new int[2]; 19 int count=0; 20 double sum=0.0; 21 min[0]=10000; 22 //階調値比較 23 for(VIntArrayWritable value:values){ 24 Writable[] tmp=value.get(); 25 int vi=((VIntWritable)tmp[1]).get(); 26 //最大値比較 27 if(max[0]<vi){ 28 max[0]=vi; 29 max[1]=((VIntWritable)tmp[0]).get(); 30 } 31 //最小値比較 32 if(min[0]>vi){ 33 min[0]=vi; 34 min[1]=((VIntWritable)tmp[0]).get(); 35 36 sum+=vi; 37 count++; 38 39 } 40 int zahyou=key.get(); 41 x=zahyou%1152; 42 y=zahyou/1152; 43 44 str="最大の輝度 "+max[0]+"日時 "+max[1]+"最小の輝度 "+min[0]+"日時"+min[1]+"平均値"+(sum/count); 45 //出力データ 46 context.write(new Text(x+","+y),new Text(str)) ; 47 } 48 49 }
B-18
B-3-4 Combine.java 1 import java.io.IOException; 2 import org.apache.hadoop.io.VIntWritable; 3 import org.apache.hadoop.io.Writable; 4 import org.apache.hadoop.mapreduce.Reducer; 5 6 public class Combine extends Reducer<VIntWritable,VIntArrayWritable,VIntWritable, VIntArrayWritable> { 7 @Override 8 protected void reduce(VIntWritable key, Iterable<VIntArrayWritable> values, Context context) throws IOException, InterruptedException { 9 //最大値と最小値のための変数 10 VIntWritable[] max=new VIntWritable[2]; 11 VIntWritable[] min=new VIntWritable[2]; 12 int default_max=0,default_min=0; 13 //階調値比較 14 for(VIntArrayWritable value:values){ 15 Writable[] tmp= value.get(); 16 int vi=((VIntWritable)tmp[1]).get(); 17 if(default_max<vi){ 18 max[1]=(VIntWritable)tmp[1]; 19 max[0]=(VIntWritable)tmp[0]; 20 } 21 if(default_min>vi){ 22 min[1]=(VIntWritable)tmp[1]; 23 min[0]=(VIntWritable)tmp[0]; 24 } 25 } 26 //Reduceへ出力 27 for(int i=0;i<2;i++){ 28 if(i==0) 29 context.write(key, new VIntArrayWritable(max)); 30 else 31 context.write(key, new VIntArrayWritable(min)); 32 33 } 34 35 } 36 }
B-19
B-3-5 VIntArrayWritable.java 1 import org.apache.hadoop.io.ArrayWritable; 2 import org.apache.hadoop.io.VIntWritable; 3 //VIntArrayを使用するためのクラス作成 4 public class VIntArrayWritable extends ArrayWritable{ 5 public VIntArrayWritable(){ 6 super(VIntWritable.class); 7 } 8 public VIntArrayWritable(VIntWritable[] colArr){ 9 super(VIntArrayWritable.class,colArr); 10 } 11 }
B-20
B-4 画素のブロック分散とブロックデータのベクトル化(2次元配列) B-4-1 groukey.java 1 import java.lang.String; 2 import java.util.Date; 3 import java.util.Formatter; 4 import org.apache.hadoop.conf.Configuration; 5 import org.apache.hadoop.conf.Configured; 6 import org.apache.hadoop.fs.Path; 7 import org.apache.hadoop.io.*; 8 import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; 9 import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; 10 import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat; 11 import org.apache.hadoop.mapreduce.Job; 12 import org.apache.hadoop.util.GenericOptionsParser; 13 import org.apache.hadoop.util.Tool; 14 import org.apache.hadoop.util.ToolRunner; 15 16 public class groupkey extends Configured implements Tool{ 17 18 19 20 21 @Override 22 public int run(String args[]) throws Exception{ 23 Configuration conf = getConf(); 24 if (conf == null) { 25 return -1; 26 } 27 28 String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs(); 29 Job job = new Job(conf, "Kadai1"); 30 job.setJarByClass(groupkey.class); 31 job.setMapperClass(groupkeymapper.class); 32 job.setReducerClass(groupkeyreducer.class); 33 job.setInputFormatClass(WholeFileInputFormat.class); 34 job.setOutputFormatClass(TextOutputFormat.class); 35 job.setNumReduceTasks(Integer.parseInt(args[2])); 36 job.setMapOutputKeyClass(VIntWritable.class); 37 job.setMapOutputValueClass(VIntTwoDArrayWritable.class); 38 job.setOutputKeyClass(Text.class); 39 job.setOutputValueClass(Text.class); 40 41 FileInputFormat.addInputPath(job, new Path(otherArgs[0])); 42 Formatter formatter = new Formatter(); 43 String outpath = "Out" 44 + formatter.format("%1$tm%1$td%1$tH%1$tM%1$tS", new Date()); 45 FileOutputFormat.setOutputPath(job, new Path(outpath)); 46 job.setPartitionerClass(kadaipartitioner.class); 47 48 return job.waitForCompletion(true) ? 0 : 1; 49 } 50
B-21
51 public static void main(String[] args) throws Exception { 52 int exitCode = ToolRunner.run(new groupkey(), args); 53 System.exit(exitCode); 54 } 55 56 57 }
B-22
B-4-2 groupkeymapper.java 1 import java.io.IOException; 2 import org.apache.hadoop.conf.Configuration; 3 import org.apache.hadoop.io.BytesWritable; 4 import org.apache.hadoop.io.NullWritable; 5 import org.apache.hadoop.io.VIntWritable; 6 import org.apache.hadoop.mapreduce.Mapper; 7 8 public class groupkeymapper extends Mapper<NullWritable, BytesWritable, VIntWritable, VIntTwoDArrayWritable>{ 9 public static final int OFFSET=8; 10 public static final int XAXIS=1152; 11 public static final int YAXIS=1152; 12 13 public void map(NullWritable key, BytesWritable value, Context context) 14 throws IOException, InterruptedException { 15 16 int k,data_count=0;//データのインデックス 17 int task_num;//keyの番号 18 int total=XAXIS*YAXIS;//データの総数 19 int numReducetasks = (context.getNumReduceTasks());//Reduceの数取得 20 int data_limit;//タスクあたりのデータサイズ 21 22 if((total%numReducetasks)==0){ 23 data_limit= (int)(total/numReducetasks);//タスクあたりのでデータサイズ 24 } 25 else{ 26 data_limit= ((int)(total/numReducetasks))+1;//タスクあたりのでデータサイズ 27 } 28 29 //ファイルから時間を取得 30 VIntWritable[][] vintvalue=new VIntWritable[data_limit][3]; 31 Configuration conf = context.getConfiguration(); 32 String filename =conf.get("map.input.file"); 33 String[] url=filename.split("/"); 34 String[] kariname=url[url.length-1].split("_"); 35 //VI取得のための配列を取得 36 byte[] data = value.getBytes(); 37 BytesWritable bw =new BytesWritable(); 38 //空配列をなくすための前処理 39 for(int last=((total%data_limit)+1);last<data_limit;last++){ 40 vintvalue[last][0]=new VIntWritable(-10000);//日時 41 vintvalue[last][1]=new VIntWritable(-10000);//植生 42 vintvalue[last][2]=new VIntWritable(-10000);//座標 43 } 44 //画像から1次元データとして順番にデータを取得 45 for(int j=0;j<XAXIS;j+=1){ 46 for(int i=0;i<YAXIS;i+=1){ 47 //画像から VI値取得 48 k=2*XAXIS*j+2*i+OFFSET; 49 bw.set(data,k,2); 50 byte[] bws=bw.getBytes();
B-23
51 int vi=(bws[1]<<8)+(bws[0]&0xFF); 52 int context_key=j*1152+i;//座標 53 //データのインデックス 54 data_count=context_key%data_limit; 55 vintvalue[data_count][0]=new VIntWritable(Integer.valueOf (kariname[0]));//日時 56 vintvalue[data_count][1]=new VIntWritable(vi);//植生 57 vintvalue[data_count][2]=new VIntWritable(context_key);//座標 58 59 //data_limitの数まで値を取得したら値を Reduceに送る 60 if (data_count == data_limit-1 || context_key == total -1){ 61 task_num=(int) Math.floor(context_key/data_limit);//ke作成 62 context.write(new VIntWritable(task_num), new VIntTwoDArrayWritable(vintvalue)); 63 } 64 } 65 } 66 } 67 }
B-24
B-4-3 groupkeyreducer.java 1 import java.io.IOException; 2 import java.util.HashMap; 3 import org.apache.hadoop.io.Text; 4 import org.apache.hadoop.io.VIntWritable; 5 import org.apache.hadoop.io.Writable; 6 import org.apache.hadoop.mapreduce.Reducer; 7 8 public class groupkeyreducer 9 extends Reducer<VIntWritable, VIntTwoDArrayWritable, Text, Text> { 10 public static final int XAXIS=1152; 11 public static final int YAXIS=1152; 12 13 @Override 14 public void reduce(VIntWritable key, Iterable<VIntTwoDArrayWritable> values, 15 Context context) 16 throws IOException, InterruptedException { 17 18 HashMap<Integer,Integer[]> map_max = new HashMap <Integer,Integer[]>(); 19 int x=0,y=0; 20 final int gazou_size=1152; 21 String str; 22 //階調値比較 23 for(VIntTwoDArrayWritable value:values){ 24 Writable[][] value_length = value.get(); 25 for(int count_array=0;count_array<value_length.length;count_array++){ 26 Integer[] first_value = new Integer[7]; 27 Writable[][] tmp = value.get(); 28 int time_max=((VIntWritable)tmp[count_array][0]).get();//time max 29 int max_vi=((VIntWritable)tmp[count_array][1]).get();//vi最大値 30 int zahyou=((VIntWritable)tmp[count_array][2]).get();//座標 31 int time_min=((VIntWritable)tmp[count_array][0]).get();//time min 32 int min_vi=((VIntWritable)tmp[count_array][1]).get();//vi最小値 33 int sum=((VIntWritable)tmp[count_array][1]).get();//総数 34 int count=1;//個数 35 first_value[0]=time_max; 36 first_value[1]=max_vi; 37 first_value[2]=zahyou; 38 first_value[3]=time_min; 39 first_value[4]=min_vi; 40 first_value[5]=sum; 41 first_value[6]=count; 42 //階調値比較 43 if(map_max.containsKey(zahyou) == true ){ 44 Integer[] tmp2 = map_max.get(zahyou); 45 46 //比べるための値設定 47 int com_vi_max=tmp2[1];//植生 48 int com_vi_min=tmp2[4];//植生 49 int com_count=tmp2[6];//個数 50 //最大値比較 51 if(com_vi_max<max_vi){ 52 first_value[3]=tmp2[3]; 53 first_value[4]=tmp2[4];
B-25
54 first_value[5]=tmp2[5]+max_vi; 55 first_value[6]=com_count+1; 56 map_max.put(zahyou, first_value); 57 } 58 //最小値比較 59 else if(com_vi_min>min_vi){ 60 first_value[0]=tmp2[0]; 61 first_value[1]=tmp2[1]; 62 first_value[5]=tmp2[5]+min_vi; 63 first_value[6]=com_count+1; 64 map_max.put(zahyou, first_value); 65 } 66 //それ以外の値 67 else{ 68 first_value[5]=tmp2[5]+max_vi; 69 first_value[6]=com_count+1; 70 map_max.put(zahyou, first_value); 71 } 72 73 } 74 else{ 75 map_max.put(zahyou, first_value); 76 77 } 78 79 } 80 81 } 82 //データ出力 83 for(int i=0;i<XAXIS;i+=1){ 84 for(int j=0;j<YAXIS;j+=1){ 85 int zahyou =j*1152+i; 86 87 if(map_max.containsKey(zahyou)==true){ 88 Integer [] max_value = map_max.get(zahyou); 89 x=(zahyou/gazou_size)*1; 90 y=zahyou-((zahyou/gazou_size)*gazou_size); 91 str="最大の輝度"+max_value[1]+"日時"+max_value[0]+"最小の輝度"+max_value[4]+"日時"+max_value[3]+"平均値"+(max_value[5]/max_value[6]); 92 //出力 93 context.write(new Text(x+","+y),new Text(str)); 94 } 95 } 96 } 97 } 98 }
B-26
B-4-4 groupkeypartioner.java 1 import org.apache.hadoop.io.VIntWritable; 2 import org.apache.hadoop.mapreduce.Partitioner; 3 //keyを振り分け 4 public class kadaipartitioner extends Partitioner<VIntWritable,VIntTwoDArrayWritable> { 5 @Override 6 public int getPartition(VIntWritable key,VIntTwoDArrayWritable value,int numPartitions) { 7 //key取得 8 int keynum=key.get(); 9 return keynum; 10 } 11 12 }
B-27
B-4-5 VIntTwoDArrayWritable.java 1 import org.apache.hadoop.io.TwoDArrayWritable; 2 import org.apache.hadoop.io.VIntWritable; 3 //VIntTwoDArrayWritableを使用するためのクラス作成 4 public class VIntTwoDArrayWritable extends TwoDArrayWritable{ 5 public VIntTwoDArrayWritable(){ 6 super(VIntWritable.class); 7 } 8 public VIntTwoDArrayWritable(VIntWritable[][] colArr){ 9 super(VIntTwoDArrayWritable.class,colArr); 10 } 11 }
B-28
B-5 画素のブロック分散とブロックデータのベクトル化(1次元配列) B-5-1 grouupkey.java 1 import java.lang.String; 2 import java.util.Date; 3 import java.util.Formatter; 4 import org.apache.hadoop.conf.Configuration; 5 import org.apache.hadoop.conf.Configured; 6 import org.apache.hadoop.fs.Path; 7 import org.apache.hadoop.io.*; 8 import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; 9 import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; 10 import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat; 11 import org.apache.hadoop.mapreduce.Job; 12 import org.apache.hadoop.io.compress.CodecPool; 13 import org.apache.hadoop.io.compress.CompressionCodec; 14 import org.apache.hadoop.io.compress.CompressionOutputStream; 15 import org.apache.hadoop.io.compress.Compressor; 16 import org.apache.hadoop.util.GenericOptionsParser; 17 import org.apache.hadoop.util.Tool; 18 import org.apache.hadoop.util.ToolRunner; 19 20 public class groupkey extends Configured implements Tool{ 21 22 @Override 23 public int run(String args[]) throws Exception{ 24 Configuration conf = getConf(); 25 if (conf == null) { 26 return -1; 27 } 28 String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs(); 29 Job job = new Job(conf, "Kadai1"); 30 //実装するクラスの設定 31 job.setJarByClass(groupkey.class); 32 job.setMapperClass(groupkeymapper.class); 33 job.setReducerClass(groupkeyreducer.class); 34 job.setInputFormatClass(WholeFileInputFormat.class); 35 job.setOutputFormatClass(TextOutputFormat.class); 36 job.setNumReduceTasks(Integer.parseInt(args[2])); 37 job.setMapOutputKeyClass(VIntWritable.class); 38 job.setMapOutputValueClass(VIntArrayWritable.class); 39 job.setOutputKeyClass(Text.class); 40 job.setOutputValueClass(Text.class); 41 42 FileInputFormat.addInputPath(job, new Path(otherArgs[0])); 43 Formatter formatter = new Formatter(); 44 //出力データ 45 String outpath = "Out" 46 47 FileOutputFormat.setOutputPath(job, new Path(outpath)); 48 job.setPartitionerClass(KeyPartitioner.class); 49 return job.waitForCompletion(true) ? 0 : 1; 50 } 51
B-29
52 public static void main(String[] args) throws Exception { 53 int exitCode = ToolRunner.run(new groupkey(), args); 54 System.exit(exitCode); 55 } 56 57 58 }
B-30
B-5-2 groupkeymapper.java 1 import java.io.IOException; 2 import java.util.ArrayList; 3 import java.util.List; 4 import org.apache.hadoop.conf.Configuration; 5 import org.apache.hadoop.io.BytesWritable; 6 import org.apache.hadoop.io.NullWritable; 7 import org.apache.hadoop.io.VIntWritable; 8 import org.apache.hadoop.mapreduce.Mapper; 9 import org.omg.CosNaming._BindingIteratorImplBase; 10 11 public class groupkeymapper extends Mapper<NullWritable, BytesWritable, VIntWritable, VIntArrayWritable>{ 12 public static final int OFFSET=8; 13 public static final int XAXIS=1152; 14 public static final int YAXIS=1152; 15 public void map(NullWritable key, BytesWritable value, Context context) 16 throws IOException, InterruptedException { 17 18 int k,data_count=0;//データのインデックス 19 int task_num;//keyの番号 20 int total=XAXIS*YAXIS;//データの総数 21 int numReducetasks = (context.getNumReduceTasks()); 22 int data_limit;//タスクあたりのデータサイズ 23 24 if((total%numReducetasks) == 0){ 25 data_limit = (int)(total/numReducetasks);//タスクあたりのデータサイズ 26 }else{ 27 data_limit = ((int)(total/numReducetasks))+1;//タスクあたりのデータサイズ 28 } 29 30 //ファイルから時間を取得; 31 List<VIntWritable> valuelist = new ArrayList<VIntWritable>(); 32 Configuration conf = context.getConfiguration(); 33 String filename =conf.get("map.input.file"); 34 String[] url=filename.split("/"); 35 String[] kariname=url[url.length-1].split("_"); 36 37 //VI取得のための配列を取得 38 byte[] data = value.getBytes(); 39 BytesWritable bw =new BytesWritable(); 40 for(int i = 0 ; i < numReducetasks; i++) { 41 valuelist.clear(); 42 valuelist.add(new VIntWritable(Integer.valueOf(kariname[0]))); 43 valuelist.add(new VIntWritable(i*data_limit)); 44 for(int j = i*data_limit+OFFSET;j<(i+1)*data_limit || j < XAXIS*YAXIS+OFFSET;j++) { 45 bw.set(data,j,2); 46 byte[] bws=bw.getBytes(); 47 int vi=(bws[1]<<8)+(bws[0]&0xFF); 48 valuelist.add(new VIntWritable(vi)); 49 } 50 VIntWritable[] valuearray = (VIntWritable[])
B-31
valuelist.toArray(new VIntWritable[valuelist.size()]); 51 context.write(new VIntWritable(i), new VIntArray Writable(valuearray)); 52 } 53 } 54 }
B-32
B-5-3 groupkeyreducer.java 1 import java.io.IOException; 2 import java.util.ArrayList; 3 import java.util.List; 4 import java.util.Map.Entry; 5 import java.util.TreeMap; 6 import org.apache.hadoop.io.Text; 7 import org.apache.hadoop.io.VIntWritable; 8 import org.apache.hadoop.io.Writable; 9 import org.apache.hadoop.mapreduce.Reducer; 10 11 public class groupkeyreducer 12 extends Reducer<VIntWritable, VIntArrayWritable, Text, Text> { 13 public static final int XAXIS=1152; 14 public static final int YAXIS=1152; 15 16 @Override 17 public void reduce(VIntWritable key, Iterable<VIntArrayWritable> values, 18 Context context) 19 throws IOException, InterruptedException { 20 21 TreeMap<Integer,Integer[]> tree =new TreeMap<Integer,Integer[]>(); 22 List<Integer> valuelist = new ArrayList<Integer>(); 23 int axis=0; 24 //データ取得 25 for(VIntArrayWritable value:values) { 26 valuelist.clear(); 27 Writable[] val = value.get(); 28 for(int i = 2;i<val.length;i++) { 29 valuelist.add(((VIntWritable)val[i]).get()); 30 } 31 tree.put(((VIntWritable)val[0]).get() ,valuelist.toArray(new Integer[valuelist.size()])); 32 axis = ((VIntWritable)val[1]).get(); 33 } 34 int[][] datalist = new int[tree.get(tree.firstKey()).length][tree.size()]; 35 36 Integer[] data_tmp; 37 int count=0; 38 for(Entry<Integer,Integer[]> e:tree.entrySet()) { 39 data_tmp = e.getValue(); 40 for(int i=0;i<data_tmp.length;i++) { 41 datalist[i][count] = data_tmp[i].intValue(); 42 } 43 count++; 44 } 45 //先頭座標 46 int x = XAXIS%axis; 47 int y = YAXIS%axis; 48 StringBuilder strbuil; 49 int[] stat; 50 for(int i=0;i<datalist.length;i++) { 51 stat = new int[6]; 52 //座標取得
B-33
53 x = XAXIS%(axis+i); 54 y = YAXIS%(axis+i); 55 String keyaxis = String.format("x.%4d,y.%4d",x,y); 56 //階調値比較 57 for(int point:datalist[i]) { 58 if(stat[0] < point) { 59 stat[0] = point; 60 stat[1] = stat[5]; 61 }else if(stat[2] > point) { 62 stat[2] = point; 63 stat[3] = stat[5]; 64 } 65 stat[4]+=point; 66 stat[5]++; 67 } 68 //出力 69 context.write(new Text(keyaxis),new Text("最大の輝度"+stat[0]+"日時"+stat[1]+"最小の輝度"+stat[2]+"日時"+stat[3]+"平均値"+(double)(stat[4]/stat[5]))); 70 71 } 72 73 } 74 }
B-34
B-5-4 KeyPartioner.java 1 import org.apache.hadoop.io.VIntWritable; 2 import org.apache.hadoop.io.Writable; 3 import org.apache.hadoop.mapreduce.Partitioner; 4 import org.omg.CosNaming._BindingIteratorImplBase; 5 6 public class KeyPartitioner extends Partitioner<VIntWritable,VIntArrayWritable> 7 @Override 8 public int getPartition(VIntWritable key,VIntArrayWritable value,int numPartitions) { 9 //key取得 10 return key.get(); 11 12 } 13 14 15 }
B-35
B-5-5 VIntArrayWritable.java 1 import org.apache.hadoop.io.ArrayWritable; 2 import org.apache.hadoop.io.VIntWritable; 3 import org.apache.hadoop.io.Writable; 4 //VIntArrayWritableを使用するためのクラス作成 5 public class VIntArrayWritable extends ArrayWritable{ 6 public VIntArrayWritable(){ 7 super(VIntWritable.class); 8 } 9 public VIntArrayWritable(VIntWritable[] colArr){ 10 super(VIntArrayWritable.class,colArr); 11 } 12 13 public int getFirstKey() { 14 Writable[] keydata = this.get(); 15 16 17 return ((VIntWritable)keydata[0]).get(); 18 } 19 public int getSecondKey() { 20 Writable[] keydata = this.get(); 21 return ((VIntWritable)keydata[1]).get(); 22 } 23 }
C-1
C 気象衛星画像から期間毎の同一地点の平均値と分散を求めるプログラム C-1 MeteorologicalDriver.java 1 import java.util.Date; 2 import java.util.Formatter; 3 import org.apache.hadoop.conf.Configuration; 4 import org.apache.hadoop.conf.Configured; 5 import org.apache.hadoop.fs.Path; 6 import org.apache.hadoop.io.Text; 7 import org.apache.hadoop.io.VIntWritable; 8 import org.apache.hadoop.mapreduce.Job; 9 import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; 10 import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; 11 import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat; 12 import org.apache.hadoop.util.GenericOptionsParser; 13 import org.apache.hadoop.util.Tool; 14 import org.apache.hadoop.util.ToolRunner; 15 16 public class MeteorologicalDriver extends Configured implements Tool { 17 @Override 18 public int run(String args[]) throws Exception{ 19 Configuration conf = getConf(); 20 if (conf == null) { 21 return -1; 22 } 23 24 String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs(); 25 Job job = new Job(conf, "SpaceToTimeline_Meteorological"); 26 //実装するクラスの設定 27 job.setJarByClass(MeteorologicalDriver.class); 28 job.setMapperClass(MeteorologicalMapper.class); 29 job.setReducerClass(MeteorologicalReducer.class); 30 job.setInputFormatClass(WholeFileInputFormat.class); 31 job.setOutputFormatClass(TextOutputFormat.class); 32 job.setNumReduceTasks(Integer.parseInt(args[2])); 33 job.setMapOutputKeyClass(VIntWritable.class); 34 job.setMapOutputValueClass(VIntArrayWritable.class); 35 job.setOutputKeyClass(Text.class); 36 job.setOutputValueClass(Text.class); 37 FileInputFormat.addInputPath(job, new Path(otherArgs[0])); 38 Formatter formatter = new Formatter(); 39 //出力データ 40 String outpath = "Out" 41 + formatter.format("%1$tm%1$td%1$tH%1$tM%1$tS", new Date()); 42 FileOutputFormat.setOutputPath(job, new Path(outpath)); 43 job.setPartitionerClass(KeyPartitioner.class); 44 return job.waitForCompletion(true) ? 0 : 1; 45 } 46 47 public static void main(String[] args) throws Exception { 48 int exitCode = ToolRunner.run(new MeteorologicalDriver(), args); 49 System.exit(exitCode); 50 } 51 }
C-2
C-2 MeteoroloicalMapper.java 1 import java.io.IOException; 2 import java.util.ArrayList; 3 import java.util.Arrays; 4 import java.util.List; 5 import org.apache.hadoop.conf.Configuration; 6 import org.apache.hadoop.io.BytesWritable; 7 import org.apache.hadoop.io.NullWritable; 8 import org.apache.hadoop.io.VIntWritable; 9 import org.apache.hadoop.mapreduce.Mapper; 10 11 public class MeteorologicalMapper extends Mapper<NullWritable, BytesWritable, VIntWritable, VIntArrayWritable>{ 12 // 気象画像の場合の設定 13 public static final int OFFSET=45; 14 public static final int XAXIS=1800; 15 public static final int YAXIS=1800; 16 17 public void map(NullWritable key, BytesWritable value, Context context) 18 throws IOException, InterruptedException { 19 20 //int k,data_count=0;//データのインデックス 21 //int task_num;//keyの番号 22 int total=XAXIS*YAXIS;//データの総数 23 int numReducetasks = (context.getNumReduceTasks());//ノード数(Reduce数) 24 int data_limit;//タスクあたりのデータサイズ 25 26 27 if((total%numReducetasks) == 0){ 28 //タスクあたりのでデータサイズ 29 data_limit = (int)(total/numReducetasks); 30 }else{ 31 //タスクあたりのでデータサイズ 32 data_limit = ((int)(total)/numReducetasks)+1; 33 } 34 35 //ファイルから時間を取得; 36 List<VIntWritable> valuelist = new ArrayList<VIntWritable>(); 37 Configuration conf = context.getConfiguration(); 38 String filename =conf.get("map.input.file"); 39 String[] url=filename.split("/"); 40 int time = Integer.parseInt(url[url.length-1].substring(4,12)); 41 //画像のサイズ分のデータ配列取得 42 byte[] data = value.getBytes(); 43 44 //VI取得のための配列を取得 45 //入力データの画像サイズが小さい場合の処理 46 if(data.length<1800*1800) { 47 for(int i = 0 ; i < numReducetasks; i++) { 48 valuelist.clear(); 49 valuelist.add(new VIntWritable(time));//時間 50 valuelist.add(new VIntWritable(i*data_limit));//開始の座標 51 52 if(i < numReducetasks-1) {
C-3
53 for(int j=0;j<data_limit;j++) { 54 //最後のタスクに対して余ったところに関係のない値を代入 55 valuelist.add(new VIntWritable(-100)); 56 } 57 }else { 58 for(int j=0;j<data_limit-((data_limit*numReducetasks)-total);j++) { 59 //使用する listに関係のない値を代入 60 valuelist.add(new VIntWritable(-100)); 61 } 62 } 63 VIntWritable[] valuearray = (VIntWritable[])valuelist.toArray(new VIntWritable[valuelist.size()]);//listを配列に変換して値を代入 64 65 context.write(new VIntWritable(i), new VIntArrayWritable(valuearray)); 66 } 67 //入力データが正しい場合の処理 68 }else{ 69 byte[] bws ; 70 for(int i = 0 ; i < numReducetasks; i++) { 71 valuelist.clear(); 72 valuelist.add(new VIntWritable(time));//時間 73 valuelist.add(new VIntWritable(i*data_limit));//開始の座標 74 75 if(i < numReducetasks-1) { 76 //タスクに対しての処理 77 bws = Arrays.copyOfRange(data ,i*data_limit+OFFSET, (i+1)*data_limit+OFFSET );//データを取得 78 }else { 79 //最後のタスクに対しての処理 80 bws=Arrays.copyOfRange(data,i*data_limit+OFFSET, (i+1)*data_limit-((data_limit*numReducetasks)-total)); 81 } 82 83 //データ代入 84 85 for(byte point:bws) { 86 valuelist.add(new VIntWritable((int)point&0xFF)); 87 } 88 VIntWritable[] valuearray = (VIntWritable[])valuelist.toArray(new VIntWritable[valuelist.size()]); 89 //Reduceへデータ出力 90 context.write(new VIntWritable(i), new VIntArrayWritable (valuearray)); 91 } 92 } 93 } 94 }
C-4
C-3 MeteorologicalReducer.java 1 import java.io.IOException; 2 import java.util.Date; 3 import java.text.ParseException; 4 import java.text.SimpleDateFormat; 5 import java.util.ArrayList; 6 import java.util.List; 7 import java.util.TreeMap; 8 import java.util.Map.Entry; 9 import org.apache.hadoop.io.Text; 10 import org.apache.hadoop.io.VIntWritable; 11 import org.apache.hadoop.io.Writable; 12 import org.apache.hadoop.mapreduce.Reducer; 13 14 public class MeteorologicalReducer extends Reducer<VIntWritable, VIntArrayWritable, Text, Text>{ 15 public static final int XAXIS=1800; 16 public static final int YAXIS=1800; 17 public int WINDOWSIZE=168; 18 public int WINDOW_SAMPLING=24; 19 public int SAMPLING=1; 20 @Override 21 public void reduce(VIntWritable key, Iterable<VIntArrayWritable> values, 22 Context context) 23 throws IOException, InterruptedException { 24 25 TreeMap<Long,Integer[]> tree =new TreeMap<Long,Integer[]>(); 26 List<Integer> valuelist = new ArrayList<Integer>(); 27 List<Integer> countlist = new ArrayList<Integer>(); 28 int axis=0; 29 //UNIX時間の取得 30 SimpleDateFormat format = new SimpleDateFormat("yyMMddHH"); 31 //時間順にデータをソート 32 Date date; 33 for(VIntArrayWritable value:values) { 34 valuelist.clear(); 35 Writable[] val = value.get(); 36 for(int i = 2;i<val.length;i++) { 37 valuelist.add(((VIntWritable)val[i]).get()); 38 } 39 String time_data = Integer.toString(((VIntWritable)val[0]).get()); 40 long hour_count=0; 41 //時間 42 try { 43 date = format.parse(time_data);//stringに変換するために try catch 44 long time = date.getTime()/1000;//秒に変換 45 hour_count = time/(60*60);//時間に変換 46 } catch (ParseException e1) { 47 e1.printStackTrace(); 48 } 49 tree.put(hour_count,valuelist.toArray(new Integer[valuelist.size()])); 50 axis = ((VIntWritable)val[1]).get();//入力座標 51 } 52 //keyが最初に入っているかの確認
C-5
53 long first_hour = tree.firstKey(); 54 int dist_hour = (int)(tree.lastKey()-tree.firstKey()); 55 values = null; 56 valuelist = null; 57 System.gc(); 58 59 //データの初期化 60 int[][] datalist = new int[tree.get(tree.firstKey()).length][dist_hour+1]; 61 for(int i=0;i<datalist.length;i++) { 62 for(int j=0;j<datalist[i].length;j++) { 63 datalist[i][j] = -100; 64 } 65 } 66 Integer[] data_tmp; 67 data_tmp = tree.firstEntry().getValue(); 68 //座標に対しての時間毎のデータ 69 for(Entry<Long,Integer[]> e:tree.entrySet()) { 70 data_tmp = e.getValue(); 71 int time = (int)(e.getKey()-first_hour);//何番目か 72 for(int i=0;i<data_tmp.length;i++) { 73 datalist[i][time] = data_tmp[i].intValue();//横軸 74 } 75 } 76 tree.clear(); 77 //データ抽出 78 int data[][] = new int[(data_tmp.length)][3]; 79 for(int i=0;i+WINDOWSIZE-1<=dist_hour;i=i+WINDOW_SAMPLING){ 80 //データの初期化 81 for(int d=0;d<data_tmp.length;d++){ 82 for(int j=0;j<3;j++){ 83 if(j==1){ 84 //最小値 85 data[d][j]=1000; 86 } 87 else{ 88 data[d][j]=0; 89 } 90 } 91 } 92 93 for(int s=0;s<WINDOWSIZE;s=s+SAMPLING){ 94 //データ比較 95 countlist.add(i+s); 96 for(int d=0;d<data_tmp.length;d++){ 97 if(data[d][0]<datalist[d][i+s]){ 98 data[d][0]=datalist[d][i+s]; 99 } 100 if(data[d][1]>datalist[d][i+s]) 101 data[d][1]=datalist[d][i+s]; 102 } 103 data[d][2]=data[d][2]+datalist[d][i+s]; 104 } 105 } 106 //データ出力
C-6
107 108 int x = 0; 109 int y = 0; 110 if(axis>0) { 111 x = axis%XAXIS; 112 y = axis/YAXIS; 113 } 114 double heikin=0.0; 115 StringBuilder strbuil; 116 String key_str=String.format("%d週",(i/WINDOW_SAMPLING)+1); 117 strbuil = new StringBuilder(); 118 119 for(int k=0;k<data_tmp.length;k++) { 120 double bunsan_sum=0.0; 121 heikin=data[k][2]/countlist.size(); 122 //分散 123 for(int c=0;c<countlist.size();c++){ 124 bunsan_sum= bunsan_sum+(((datalist[k][countlist.get(c)])-(heikin))*((datalist[k][countlist.get(c)])-(heikin))); 125 } 126 127 x = (axis+k)%XAXIS; 128 y = (axis+k)/YAXIS; 129 //} 130 131 //分散 132 String value_str=String.format("%4.4f,",bunsan_sum/countlist.size()); 133 //平均値 134 //String value_str=String.format("%4.4f,",(double)(data[k][2]/countlist.size())); 135 136 strbuil.append(value_str); 137 } 138 String outdata = strbuil.toString().substring(0,strbuil.toString().length()-1); 139 context.write(new Text(key_str),new Text(outdata)); 140 countlist.clear(); 141 } 142 } 143 }
C-7
C-4 KeyPartioner.java 1 import org.apache.hadoop.io.VIntWritable; 2 import org.apache.hadoop.io.Writable; 3 import org.apache.hadoop.mapreduce.Partitioner; 4 import org.omg.CosNaming._BindingIteratorImplBase; 5 6 public class KeyPartitioner extends Partitioner<VIntWritable,VIntArrayWritable> { 7 @Override 8 public int getPartition(VIntWritable key,VIntArrayWritable value,int numPartitions) { 9 //key取得 10 return key.get(); 11 12 } 13 }
C-8
C-5 VIntArrayWritable.java 1 import org.apache.hadoop.io.ArrayWritable; 2 import org.apache.hadoop.io.VIntWritable; 3 import org.apache.hadoop.io.Writable; 4 //VIntArrayWritableを使用するためのクラス設定 5 public class VIntArrayWritable extends ArrayWritable{ 6 public VIntArrayWritable(){ 7 super(VIntWritable.class); 8 } 9 public VIntArrayWritable(VIntWritable[] colArr){ 10 super(VIntArrayWritable.class,colArr); 11 } 12 13 public int getFirstKey() { 14 Writable[] keydata = this.get(); 15 16 // int keynum=key.get(); 17 return ((VIntWritable)keydata[0]).get(); 18 } 19 public int getSecondKey() { 20 Writable[] keydata = this.get(); 21 return ((VIntWritable)keydata[1]).get(); 22 } 23 }