hadoop MapReduce 三种连接

本文介绍MapReduce中的三种连接策略:重分区连接、复制连接及半连接。这些策略针对排序-合并架构进行了优化,适用于不同规模的数据集连接场景。

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

为了实现内连接和外连接,MapReduce中有三种连接策略,如下所示。这三种连接策略有的在map阶段,有的在reduce阶段。它们都针对MapReduce的排序-合并(sort-merge)的架构进行了优化。
  1. 重分区连接(Repartition join)——reduce端连接。使用场景:连接两个或多个大型数据集。
  2. 复制连接(Replication join)——map端连接。使用场景:待连接的数据集中有一个数据集小到可以完全放在缓存中。
  3. 半连接(Semi-join)——另一个map端连接。使用场景:待连接的数据集中有一个数据集非常大,但同时这个数据集可以被过滤成小到可以放在内存中。
数据模型:
tb_dim_city.dat
[plain]  view plain copy
  1. 0|其他|9999|9999|0  
  2. 1|长春|1|901|1  
  3. 2|吉林|2|902|1  
  4. 3|四平|3|903|1  
  5. 4|松原|4|904|1  
  6. 5|通化|5|905|1  
  7. 6|辽源|6|906|1  
  8. 7|白城|7|907|1  
  9. 8|白山|8|908|1  

tb_user_profiles.dat
[plain]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. 1|2G|123|1  
  2. 2|3G|333|2  
  3. 3|3G|555|1  
  4. 4|2G|777|3  
  5. 5|3G|666|4  



reduce端连接:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.mr.reduceSideJoin;  
  2.   
  3. import java.io.DataInput;  
  4. import java.io.DataOutput;  
  5. import java.io.IOException;  
  6.   
  7. import org.apache.hadoop.io.Text;  
  8. import org.apache.hadoop.io.WritableComparable;  
  9.   
  10. public class CombineValues implements WritableComparable<CombineValues> {  
  11.     private Text joinKey;// 链接关键字  
  12.     private Text flag;// 文件来源标志  
  13.     private Text secondPart;// 除了链接键外的其他部分  
  14.   
  15.     public void setJoinKey(Text joinKey) {  
  16.         this.joinKey = joinKey;  
  17.     }  
  18.   
  19.     public void setFlag(Text flag) {  
  20.         this.flag = flag;  
  21.     }  
  22.   
  23.     public void setSecondPart(Text secondPart) {  
  24.         this.secondPart = secondPart;  
  25.     }  
  26.   
  27.     public Text getFlag() {  
  28.         return flag;  
  29.     }  
  30.   
  31.     public Text getSecondPart() {  
  32.         return secondPart;  
  33.     }  
  34.   
  35.     public Text getJoinKey() {  
  36.         return joinKey;  
  37.     }  
  38.   
  39.     public CombineValues() {  
  40.         this.joinKey = new Text();  
  41.         this.flag = new Text();  
  42.         this.secondPart = new Text();  
  43.     }  
  44.   
  45.     @Override  
  46.     public void write(DataOutput out) throws IOException {  
  47.         this.joinKey.write(out);  
  48.         this.flag.write(out);  
  49.         this.secondPart.write(out);  
  50.     }  
  51.   
  52.     @Override  
  53.     public void readFields(DataInput in) throws IOException {  
  54.         this.joinKey.readFields(in);  
  55.         this.flag.readFields(in);  
  56.         this.secondPart.readFields(in);  
  57.     }  
  58.   
  59.     @Override  
  60.     public int compareTo(CombineValues o) {  
  61.         return this.joinKey.compareTo(o.getJoinKey());  
  62.     }  
  63.   
  64.     @Override  
  65.     public String toString() {  
  66.         // TODO Auto-generated method stub  
  67.         return "[flag=" + this.flag.toString() + ",joinKey="  
  68.                 + this.joinKey.toString() + ",secondPart="  
  69.                 + this.secondPart.toString() + "]";  
  70.     }  
  71. }  

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.mr.reduceSideJoin;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.ArrayList;  
  5.   
  6. import org.apache.hadoop.conf.Configuration;  
  7. import org.apache.hadoop.conf.Configured;  
  8. import org.apache.hadoop.fs.Path;  
  9. import org.apache.hadoop.io.Text;  
  10. import org.apache.hadoop.mapreduce.Job;  
  11. import org.apache.hadoop.mapreduce.Mapper;  
  12. import org.apache.hadoop.mapreduce.Reducer;  
  13. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  14. import org.apache.hadoop.mapreduce.lib.input.FileSplit;  
  15. import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;  
  16. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  17. import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;  
  18. import org.apache.hadoop.util.Tool;  
  19. import org.apache.hadoop.util.ToolRunner;  
  20. import org.slf4j.Logger;  
  21. import org.slf4j.LoggerFactory;  
  22.   
  23. public class ReduceSideJoin_LeftOuterJoin extends Configured implements Tool {  
  24.     private static final Logger logger = LoggerFactory  
  25.             .getLogger(ReduceSideJoin_LeftOuterJoin.class);  
  26.   
  27.     public static class LeftOutJoinMapper extends  
  28.             Mapper<Object, Text, Text, CombineValues> {  
  29.         private CombineValues combineValues = new CombineValues();  
  30.         private Text flag = new Text();  
  31.         private Text joinKey = new Text();  
  32.         private Text secondPart = new Text();  
  33.   
  34.         @Override  
  35.         protected void map(Object key, Text value, Context context)  
  36.                 throws IOException, InterruptedException {  
  37.             // 获得文件输入路径  
  38.             String pathName = ((FileSplit) context.getInputSplit()).getPath()  
  39.                     .toString();  
  40.             // 数据来自tb_dim_city.dat文件,标志即为"0"  
  41.             if (pathName.endsWith("tb_dim_city.dat")) {  
  42.                 String[] valueItems = value.toString().split("\\|");  
  43.                 // 过滤格式错误的记录  
  44.                 if (valueItems.length != 5) {  
  45.                     return;  
  46.                 }  
  47.                 flag.set("0");  
  48.                 joinKey.set(valueItems[0]);  
  49.                 secondPart.set(valueItems[1] + "\t" + valueItems[2] + "\t"  
  50.                         + valueItems[3] + "\t" + valueItems[4]);  
  51.                 combineValues.setFlag(flag);  
  52.                 combineValues.setJoinKey(joinKey);  
  53.                 combineValues.setSecondPart(secondPart);  
  54.                 context.write(combineValues.getJoinKey(), combineValues);  
  55.   
  56.             }// 数据来自于tb_user_profiles.dat,标志即为"1"  
  57.             else if (pathName.endsWith("tb_user_profiles.dat")) {  
  58.                 String[] valueItems = value.toString().split("\\|");  
  59.                 // 过滤格式错误的记录  
  60.                 if (valueItems.length != 4) {  
  61.                     return;  
  62.                 }  
  63.                 flag.set("1");  
  64.                 joinKey.set(valueItems[3]);  
  65.                 secondPart.set(valueItems[0] + "\t" + valueItems[1] + "\t"  
  66.                         + valueItems[2]);  
  67.                 combineValues.setFlag(flag);  
  68.                 combineValues.setJoinKey(joinKey);  
  69.                 combineValues.setSecondPart(secondPart);  
  70.                 context.write(combineValues.getJoinKey(), combineValues);  
  71.             }  
  72.         }  
  73.     }  
  74.   
  75.     public static class LeftOutJoinReducer extends  
  76.             Reducer<Text, CombineValues, Text, Text> {  
  77.         // 存储一个分组中的左表信息  
  78.         private ArrayList<Text> leftTable = new ArrayList<Text>();  
  79.         // 存储一个分组中的右表信息  
  80.         private ArrayList<Text> rightTable = new ArrayList<Text>();  
  81.         private Text secondPar = null;  
  82.         private Text output = new Text();  
  83.   
  84.         /** 
  85.          * 一个分组调用一次reduce函数;相同key的数据进了同一个reduce,这样就实现了join。 
  86.          */  
  87.         @Override  
  88.         protected void reduce(Text key, Iterable<CombineValues> value,  
  89.                 Context context) throws IOException, InterruptedException {  
  90.             leftTable.clear();  
  91.             rightTable.clear();  
  92.             /** 
  93.              * 将分组中的元素按照文件分别进行存放 这种方法要注意的问题: 如果一个分组内的元素太多的话,可能会导致在reduce阶段出现OOM, 
  94.              * 在处理分布式问题之前最好先了解数据的分布情况,根据不同的分布采取最 
  95.              * 适当的处理方法,这样可以有效的防止导致OOM和数据过度倾斜问题。 
  96.              */  
  97.             for (CombineValues cv : value) {  
  98.                 secondPar = new Text(cv.getSecondPart().toString());  
  99.                 // 左表tb_dim_city  
  100.                 if ("0".equals(cv.getFlag().toString().trim())) {  
  101.                     leftTable.add(secondPar);  
  102.                 }  
  103.                 // 右表tb_user_profiles  
  104.                 else if ("1".equals(cv.getFlag().toString().trim())) {  
  105.                     rightTable.add(secondPar);  
  106.                 }  
  107.             }  
  108.             logger.info("tb_dim_city:" + leftTable.toString());  
  109.             logger.info("tb_user_profiles:" + rightTable.toString());  
  110.             // 这里体现了左连接  
  111.             for (Text leftPart : leftTable) {  
  112.                 for (Text rightPart : rightTable) {  
  113.                     output.set(leftPart + "\t" + rightPart);  
  114.                     // leftTable中有数据 rightTable中没有数据 就无法进到这一步  
  115.                     // rightTable中有数据 leftTable中没有数据 外面的循环就进不去  
  116.                     context.write(key, output);  
  117.                 }  
  118.             }  
  119.         }  
  120.     }  
  121.   
  122.     @Override  
  123.     public int run(String[] args) throws Exception {  
  124.         Configuration conf = getConf(); // 获得配置文件对象  
  125.         Job job = new Job(conf, "LeftOutJoinMR");  
  126.         job.setJarByClass(ReduceSideJoin_LeftOuterJoin.class);  
  127.   
  128.         FileInputFormat.addInputPath(job, new Path(args[0])); // 设置map输入文件路径  
  129.         FileOutputFormat.setOutputPath(job, new Path(args[1])); // 设置reduce输出文件路径  
  130.   
  131.         job.setMapperClass(LeftOutJoinMapper.class);  
  132.         job.setReducerClass(LeftOutJoinReducer.class);  
  133.   
  134.         job.setInputFormatClass(TextInputFormat.class); // 设置文件输入格式  
  135.         job.setOutputFormatClass(TextOutputFormat.class);// 使用默认的output格式  
  136.   
  137.         // 设置map的输出key和value类型  
  138.         job.setMapOutputKeyClass(Text.class);  
  139.         job.setMapOutputValueClass(CombineValues.class);  
  140.   
  141.         // 设置reduce的输出key和value类型  
  142.         job.setOutputKeyClass(Text.class);  
  143.         job.setOutputValueClass(Text.class);  
  144.         job.waitForCompletion(true);  
  145.         return job.isSuccessful() ? 0 : 1;  
  146.     }  
  147.   
  148.     public static void main(String[] args) throws IOException,  
  149.             ClassNotFoundException, InterruptedException {  
  150.         try {  
  151.             Tool rdf = new ReduceSideJoin_LeftOuterJoin();  
  152.             int returnCode = ToolRunner.run(rdf, args);  
  153.             System.exit(returnCode);  
  154.         } catch (Exception e) {  
  155.             System.out.println(e.getMessage());  
  156.         }  
  157.     }  
  158. }  

Map端的连接
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.mr.mapSideJoin;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.FileReader;  
  5. import java.io.IOException;  
  6. import java.util.HashMap;  
  7.   
  8. import org.apache.hadoop.conf.Configuration;  
  9. import org.apache.hadoop.conf.Configured;  
  10. import org.apache.hadoop.fs.Path;  
  11. import org.apache.hadoop.io.Text;  
  12. import org.apache.hadoop.mapreduce.Job;  
  13. import org.apache.hadoop.mapreduce.Mapper;  
  14. import org.apache.hadoop.mapreduce.filecache.DistributedCache;  
  15. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  16. import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;  
  17. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  18. import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;  
  19. import org.apache.hadoop.util.Tool;  
  20. import org.apache.hadoop.util.ToolRunner;  
  21. import org.slf4j.Logger;  
  22. import org.slf4j.LoggerFactory;  
  23.   
  24. public class MapSideJoinMain extends Configured implements Tool {  
  25.     private static final Logger logger = LoggerFactory  
  26.             .getLogger(MapSideJoinMain.class);  
  27.   
  28.     public static class LeftOutJoinMapper extends  
  29.             Mapper<Object, Text, Text, Text> {  
  30.   
  31.         private HashMap<String, String> city_info = new HashMap<String, String>();  
  32.         private Text outPutKey = new Text();  
  33.         private Text outPutValue = new Text();  
  34.         private String mapInputStr = null;  
  35.         private String mapInputSpit[] = null;  
  36.         private String city_secondPart = null;  
  37.   
  38.         /** 
  39.          * 此方法在每个task开始之前执行,这里主要用作从DistributedCache 
  40.          * 中取到tb_dim_city文件,并将里边记录取出放到内存中。 
  41.          */  
  42.         @Override  
  43.         protected void setup(Context context) throws IOException,  
  44.                 InterruptedException {  
  45.             BufferedReader br = null;  
  46.             // 获得当前作业的DistributedCache相关文件  
  47.             Path[] distributePaths = DistributedCache  
  48.                     .getLocalCacheFiles(context.getConfiguration());  
  49.             String cityInfo = null;  
  50.             for (Path p : distributePaths) {  
  51.                 if (p.toString().endsWith("tb_dim_city.dat")) {  
  52.                     // 读缓存文件,并放到mem中  
  53.                     br = new BufferedReader(new FileReader(p.toString()));  
  54.                     while (null != (cityInfo = br.readLine())) {  
  55.                         String[] cityPart = cityInfo.split("\\|"5);  
  56.                         if (cityPart.length == 5) {  
  57.                             city_info.put(cityPart[0], cityPart[1] + "\t"  
  58.                                     + cityPart[2] + "\t" + cityPart[3] + "\t"  
  59.                                     + cityPart[4]);  
  60.                         }  
  61.                     }  
  62.                 }  
  63.             }  
  64.         }  
  65.   
  66.         /** 
  67.          * Map端的实现相当简单,直接判断tb_user_profiles.dat中的 
  68.          * cityID是否存在我的map中就ok了,这样就可以实现Map Join了 
  69.          */  
  70.         @Override  
  71.         protected void map(Object key, Text value, Context context)  
  72.                 throws IOException, InterruptedException {  
  73.             // 排掉空行  
  74.             if (value == null || value.toString().equals("")) {  
  75.                 return;  
  76.             }  
  77.             mapInputStr = value.toString();  
  78.             mapInputSpit = mapInputStr.split("\\|"4);  
  79.             // 过滤非法记录  
  80.             if (mapInputSpit.length != 4) {  
  81.                 return;  
  82.             }  
  83.             // 判断链接字段是否在map中存在  
  84.             city_secondPart = city_info.get(mapInputSpit[3]);  
  85.             if (city_secondPart != null) {  
  86.                 this.outPutKey.set(mapInputSpit[3]);  
  87.                 this.outPutValue.set(city_secondPart + "\t" + mapInputSpit[0]  
  88.                         + "\t" + mapInputSpit[1] + "\t" + mapInputSpit[2]);  
  89.                 context.write(outPutKey, outPutValue);  
  90.             }  
  91.         }  
  92.     }  
  93.   
  94.     @Override  
  95.     public int run(String[] args) throws Exception {  
  96.         Configuration conf = getConf(); // 获得配置文件对象  
  97.         DistributedCache.addCacheFile(new Path(args[0]).toUri(), conf);// 为该job添加缓存文件  
  98.         Job job = new Job(conf, "MapJoinMR");  
  99.         job.setNumReduceTasks(0);  
  100.   
  101.         FileInputFormat.addInputPath(job, new Path(args[0])); // 设置map输入文件路径  
  102.         FileOutputFormat.setOutputPath(job, new Path(args[1])); // 设置reduce输出文件路径  
  103.   
  104.         job.setJarByClass(MapSideJoinMain.class);  
  105.         job.setMapperClass(LeftOutJoinMapper.class);  
  106.   
  107.         job.setInputFormatClass(TextInputFormat.class); // 设置文件输入格式  
  108.         job.setOutputFormatClass(TextOutputFormat.class);// 使用默认的output格式  
  109.   
  110.         // 设置map的输出key和value类型  
  111.         job.setMapOutputKeyClass(Text.class);  
  112.   
  113.         // 设置reduce的输出key和value类型  
  114.         job.setOutputKeyClass(Text.class);  
  115.         job.setOutputValueClass(Text.class);  
  116.         job.waitForCompletion(true);  
  117.         return job.isSuccessful() ? 0 : 1;  
  118.     }  
  119.   
  120.     public static void main(String[] args) throws IOException,  
  121.             ClassNotFoundException, InterruptedException {  
  122.         try {  
  123.             int returnCode = ToolRunner.run(new MapSideJoinMain(), args);  
  124.             System.exit(returnCode);  
  125.         } catch (Exception e) {  
  126.             // TODO Auto-generated catch block  
  127.             logger.error(e.getMessage());  
  128.         }  
  129.     }  
  130. }  

Semi连接
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.mr.SemiJoin;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.FileReader;  
  5. import java.io.IOException;  
  6. import java.util.ArrayList;  
  7. import java.util.HashSet;  
  8.   
  9. import org.apache.hadoop.conf.Configuration;  
  10. import org.apache.hadoop.conf.Configured;  
  11. import org.apache.hadoop.filecache.DistributedCache;  
  12. import org.apache.hadoop.fs.Path;  
  13. import org.apache.hadoop.io.Text;  
  14. import org.apache.hadoop.mapreduce.Job;  
  15. import org.apache.hadoop.mapreduce.Mapper;  
  16. import org.apache.hadoop.mapreduce.Reducer;  
  17. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  18. import org.apache.hadoop.mapreduce.lib.input.FileSplit;  
  19. import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;  
  20. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  21. import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;  
  22. import org.apache.hadoop.util.Tool;  
  23. import org.apache.hadoop.util.ToolRunner;  
  24. import org.slf4j.Logger;  
  25. import org.slf4j.LoggerFactory;  
  26.   
  27. import com.mr.reduceSideJoin.CombineValues;  
  28.   
  29. public class SemiJoin extends Configured implements Tool {  
  30.     private static final Logger logger = LoggerFactory  
  31.             .getLogger(SemiJoin.class);  
  32.   
  33.     public static class SemiJoinMapper extends  
  34.             Mapper<Object, Text, Text, CombineValues> {  
  35.         private CombineValues combineValues = new CombineValues();  
  36.         private HashSet<String> joinKeySet = new HashSet<String>();  
  37.         private Text flag = new Text();  
  38.         private Text joinKey = new Text();  
  39.         private Text secondPart = new Text();  
  40.   
  41.         /** 
  42.          * 将参加join的key从DistributedCache取出放到内存中,以便在map端将要参加join的key过滤出来。b 
  43.          */  
  44.         @Override  
  45.         protected void setup(Context context) throws IOException,  
  46.                 InterruptedException {  
  47.             BufferedReader br = null;  
  48.             // 获得当前作业的DistributedCache相关文件  
  49.             Path[] distributePaths = DistributedCache  
  50.                     .getLocalCacheFiles(context.getConfiguration());  
  51.             String joinKeyStr = null;  
  52.             for (Path p : distributePaths) {  
  53.                 if (p.toString().endsWith("joinKey.dat")) {  
  54.                     // 读缓存文件,并放到mem中  
  55.                     br = new BufferedReader(new FileReader(p.toString()));  
  56.                     while (null != (joinKeyStr = br.readLine())) {  
  57.                         joinKeySet.add(joinKeyStr);  
  58.                     }  
  59.                 }  
  60.             }  
  61.         }  
  62.   
  63.         @Override  
  64.         protected void map(Object key, Text value, Context context)  
  65.                 throws IOException, InterruptedException {  
  66.             // 获得文件输入路径  
  67.             String pathName = ((FileSplit) context.getInputSplit()).getPath()  
  68.                     .toString();  
  69.             // 数据来自tb_dim_city.dat文件,标志即为"0"  
  70.             if (pathName.endsWith("tb_dim_city.dat")) {  
  71.                 String[] valueItems = value.toString().split("\\|");  
  72.                 // 过滤格式错误的记录  
  73.                 if (valueItems.length != 5) {  
  74.                     return;  
  75.                 }  
  76.                 // 过滤掉不需要参加join的记录  
  77.                 if (joinKeySet.contains(valueItems[0])) {  
  78.                     flag.set("0");  
  79.                     joinKey.set(valueItems[0]);  
  80.                     secondPart.set(valueItems[1] + "\t" + valueItems[2] + "\t"  
  81.                             + valueItems[3] + "\t" + valueItems[4]);  
  82.                     combineValues.setFlag(flag);  
  83.                     combineValues.setJoinKey(joinKey);  
  84.                     combineValues.setSecondPart(secondPart);  
  85.                     context.write(combineValues.getJoinKey(), combineValues);  
  86.                 } else {  
  87.                     return;  
  88.                 }  
  89.             }// 数据来自于tb_user_profiles.dat,标志即为"1"  
  90.             else if (pathName.endsWith("tb_user_profiles.dat")) {  
  91.                 String[] valueItems = value.toString().split("\\|");  
  92.                 // 过滤格式错误的记录  
  93.                 if (valueItems.length != 4) {  
  94.                     return;  
  95.                 }  
  96.                 // 过滤掉不需要参加join的记录  
  97.                 if (joinKeySet.contains(valueItems[3])) {  
  98.                     flag.set("1");  
  99.                     joinKey.set(valueItems[3]);  
  100.                     secondPart.set(valueItems[0] + "\t" + valueItems[1] + "\t"  
  101.                             + valueItems[2]);  
  102.                     combineValues.setFlag(flag);  
  103.                     combineValues.setJoinKey(joinKey);  
  104.                     combineValues.setSecondPart(secondPart);  
  105.                     context.write(combineValues.getJoinKey(), combineValues);  
  106.                 } else {  
  107.                     return;  
  108.                 }  
  109.             }  
  110.         }  
  111.     }  
  112.   
  113.     public static class SemiJoinReducer extends  
  114.             Reducer<Text, CombineValues, Text, Text> {  
  115.         // 存储一个分组中的左表信息  
  116.         private ArrayList<Text> leftTable = new ArrayList<Text>();  
  117.         // 存储一个分组中的右表信息  
  118.         private ArrayList<Text> rightTable = new ArrayList<Text>();  
  119.         private Text secondPar = null;  
  120.         private Text output = new Text();  
  121.   
  122.         /** 
  123.          * 一个分组调用一次reduce函数 
  124.          */  
  125.         @Override  
  126.         protected void reduce(Text key, Iterable<CombineValues> value,  
  127.                 Context context) throws IOException, InterruptedException {  
  128.             leftTable.clear();  
  129.             rightTable.clear();  
  130.             /** 
  131.              * 将分组中的元素按照文件分别进行存放 这种方法要注意的问题: 如果一个分组内的元素太多的话,可能会导致在reduce阶段出现OOM, 
  132.              * 在处理分布式问题之前最好先了解数据的分布情况,根据不同的分布采取最 
  133.              * 适当的处理方法,这样可以有效的防止导致OOM和数据过度倾斜问题。 
  134.              */  
  135.             for (CombineValues cv : value) {  
  136.                 secondPar = new Text(cv.getSecondPart().toString());  
  137.                 // 左表tb_dim_city  
  138.                 if ("0".equals(cv.getFlag().toString().trim())) {  
  139.                     leftTable.add(secondPar);  
  140.                 }  
  141.                 // 右表tb_user_profiles  
  142.                 else if ("1".equals(cv.getFlag().toString().trim())) {  
  143.                     rightTable.add(secondPar);  
  144.                 }  
  145.             }  
  146.             logger.info("tb_dim_city:" + leftTable.toString());  
  147.             logger.info("tb_user_profiles:" + rightTable.toString());  
  148.             for (Text leftPart : leftTable) {  
  149.                 for (Text rightPart : rightTable) {  
  150.                     output.set(leftPart + "\t" + rightPart);  
  151.                     context.write(key, output);  
  152.                 }  
  153.             }  
  154.         }  
  155.     }  
  156.   
  157.     @Override  
  158.     public int run(String[] args) throws Exception {  
  159.         Configuration conf = getConf(); // 获得配置文件对象  
  160.         DistributedCache.addCacheFile(new Path(args[2]).toUri(), conf);  
  161.   
  162.         Job job = new Job(conf, "LeftOutJoinMR");  
  163.         job.setJarByClass(SemiJoin.class);  
  164.   
  165.         FileInputFormat.addInputPath(job, new Path(args[0])); // 设置map输入文件路径  
  166.         FileOutputFormat.setOutputPath(job, new Path(args[1])); // 设置reduce输出文件路径  
  167.   
  168.         job.setMapperClass(SemiJoinMapper.class);  
  169.         job.setReducerClass(SemiJoinReducer.class);  
  170.   
  171.         job.setInputFormatClass(TextInputFormat.class); // 设置文件输入格式  
  172.         job.setOutputFormatClass(TextOutputFormat.class);// 使用默认的output格式  
  173.   
  174.         // 设置map的输出key和value类型  
  175.         job.setMapOutputKeyClass(Text.class);  
  176.         job.setMapOutputValueClass(CombineValues.class);  
  177.   
  178.         // 设置reduce的输出key和value类型  
  179.         job.setOutputKeyClass(Text.class);  
  180.         job.setOutputValueClass(Text.class);  
  181.         job.waitForCompletion(true);  
  182.         return job.isSuccessful() ? 0 : 1;  
  183.     }  
  184.   
  185.     public static void main(String[] args) throws IOException,  
  186.             ClassNotFoundException, InterruptedException {  
  187.         try {  
  188.             int returnCode = ToolRunner.run(new SemiJoin(), args);  
  189.             System.exit(returnCode);  
  190.         } catch (Exception e) {  
  191.             logger.error(e.getMessage());  
  192.         }  
  193.     }  
  194. }  

注意事项:
只有reduce连接实例能在eclipse中运行,另外两个必须打成JAR包放到hadoop上去运行。
参考:
http://zengzhaozheng.blog.51cto.com/8219051/139296
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值