学习MapReduce(三)

    2017.3.12 更加深入了解MapReduce机制,学习使用Combiner类来对map的输出进行本地的合并。这里有个坑,真是,不自己写代码,不了解Combiner的机制啊。总结一句:Combiner只适合对map输出的结果集进行合并,合并成一个K,V值,这样可以大量减少shuffle阶段的网络传输。(网络是Hadoop最大的瓶颈)。这样看来,Combiner适合做的事情是,求一个K的最大值,最小值,对同一个K集合的合并之类的事情。诸如:排序,比较之类的事情不是很合适。(我是个菜鸟,所以想不到怎么解决这个问题,哪位大神看到这个,求帮忙啊。)还是之前的那个案例:有手机用户的流量数据,如果不写自己Combiner类,那么map会产生一对像这样的结果集在网络上传输:{138333333333,list(v1,v2,v3,............)}。写了自己Combiner类之后:网络上传输的数据会是这样:{138333333333,list(v1)}这样就完成了数据量的减少。

    概念:Combiner继承了Reducer,可以理解成本地的Reducer。这里有个问题--->>必须符合这样的书写规则:combiner的输入和reduce的输入完全一致,输出和map的输出完全一致。

    仔细的想了想这句话发现:map阶段输出的 k,v是combiner的输入,而combiner的输出又要和map的输出一致,那么combiner的输入和输出就必须一样。如果实现了这句话,那么combiner的输出就是Reduce的输入。这就等价于(map的输出就是reduce的输入。)----->>这样理解不知道对不对。所以这就有一个问题。如果我想排序,map的输出k,v集合的k必须是自己写的序列化类。而这样又不能实现在combiner中对同一手机号的流量累加。呵呵,心好累。好了,下面贴上代码:

-------------------------->>>自己写的序列化类:


 


package lcPhoneFolw;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import org.apache.hadoop.io.WritableComparable;

public class PhoneFlow implements WritableComparable{
    private long upload;
    private long download;
    private long sumload;
    
    public PhoneFlow(){}
    
    @Override
    public String toString() {
        
        return upload+"\t"+download+"\t"+sumload;
    }

    public PhoneFlow(long upload, long download) {
        this.upload = upload;
        this.download = download;
        this.sumload = upload+download;
    }

    public long getUpload() {
        return upload;
    }

    public void setUpload(long upload) {
        this.upload = upload;
    }

    public long getDownload() {
        return download;
    }

    public void setDownload(long download) {
        this.download = download;
    }

    public long getSumload() {
        return sumload;
    }

    public void setSumload(long sumload) {
        this.sumload = sumload;
    }
    //序列化
    public void write(DataOutput out) throws IOException {
        // TODO Auto-generated method stub
        out.writeLong(upload);
        out.writeLong(download);
        out.writeLong(sumload);
    }
    //反序列化(应该是和序列化的顺序一样,如果不一样应该是会出问题。没有研究过)
    public void readFields(DataInput in) throws IOException {
        // TODO Auto-generated method stub
        upload = in.readLong();
        download = in.readLong();
        sumload = in.readLong();
    }


    //自定义比较器,会在map输出结果 PhoneFlow为K时,自动按照这个比较器传给reduce
    public int compareTo(PhoneFlow o) {

        return this.sumload>o.getSumload() ? -1 : 1 ;
    }

}


 

------------------------------------------->>>>combiner类

 

package lcPhoneFolw;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
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;

public class PhoneAllDemo {
	
	/**
	 * Mapper类
	 * @author admin
	 *
	 */
	
	static class PhoneMapper2 extends Mapper{
		//一般在Map阶段传入的K是没什么作用的,V一般是一个数据文件,这个案例是统计手机总流量,并排序,所以输出的k,v先按照<13833333333,自己写的序列化类>输出
		@Override
		protected void map(LongWritable key, Text value,Context context)
				throws IOException, InterruptedException {
			//这里是对V来进行逻辑运算一个手机流量文件我们需要它的手机号,上行流量和下行流量所以
			String line = value.toString();
			//得到每行的字符串之后 ,分析数据文件找到想要的数据,如手机号,上行流量和下行流量
			String[] strs = line.split("\t");
			long phoneNumber =Long.valueOf(strs[0]);//将手机号转为long类型
			//需要一个PhoneFlow的实例
			
			long upload = Long.valueOf(strs[1]);
			long download = Long.valueOf(strs[2]);
			PhoneFlow pf = new PhoneFlow(upload,download);
			context.write(new LongWritable(phoneNumber), pf);//输入k,v 这个k,v值会交给自己写的combiner类

		}
		
		
		
	}
	/**
	 * 自己的定义的combiner类,这个类实现map后的数据在本地的诸如合并,计算等等。。。。为了减少网络传输
	 * combiner也是继承的Reducer,重写reduce方法,针对这个案例,我们是为了完成相同手机号在本地上的合并和流量累加
	 * @author admin
	 *
	 */
	
	static class PhoneCombiner extends Reducer{
		
		@Override
		protected void reduce(
				LongWritable key,
				Iterable values,Context context)
				throws IOException, InterruptedException {
			//业务需要我们将相同手机号的流量进行汇总,注意,当这个reduce方法接受到map传过来的k,v值时,是一个一个相同k的集合,一个集合运行一次reduce方法
			//对V进行计算,注意,上面的map方法传进来的K,V为{135333333333,PhoneFlow}这个样子的 ,那么 我们遍历PhoneFlow,得到总流量可不可以累加?
			long upload = 0;
			long download = 0;
			for (PhoneFlow value : values) {
				upload +=value.getUpload();
				download += value.getDownload();
			}
			PhoneFlow pf = new PhoneFlow(upload, download);//定义一个新的PhoneFlow的实例来接受累加过后的upload和download
			//遍历完成,可以输出了,注意,输出的顺序,输出的k,v类型必须和map的输出类型一致。
			context.write(key, pf);
		}
	}
	/**注意:combine的输入和reduce的输入完全一致,输出和map的输出完全一致
	 * 真正的reduce方法,这里接受combiner的输出k,v值,输出为<手机号,PhoneFlow>
	 * @author admin
	 *
	 */
	
	static class PhoneReducer2 extends Reducer{
		
		@Override
		protected void reduce(
				LongWritable key,
				Iterable values,Context context)
				throws IOException, InterruptedException {
			//因为我们在combiner中已经对map的结果进行了合并,所以得到的k,v集合肯定只有一个元素
			context.write(key,values.iterator().next());
		}
		
		
	}
	/**
	 * 主方法
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		//这个类,就不多解释了
		Configuration conf = new Configuration();
//		conf.set("fs.defualtFS", "hdfs://192.168.1.101:8020");设置使用的集群环境,我这里使用本地测试,所以注掉了
		Job job = Job.getInstance(conf);
		//设置MapReduce的主类
		job.setJarByClass(PhoneAllDemo.class);
		//设置自己定义的combiner类
		job.setCombinerClass(PhoneCombiner.class);
		
		//下面就开始设定mapper类和reducer类
		job.setMapperClass(PhoneMapper2.class);
		job.setReducerClass(PhoneReducer2.class);
		
		job.setMapOutputKeyClass(LongWritable.class);
		job.setMapOutputValueClass(PhoneFlow.class); 
		
		job.setOutputKeyClass(LongWritable.class);
		job.setOutputValueClass(PhoneFlow.class);
//		job.setOutputKeyClass(PhoneFlow.class);
//		job.setOutputValueClass(LongWritable.class);
		//设定输入文件路径和输出路径
		FileInputFormat.setInputPaths(job,new Path(args[0]));
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		
		job.waitForCompletion(true);
	}
	

}

 

以上就是今天学习到的内容。谢谢观看------->>>>我去想静静去了

 

转载于:https://my.oschina.net/u/3294842/blog/857098

你可能感兴趣的:(学习MapReduce(三))