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