10.用mapReduce统计流量
这篇文章中所包含的新知识点:
1.map和reduce输出的不是基本类型的序列化对象,而是自定义的对象。需要实现import org.apache.hadoop.io.Writable;接口,还需要重写import java.io.DataInput;
import java.io.DataOutput;序列化和反序列化的方法。
2.hadoop jar命令可以调用main方法时args【】输入参数
3.利用return过滤map阶段的特殊数据不做处理
接下来就是代码:我将map,reduce代码和main代码放入一个类中。(java内置类)
package com.xws.flowCountMapreduce; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import org.apache.hadoop.io.Writable; /** * 流量bean * 我们在使用这个类时,用context.write()将序列化的类输出,那么需要这个类实现一个接口: * * @author root * */ public class FlowBean implements Writable{ private long upFlow; private long dFlow; private long sumFlow; /** * 因为有两参构造方法,所以无参构造默认没有,但我们必须手动创建, * 因为在对FlowBean序列化时,反射用到了无参构造方法,会出错。 */ public FlowBean() { } /** * 用两参构造函数创建flowBean * @param upFlow * @param dFlow */ public FlowBean(long upFlow, long dFlow) { this.upFlow = upFlow; this.dFlow = dFlow; this.sumFlow = upFlow+dFlow; } public long getUpFlow() { return upFlow; } public void setUpFlow(long upFlow) { this.upFlow = upFlow; } public long getdFlow() { return dFlow; } public void setdFlow(long dFlow) { this.dFlow = dFlow; } public long getSumFlow() { return sumFlow; } public void setSumFlow(long sumFlow) { this.sumFlow = sumFlow; } /** * 反序列化的方法 */ @Override public void readFields(DataInput in) throws IOException { upFlow = in.readLong(); dFlow = in.readLong(); sumFlow = in.readLong(); } /** * 对这个类序列化的方法 * 成员变量的类型对应序列化的类型 */ @Override public void write(DataOutput out) throws IOException { out.writeLong(upFlow); out.writeLong(dFlow); out.writeLong(sumFlow); } @Override public String toString() { return "\t" + upFlow + "\t" + dFlow + "\t" +sumFlow ; } }
package com.xws.flowCountMapreduce; import java.io.IOException; import org.apache.commons.lang.StringUtils; 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; /** * 统计上下行流量的mapreduce * @author root * */ //com.xws.flowCountMapreduce.FlowCount public class FlowCount { /** * 在map阶段,我们先把每行数据的key和value作为分析元数据输出,其中value包括上行流量,下行流量和总流量 * @author root * */ public static class FlowCountMapper extends Mapper<LongWritable, Text, Text, FlowBean>{ @Override protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, FlowBean>.Context context) throws IOException, InterruptedException { //获取本行数据 String line = value.toString(); //将数据拆分 String [] fileds = StringUtils.split(line, "\t"); String phone =""; long upFlow=0; long dFlow=0; try { //排除文件空行 if(fileds.length==0){ //对此行数据不处理 return; } phone = fileds[1]; upFlow = Long.parseLong(fileds[fileds.length-3]); dFlow = Long.parseLong(fileds[fileds.length-2]); context.write(new Text(phone), new FlowBean(upFlow,dFlow)); } catch (Exception e) { } } } /** * 在reduce阶段,我们把同一个手机号的不同FlowBean里的流量统计出综合数据,并输出到一个文件中 * @author root * */ public static class FlowCountReducer extends Reducer<Text, FlowBean, Text, FlowBean>{ @Override protected void reduce(Text key, Iterable<FlowBean> values, Reducer<Text, FlowBean, Text, FlowBean>.Context context) throws IOException, InterruptedException { //统计 long upFlow=0; long dFlow=0; for(FlowBean fb:values){ upFlow+=fb.getUpFlow(); dFlow+=fb.getdFlow(); } //输出结果 context.write(key, new FlowBean(upFlow,dFlow)); //在这里需要注意,我们将手机号和FLowBean输出的结果会怎么样呢?默认会调用toString方法输出key的值和FlowBean的值, //所以我们会知道FlowBean会是一个地址,并不是我们要的,所以要重写FlowBean的toString方法 } } public static void main(String[] args) throws Exception { Job job = Job.getInstance(); //设置工作类 job.setJarByClass(FlowCount.class); //设置map和reduce类 job.setMapperClass(FlowCountMapper.class); job.setReducerClass(FlowCountReducer.class); //设置map输出结果类型 job.setMapOutputKeyClass(Text.class); job.setMapOutputValueClass(FlowBean.class); //设置输出结果类型 job.setOutputKeyClass(Text.class); job.setOutputValueClass(FlowBean.class); //设置输入输出文件路径 FileInputFormat.setInputPaths(job, args[0]); FileOutputFormat.setOutputPath(job, new Path(args[1])); //打印过程信息 boolean flag = job.waitForCompletion(true); System.exit(flag?0:1); } }
在linux终端运行
hadoop jar flow.jar com.xws.flowCountMapreduce.FlowCount /flow/data /flow/output5
如何制造大的文件?
touch 文件名:制作一个空文件
cat 源文件 >> 文件名:将源文件复制到文件名中(追加的)
while true
do cat 源文件 >> 文件名
done
循环复制

浙公网安备 33010602011771号