Transcript Chapter9

使用Hadoop實作MapReduce
Outline
 開發環境設定
 新增專案
 MapReduce程式架構
 MapReduce基礎實作範例
 MapReduce進階實作範例
 Hadoop MapReduce專題
2
開發環境設定
新增專案
MapReduce程式架構
MapReduce基礎實作範例
MapReduce進階實作範例
Hadoop專題
3
開發環境設定
 Hadoop程式開發環境
的架設可分為兩種;
 不透過Integrated
Development
Environment (IDE)
 透過IDE
4
不使用IDE環境(1/2)
 首先設定環境變數如下:
 在/etc/profile中加入Java及Hadoop的CLASSPATH:
~# vi /etc/profile
CLASSPATH=/opt/hadoop/hadoop-0.20.2-core.jar ←加入這兩行
export CLASSPATH
 透過source讓設定的profile環境變數生效,或者重新登
入也可以:
~# source /etc/profile
 將撰寫好的Java程式編譯成class檔:
~# javac [程式名稱].java
5
不使用IDE環境(2/2)
 在Hadoop上執行程式 (只有一個class檔時):
在Hadoop上執行程式 (只有一個class檔時):
 若有多個class檔,則需要將class檔包裝成jar檔:
~# jar cvf [jar檔名稱].jar [程式名稱].class
 在Hadoop上執行包裝好的jar檔:
/hadoop# bin/hadoop jar [jar檔名稱].jar [主函式名稱] [參數0] [參數1] …
6
使用IDE (Eclipse) (1/2)
 先到Eclipse官網 (http://www.eclipse.org) 下載Eclipse安
裝檔
 Linux系統上需先安裝圖形化套件
 目前下載版本是Eclipse Classic 3.6.2
 下載完後解壓縮,並將解壓縮後的目錄移到/opt/eclipse
7
使用IDE (Eclipse) (2/2)
 也可以開啟終端機輸入下列指令:
~# wget http://ftp.cs.pu.edu.tw/pub/eclipse/eclipse/downloads/drops/R-3.6.2201102101200/eclipse-SDK-3.6.2-linux-gtk.tar.gz
~# tar zxvf eclipse-SDK-3.6.2-linux-gtk.tar.gz
~# mv eclipse /opt/
 在/usr/local/bin/裡建立eclipse執行檔的連結:
~# ln -sf /opt/eclipse/eclipse /usr/local/bin/
 將/opt/hadoop裡的eclipse plugin搬到eclipse/plugin裡:
~# cp /opt/hadoop/contrib/eclipse-plugin/hadoop-0.20.2-eclipse-plugin.jar /opt/eclipse/plugins/
 接下來便可以啟動Eclipse了:
~# eclipse &
8
開發環境設定
新增專案
MapReduce程式架構
MapReduce基礎實作範例
MapReduce進階實作範例
Hadoop專題
9
新增專案(1/15)
10
新增專案(2/15)
11
新增專案(3/15)
12
新增專案(4/15)
13
新增專案(5/15)
14
新增專案(6/15)
15
新增專案(7/15)
16
新增專案(8/15)
17
新增專案(9/15)
18
新增專案(10/15)
19
新增專案(11/15)
20
新增專案(12/15)
21
新增專案(13/15)
22
新增專案(14/15)
23
新增專案(15/15)
24
開發環境設定
新增專案
MapReduce程式架構
MapReduce基礎實作範例
MapReduce進階實作範例
Hadoop專題
25
MapReduce程式架構
 MapReduce程式主要可分為三個部份
 MapReduce Driver

扮演整個MapReduce程式主函式角色,在此類別中定義
MapReduce程式的相關設定
 Mapper

利用一個輸入key/value pair集合來產生一個輸出的key/value
pair集合
 Reducer

接受一個中間key的值和相關的一個value值的集合
26
MapReduce Driver
01. Class MapReduceDriver類別名稱 {
02. main(){
03. Configuration conf = new Configuration();
04. Job job = new Job(conf, Job名稱);
05. job.setJarByClass( MapReduceDriver類別(即此類別) );
06. job.setMapperClass( Mapper類別 );
07. job.setReducerClass( Reducer類別 );
08. FileInputFormat.addInputPath( job, new Path(args[0]));
09. FileOutputFormat.setOutputPath( job, new Path(args[1]));
10.
其它參數設定
11. job.waitForCompletion(true);
12. }
13. }
27
Mapper程式架構
01. class Mapper類別名稱 extends
Mapper< 輸入鍵類型, 輸入值類型, 輸出鍵類型, 輸出鍵值型 > {
02.
全域變數
03. public void map( 輸入鍵類型 key, 輸入值類型 value, Context context) throws IOException,
InterruptedException {
04.
Map程式碼區
05. context.write(IntermediateKey, IntermediateValue);
06. }
07. }
28
Reducer程式架構
01. class Reducer類別名稱 extends
Redcuer < 輸入鍵類型, 輸入值類型, 輸出鍵類型, 輸出鍵值型 > {
02.
全域變數
03. public void reduce( 輸入鍵類型 key, Iterable< 輸入值類型 > value, Context context) throws
IOException, InterruptedException {
04.
Reduce程式碼
05. context.write(ResultKey, ResultValue);
06. }
07. }
29
開發環境設定
新增專案
MapReduce程式架構
MapReduce基礎實作範例
MapReduce進階實作範例
Hadoop專題
30
MapReduce基礎實作範例(1/2)
 本範例以一個簡單的maxCPU程式說明如何使用Eclipse
開發MapReduce程式
 此範例中,系統每小時記錄一次CPU使用率到日誌檔中,
而maxCPU程式會分析日誌檔,並透過MapReduce的方式,
找出每天最高的CPU使用率。
 本範例中將以這個日誌檔做為輸入檔,先在HDFS上新創
一個log目錄,再根據上述格式建立一個日誌檔並上傳到
log目錄中。
31
MapReduce基礎實作範例(2/2)
 日誌檔中記錄的欄位分別為日期、時段及CPU使用率,
目誌檔部份內容如下
2011/01/01 00:00 40
2011/01/01 01:00 30
…
…
2011/01/02 22:00 40
2011/01/02 23:00 30
…
…
32
新增Mapper類別(1/3)
33
新增Mapper類別(2/3)
 之後在HadoopLab專案中便會新增一個新的package
MR_Lab及mymapper.java ,並修改mymapper.java的內
容:
01. public
class mymapper extends Mapper<Ob 09. idata.set(Integer.valueOf(data));
ject, Text, Text, IntWritable> {
02. private Text tday = new Text();
03. private IntWritable idata = new IntWritabl
e();
04. public void map(Object key, Text value, Co
ntext context)
throws IOException, InterruptedException {
05. String line = value.toString();
06. String day = line.substring(0, 10);
07. String data = line.substring(17);
08. tday.set(day);
10. context.write(tday, idata);
11. }
12. }
34
新增Mapper類別(3/3)
35
新增Reducer類別(1/3)
36
新增Reducer類別(2/3)
 在MR_Lab的package中出現myreducer.java ,並修改
myreducer.java的內容為:
01. public class myreducer extends Reducer<Te
xt, IntWritable, Text, IntWritable> {
02. IntWritable cpuUtil = new IntWritable();
03. public void reduce(Text key, Iterable<IntW
ritable> values, Context context) throws IOExce
ption, InterruptedException {
04. int maxValue = Integer.MIN_VALUE;
05. for (IntWritable val : values) {
06.
maxValue = Math.max(maxValue, val.ge
t());
07. }
08. cpuUtil.set(maxValue);
09. context.write(key, cpuUtil);
10. }
11. }
37
新增Reducer類別(3/3)
38
新增MapReduce Driver類別(1/4)
39
新增MapReduce Driver類別(2/4)
 在MR_Lab的package中出現maxCPU.java ,並修改
maxCPU.java的內容為:
01. public class maxCPU {
02. public static void main(String[] args) throw
s Exception {
03. Configuration conf = new Configuration();
04. String[] otherArgs = new GenericOptions
Parser(conf,
args).getRemainingArgs();
05. if (otherArgs.length != 2) {
06.
System.err.println("Usage: maxCPU <in>
<out>");
07.
System.exit(2);
08. }
09. Job job = new Job(conf, "max CPU");
10. job.setJarByClass(maxCPU.class);
11. job.setMapperClass(mymapper.class);
12. job.setCombinerClass(myreducer.class);
13. job.setReducerClass(myreducer.class);
14. job.setOutputKeyClass(Text.class);
15. job.setOutputValueClass(IntWritable.clas
s);
16. FileInputFormat.addInputPath(job, new P
ath(otherArgs[0]));
17. FileOutputFormat.setOutputPath(job, ne
w Path(otherArgs[1]));
40
新增MapReduce Driver類別(3/4)
18.
boolean status = job.waitForCompletion
(true);
19. if (status) {
20.
System.exit(0);
21. } else {
22.
System.err.print("Not Complete!");
23.
System.exit(1);
24. }
25. }
26. }
41
新增MapReduce Driver類別(4/4)
42
在Hadoop上執行MapReduce程式(1/3)
43
在Hadoop上執行MapReduce程式(2/3)
44
在Hadoop上執行MapReduce程式(3/3)
 執行結束後,在HDFS上的output目錄中即可看到最後
結果:
2011/01/01
2011/01/02
2011/01/03
2011/01/04
100
90
80
30
45
開發環境設定
新增專案
MapReduce程式架構
MapReduce基礎實作範例
MapReduce進階實作範例
Hadoop專題
46
MapReduce進階實作範例
 本範例將所介紹的MapReduce程式 (maxCPU),加入
HDFS及HBase的相關操作。
7.
HBase
3.
MapReduce
4.
Mapper Reducer
6.
5.
2.
HDFS
1.
Local host
47
新增maxCPU類別(1/2)
 新增一個MapReduce Driver類別並命名為maxCPU,
maxCPU類別負責MapReduce相關設定及運作流程
01. public class maxCPU {
02. public static void main(String[] args) throw
s Exception {
03. Configuration conf = new Configuration();
04. String[] otherArgs = new GenericOptions
Parser(conf, args)
.getRemainingArgs();
05. if (otherArgs.length != 2) {
06.
System.err.println("Usage: maxCPU <in>
<out>");
07.
System.exit(2);
08. }
09. Job job = new Job(conf, "max CPU");
10. job.setJarByClass(maxCPU.class);
11. job.setMapperClass(mymapper.class);
12. job.setCombinerClass(myreducer.class);
13. job.setReducerClass(myreducer.class);
14. job.setOutputKeyClass(Text.class);
15. job.setOutputValueClass(IntWritable.clas
s);
16. FileInputFormat.addInputPath(job, new P
ath(otherArgs[0]));
48
新增maxCPU類別(2/2)
17. FileOutputFormat.setOutputPath(job, ne
w Path(otherArgs[1]));
18. CheckDir.check(otherArgs[0].toString(), c
onf);
19.
LocalToHdfs.localToHdfs(otherArgs[0].to
String(),
otherArgs[0].toString(), conf);
20. CheckDir.check(otherArgs[1].toString(), c
onf);
21. CheckTable.check("CPU");
22. CheckTable.addFamily("CPU", "CPUUtil");
23.
boolean status = job.waitForCompletion
(true);
24. if (status) {
25.
OutputResult.output(otherArgs[1].toStri
ng(), conf);
26.
System.exit(0);
27. } else {
28.
System.err.print("Not Complete!");
29.
System.exit(1);
30. }
31. }
32. }
49
新增mymapper類別
 新增一個Mapper類別並命名為mymapper,其功能為整
理輸入的鍵/值,並在第10行呼叫AddData類別將資料存
入HBase
01. public class mymapper extends Mapper<Ob
ject, Text, Text, IntWritable> {
02. private Text tday = new Text();
03. private IntWritable idata = new IntWritabl
e();
04. public void map(Object key, Text value, Co
ntext context) throws IOException, Interrupted
Exception {
05. String line = value.toString();
06. String day = line.substring(0, 10);
07. String time = line.substring(11, 16);
08. String data = line.substring(17);
09. try {
10.
AddData.add("CPU", "CPUUtil", day + " "
+ time, data);
11. } catch (Exception e) {
12. System.err.print("ERROR! (add data to H
Base)");
13. }
14. tday.set(day);
15. idata.set(Integer.valueOf(data));
16. context.write(tday, idata);
17. }
18. }
50
新增AddData類別
 此類別負責將資料插入HBase中
01. public class AddData {
02. public static Configuration configuration =
null;
03. static {
04. configuration = HBaseConfiguration.creat
e();
05. configuration.set("hbase.master", "Host0
1:60000");
06. configuration.set("hbase.zookeeper.quor
um", "Host01,Host02");
07. configuration.set("hbase.zookeeper.prop
erty.clientPort", "2222");
08. }
09. static void add(String table, String family, S
tring dtime, String data) throws Exception {
10. HTable htable = new HTable(configuration,
table);
11. Put row = new Put(dtime.getBytes());
12. row.add(family.getBytes(), new String("da
ta").getBytes(), data.getBytes());
13. htable.put(row);
14. htable.flushCommits();
15. }
16. }
51
新增myreducer類別
 新增一個Reducer類別並命名為myreducer,其程式碼如
下
01. public class myreducer extends Reducer<Te
xt, IntWritable, Text, IntWritable> {
02. IntWritable cpuUtil = new IntWritable();
03. public void reduce(Text key, Iterable<IntW
ritable> values, Context context) throws IOExce
ption, InterruptedException {
04. int maxValue = Integer.MIN_VALUE;
05. for (IntWritable val : values) {
06.
maxValue = Math.max(maxValue, val.ge
t());
07. }
08. cpuUtil.set(maxValue);
09. context.write(key, cpuUtil);
10. }
11. }
52
新增CheckDir類別
 此類別的功能為檢查HDFS上是否有已存在某個檔案或目
錄,若有則刪除該檔案或目錄,因此在每次執行程式
時,都能自動刪除HDFS上的輸出檔案或目錄
01. public class CheckDir {
02. static void check(final String path, Configur
ation conf) {
03. Path dstPath = new Path(path);
04. try {
05.
FileSystem hdfs = dstPath.getFileSystem
(conf);
06.
if (hdfs.exists(dstPath)) {
07.
hdfs.delete(dstPath, true);
08.
}
09. } catch (IOException e) {
10.
e.printStackTrace();
11. }
12. }
13. }
53
新增LocalToHdfs類別
 此類別將本地端檔案系統中路徑為src的檔案或目錄上傳
至HDFS中路徑為dst的目錄中
01. public class LocalToHdfs {
02. static void localToHdfs(String src, String ds
t, Configuration conf) {
03. Path dstPath = new Path(dst);
04. try {
05.
FileSystem hdfs = dstPath.getFileSystem
(conf);
06.
hdfs.copyFromLocalFile(false, new Path
(src), new Path(dst));
07. } catch (IOException e) {
08.
e.printStackTrace();
09. }
10. }
11. }
54
新增CheckTable類別(1/2)
 此類別中的.check() method與CheckDir類別的功能類似;
先檢查HBase中是否有相同的表格,若有則刪除該表格
 而.addFamily() method的功能為新增表格並設定其
column family。
01. public class CheckTable {
02. public static Configuration configuration =
null;
03. static {
04. configuration = HBaseConfiguration.creat
e();
05. configuration.set("hbase.master", "Host0
1:60000");
06. configuration.set("hbase.zookeeper.quor
um", "Host01,Host02");
07. configuration.set("hbase.zookeeper.prop
erty.clientPort", "2222");
08. }
09. public static void check(String table) throw
s Exception {
10. HBaseAdmin admin = new HBaseAdmin(c
onfiguration);
11. if (admin.tableExists(table)) {
12.
System.out.println("delete the table ");
13.
admin.disableTable(table);
55
新增CheckTable類別(2/2)
14.
admin.deleteTable(table);
15. }
16. }
17. public static void addFamily(String table, S
tring family) throws Exception {
18. HBaseAdmin admin = new HBaseAdmin(c
onfiguration);
19.
HTableDescriptor tableDescripter = new
HTableDescriptor(table
.getBytes());
20. tableDescripter.addFamily(new HColumn
Descriptor(family));
21. admin.createTable(tableDescripter);
22. }
23. }
56
新增OutputResult類別(1/2)
 此類別由HDFS讀取myreducer的執行結果,得知每日最
高CPU使用率,再呼叫ScanTable類別並傳送相關資訊,
以找出每日CPU使用率最高的所有時段。
01. public class OutputResult {
02. static void output(final String path, Config
uration conf) {
03. Path dst_path = new Path(path);
04. String day = null;
05. String value = null;
06. try {
07.
FileSystem hdfs = dst_path.getFileSyste
m(conf);
08.
FSDataInputStream in = null;
09.
if (hdfs.exists(dst_path)) {
10.
in = hdfs.open(new Path(dst_path.toSt
ring() + "/part-r-00000"));
11.
String messagein = null;
12.
while ((messagein = in.readLine()) != nu
ll) {
13.
StringTokenizer itr = new StringTokeni
zer(messagein);
14.
day = itr.nextToken();
15.
value = itr.nextToken();
16.
ScanTable.setFilter("CPU", day, value);
17.
}
57
新增OutputResult類別(2/2)
18.
in.close();
19.
}
20. } catch (IOException e) {
21.
e.printStackTrace();
22. }
23. }
24. }
58
新增ScanTable類別(1/2)
 類別根據myreducer類別所計算出的每日最高CPU使用
率,再到HBase表格中過濾出每日最高使用率的時段並
顯示出來
01. public class ScanTable {
02. public static Configuration configuration =
null;
03. static {
04. configuration = HBaseConfiguration.creat
e();
05. configuration.set("hbase.master", "Host0
1:60000");
06. configuration.set("hbase.zookeeper.quor
um", "Host01,Host02");
07. configuration.set("hbase.zookeeper.prop
erty.clientPort", "2222");
08. }
09. public static void setFilter(String tablenam
e, String day, String value) throws IOException {
10. HTable table = new HTable(configuration,
tablename);
11. Scan scan = new Scan((day + " 00:00").get
Bytes(), (day +
" 23:00").getBytes());
12. FilterList filterList = new FilterList();
13. filterList.addFilter(new SingleColumnValu
eFilter("CPUUtil".getBytes(),
"data".getBytes(), CompareOp.EQUAL, value.ge
tBytes()));
14. scan.setFilter(filterList);
59
新增ScanTable類別(2/2)
15. ResultScanner ResultScannerFilterList = t
able.getScanner(scan);
16. for (Result rs = ResultScannerFilterList.ne
xt(); rs != null; rs = ResultScannerFilterList.next
()) {
17.
for (KeyValue kv : rs.list()) {
18.
System.out.println(new String(kv.getR
ow()) + " " + new
String(kv.getValue()));
19.
}
20. }
21. }
22. }
60
執行結果
 最終的輸出結果如下:
2011/01/01 16:00 100
2011/01/01 17:00 100
2011/01/02 15:00 90
2011/01/03 16:00 80
2011/01/03 17:00 80
2011/01/03 18:00 80
2011/01/04 00:00 40
61
開發環境設定
新增專案
MapReduce程式架構
MapReduce基礎實作範例
MapReduce進階實作範例
Hadoop專題
62
Hadoop專題
 專題內容必須包含下列技術:
 MapReduce

利用Hadoop MapReduce處理HDFS的資料
 HDFS

考慮網路上大量的資料,分別存放在不同的Node,並建立一
組HDFS
 Hbase

利用Hbase過濾出重要資訊,並顯示出來
 可考慮加入Hadoop其他子專案技術
 Avro、Pig、Hive、Chukwa
63