MapReduce之Join操作(3)

本文介绍了一种在Hadoop MapReduce中实现高效Join操作的方法,即利用DistributedCache机制将小表缓存在内存中,并在Map阶段完成Join,有效减少网络传输开销。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文链接:http://bjyjtdj.iteye.com/blog/1454803   

 本文讲述如何在map端完成join操作。之前我们提到了reduce-join,这种方法的灵活性不错,也是理所当然地能够想到的方法;但这种方法存在的一个最大的问题是性能。大量的中间数据需要从map节点通过网络发送到reduce节点,因而效率比较低。实际上,两表的join操作中很多都是无用的数据。现在考虑可能的一种场景,其中一个表非常小,以致于可以直接存放在内存中,那么我们可以利用Hadoop提供的DistributedCache机制,将较小的表加入到其中,在每个map节点都能够访问到该表,最终实现在map阶段完成join操作。这里提一下DistributedCache,可以直观上将它看作是一个全局的只读空间,存储一些需要共享的数据;具体可以参看Hadoop相关资料,这里不进行深入讨论。

     实现的源码如下,原理非常简单明了:     

Java代码   收藏代码
  1. import java.io.BufferedReader;  
  2. import java.io.FileReader;  
  3. import java.io.IOException;  
  4. import java.util.Hashtable;  
  5.   
  6. import org.apache.hadoop.conf.Configuration;  
  7. import org.apache.hadoop.conf.Configured;  
  8. import org.apache.hadoop.filecache.DistributedCache;  
  9. import org.apache.hadoop.fs.Path;  
  10. import org.apache.hadoop.io.Text;  
  11. import org.apache.hadoop.mapred.FileInputFormat;  
  12. import org.apache.hadoop.mapred.FileOutputFormat;  
  13. import org.apache.hadoop.mapred.JobClient;  
  14. import org.apache.hadoop.mapred.JobConf;  
  15. import org.apache.hadoop.mapred.KeyValueTextInputFormat;  
  16. import org.apache.hadoop.mapred.MapReduceBase;  
  17. import org.apache.hadoop.mapred.Mapper;  
  18. import org.apache.hadoop.mapred.OutputCollector;  
  19. import org.apache.hadoop.mapred.Reporter;  
  20. import org.apache.hadoop.mapred.TextOutputFormat;  
  21. import org.apache.hadoop.util.Tool;  
  22. import org.apache.hadoop.util.ToolRunner;  
  23.   
  24. @SuppressWarnings("deprecation")  
  25. public class DataJoinDC extends Configured implements Tool{  
  26.   
  27.     private final static String inputa = "hdfs://m100:9000/joinTest/Customers";  
  28.     private final static String inputb = "hdfs://m100:9000/joinTest/Orders";  
  29.     private final static String output = "hdfs://m100:9000/joinTest/output";  
  30.       
  31.     public static class MapClass extends MapReduceBase  
  32.                               implements Mapper<Text, Text, Text, Text> {  
  33.         private Hashtable<String, String> joinData = new Hashtable<String, String>();  
  34.         @Override  
  35.         public void configure(JobConf conf) {  
  36.             try {  
  37.                 Path [] cacheFiles = DistributedCache.getLocalCacheFiles(conf);  
  38.                 if (cacheFiles != null && cacheFiles.length > 0) {  
  39.                     String line;  
  40.                     String[] tokens;  
  41.                     BufferedReader joinReader = new BufferedReader(  
  42.                                             new FileReader(cacheFiles[0].toString()));  
  43.                     try {  
  44.                         while ((line = joinReader.readLine()) != null) {  
  45.                             tokens = line.split(","2);  
  46.                             joinData.put(tokens[0], tokens[1]);  
  47.                         }  
  48.                     }finally {  
  49.                         joinReader.close();  
  50.                     }}} catch (IOException e) {  
  51.                         System.err.println("Exception reading DistributedCache: " + e);  
  52.                     }  
  53.                 }  
  54.         public void map(Text key, Text value,OutputCollector<Text, Text> output,  
  55.                 Reporter reporter) throws IOException {  
  56.         //  for(String t: joinData.keySet()){  
  57.         //      output.collect(new Text(t), new Text(joinData.get(t)));  
  58.         //  }  
  59.             String joinValue = joinData.get(key.toString());  
  60.             if (joinValue != null) {  
  61.                 output.collect(key,new Text(value.toString() + "," + joinValue));  
  62.             }  
  63.         }  
  64.     }  
  65.       
  66.     @Override  
  67.     public int run(String[] args) throws Exception {  
  68.         Configuration conf = getConf();  
  69.         DistributedCache.addCacheFile(new Path(inputa).toUri(), conf);  
  70.         JobConf job = new JobConf(conf, DataJoinDC.class);    
  71.         Path in = new Path(inputb);  
  72.         Path out = new Path(output);  
  73.         FileInputFormat.setInputPaths(job, in);  
  74.         FileOutputFormat.setOutputPath(job, out);  
  75.         job.setJobName("DataJoin with DistributedCache");  
  76.         job.setMapperClass(MapClass.class);  
  77.         job.setNumReduceTasks(0);  
  78.         job.setInputFormat(KeyValueTextInputFormat.class);  
  79.         job.setOutputFormat(TextOutputFormat.class);  
  80.         job.set("key.value.separator.in.input.line"",");  
  81.         JobClient.runJob(job);  
  82.         return 0;  
  83.     }  
  84.       
  85.     public static void main(String[] args) throws Exception{  
  86.         int res = ToolRunner.run(new Configuration(), new DataJoinDC(), args);  
  87.         System.exit(res);  
  88.     }  
  89.   
  90. }  
  91.    

  以上参照《Hadoop in Action》 所附代码,我这里是将Customers表作为较小的表,传入DistributedCache。

  这里需要注意的地方

Java代码   收藏代码
  1. DistributedCache.addCacheFile(new Path(inputa).toUri(), conf);  

  这句一定要放在job初始化之前,否则在map中读取不到文件。因为job初始化时将传入Configuration对象拷贝了一份给了JobContext!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值