一小时搞定Mapreduce程序

之前一直用hive处理数据,觉得MR程序打包上传的比较麻烦,后来偶遇hive搞不定的文件网上找了个MR的例子稍微改一下感觉也比较方便,主要是处理速度快。

MR程序主要是有3各类:main函数类,map重载类,reduce重载类。

第一步:maven里面添加几个jar包:

代码如下:


第二步:main类:主要是调度MR程序的启动运行

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.Path;

import org.apache.hadoop.io.IntWritable;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Job;

import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;

import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import org.apache.hadoop.util.GenericOptionsParser;

public class WordCount {

public static void main(String[]args)throws Exception

{

Configuration conf =new Configuration();//从hadoop配置文件读取参数

 String [] otherArgs =new GenericOptionsParser(conf,args).getRemainingArgs();//从命令行读取参数

 if(otherArgs.length!=2)

{

System.err.println("Usage:wordcount");

System.exit(2);

}

Job job =new Job(conf,"wordcount");

job.setJarByClass(WordCount.class);

job.setMapperClass(TokenizerMapper.class);

job.setReducerClass(IntSumReducer.class);

job.setOutputKeyClass(Text.class);

job.setOutputValueClass(IntWritable.class);

FileInputFormat.addInputPath(job,new Path(otherArgs[0]));

FileOutputFormat.setOutputPath(job,new Path(otherArgs[1]));

System.exit(job.waitForCompletion(true)?0:1);

}

}

第三步:Map类:主要是按行读取文件内容,根据自己需要处理(默认按回车换行分割,如果要改动需要重载某个函数)

代码如下:

import java.io.IOException; //导入异常处理类

import org.apache.hadoop.io.IntWritable; //导入整数类

import org.apache.hadoop.io.Text; //导入文本类

import org.apache.hadoop.mapreduce.Mapper; //导入Mapper类

public class TokenizerMapper extends Mapper{

    Text word = new Text();                //定义输出键

    //统计每行数据每个id,aaa字符出现的次数

    public void map(Object key,Text value,Context context)throws IOException,InterruptedException

    {

        int len = 0;

        String id="";

        len = appearNumber(value.toString(),"aaa");    //统计aaa出现次数

        index = value.toString().indexOf("\"id\":\"");

        if(index>0)

        {

            id = value.toString().substring(index+n,index+m); //取每行id值

            IntWritable one = new IntWritable(len);

            Text id_t = new Text(id);

            context.write(id_t,one);

        }

    }

    public static int appearNumber(String srcText, String findText) {

        int count = 0;

        int index = 0;

        while ((index = srcText.indexOf(findText, index)) != -1) {

            index = index + findText.length();

            count++;

        }

        return count;

    }

}

第四步:重载reduce类

  代码如下:

import java.io.IOException;import org.apache.hadoop.io.IntWritable;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Reducer;

public class IntSumReducer extends Reducer{

 IntWritable result = new IntWritable();

 public void reduce(Text key,Iterable values,Context context)

            throws IOException,InterruptedException

    {

        int sum = 0;

        for(IntWritable val:values) //不断地将values中的IntWritable整数提取出来给val

        {

            sum=sum + val.get();

        }

        result.set(sum);

        context.write(key,result);  //每个id的aaa出现的次数求和输出

    }

}

第五步:打成jar包。上传hadoop,运行

hadoop  jar  mr_test1.jar  WordCount  hdfs:///myfile/test.log    hdfs:///myfile/output10

PS:hdfs:///myfile/2018042319.log  为输入日志文件

        hdfs:///myfile/output10 指定的输出目录

结果文件在:hdfs:///myfile/output10/part-r-00000

为了验证reduce阶段的作用,我曾把main函数中job.setReducerClass(IntSumReducer.class); 这句代码注掉,跑出的结果为每个id每行aaa出现的次数。将结果文件某个id  grep出来,例如结果有17行,然后对17行的value求和,和加上job.setReducerClass(IntSumReducer.class)这句,这个id的结果完全一致。

MR程序的运行速度对比

MR程序的运行速度感觉比较快,像这个日志文件约10G,一开始的时候出于简单的想法写了一个shell脚本去处理,放在内存192G,CPU64核物理机运行,发现每秒大概只能处理不到1000条数据,算下来跑完需要约10小时,想shell的结果和mr的结果进行对比,所以就没有kill。如果只是慢也就算了,shell脚本执行完几个小时,运维忽然通知这台服务器重启了,也没有太详细的dump信息,说大概是内存不足。。。幸亏只是一台节点机,无其它定时任务,所以对集群无影响。估计是shell管理内存有硬伤,系统本身也有一些内存没来得及释放。

上面的MR程序运行在同样配置的物理机集群,约40台,10G文件运行也就几分钟,对比shell的结果基本相同,感觉速度快了不止一个数量级。

你可能感兴趣的:(一小时搞定Mapreduce程序)