map端join实现

package cn.smart.bigdata.mr.mapsidejoin;


import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;


import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;


public class MapSideJoin {


	
	
	static class MapsideJoinMapper extends Mapper<LongWritable, Text, Text, NullWritable>{
		
		Map<String, String> pdInfoMap = new HashMap<>();
		
		Text k = new Text();
		
		@Override
		protected void setup(Mapper<LongWritable, Text, Text, NullWritable>.Context context)
				throws IOException, InterruptedException {


			BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("/D:/data/mapjoincache/pdts.txt")));			
			String line;
			while(StringUtils.isNotBlank(line=br.readLine())){
				String[] fields = line.split(",");
				
				pdInfoMap.put(fields[0], fields[1]);
			}
			br.close();
		}
		
		@Override
		protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, NullWritable>.Context context)
				throws IOException, InterruptedException {


			String orderLine = value.toString();
			String[] fields = orderLine.split("\t");
			String pdName = pdInfoMap.get(fields[1]);
			k.set(orderLine + "\t" + pdName);
			context.write(k, NullWritable.get());
		}
		
	}
	
	public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		Job job = Job.getInstance(conf);
		job.setJarByClass(MapSideJoin.class);
		job.setMapperClass(MapsideJoinMapper.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(NullWritable.class);
		FileInputFormat.setInputPaths(job, new Path("D:/data/mapjoininput"));
		FileOutputFormat.setOutputPath(job, new Path("D:/data/mapjoinoutput"));
		
		job.addCacheFile(new URI("file:/D:/data/mapjoincache/pdts.txt"));
		job.setNumReduceTasks(0);
		
		boolean res = job.waitForCompletion(true);
		System.exit(res?1:0);
		
		
	}
}

 

pdts.txt

pd001,apple
pd002,banana

pd003,orange

 

order.txt

1001 pd001 300
1001 pd002 20
1002 pd003 40
1003 pd002 50

### mapjoin介绍 mapjoin会把小表全部加载到内存中,在map阶段直接拿另外一个表的数据和内存中表数据做匹配,由于在map进行了join操作,省去了reduce运行的时间,是Hive中的一种优化方式。在SparkSQL中,目前还不支持自动或者手动使用MapJoin,不过可以将小表进行cache,然后再和大表做join,SparkSQL中cache的作用是将小表数据广播到每一个Worker的内存中,和加载到DistributeCache中的原理相同。这里的内存指的是executor,每个executor保存一份小表副本,再由executor下的task进行拉取,基本就是广播变量的原理。mapjoin适用于在join的表比较小的情况,如字典表与其他表join时,使用mapjoin可避免数据严重倾斜问题 [^2][^4]。 ### 在优化SparkSQL代码性能中的应用 在SparkSQL中,对于表之间的join操作,通常有map join和reduce join两种情况。reduce会按map输出的key的分布处理相应的数据,在数据倾斜的情况下会造成单个task压力过大,拖累整个job时间,甚至出现OOM等问题。而如果能在map完成join,就会极大地减小reduce的压力,提升并行度 [^1]。 对于使用HiveContext(Spark on Hive)的情况,实现map join的方式是将小表进行cache,然后再做查询。原来的SQL不需要修改,只需要对小表执行 `CACHE TABLE xx as select * from xx`。以一个大表和一个字典表的join为例,优化前join在reduce,数据倾斜严重,优化后执行计划变成一个stage,实际运行时间明显提升 [^1]。 另外,也可以在SQL语句中使用特定的提示来实现mapjoin优化,例如: ```sql select /*+ mapjoin(bb)*/ aa.*, sum(bb.work_date) as '工作日' from aa cross join work_date_dim bb on bb.begin_tm >= aa.任务开始时间 and bb.end_tm < aa.任务结束时间 group by ... ``` 这种方式适用于笛卡尔积(cross join)的优化 [^3]。 ### 对计算页面贡献量代码性能优化的可能应用 如果在计算页面贡献量的代码中涉及到表的join操作,且存在小表和大表的情况,就可以使用mapjoin进行优化。例如,页面数据是大表,而页面类型的字典表是小表,在关联这两个表计算页面贡献量时,将字典表进行cache后再和页面数据进行join操作,可减少数据倾斜,提升性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值