Hadoop-MR实现日志清洗(二)
(接上:Hadoop-MR实现日志清洗(一))
4.groupbycount测试
编写Hadoop-MR的groupbycount程序测试Hadoop运行环境,同时也是对mapreduce程序的一次复习。
为了不影响logparser项目结构,单独创建了groupbycount项目,配置与logparser一致。
初始结构:
4.1源文件准备
源文件取自工作中部分数据集。
下载地址:2018-08-29-15-03-13_1959.rar
样例数据:
leeyk99 fr fr pc Boutique Day Dresses 18 0 0 20180828 leeyk99 fr fr pc Women Accessories Phone Cases 4 0 0 20180828 leeyk99 fr fr pc Women Accessories Scarves 5 0 0 20180828 leeyk99 fr fr pc Women Beauty Beauty Tools Makeup Tools 1 0 0 20180828 leeyk99 fr fr pc Women Clothing Beachwear Swimwear 4 0 0 20180828 leeyk99 fr fr pc Women Clothing Bottoms Shorts 1 0 0 20180828
数据结构:
4.2map函数
package com.leeyk99.udp; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; import java.io.IOException; public class GroupByCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> { private final int ONE=1; @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { //super.map(key, value, context); String line=value.toString(); String[] lineSplit=line.split("\t"); String siteTp=lineSplit[0]; context.write(new Text(siteTp),new IntWritable(ONE)); } }
4.3reduce函数
package com.leeyk99.udp; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; import java.io.IOException; //import java.util.Iterator; public class GroupByCountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{ @Override protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { //super.reduce(key, values, context); Integer sum=0; /*Iterator<IntWritable> it=values.iterator(); if(it.hasNext()){ sum+=it.next().get(); }*/ for (IntWritable value : values ) { sum+=value.get(); } context.write(key,new IntWritable(sum)); } }
4.4程序入口
package com.leeyk99.udp; 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 java.io.File; //import java.io.IOException; public class GroupByCount { public static void main(String[] args) throws Exception{//Exception范围比较大,包含IOException、InterruptedException if(args.length != 2){ System.err.println("Usage: GroupByCount <input path> <output path>"); System.exit(-1); } Job job=new Job(); job.setJarByClass(GroupByCount.class); job.setJobName("job-GroupByCount"); FileInputFormat.addInputPath(job, new Path(args[0])); FileOutputFormat.setOutputPath(job, new Path(args[1])); job.setMapperClass(GroupByCountMapper.class); job.setReducerClass(GroupByCountReducer.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class); delDir(args[1]); System.exit(job.waitForCompletion(true)? 0 : 1); } private static void delDir(String path){ File f=new File(path); if(f.exists()){ if(f.isDirectory()){ String[] items=f.list(); for( String item : items ){ File f2=new File(path+"/"+item); if(f2.isDirectory()){ delDir(path+"/"+item); } else{ f2.delete(); } } } f.delete(); //删除文件或者最后的空目录 } else{ System.out.println("Output directory does not exist ."); } } }
4.5del函数
写在入口函数中,也可以单独创建个类。
private static void delDir(String path){ File f=new File(path); if(f.exists()){ if(f.isDirectory()){ String[] items=f.list(); for( String item : items ){ File f2=new File(path+"/"+item); if(f2.isDirectory()){ delDir(path+"/"+item); } else{ f2.delete(); } } } f.delete(); //删除文件或者最后的空目录 } else{ System.out.println("Output directory does not exist ."); } }
4.6测试
在IDEA中需要设置下运行配置(Run/Debug Configurations):点击 + ,创建一个Application,选一下main class(一般输入项目名或类名,去查找的时候已经自动列出来可选的main了),设置下程序参数(Program arguments): input/ output/
得到:
点击 ▶ 运行,得到结果:
4.7小结
本次测试使用mapreduce实现类似sql: select key,count(user_id) from tableName group by key 用法的功能。
mapreduce程序的核心就是reduce函数中的计算实现,即对输入值的遍历处理,比如求和、计数、比较、取均、去重等多种运算。
目前已完成 单维度求和、单维度计数。像Max、Min、取均这三类无需再尝试,因为这个三类和求和、计数类似。
后续继续实现 单维度去重计数、单维度去重、无维度求和。
至于多维度,其实很简单,因为在map函数中,得到多列后合并成一个字符串作为key(这几个字段的分隔符相当于在Hive中指定的列分隔符)。(初步思路)
key和value的分隔符,如何指定呢(不是用默认的\t)?后续做一次多维度单指标求和测试。
那么多维度多指标求和如何做呢?后续继续测试。