MapReduce之Map join操作(分布式缓存)
文章目录
案例结合
分析手机销售量前三位的品牌,这三个品牌中每个品牌销售量前三位的型号
file:part-r-00000 (小表)
file:test2.txt (大表,部分数据)
Apple iPhone 11 Pro 9月 "'暗夜绿色', '深空灰色', '金色', '银色'" 5.8英寸 CPU型号:其他 电池不可拆卸 其他 256GB 8329.0 7600.0
Apple iPhone 12 Pro 10月 "'海蓝色', '石墨色', '银色', '金色'" 6.1英寸 CPU型号:其他 电池不可拆卸 其他 128GB 8879.0 3300.0
Apple iPhone 12 mini 以官网信息为准 "'黑色', '白色', '蓝色', '绿色', '红色'" 5.4英寸 CPU型号:其他 电池不可拆卸 其他 64GB 5566.0 30.0
Apple Apple iPhone 11 9月 "'白色', '绿色', '红色', '紫色', '黑色', '黄色'" 6.1英寸 CPU型号:其他 电池不可拆卸 其他 其他 4458.5 47000.0
华为(HUAWEI) 华为畅享Z 5G 5月 "'深海蓝', '幻夜黑', '樱雪晴空'" 6.5英寸 CPU型号:其他 电池不可拆卸 6GB 128GB 2599.0 400.0
华为(HUAWEI) 华为畅享Z 5G 以官网信息为准 "'幻夜黑', '深海蓝', '樱雪晴空'" 6.5英寸 CPU型号:其他 电池不可拆卸 8GB 128GB 2499.0 7.0
华为(HUAWEI) 华为(HUAWEI)nova6 12月 "'亮黑色', '普罗旺斯', '苏音蓝', '蜜语红·星耀版'" 6.57英寸 CPU型号:其他 电池不可拆卸 8GB 128GB 3699.0 6.0
华为(HUAWEI) - 10月 "'天空之境', '幻夜黑', '极光蓝', '相思红'" 6.39英寸 CPU型号:其他 电池不可拆卸 其他 128GB 1399.0 3200.0
飞利浦(PHILIPS) E102A 6月 1.8英寸 CPU型号:其他 电池可拆卸 2GB以下 8GB以下 99.0 3800.0
飞利浦(PHILIPS) E106 1月 "'黑色', '红色'" 其他英寸 CPU型号:其他 电池可拆卸 2GB以下 8GB以下 99.0 520000.0
飞利浦(PHILIPS) E109 10月 "'黑色', '红色', '深海蓝', 'E109C电信版黑色', 'E109C电信版红色'" 1.8英寸 CPU型号:其他 电池可拆卸 2GB以下 8GB以下 99.0 1600.0
飞利浦(PHILIPS) E109 6月 "'深海蓝', '陨石黑', '炫酷红'" 其他英寸 CPU型号:其他 电池可拆卸 其他 其他 99.0 51000.0
飞利浦(PHILIPS) E109C 8月 "'黑色', '红色'" 1.77英寸 CPU型号:其他 电池可拆卸 2GB以下 8GB以下 175.0 24750.0
金立(Gionee) 金立A880 以官网信息为准 "'红色', '黑色'" 2.8英寸 CPU型号:其他 电池可拆卸 2GB以下 8GB以下 268.0 400.0
金立(Gionee) 金立GN5601 3月 "'星空黑', '流沙金'" 6.21英寸 CPU型号:其他 电池不可拆卸 4GB 64GB 799.0 100.0
金立(Gionee) 金立M11s 9月 "'梦幻蓝', '墨玉绿', '黑色'" 6.3英寸 CPU型号:其他 电池不可拆卸 6GB 128GB 1099.0 200.0
金立(Gionee) 金立M30 8月 6.0英寸 CPU型号:其他 电池不可拆卸 8GB 128GB 1399.0 500.0
金立(Gionee) 金立(Gionee) K50 Pro 10月 "'冰霜银', '深海蓝', '零度白'" 6.5英寸 CPU型号:其他 电池不可拆卸 8GB 128GB 799.0 10.0
锤子(smartisan) 以官网信息为准 以官网信息为准 "'黑色', '松绿色'" 6.67英寸 CPU型号:骁龙865 电池不可拆卸 其他 其他 4799.0 20.0
锤子(smartisan) 坚果R2 10月 "'浅黑色 8GB+128GB', '浅黑色 8GB+256GB', '松绿色 8GB+256GB', '松绿色 12GB+256GB'" 6.67英寸 CPU型号:骁龙865
利用MapReduce中的setup方法与DistributedCache
-
setup()
此方法被MapReduce框架仅且执行一次,在执行Map任务前,进行相关变量或者资源的集中初始化工作。若是将资源初始化工作放在方法map()中,导致Mapper任务在解析每一行输入时都会进行资源初始化工作,导致重复,程序运行效率不高!
-
DistributedCache(分布式缓存)
DistributedCache有效地分发特定于应用程序的大型只读文件。DistributedCache是MapReduce框架提供的一种工具,用于缓存应用程序所需的文件(文本,档案,jars等)。
Notice:使用分布式缓存需要事先将小表存放入hdfs中
Main(主类)
package Clean_TopN_s;
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;
import java.net.URI;
import java.net.URISyntaxException;
public class TopNMain {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException, URISyntaxException {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
// 添加小表在hdfs的路径
job.addCacheFile(new URI("hdfs://localhost:9090/test/part-r-00000"));
job.setJarByClass(TopNMain.class);
job.setMapperClass(TopNMapper.class);
job.setReducerClass(TopNReducer.class);
job.setPartitionerClass(TopNPartitioner.class);
job.setGroupingComparatorClass(TopNGroupPartitioner.class);
job.setMapOutputKeyClass(TopNBean.class);
job.setMapOutputValueClass(Text.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(NullWritable.class);
Path in = new Path("file:///H:\\newData\\test2.txt");
Path out = new Path("file:///H:\\newData\\map_join_out");
FileInputFormat.addInputPath(job, in);
FileOutputFormat.setOutputPath(job, out);
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
Map(含改进前与改进后对比)
package Clean_TopN_s;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.HashMap;
public class TopNMapper extends Mapper<LongWritable, Text, TopNBean,Text> {
private HashMap<String,String> map = new HashMap<>();
@Override
protected void setup(Context context) throws IOException, InterruptedException {
// 第一件事:将分布式缓存中的小表数据读取到本地map集合中
// 1:获取分布式缓存文件列表
URI[] cacheFiles = context.getCacheFiles();
// 2:获取指定的分布式缓存文件的文件系统(FileSystem)
FileSystem fileSystem = FileSystem.get(cacheFiles[0], context.getConfiguration());
// 3:获取文件的输入流
FSDataInputStream inputStream = fileSystem.open(new Path(cacheFiles[0]));
// 4:读取文件内容,并将数据存入Map集合
//4.1 将字节输入流转为字符缓冲流FSDataInputStream----->BufferedReader
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
//4.2 读取小表文件内容,以行为单位,并将读取的数据存入map集合
String line = null;
while((line = bufferedReader.readLine()) != null){
map.put(line,line);
}
// 5:关闭流
bufferedReader.close();
fileSystem.close();
}
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
/**
* 半自动,需要手动填写Top3品牌
*/
/**
// 拆分文本数据,得到城市和房价
String [] split = value.toString().split("\t");
if (split[0].equals("Apple")||split[0].equals("华为(HUAWEI)")||split[0].equals("飞利浦(PHILIPS)")){
// 封装topNBean 得到K2
TopNBean topNBean = new TopNBean();
// topNBean.setH_city(split[0]);
// topNBean.setH_price(Integer.parseInt(split[7]));
topNBean.setH_city(split[0]);
topNBean.setH_price(Double.parseDouble(split[10]));
// 将K2,V2写入上下文
context.write(topNBean,value);
}else {
return;
}
**/
/**
* 改进后,不需要手动填写品牌
*/
String[] split = value.toString().split("\t");
String brandname = split[0]; // K2
String brandLine = map.get(brandname);
if (brandLine != null) {
TopNBean topNBean = new TopNBean();
topNBean.setH_city(split[0]);
topNBean.setH_price(Double.parseDouble(split[10]));
context.write(topNBean, new Text(value));
}
}
}
Partitioner(自定义分组)
package Clean_TopN_s;
import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator;
// 1:继承WriteableComparator
public class TopNGroupPartitioner extends WritableComparator {
// 2:调用父类的有参构造
public TopNGroupPartitioner() {
super(TopNBean.class,true);
}
// 3:指定分组的规则(重写方法)
@Override
public int compare(WritableComparable a, WritableComparable b) {
// 3.1 对形参做强制类型转换
TopNBean frist = (TopNBean)a;
TopNBean second = (TopNBean)b;
// 3.2 指定分组规则
return frist.getH_city().compareTo(second.getH_city());
}
}
Bean(实现组内排序)
package Clean_TopN_s;
import org.apache.hadoop.io.WritableComparable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
public class TopNBean implements WritableComparable<TopNBean> {
private String h_city;
private Double h_price;
public String getH_city() {
return h_city;
}
public void setH_city(String h_city) {
this.h_city = h_city;
}
public Double getH_price() {
return h_price;
}
public void setH_price(Double h_price) {
this.h_price = h_price;
}
@Override
public String toString() {
return h_city + '\t' +
h_price ;
}
@Override
public int compareTo(TopNBean topNBean) {
int i = this.h_city.compareTo(topNBean.h_city);
if(i == 0){
i = this.h_price.compareTo(topNBean.h_price) * -1;
}
return i;
}
@Override
public void write(DataOutput dataOutput) throws IOException {
dataOutput.writeUTF(h_city);
dataOutput.writeDouble(h_price);
}
@Override
public void readFields(DataInput dataInput) throws IOException {
this.h_city = dataInput.readUTF();
this.h_price = dataInput.readDouble();
}
}
Reduce(取Top3)
package Clean_TopN_s;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
public class TopNReducer extends Reducer<TopNBean, Text,Text, NullWritable> {
@Override
protected void reduce(TopNBean key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
int i = 0;
for (Text value : values) {
context.write(value, NullWritable.get());
i++;
if (i >= 3){
break;
}
}
}
}