前提準備:
1.hadoop安裝運行正常。Hadoop安裝配置請參考:Ubuntu下 Hadoop 1.2.1 配置安裝
2.集成開發環境正常。集成開發環境配置請參考 :Ubuntu 搭建Hadoop源碼閱讀環境
MapReduce編程實例:
MapReduce編程實例(一),詳細介紹在集成環境中運行第一個MapReduce程序 WordCount及代碼分析
MapReduce編程實例(五),MapReduce實現單表關聯
開發示例:WordCount
本文例詳細的介紹如何在集成環境中運行第一個MapReduce程序 WordCount,以及WordCount代碼分析
新建MapReduce項目:
Finish生成項目如下,建立WordCount.java類
WordCount.java類代碼以下詳細解,先運行起來。
在HDFS建立新目錄並上傳若干實驗用的文本,上傳後如下:
配置Run Configuration 參數:
hdfs://localhost:9000/user/dat/input hdfs://localhost:9000/user/dat/output
Run On Hadoop,
OK,運行成功,檢查HDFS的文件生成
Eclipse中可以直接查看也可以在命令行中查看結果
OK,第一個MapReduce程序 WordCount已經成功運行。下面開始解析代碼部分
----------------------------------------------煩人的分割線-----------------------------------------------------
代碼:
import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
public class WordCount {
//嵌套類 Mapper
//Mapper<keyin,valuein,keyout,valueout>
public static class WordCountMapper extends Mapper<Object, Text, Text, IntWritable>{
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
@Override
protected void map(Object key, Text value, Context context)
throws IOException, InterruptedException {
StringTokenizer itr = new StringTokenizer(value.toString());
while(itr.hasMoreTokens()){
word.set(itr.nextToken());
context.write(word, one);//Context機制
}
}
}
//嵌套類Reducer
//Reduce<keyin,valuein,keyout,valueout>
//Reducer的valuein類型要和Mapper的va lueout類型一致,Reducer的valuein是Mapper的valueout經過shuffle之後的值
public static class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
private IntWritable result = new IntWritable();
@Override
protected void reduce(Text key, Iterable<IntWritable> values,
Context context)
throws IOException, InterruptedException {
int sum = 0;
for(IntWritable i:values){
sum += i.get();
}
result.set(sum);
context.write(key,result);//Context機制
}
}
public static void main(String[] args) throws Exception{
Configuration conf = new Configuration();//獲得Configuration配置 Configuration: core-default.xml, core-site.xml
String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();//獲得輸入參數 [hdfs://localhost:9000/user/dat/input, hdfs://localhost:9000/user/dat/output]
if(otherArgs.length != 2){//判斷輸入參數個數,不爲兩個異常退出
System.err.println("Usage:wordcount <in> <out>");
System.exit(2);
}
////設置Job屬性
Job job = new Job(conf,"word count");
job.setJarByClass(WordCount.class);
job.setMapperClass(WordCountMapper.class);
job.setCombinerClass(WordCountReducer.class);//將結果進行局部合併
job.setReducerClass(WordCountReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
FileInputFormat.addInputPath(job, new Path(otherArgs[0]));//傳入input path
FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));//傳入output path,輸出路徑應該爲空,否則報錯org.apache.hadoop.mapred.FileAlreadyExistsException。
System.exit(job.waitForCompletion(true)?0:1);//是否正常退出
}
}
先解釋兩個Java基礎問題
----------------------------------StringTokener類--------------------------------------------------------------
Java語言中,提供了專門用來分析字符串的類StringTokenizer(位於java.util包中)。該類可以將字符串分解爲獨立使用的單詞,並稱之爲語言符號。語言符號之間由定界符(delim)或者是空格、製表符、換行符等典型的空白字符來分隔。其他的字符也同樣可以設定爲定界符。StringTokenizer類的構造方法及描述見表15-6所示。
表15-6 StringTokenizer類的構造方法及描述
構 造 方 法 |
描 述 |
StringTokenizer(String str) |
爲字符串str構造一個字符串分析器。使用默認的定界符,即空格符(如果有多個連續的空格符,則看作是一個)、換行符、回車符、Tab符號等 |
StringTokenizer(String str, String delim) |
爲字符串str構造一個字符串分析器,並使用字符串delim作爲定界符 |
StringTokenizer類的主要方法及功能見表15-7所示。
表15-7 StringTokenizer類的主要方法及功能
方 法 |
功 能 |
String nextToken() |
用於逐個獲取字符串中的語言符號(單詞) |
boolean hasMoreTokens() |
用於判斷所要分析的字符串中,是否還有語言符號,如果有則返回true,反之返回false |
int countTokens() |
用於得到所要分析的字符串中,一共含有多少個語言符號 |
下面是一個例子。
String s1 = "|ln|ln/sy|ln/dl|ln/as|ln/bx|";
StringTokenizer stringtokenizer1 = new StringTokenizer(s1, "|");
while(stringtokenizer1 .hasMoreTokens()) {
String s3 = stringtokenizer.nextToken();
System.out.println(s3);
}
輸出:
ln
ln/sy
ln/dl
ln/as
ln/bx
請參考文章:http://blog.csdn.net/yakihappy/article/details/3979858
-------------------------------------------Java的反射機制--------------------------------------------------------
請參考文章:http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html
請參考文章:http://lavasoft.blog.51cto.com/62575/15433/
請參考文章: http://lavasoft.blog.51cto.com/62575/43218/
----------------------------------------WordCount MapReduce代碼分析-------------------------------------
代碼分爲三部分,一個主函數,一個嵌套類WordCountMapper繼承Mapper,一個嵌套類WordCountReducer繼承Reducer。
主函數通過反射設置Job屬性,設置輸入輸出路徑.。
WordCountMapper:
一個常量IntWritable做valueout,一個Text做keyout.
重寫map方法,用StringTokener解析字符串,寫入context
WordCountReducer:
一個Intwritable變量,記錄輸出個數。
reduce函數解析values計算數量,設置context的keyout,valueout。
ok,就是這麼easy。。。
注意map和reduce都是回調函數,是由MapReduce框架控制的,還未深入研究。