Map端join算法實現,解決Reduce端數據傾斜,負載不均(分佈式緩存)

1.需求:

訂單數據表t_order:

關係數據庫表-

id

date

pid

amount

1001

20150710

P0001

2

1002

20150710

P0001

3

1002

20150710

P0002

3

抽象成文件數據:

1001,20150710,P0001,2
1002,20150710,P0001,3
1003,20150710,P0002,3
1002,20150710,P0003,3
1002,20150710,P0002,4

。。。。。。
商品信息表t_product:

id

pname



P0001

小米5



P0002

魅族



抽象成文件數據:
p0001,小米
p0002,魅族
p0003,oppo

 。。。。。。

現在要把2個文件通過pID進行關聯,如果按照上一遍文章,在Reduce中做關聯那麼問題來了,如果小米手機的訂單量遠遠大於魅族手機的訂單量,這樣就會產生處理小米手機的ReduceTask任務量很大,執行時間久,而處理魅族的ReduceTask任務輕很快就執行完了,出現了負載不均衡,數據傾斜。

2.實現

鑑於是小數據量的表和大數據量的表進行join,可以用分佈式緩存把小表緩存到map節點,在map階段直接使用,與大表進行join,不在reduce階段進行join,避免數據傾斜,提高併發量和效率。

通過main函數先把緩存文件加載到節點(底層自動分發到map節點--分佈式緩存):

job.addCacheFile(“文件路徑”);

代碼:

package join;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
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;

public class MapJoin {

	static class JoinMapper extends Mapper<LongWritable,Text,Text,Text>{
		Map<String,String> pmap=new HashMap<String,String>();//裝產品數據
		Text k=new Text();
		/*重寫setup方法,看Mapper源碼裏面有個線程的run方法,
		  方法執行順序是setup()-->map(),所以會先加載setup方法
		  */
		@Override
		protected void setup(Context context)throws IOException, InterruptedException {
			//讀取本地緩存中文件的數據
			BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("product")));
			String line;
			//如果讀取的一行數據不爲空,則把產品數據切分,存儲在pmap中
			while(StringUtils.isNotEmpty(line=br.readLine())){
				String[] fields = line.split(",");
				pmap.put(fields[0], fields[1]);//K爲商品id,v爲商品名
			}
			br.close();
		}
		//由於已經持有完整的產品信息表,所以直接在map中實現join操作,不需要reduce操作,就不會有數據傾斜
		@Override
		protected void map(LongWritable key, Text value,Context context)throws IOException, InterruptedException {
		    String oline = value.toString();//獲取訂單信息
		    String[] fields = oline.split(",");
		    String pName = pmap.get(fields[2]);//根據pid獲取pName
		    k.set(oline+","+pName);//數據拼接
		    context.write(k, new Text(""));//輸出
		}
	}
	public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		Job job = Job.getInstance(conf);
		
		job.setJarByClass(MapJoin.class);
		job.setMapperClass(JoinMapper.class);
		job.setMapOutputKeyClass(Text.class);
		job.setOutputValueClass(NullWritable.class);
		
		FileInputFormat.setInputPaths(job, new Path(args[0]));//訂單文件地址
		FileOutputFormat.setOutputPath(job, new Path(args[1]));//join後的文件數據地址
		//指定需要緩存文件到所有mapTask運行節點工作目錄
		job.addCacheFile(new URI(args[2]));//args[2]緩存文件路徑可以寫死(product)
		//由於Map就把事情搞定了,所以不需要reduce階段,reduceTask爲0
		job.setNumReduceTasks(0);
		boolean res = job.waitForCompletion(true);
		System.exit(res?0:1);
	}
}

結果:

1001,20150710,P0001,2,小米

。。。。。。

。。。。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章