Map/Reduce實現Big矩陣乘法

                                                                                       作業報告

                                                                            ( 2019學年春季學期 )

課程名稱

大數據與深度學習

作業名稱

大數據矩陣乘法

組長

LFY

學號

2016

組員

 

學號

 

組員

 

學號

 

組員

 

學號

 

組員

 

學號

 

專業

 

教師

 


1、問題描述

利用擬分佈式系統,利用map/reduce編寫程序計數大數據的矩陣乘法,大型矩陣一般採用稀疏矩陣存儲,只存儲非0數據。

注意: 由於矩陣過大,所以合理的存儲是分佈式的稀疏矩陣存儲,稀疏矩陣不懂的請先修《數據結構》

2、實現描述

按照老師提醒的思路,在map階段把兩個輸入的矩陣的值進行劃分成對應的key,value值進行輸出,裏面存放計數算法所必須的內容,這樣就能對應這是用於計算哪個結果位置的哪個矩陣的什麼值,reduce階段,同一個key表示都是用於計算該位置的值,對應相同的行列序號進行相乘對應相加即得結果,若某數據不存在即根據稀疏矩陣的存儲,該值爲0。

3、運行效果

1、輸入文本

矩陣一: 

     

矩陣二:

2、輸出文本

3、輸出日誌

4、源碼

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
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.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;

/**
 * @author liufangyu
 * @version 1.0 Created on 2019年3月14日
 */
public class SparseMatrixMultiply {
	private final static int ax = 4;
	private final static int ay = 3;
	private final static int bx = 3;
	private final static int by = 2;
	public static class SMMapper extends Mapper<LongWritable, Text, Text, Text>{
		private Text keys = new Text();
		private Text values = new Text();
		@Override
		protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
			String fileName=getFileName(((FileSplit)context.getInputSplit()).getPath().toString());
			String[] fields = value.toString().split(",");
			String k="",val="";
			if(fileName.equals("matrix1.txt")) {
				k=fields[0]+",";
				val="a,"+fields[1]+","+fields[2];
				values.set(val);
				for(int i=1;i<=by;i++) {
					keys.set(k+String.valueOf(i));
					context.write(keys, values);
				}
			}else if(fileName.equals("matrix2.txt")) {
				k=","+fields[1];
				val="b,"+fields[0]+","+fields[2];
				values.set(val);
				for(int i=1;i<=ax;i++) {
					keys.set(String.valueOf(i)+k);
					context.write(keys, values);
				}
			}
		}
		
		private String getFileName(String path) {
			int index = path.lastIndexOf("/");//最後一個斜線的位置
			String fileName = path.substring(index+1);//得到輸入文件的文件名
			return fileName;
		}
	}

	public static class SMReducer extends Reducer<Text, Text, Text, IntWritable> {

		protected void reduce(Text key, Iterable<Text> values, Context context)throws IOException, InterruptedException {
			Map<String, String> mapA = new HashMap<String, String>();
			Map<String, String> mapB = new HashMap<String, String>();
			for (Text value : values) {
				String[] val = value.toString().split(",");
				if ("a".equals(val[0])) {
					mapA.put(val[1], val[2]);
				} else if ("b".equals(val[0])) {
					mapB.put(val[1], val[2]);
				}
			}
			int result = 0;
			// 可能在mapA中存在在mapB中不存在的key,或相反情況
			// 因爲,數據定義的時候使用的是稀疏矩陣的定義
			// 所以,這種只存在於一個map中的key,說明其對應元素爲0,不影響結果
			Iterator<String> mKeys = mapA.keySet().iterator();
			while (mKeys.hasNext()) {
				String mkey = mKeys.next();
				if (mapB.get(mkey) == null) {// 因爲mkey取的是mapA的key集合,所以只需要判斷mapB是否存在即可。
					continue;
				}
				result += Integer.parseInt(mapA.get(mkey))*Integer.parseInt(mapB.get(mkey));
			}
			String s=key.toString();
			Text t=new Text();
			t.set("("+s+")\t");
			IntWritable ans=new IntWritable();
			ans.set(result);
			context.write(t,ans);
		}
	}

	public static void main(String[] args) throws IOException,ClassNotFoundException, InterruptedException {  
        Configuration conf = new Configuration();

        Job job = Job.getInstance(conf, "SparseMatrixMultiply");  
        job.setJarByClass(SparseMatrixMultiply.class); 
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(Text.class);
        job.setOutputKeyClass(Text.class);  
        job.setOutputValueClass(IntWritable.class);  

        job.setMapperClass(SMMapper.class);  
        job.setReducerClass(SMReducer.class);  

        job.setInputFormatClass(TextInputFormat.class);  
        job.setOutputFormatClass(TextOutputFormat.class);  

        FileInputFormat.setInputPaths(job, new Path(args[0]), new Path(args[1]));// 加載2個輸入數據集  
        Path outputPath = new Path(args[2]);  
        outputPath.getFileSystem(conf).delete(outputPath, true);  
        FileOutputFormat.setOutputPath(job, outputPath);  

        System.exit(job.waitForCompletion(true)?0 : 1);  
    }
}

5、總結

通過該次作業,我發現雖說map/reduce提供的接口雖然有點死板,但是靈活運用的話可以解決其他很多問題。

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