MapReduce学习总结
MapReduce计算过程
-
全流程
-
文件读取阶段
MapReduce默认是Text读取方式,即一行一行读取文本内容,以读取数据的偏移量,每行文本内容组成”KEY-VALUE“键值对输送给下一阶段。
PS:如果指定一个文件夹,则会读取文件夹下所有文件;如果指定文件,则只会读取此文件。
-
Map阶段
在Map阶段,我们可以获取每个MapTask任务文件读取所返回的“KEY-VALUE”键值对,我们可以根据不同的业务逻辑需求将其重新切分组合,形成新的键值对写入上下文中,进入下一阶段。
此步需要继承Mapper,重写map方法进行业务逻辑的重写。
-
分区
我们可以自定义条件为每条数据打上TAG标记,将来进行Reduce操作时,不同的ReduceTask会拉取某一TAG标记的数据,进行数据的聚合。
如果需要进行分区操作,继承Partitioner重写getPartition方法。
-
排序
排序步骤其实分为两次,一次是在Map阶段,在数据分区打上TAG标志之后,会进行一次局部排序;另一次是在Reduce阶段,数据汇总之后,数据会进行一次全排序。
如果需要进行排序,则需要自己编写一个JAVABEAN类实现WritableComparable重写序列化方法(write、read)、排序方法(compareTo)。排序方法返回的int值大于0则代表升序,小于0为降序。
PS:排序是根据KEY值进行排序的,所以Map阶段所输出的格式的KEY必须是需要进行比较数据(一般为自定义的BEAN类)。
-
规约
为了减少网络传输过程中的数据冗余,可以先在Map阶段向Reduce阶段传输之前,先进行一次Reduce操作,进行冗余数据的局部合并。
如果需要进行规约操作,则需要继承Reduce重写reduce方法。
-
分组
判断是否将同一Reduce内的数据聚合在同一组。
如果需要进行进行分组操作,则需要继承WritableComparator并重写compare方法。
PS:此阶段以上阶段,所有操作均在Hadoop集群中运行,不在同一机器上。
-
Reduce阶段
接受Map阶段汇总的数据,按照上述的分组操作进行分组(默认为将同一KEY的数据聚合在同一组)。
此阶段需要继承Reduce,并重写reduce方法。
-
文件输出阶段
根据输出格式(默认是TextOutputFormat),保存到设置路径。
PS:保存路径不可存在,如果输出路径存在,程序则会报错。
模板代码
-
Bean
public class FlowBean implements WritableComparable<FlowBean> { private Integer upFlow=0; private Integer downFlow=0; private Integer upCountFlow=0; private Integer downCountFlow=0; @Override public String toString() { return upFlow + "\t" + downFlow + "\t" + upCountFlow + "\t" + downCountFlow; } public Integer getUpFlow() { return upFlow; } public void setUpFlow(Integer upFlow) { this.upFlow = upFlow; } public Integer getDownFlow() { return downFlow; } public void setDownFlow(Integer downFlow) { this.downFlow = downFlow; } public Integer getUpCountFlow() { return upCountFlow; } public void setUpCountFlow(Integer upCountFlow) { this.upCountFlow = upCountFlow; } public Integer getDownCountFlow() { return downCountFlow; } public void setDownCountFlow(Integer downCountFlow) { this.downCountFlow = downCountFlow; } @Override public void write(DataOutput out) throws IOException { out.writeInt(upFlow); out.writeInt(downFlow); out.writeInt(downCountFlow); out.writeInt(upCountFlow); } @Override public void readFields(DataInput in) throws IOException { this.upFlow=in.readInt(); this.downFlow=in.readInt(); this.downCountFlow=in.readInt(); this.upCountFlow=in.readInt(); } @Override public int compareTo(FlowBean o) { return o.getUpFlow()-this.upFlow; } }
-
Map
public class FlowSortMapper extends Mapper<LongWritable, Text,FlowBean,Text> { @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String[] split = value.toString().split("\t"); FlowBean flowBean = new FlowBean(); flowBean.setUpFlow(Integer.parseInt(split[1])); flowBean.setDownFlow(Integer.parseInt(split[2])); flowBean.setUpCountFlow(Integer.parseInt(split[3])); flowBean.setDownCountFlow(Integer.parseInt(split[4])); context.write(flowBean,new Text(split[0])); } }
-
Reduce
public class FlowSortReduce extends Reducer<FlowBean,Text,Text,FlowBean> { @Override protected void reduce(FlowBean key, Iterable<Text> values, Context context) throws IOException, InterruptedException { for(Text value:values){ context.getCounter("AllCount","MyAllCount").increment(1); context.write(value,key); }
-
JobMain
public class JobMain extends Configured implements Tool { //定义一个job任务 @Override public int run(String[] args) throws Exception { Job job = Job.getInstance(super.getConf(), "fc"); //设置输入类型 job.setInputFormatClass(TextInputFormat.class); // job.setJarByClass(JobMain.class); //设置文件路径 TextInputFormat.addInputPath(job, new Path("hdfs://192.168.2.135:8020/laow/part-r-00000")); // TextInputFormat.addInputPath(job,new Path("file:///D:\\a.txt")); //本地执行 //设置访问用户名 // job.setUser("root"); //设置Map阶段的类 job.setMapperClass(FlowSortMapper.class); //设置map阶段key类型 job.setMapOutputKeyClass(FlowBean.class); //设置map阶段value类型 job.setMapOutputValueClass(Text.class); //设置Reduce阶段的类 job.setReducerClass(FlowSortReduce.class); //设置reduce阶段的key类型 job.setOutputKeyClass(Text.class); //设置reduce阶段的value类型 job.setOutputValueClass(FlowBean.class); //设置输出类型 job.setOutputFormatClass(TextOutputFormat.class); //设置输出路径 Path path = new Path("hdfs://192.168.2.135:8020/laow1/"); FileSystem fs = FileSystem.get(new URI("hdfs://192.168.2.135:8020/"), new Configuration(), "root"); if (fs.exists(path)) { fs.delete(path, true); } TextOutputFormat.setOutputPath(job, path); // TextOutputFormat.setOutputPath(job,new Path("file:///D:\\hadoop\\")); //本地执行 //等待运行结束 boolean b = job.waitForCompletion(true); return b ? 0 : 1; } public static void main(String[] args) throws Exception { Configuration configuration = new Configuration(); //启动job任务 int run = ToolRunner.run(configuration, new JobMain(), args); System.exit(run); } }
Maven依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
</dependency>
<!-- Hadoop-->
<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-common -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-hdfs -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.7.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-client -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-mapreduce-client-core -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-core</artifactId>
<version>2.7.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-core -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-core</artifactId>
<version>1.2.1</version>
</dependency>
</dependencies>