MapReduce 连接操作

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表创建的数组中,最后对两个数组进行求笛卡儿积,然后输出结果,即为最终表的连接结果。

样例输入:
file1:
Beijing Red Star,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

预期输出:

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

代码:
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相同,则对数据进行格式化处理,然后直接输出。

代码和reduce side join 类似。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值