聊聊MapReduce
Mapreduce是一個分佈式運算程序的編程框架,是用戶開發“基於hadoop的數據分析應用”的核心框架。
Mapreduce核心功能是將用戶編寫的業務邏輯代碼和自帶默認組件整合成一個完整的分佈式運算程序,併發運行在一個hadoop集羣上。
MapReduce核心思想
MapReduce核心編程思想,如圖
1)分佈式的運算程序往往需要分成至少2個階段。
2)第一個階段的maptask併發實例,完全並行運行,互不相干。
3)第二個階段的reduce task併發實例互不相干,但是他們的數據依賴於上一個階段的所有maptask併發實例的輸出。
4)MapReduce編程模型只能包含一個map階段和一個reduce階段,如果用戶的業務邏輯非常複雜,那就只能多個mapreduce程序,串行運行。
MapReduce進程
一個完整的mapreduce程序在分佈式運行時有三類實例進程:
1)MrAppMaster:負責整個程序的過程調度及狀態協調。
2)MapTask:負責map階段的整個數據處理流程。
3)ReduceTask:負責reduce階段的整個數據處理流程。
MapReduce編程規範
用戶編寫的程序分成三個部分:Mapper、Reducer和Driver。
1.Mapper階段
(1)用戶自定義的Mapper要繼承自己的父類
(2)Mapper的輸入數據是KV對的形式(KV的類型可自定義)
(3)Mapper中的業務邏輯寫在map()方法中
(4)Mapper的輸出數據是KV對的形式(KV的類型可自定義)
(5)map()方法(maptask進程)對每一個<K,V>調用一次
2.Reducer階段
(1)用戶自定義的Reducer要繼承自己的父類
(2)Reducer的輸入數據類型對應Mapper的輸出數據類型,也是KV
(3)Reducer的業務邏輯寫在reduce()方法中
(4)Reducetask進程對每一組相同k的<k,v>組調用一次reduce()方法
3.Driver階段
相當於yarn集羣的客戶端,用於提交我們整個程序到yarn集羣,
提交的是封裝了mapreduce程序相關運行參數的job對象
WordCount案例詳解
1.需求
在給定的文本文件中統計輸出每一個單詞出現的總次數
2.數據準備(word.txt)
hello world
zookeeper zookeeper
hadoop
spark
hello world
scala scala
hadoop
spark
hello world
hbase hbase
hadoop
spark
3.分析
按照mapreduce編程規範,分別編寫Mapper,Reducer,Driver,如圖。
4.導入相應的依賴座標+日誌添加
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.7.2</version>
</dependency>
</dependencies>
在項目的src/main/resources目錄下,新建一個文件,命名爲“log4j.properties
”,在文件中填入
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
5.編寫程序
(1)編寫mapper類
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
public class WordcountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
Text k = new Text();
IntWritable v = new IntWritable(1);
@Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
// 1 獲取一行
String line = value.toString();
// 2 切割
String[] words = line.split(" ");
// 3 輸出
for (String word : words) {
k.set(word);
context.write(k, v);
}
}
}
(2)編寫reducer類
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
public class WordcountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
int sum;
IntWritable v = new IntWritable();
@Override
protected void reduce(Text key, Iterable<IntWritable> value,
Context context) throws IOException, InterruptedException {
// 1 累加求和
sum = 0;
for (IntWritable count : value) {
sum += count.get();
}
// 2 輸出
v.set(sum);
context.write(key,v);
}
}
(3)編寫驅動類
import java.io.IOException;
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.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class WordcountDriver {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
// 1 獲取配置信息以及封裝任務
Configuration configuration = new Configuration();
Job job = Job.getInstance(configuration);
// 2 設置jar加載路徑
job.setJarByClass(WordcountDriver.class);
// 3 設置map和reduce類
job.setMapperClass(WordcountMapper.class);
job.setReducerClass(WordcountReducer.class);
// 4 設置map輸出
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
// 5 設置Reduce輸出
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
// 6 設置輸入和輸出路徑
FileInputFormat.setInputPaths(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
// 7 提交
boolean result = job.waitForCompletion(true);
System.exit(result ? 0 : 1);
}
}
5.本地測試
(1)在windows環境上配置HADOOP_HOME
環境變量
(2)在eclipse/idea上運行程序
6.集羣上測試
(1)將程序打成jar包,然後拷貝到hadoop集羣中
(2)啓動hadoop集羣
(3)執行wordcount程序
[admin@hadoop102 software]$ hadoop jar wc.jar
包名.WordcountDriver /user/admin/input /user/admin/output1