Hadoop的Map侧join

写了关于Hadoop的Map侧join 
和Reduce的join,今天我们就来在看另外一种比较中立的Join。 

SemiJoin,一般称为半链接,其原理是在Map侧过滤掉了一些不需要join的数据,从而大大减少了reduce的shffule时间,因为我们知道,如果仅仅使用Reduce侧连接,那么如果一份数据中,存在大量的无效数据,而这些数据,在join中,并不需要,但是因为没有做过预处理,所以这些数据,直到真正的执行reduce函数时,才被定义为无效数据,而这时候,前面已经执行过shuffle和merge和sort,所以这部分无效的数据,就浪费了大量的网络IO和磁盘IO,所以在整体来讲,这是一种降低性能的表现,如果存在的无效数据越多,那么这种趋势,就越明显。 

之所以会出现半连接,这其实也是reduce侧连接的一个变种,只不过我们在Map侧,过滤掉了一些无效的数据,所以减少了reduce过程的shuffle时间,所以能获取一个性能的提升。 

具体的原理也是利用DistributedCache将小表的的分发到各个节点上,在Map过程的setup函数里,读取缓存里面的文件,只将小表的链接键存储在hashset里,在map函数执行时,对每一条数据,进行判断,如果这条数据的链接键为空或者在hashset里面不存在,那么则认为这条数据,是无效的数据,所以这条数据,并不会被partition分区后写入磁盘,参与reduce阶段的shuffle和sort,所以在一定程序上,提升了join性能。需要注意的是如果 
小表的key依然非常巨大,可能会导致我们的程序出现OOM的情况,那么这时候我们就需要考虑其他的链接方式了。 

测试数据如下: 
模拟小表数据: 
1,三劫散仙,13575468248 
2,凤舞九天,18965235874 
3,忙忙碌碌,15986854789 
4,少林寺方丈,15698745862 


模拟大表数据: 
3,A,99,2013-03-05 
1,B,89,2013-02-05 
2,C,69,2013-03-09 
3,D,56,2013-06-07 
5,E,100,2013-09-09 
6,H,200,2014-01-10 

代码如下: 

Java代码 【下载地址】    复制代码  收藏代码
  1. package com.semijoin;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.DataInput;  
  5. import java.io.DataOutput;  
  6. import java.io.FileReader;  
  7. import java.io.IOException;  
  8. import java.net.URI;  
  9. import java.util.ArrayList;  
  10. import java.util.HashSet;  
  11. import java.util.List;  
  12.   
  13. import org.apache.hadoop.conf.Configuration;  
  14. import org.apache.hadoop.filecache.DistributedCache;  
  15. import org.apache.hadoop.fs.FileSystem;  
  16. import org.apache.hadoop.fs.Path;  
  17. import org.apache.hadoop.io.LongWritable;  
  18. import org.apache.hadoop.io.Text;  
  19. import org.apache.hadoop.io.WritableComparable;  
  20.   
  21. import org.apache.hadoop.mapred.JobConf;  
  22. import org.apache.hadoop.mapreduce.Job;  
  23. import org.apache.hadoop.mapreduce.Mapper;  
  24. import org.apache.hadoop.mapreduce.Reducer;  
  25. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  26. import org.apache.hadoop.mapreduce.lib.input.FileSplit;  
  27. import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;  
  28. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  29. import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;  
  30.   
  31. /*** 
  32.  *  
  33.  * Hadoop1.2的版本 
  34.  *  
  35.  * hadoop的半链接 
  36.  *  
  37.  * SemiJoin实现 
  38.  *  
  39.  * @author qindongliang 
  40.  *  
  41.  *    大数据交流群:376932160 
  42.  *  搜索技术交流群:324714439 
  43.  *  
  44.  *  
  45.  *  
  46.  * **/  
  47. public class Semjoin {  
  48.       
  49.       
  50.       
  51.     /** 
  52.      *  
  53.      *  
  54.      * 自定义一个输出实体 
  55.      *  
  56.      * **/  
  57.     private static class CombineEntity implements WritableComparable<CombineEntity>{  
  58.   
  59.           
  60.         private Text joinKey;//连接key  
  61.         private Text flag;//文件来源标志  
  62.         private Text secondPart;//除了键外的其他部分的数据  
  63.           
  64.           
  65.         public CombineEntity() {  
  66.             // TODO Auto-generated constructor stub  
  67.             this.joinKey=new Text();  
  68.             this.flag=new Text();  
  69.             this.secondPart=new Text();  
  70.         }  
  71.           
  72.         public Text getJoinKey() {  
  73.             return joinKey;  
  74.         }  
  75.   
  76.         public void setJoinKey(Text joinKey) {  
  77.             this.joinKey = joinKey;  
  78.         }  
  79.   
  80.         public Text getFlag() {  
  81.             return flag;  
  82.         }  
  83.   
  84.         public void setFlag(Text flag) {  
  85.             this.flag = flag;  
  86.         }  
  87.   
  88.         public Text getSecondPart() {  
  89.             return secondPart;  
  90.         }  
  91.   
  92.         public void setSecondPart(Text secondPart) {  
  93.             this.secondPart = secondPart;  
  94.         }  
  95.   
  96.         @Override  
  97.         public void readFields(DataInput in) throws IOException {  
  98.             this.joinKey.readFields(in);  
  99.             this.flag.readFields(in);  
  100.             this.secondPart.readFields(in);  
  101.               
  102.         }  
  103.   
  104.         @Override  
  105.         public void write(DataOutput out) throws IOException {  
  106.             this.joinKey.write(out);  
  107.             this.flag.write(out);  
  108.             this.secondPart.write(out);  
  109.               
  110.         }  
  111.   
  112.         @Override  
  113.         public int compareTo(CombineEntity o) {  
  114.             // TODO Auto-generated method stub  
  115.             return this.joinKey.compareTo(o.joinKey);  
  116.         }  
  117.           
  118.           
  119.           
  120.     }  
  121.       
  122.       
  123.       
  124.       
  125.     private static class JMapper extends Mapper<LongWritable, Text, Text, CombineEntity>{  
  126.           
  127.         private CombineEntity combine=new CombineEntity();  
  128.         private Text flag=new Text();  
  129.         private  Text joinKey=new Text();  
  130.         private Text secondPart=new Text();  
  131.         /** 
  132.          * 存储小表的key 
  133.          *  
  134.          *  
  135.          * */  
  136.         private HashSet<String> joinKeySet=new HashSet<String>();  
  137.           
  138.           
  139.         @Override  
  140.         protected void setup(Context context)throws IOException, InterruptedException {  
  141.            
  142.             //读取文件流  
  143.             BufferedReader br=null;  
  144.             String temp;  
  145.             // 获取DistributedCached里面 的共享文件  
  146.             Path path[]=DistributedCache.getLocalCacheFiles(context.getConfiguration());  
  147.               
  148.             for(Path p:path){  
  149.                   
  150.                 if(p.getName().endsWith("a.txt")){  
  151.                     br=new BufferedReader(new FileReader(p.toString()));  
  152.                     //List<String> list=Files.readAllLines(Paths.get(p.getName()), Charset.forName("UTF-8"));  
  153.                       
  154.                     while((temp=br.readLine())!=null){  
  155.                         String ss[]=temp.split(",");  
  156.                         //map.put(ss[0], ss[1]+"\t"+ss[2]);//放入hash表中  
  157.                         joinKeySet.add(ss[0]);//加入小表的key  
  158.                     }  
  159.                 }  
  160.             }  
  161.               
  162.               
  163.         }  
  164.           
  165.           
  166.           
  167.         @Override  
  168.         protected void map(LongWritable key, Text value,Context context)  
  169.                 throws IOException, InterruptedException {  
  170.               
  171.           
  172.                //获得文件输入路径  
  173.             String pathName = ((FileSplit) context.getInputSplit()).getPath().toString();  
  174.           
  175.             if(pathName.endsWith("a.txt")){  
  176.                   
  177.                 String  valueItems[]=value.toString().split(",");  
  178.                   
  179.                   
  180.                 /** 
  181.                  * 在这里过滤必须要的连接字符 
  182.                  *  
  183.                  * */  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值