目录
一、partflow
Flow.java
public class Flow implements Writable{
//MapReduce中不允许属性值为null
//手机号
private String phone = "";
//地址
private String addr = "";
//姓名
private String name = "";
//流量
private int flow;
//setter和getter
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getFlow() {
return flow;
}
public void setFlow(int flow) {
this.flow = flow;
}
//序列化
//在序列化的时候,只需要将必要的属性依次写出即可
//在实际开发中,开发文档会规定必须序列化的属性以及可以选择序列化的属性
@Override
public void write(DataOutput out) throws IOException {
out.writeUTF(phone);
out.writeUTF(addr);
out.writeUTF(name);
out.writeInt(flow);
}
//反序列化
//按照什么顺序写出的,就要按照什么顺序读处来
@Override
public void readFields(DataInput in) throws IOException {
//this代表当前
this.phone = in.readUTF();
this.addr = in.readUTF();
this.name = in.readUTF();
this.flow = in.readInt();
}
}
FlowDrive,.java
public class FlowDriver {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
//配置环境变量
Configuration conf = new Configuration();
//向Yarn申请任务
Job job = Job.getInstance(conf);
//设置入口类
job.setJarByClass(FlowDriver.class);
//设置mapper类
job.setMapperClass(FlowMapper.class);
//设置reduce类
job.setReducerClass(FlowReducer.class);
//指定分区类
job.setPartitionerClass(FlowPartitioner.class);
//设置ReducerTask的个数
job.setNumReduceTasks(3);
//指定mapper类的输出键和值的类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Flow.class);
//指定reducer类的输出键和值的类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//设置输入路径--->告诉电脑要处理那个文件
FileInputFormat.addInputPath(job, new Path("hdfs://hadoop01:9000/txt/flow.txt"));
//设置输出路径--->电脑给你所需要的结果放到那?
//注意设置输出路径要求不存在
FileOutputFormat.setOutputPath(job, new Path("hdfs://hadoop01:9000/result/partflow"));
//执行任务
job.waitForCompletion(true);
}
}
FlowMapper.java
public class FlowMapper extends Mapper<LongWritable, Text, Text, Flow>{
/**
* map方法怎么出来?先写map在按alt + /
* map方法默认是按行进行处理的
* key--> 指的是行偏移量
* value-->指的读取的一行数据
* context-->环境参数。可以将数据出入到reduce阶段
* ***/
@Override
protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, Flow>.Context context)
throws IOException, InterruptedException {
//13877779999 bj zs 2145--->"13877779999 bj zs 2145"--->["13877779999", "bj" ,"zs" ,"2145"]
String[] arr = value.toString().split(" ");
//实例化对象
Flow f = new Flow();
//需要把读取的数据封装到所写的对象中的属性中
f.setPhone(arr[0]);
f.setAddr(arr[1]);
f.setName(arr[2]);
//字符串转换成整数类型Integer.parseInt()
f.setFlow(Integer.parseInt(arr[3]));
//通过环境参数进行输出
context.write(new Text(f.getName()), f);
}
}
FlowPartitioner.java
/**
*
* 由于分区类中数据从mapper类中获取,所以mapper类输出就是分区类的输入
* KEY, VALUE-->Text, Flow
*
* **/
public class FlowPartitioner extends Partitioner<Text, Flow>{
//分类逻辑就是覆盖在这个方法中
//text-->根据mapper类中分析-->姓名
//flow-->根据mapper类中分析-->对象(f)
//numPartitions-->分几个区
@Override
public int getPartition(Text text, Flow flow, int numPartitions) {
//1.获取地址(通过flow对象进行获取)
String addr = flow.getAddr();
//按地区进行分类
//success part_00000 part_00001 part_00002
//判断地址是否是北京
if(addr.equals("bj")){
return 0;
} else if(addr.equals("sh")){ //判断地址是否是上海
return 1;
} else {
return 2; //判断地址是否是其它
}
}
}
FlowReducer.java
/**
* KEYIN:输入键的类型
* VALUEIN:输入值的类型
* 注意由于mapredce阶段输入键和值从map阶段获取的,所以mapreduce阶段的输入键和值就是map阶段的输出键和值
* KEYOUT:输出键的类型--->根据具体的情况具体分析,根据本案例分析key--->姓名(字符串--->Text)