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

  循环复制

posted @ 2016-07-27 14:57  博智星  Views(209)  Comments(0)    收藏  举报