reduce side join
在reduce端进行表的连接,该方法的特点就是操作简单,缺点是map端shffule后传递给reduce端的数据量过大,极大的降低了性能
连接方法:
(1)map端读入输入数据,以连接键为Key,待连接的内容为value,但是value需要添加特别的标识,表示的内容为表的表示,即 若value来自于表1,则标识位设置为1,若来自表2,则设置为2,然后将map的内容输出到reduce
(2)reduce端接收来自map端shuffle后的结果,即<key, values>内容,然后遍历values,对每一个value进行处理,主要的处理过程是:判断每一个标志位,如果来自1表,则将value放置在特地为1表创建的数组之中,若来自2表,则将value放置在为2表创建的数组中,最后对两个数组进行求笛卡儿积,然后输出结果,即为最终表的连接结果。
(1)map端读入输入数据,以连接键为Key,待连接的内容为value,但是value需要添加特别的标识,表示的内容为表的表示,即 若value来自于表1,则标识位设置为1,若来自表2,则设置为2,然后将map的内容输出到reduce
(2)reduce端接收来自map端shuffle后的结果,即<key, values>内容,然后遍历values,对每一个value进行处理,主要的处理过程是:判断每一个标志位,如果来自1表,则将value放置在特地为1表创建的数组之中,若来自2表,则将value放置在为2表创建的数组中,最后对两个数组进行求笛卡儿积,然后输出结果,即为最终表的连接结果。
样例输入:
file1:
Beijing Red Star,1
Shenzhen Thunder,3
Guangzhou Honda,2
Beijing Rising,1
Guangzhou Development Bank,2
Tencent,3
Back of Beijing,1
Shenzhen Thunder,3
Guangzhou Honda,2
Beijing Rising,1
Guangzhou Development Bank,2
Tencent,3
Back of Beijing,1
file2:
1,Beijing
2,Guangzhou
3,Shenzhen
4,Xian
2,Guangzhou
3,Shenzhen
4,Xian
预期输出:
factoryname addressname
Back of Beijing Beijing
Beijing Red Star Beijing
Beijing Rising Beijing
Guangzhou Development Bank Guangzhou
Guangzhou Honda Guangzhou
Shenzhen Thunder Shenzhen
Tencent Shenzhen
Back of Beijing Beijing
Beijing Red Star Beijing
Beijing Rising Beijing
Guangzhou Development Bank Guangzhou
Guangzhou Honda Guangzhou
Shenzhen Thunder Shenzhen
Tencent Shenzhen
代码:
package mapreduce;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import mapreduce.sort.MyMapper;
import mapreduce.sort.MyReduce;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.DoubleWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.Reducer.Context;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import org.apache.hadoop.util.LineReader;
public class reducejoin {
static String INPUT_PATH="hdfs://master:9000/show/file1";
static String OUTPUT_PATH="hdfs://master:9000/output";
static class MyMapper extends Mapper<Object, Object, Text, Text>{
Text output_key=new Text();
Text output_value=new Text();
// String tableName="";
protected void setup(Context context) throws java.io.IOException, java.lang.InterruptedException{
// FileSplit fs= (FileSplit) context.getInputSplit();
// tableName=fs.getPath().getName();
// System.out.println(tableName);
}
protected void map(Object key,Object value,Context context) throws IOException, InterruptedException{
String[] str=value.toString().split(",");
// if(tableName.equals("file1")){
// output_key.set(str[1]);
// output_value.set(1+","+str[0]+","+str[1]);
// }
//
// else if(tableName.equals("file2")){
// output_key.set(str[0]);
// output_value.set(2+","+str[0]+","+str[1]);
// }
output_key.set(str[0]);
output_value.set(str[1]);
context.write(output_key,output_value);
//System.out.println(str[0]+str[1]);
}
}
static class MyReduce extends Reducer<Text, Text, Text, Text>{
Text outputkey=new Text();
Text outputvalue=new Text();
Map<String,String> addMap=new HashMap<String,String>();
protected void setup(Context context) throws java.io.IOException, java.lang.InterruptedException{
//for(URI uri:context.getCacheFiles()){
//FileInputStream fs=new FileInputStream(uri.toString());
URI uri=context.getCacheFiles()[0];
Path path=new Path(uri);
FileSystem fs=path.getFileSystem(context.getConfiguration());
LineReader linereader=new LineReader(fs.open(path));
Text line=new Text();
while(linereader.readLine(line)>0){
String[] tokens=line.toString().split(",");
if(tokens!=null &&tokens.length==2)
addMap.put(tokens[0], tokens[1]); //将数据放入map中 (1,beijing)
}
// BufferedReader br=new BufferedReader(new FileReader(uri.toString()));
// String line=br.readLine();
//}
}
protected void reduce(Text key, Iterable<Text> values, Context context)
throws IOException, InterruptedException{
String addrName=addMap.get(values.iterator().next().toString()); //获得与values值相同的键的值 比如 values为1,map中1的键的值为beijing 。
outputvalue.set(addrName);
context.write(key, outputvalue);
//
}
}
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
// TODO Auto-generated method stub
Path outputpath=new Path(OUTPUT_PATH);
Path cacheFile=new Path("hdfs://master:9000/show/file2");
Configuration conf=new Configuration();
FileSystem fs=outputpath.getFileSystem(conf);
Job job=Job.getInstance(conf);
FileInputFormat.setInputPaths(job, INPUT_PATH);
FileOutputFormat.setOutputPath(job,outputpath);
if( fs.exists(outputpath)){
fs.delete(outputpath);
//System.out.print("success");
}
URI uri=cacheFile.toUri();
job.setCacheFiles(new URI[]{uri});
job.setMapperClass(MyMapper.class);
job.setReducerClass(MyReduce.class);
// job.setPartitionerClass(MyPartitioner.class);
// job.setNumReduceTasks(2);
// job.setMapOutputValueClass(NullWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
job.waitForCompletion(true);
}
}
在map阶段,将file1中的内容分为key和value输出,不做其它处理。
进入reduce阶段,在setup中,将file2读入内存。将数据进行处理。
addMap.put(tokens[0], tokens[1]); //将数据放入map中 (1,beijing)
String addrName=addMap.get(values.iterator().next().toString()); //获得与values值相同的键的值 比如 values为1,map中1的键的值为beijing 。这样公司名与地名就对应了。
map side join
在map端进行表的连接,对表的大小有要求,首先有一个表必须足够小,可以读入内存,另外的一个表很大,与reduce端连接比较,map端的连接,不会产生大量数据的传递,而是在map端连接完毕之后就进行输出,效率极大的提高
连接方法:
(1)首先要重写Mapper类下面的setup方法,因为这个方法是先于map方法执行的,将较小的表先读入到一个HashMap中。
(2)重写map函数,一行行读入大表的内容,逐一的与HashMap中的内容进行比较,若Key相同,则对数据进行格式化处理,然后直接输出。
连接方法:
(1)首先要重写Mapper类下面的setup方法,因为这个方法是先于map方法执行的,将较小的表先读入到一个HashMap中。
(2)重写map函数,一行行读入大表的内容,逐一的与HashMap中的内容进行比较,若Key相同,则对数据进行格式化处理,然后直接输出。
代码和reduce side join 类似。