咳咳,终于要写mapreduce了,算是填上了以前挖的坑,虽然时间有点晚。。。。。。
mapreduce去空去重并格式化输出数据
前提:解析json的库:我使用的是阿里的fastjson
思路:
数据去重:map的输出<key,value>经过shuffle过程聚集成<key,value-list>后交给reduce,无论这个数据出现多少次,只要在最终结果中输出一次就可以了。具体就是reduce的输入应该以数据作为key,而对value-list则没有要求(可以设置为空)。当reduce接收到一个<key,value-list>时就直接将输入的key复制到输出的key中,并将value设置成空值,然后输出<key,value>。
数据去空:map阶段在读取一行数据时我们将这一行数据分割放到一个数组中遍历这个数组并判断它是不是空如果是空我们可以删除这条数据也可以使用指定值填充。
分隔数据:在map阶段我们将分割好的数据放在一个数组中,遍历这个数组时使用字符串拼接的方式拼接上指定符号并将它作为key输出
分析:
先来看一下数据的格式:
数据的第一行和最后一行是 ‘[’ 和 ‘]’ 如果我们读取到的行包含这两个符号或读取的行为空则不做任何处理。
然后我们发现每条数据的最后都有一个逗号,我们需要删除每行最后的逗号,然后就是解析json数据然后提取相应字段。
map代码:
import com.alibaba.fastjson.JSONObject;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
public class CleanMap extends Mapper<LongWritable,Text,Text,NullWritable> {
private static Text text = new Text();
public void map(LongWritable key,Text value,Context context) throws IOException, InterruptedException {
String line = value.toString();
//判断读取的行是否包含“[” 和 “]” 或读取的行为空
if (line.indexOf("[")==0 || line.indexOf("]")==0 || line.trim().isEmpty()){
return;
}
//删除逗号
line = line.substring(0, line.length()-1);
//删除逗号时可能会删掉每行最后的"}"就是判断数据是否符合json格式这里我们要加一层判断否则解析json数据会出错
if (!line.endsWith("}")){
line = line.concat("}");
}
//解析json数据
JSONObject jsonObject = JSONObject.parseObject(line);
String[] data = new String[5];
String name = jsonObject.getString("name");
判断name字段是否为空
if (name==null || name.trim().isEmpty()) {
return;
}
data[0] = jsonObject.getString("rank");
data[1] = name.trim();
data[2] = jsonObject.getString("actors");
data[3] = jsonObject.getString("time");
data[4] = jsonObject.getString("score");
//循环判空
for(String i : data) {
if(i==null||i.equals("")) {
return;
}
}
//分隔数据
String end = "";
for (String item: data){
end = end + item + "|";
}
end = end.substring(0, end.length()-1);
//将数据转为text类型并作为key输出
text.set(end);
context.write(text, NullWritable.get());
}
}
reduce不需要做任何处理直接输出即可
reduce代码:
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
public class CleanReduce extends Reducer<Text, NullWritable, Text, NullWritable> {
public void reduce(Text key, Iterable<NullWritable> value, Context context) throws IOException, InterruptedException {
context.write(key, NullWritable.get());
}
}
main:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.NullWritable;
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.IOException;
public class CleanJob {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
job.setJarByClass(CleanJob.class);
job.setMapperClass(CleanMap.class);
job.setReducerClass(CleanReduce.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(NullWritable.class);
Path in = new Path("hdfs://localhost:9000/maoyan/in/");
Path out = new Path("hdfs://localhost:9000/maoyan/out");
FileInputFormat.addInputPath(job, in);
FileOutputFormat.setOutputPath(job, out);
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
以上就是去空去重以及分割数据的全部代码!希望对大家有所帮助!
看一下运行效果: