完成的任务多表链接,前面已经实现过一次了,这次使用hadoop的分布式缓存DistributedCache来实现,节省了map之后要传输给reducer大量的数据开销,使用DistributedCache的前提条件是,链接的两个表,有一个是小表,另一个是大表,将小表放入DistributedCache中,从而实现将小表分布式存储在每个map节点,节省了大部分传出开销,这里的饿例子只是一个测试用的小例子,可以知道表一公司表可以做的很大,但是表二地址表应该不会是太大的。
表一:大表,左侧是公司名称,右侧是地址ID
Beijing Red Star,1
Shenzhen Thunder,3
Guangzhou Honda,2
Beijing Rising,1
Guangzhou Development Bank,2
Tencent,3
Back of Beijing,1
表二:小表 ,左侧是地址ID,右侧是地址名称
1 Beijing
2 Guangzhou
3 Shenzhen
4 Xian
//需要解释一下Mapper类的关于setup函数,在Hadoop in Action中,用的是老版的API,使用的Configure函数,我们查阅源码可以发现,新版的API已经舍弃了将Job和Configuration放在一个Jobconf中使用的方法,分开为Job和Configuration两个类
//所以,在使用新版API时,建议大家一定要多多查看源码,看看其中到底是怎么实现的,其实hadoop的源码java实现都很平易近人易懂的。//这里我们查阅Mapper的源码可以发现,Mapper类加载时会执行四个函数:1、protected void setup(Context context)
// 2、protected void map(KEYIN key, VALUEIN value, Context context)
// 3、protected void cleanup(Context context)
// 4、public void run(Context context)
//这里的setup函数代替了老板中集成了JobConfigure的Configure函数,也体现了该团队要将Job和Configuration分离的思想,所以这里使用到了setup函数
自己写的程序源码:
package bin;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.filecache.DistributedCache;
import org.apache.hadoop.fs.Path;
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;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
public class MTJoinDC extends Configured implements Tool{
public static class MTJoinDCMap extends Mapper<Text, Text, Text, Text>{
private HashMap<String, String> joinData =new HashMap<String,String>();
//定义方法setup分割文件中的每一行,","前的字符串放在tokens[0]中,","后的字符串放在tokens[1]中
public void setup(Context context) {
try {
Path[] cacheFiles=DistributedCache.getLocalCacheFiles(context.getConfiguration());//设置分布式cache的路径
if (cacheFiles!=null && cacheFiles.length!=0) {
String lineString;
String[] tokens;
BufferedReader bReader=new BufferedReader(new FileReader(cacheFiles[0].toString()));
try {
while ((lineString=bReader.readLine())!=null) {
tokens=lineString.split(" ",2);
joinData.put(tokens[0], tokens[1]);
}
}finally{
bReader.close();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//实现mapper接口中的抽象方法map()
public void map(Text key,Text value,Context context) {
String joinValue=joinData.get(value.toString());//这里是value.toString(),用value不行。。。。。。。。。。!!!
if (null!=joinValue) {
try {
context.write(key, new Text(joinValue));
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
@Override
/*
* 通过主函数中 ToolRunner.run(new Configuration(), new DistributedCacheJoin(), args); 方法调用
* (non-Javadoc)run方法是 Tool接口中定义的抽象方法,在实现该类的时候,一定要实现run方法
* @see org.apache.hadoop.util.Tool#run(java.lang.String[])
*/
public int run(String[] args) throws Exception {//具体实现作业分配
Configuration configuration=getConf();//全局使用同一个
Job job=new Job(configuration, "MTJoinDC");
job.setJarByClass(MTJoinDC.class);
DistributedCache.addCacheFile(new Path(args[0]).toUri(), job.getConfiguration());
Path in=new Path(args[1]);
Path out= new Path(args[2]);
FileInputFormat.setInputPaths(job, in);
FileOutputFormat.setOutputPath(job, out);
job.setMapperClass(MTJoinDCMap.class);
job.setNumReduceTasks(0);//不进行Reduce操作
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
job.setInputFormatClass(org.apache.hadoop.mapreduce.lib.input.KeyValueTextInputFormat.class);
job.setOutputFormatClass(TextOutputFormat.class);
job.getConfiguration().set("mapreduce.input.keyvaluelinerecordreader.key.value.separator", ",");
System.exit(job.waitForCompletion(true)?0:1);
return 0;
}
public static void main(String[] args) throws Exception {
int res=ToolRunner.run(new Configuration(),new MTJoinDC(), args);//参数:新建Configuration,其中的tool参数传递的是主类
System.exit(res);
}
}
运行时,了解程序代码真正含义的人都可写出正确的参数args列表,但是初学者,一知半解的可能就比较困难了,在这里提示大家一下:
第一个参数,也就是args[0],是分布式cache中要存放的文件(---------即,那张小表,表二,是setup需要处理的-----------)
第二个参数,也就是args[1],是分布式cache中要存放的文件(---------即,那张大表,表一,map需要处理的输入-----------)
第三个参数就很显然了是你的输出文件。
--------------------------------------------------------------尊重劳动成果尊重原创----------------------------------转载请注明出处,3Q
学习路上困苦实多,得到了网上很多好心人的大方帮助,他们分享了自己遇到的问题和一些经验心得,我从中受益匪浅,在这里我也贡献出自记得一份力量,希望正好学习它的人能够有一些收获,也希望我这个菜鸟能够在跟大家的交流中成长进步。
--------------欣