1. 矩阵乘法原理和实现思路
对于任意矩阵
和
,若矩阵
的列数等于矩阵
的行数,则记
和
的乘积
。其中
记作矩阵
的第
行第
列的元素,
记作矩阵
的第
行第
列的元素,则其乘积矩阵
的元素可由下式求得:
可以得出,决定最后
位置的是
,所以可以将其作为
的输入
值。而为了求出
,我们需要分别知道
和
。对于
,其所需要的属性有矩阵名称
,所在行数
,所在列数
,和其本身的数值大小
;同样对于
,其所需要的属性有矩阵名称
,所在行数
,所在列数
,和其本身的数值大小
。这些属性值由
处理得到,基本处理思路下:
Map函数:对于矩阵
中的每个元素
,产生一系列的
对
,其中
直到矩阵
的总列数;对于矩阵
中的每个元素
,产生一系列的
对
,其中
直到矩阵
的总行数。
Reduce函数:对于每个键
相关联的值
及
,根据相同的
值将
和
分别存入不同数组中,然后将两者的第
个元素抽取出来分别相乘,最后相加,即可得到
的值。
示例:
设矩阵
,矩阵
,其中,
经过
函数之后得到如下的输出。
Reduce 函数对于输入的每个
值
,根据
值进行抽取出对应的元素
和
相乘,然后再累加。
对于
值为(1,1)的输入:
对于 值为(1,2)的输入:
对于 值为(1,1)的输入:
2.矩阵乘法的MapReduce程序实现
思路:一共有两个输入文本文件,分别存放矩阵 和 的元素,文件内容每一行的形式是”行坐标,列坐标\t元素数值”,在map端,输出形式为 ,同理,N矩阵也是如此。在reduce端,使用两个数组分别存来自 端的相同键的不同值 的M矩阵的行值,N矩阵的列值。
Sell生成实验数据:
#!/bin/bash
if [ $# -ne 3 ]
then
echo "there must be 3 arguments to generate the two matries file!"
exit 1
fi
cat /dev/null > M_$1_$2
cat /dev/null > N_$2_$3
for i in `seq 1 $1`
do
for j in `seq 1 $2`
do
s=$((RANDOM%100))
echo –e "$i,$j\t$s" >>M_$1_$2
done
done
echo "we have built the matrix file M"
for i in `seq 1 $2`
do
for j in ` seq 1 $3`
do
s=$((RANDOM%100))
echo -e "$i,$j\t$s" >>N_$2_$3
done
done
echo "we have built the matrix file N"
MapReduce 代码:
package cn.zzuli.zcs0;
import org.apache.hadoop.conf.Configuration;
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.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
/**
* Created by 张超帅 on 2018/8/15.
*/
public class MatrixMultiply {
public static int rowM = 0;
public static int columnM = 0;
public static int columnN = 0;
public static class MatrixMapper extends Mapper<Object, Text, Text, Text> {
private Text map_key = new Text();
private Text map_value = new Text();
public void setup(Context context) throws IOException {
Configuration conf = context.getConfiguration();
columnM = Integer.parseInt(conf.get("columnN"));
rowM = Integer.parseInt(conf.get("rowM"));
}
@Override
protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
FileSplit fileSplit = (FileSplit) context.getInputSplit();
String filename = fileSplit.getPath().getName();
if(filename.contains("M")) {
String[] tuple = value.toString().split(",");
int i = Integer.parseInt(tuple[0]);
String[] tuples = tuple[1].split("\t");
int j = Integer.parseInt(tuples[0]);
int Mij = Integer.parseInt(tuples[1]);
for(int k = 1; k < columnN + 1; k ++) {
map_key.set(i + "," + k);
map_value.set("M" + "," + j + "," + Mij);
context.write(map_key,map_value);
}
}
else if(filename.contains("N")) {
String[] tuple = value.toString().split(",");
int j = Integer.parseInt(tuple[0]);
String[] tuples = tuple[1].split("\t");
int k = Integer.parseInt(tuples[0]);
int Njk = Integer.parseInt(tuples[1]);
for(int i = 1; i < rowM + 1; i ++) {
map_key.set(i + "," + k);
map_value.set("N" + "," + j + "," + Njk);
context.write(map_key, map_value);
}
}
}
}
public static class MatrixReducer extends Reducer<Text, Text, Text, Text> {
private int sum = 0;
@Override
protected void setup(Context context) throws IOException, InterruptedException {
Configuration conf = context.getConfiguration();
columnM = Integer.parseInt(conf.get("columnM"));
}
@Override
protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
int[] M = new int[columnM + 1];
int[] N = new int[columnM + 1];
for(Text val : values) {
String[] tuple = val.toString().split(",");
if(tuple[0].equals("M")) {
M[Integer.parseInt(tuple[1])] = Integer.parseInt(tuple[2]);
} else
N[Integer.parseInt(tuple[1])] = Integer.parseInt(tuple[2]);
}
for(int j = 1; j < columnM + 1; j ++) {
sum += M[j] * N[j];
}
context.write(key, new Text(Integer.toString(sum)));
sum = 0;
}
}
public static void main(String[] args) throws Exception{
if(args.length != 3) {
System.err.println("Usage: MatrixMultiply <inputPathM> <inputPathN> <outputPath>");
System.exit(2);
} else {
String[] infoTupleM = args[0].split("_");
rowM = Integer.parseInt(infoTupleM[1]);
columnM = Integer.parseInt(infoTupleM[2]);
String[] infoTupleN = args[1].split("_");
columnN = Integer.parseInt(infoTupleN[2]);
}
Configuration conf = new Configuration();
conf.setInt("rowM",rowM);
conf.setInt("columnM", columnM);
conf.setInt("columnN", columnN);
Job job = Job.getInstance(conf, "MatrixMultiply");
job.setJarByClass(MatrixMultiply.class);
job.setMapperClass(MatrixMapper.class);
job.setReducerClass(MatrixReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
FileInputFormat.setInputPaths(job,new Path(args[0]), new Path(args[1]));
FileOutputFormat.setOutputPath(job,new Path(args[2]));
System.exit(job.waitForCompletion(true)? 0: 1);
}
}