MapReduce:输出是一个文本文件,每一行第一个数字式行标,第二个数字是输入文件中每一行除行标外数字的平均值,且整数不保留小数,小数保留两位小数点

有时候你会遇到这样的问题:你有一个表格,给出了每个人在十二月,一月和二月的收入。

表格如下:

姓名 一月 二月 三月

楚乔     200   314   3500

宇文玥     2000  332   2300

烟熏柿子    6000  333   680

淳儿    5000  333   789

洛河     30    12    2900

 

现在需要知道每个人这三个月的收入平均值,那么你就需要将表格中一行代表收入的数字相加除以月数.下面请编写MR程序解决这个简单的问题。

 

输入只包含一个文件,它的结构如下:(数据自己做格式化)

input:

1    200    314    3500
2    2000    332    2300
3    6000    333    680
4    5000    333    789
5    30    12    2900

 

其中每行最前面的数字是行标

输出是一个文本文件,每一行第一个数字式行标,第二个数字是输入文件中每一行除行标外数字的平均值

如下:

Output:

1    1338
2    1544
3    2337.67
4    2040.67
5    980.67

 

 

代码如下(由于水平有限,不保证完全正确,如果发现错误欢迎指正):

 

package com;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
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 MonthTest2 {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        Configuration config = new  Configuration();
        config.set("fs.defaultFS", "hdfs://192.168.0.100:9000");
        config.set("yarn.resourcemanager.hostname", "192.168.0.100");
        
        FileSystem fs = FileSystem.get(config);  
       
        Job job = Job.getInstance(config);
        
        job.setJarByClass(MonthTest2.class);
        
        //设置所用到的map类
        job.setMapperClass(myMapper.class);
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(Text.class);
        
        //设置所用到的reduce类
        job.setReducerClass(myReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);
        
        //设置输入输出地址
        FileInputFormat.addInputPath(job, new Path("/input/month.txt"));
        
        Path path = new Path("/output1/");
        
        //判断目录文件是否存在,存在的话,删除
        if(fs.exists(path)){
            fs.delete(path, true);
        }
        //指定结果文件的输出地址
        FileOutputFormat.setOutputPath(job,path);
        
        //启动处理任务job
        boolean completion = job.waitForCompletion(true);
        if(completion){
            System.out.println("Job Success!");
        }
    }
    
    public static class myMapper extends Mapper<LongWritable,Text, Text, Text>{

        @Override
        protected void map(LongWritable key, Text value,Context context) throws IOException, InterruptedException {
            String values=value.toString();
            String words[]=values.split("\t");  //1    200    314    3500
            float avg=(Float.parseFloat(words[1])+Float.parseFloat(words[2])+Float.parseFloat(words[3]))/3;
            String aaa=String.format("%.2f", avg);//保留两位小数
            context.write(new Text(words[0]), new Text(aaa));
        }
    }
    
    public static class myReducer extends Reducer< Text, Text, Text, Text>{

        @Override
        protected void reduce(Text key, Iterable<Text> values,Context context) throws IOException, InterruptedException {
            for (Text value : values) {
                if(value.toString().endsWith(".00")){ //  判断出以.00结尾的数字
                    String[] aa = value.toString().split(".00");//1338.00--->aa[0]=1338
                    context.write(key,new Text(aa[0]));
                }else{
                    context.write(key, value);
                }
            }
        }
        
    }
}

注意:主要难点在于整数不要求保留两位小数且不要小数点,float类型的话要求保留两位小数

 

如果您认为这篇文章还不错或者有所收获,您可以通过右边的“打赏”功能 打赏我一杯咖啡【物质支持】,也可以点击下方的【好文要顶】按钮【精神支持】,因为这两种支持都是使我继续写作、分享的最大动力!

 

posted @ 2017-07-31 19:11  素净  阅读(353)  评论(0编辑  收藏  举报