mapreduce实现矩阵相乘

,那么


矩阵乘法要求左矩阵的列数与右矩阵的行数相等,的矩阵,与的矩阵相乘,结果为的矩阵

现在我们来分析一下,哪些操作是相互独立的(从而可以进行分布式计算)。很显然,的计算和的计算是互不干扰的;事实上,中各个元素的计算都是相互独立的。这样,我们在Map阶段,可以把计算所需要的元素都集中到同一个key中,然后,在Reduce阶段就可以从中解析出各个元素来计算的其他元素的计算同理。


我们还需要注意,会被……的计算所使用,会被……的计算所使用。也就是说,在Map阶段,当我们从HDFS取出一行记录时,如果该记录是的元素,则需要存储成个<key, value>对,并且这个key互不相同;如果该记录是的元素,则需要存储成个<key, value>对,同样的,个key也应互不相同;但同时,用于计算的、存放…………的<key, value>对的key应该都是相同的,这样才能被传递到同一个Reduce中。


经过以上分析,整个计算过程设计为:

(1)在Map阶段,把来自表的元素,标识成条<key, value>的形式。其中;把来自表的元素,标识成条<key, value>形式,其中

于是乎,在Map阶段,我们实现了这样的战术目的:通过key,我们把参与计算的数据归为一类。通过value,我们能区分元素是来自还是,以及具体的位置。

(2)在Shuffle阶段,相同key的value会被加入到同一个列表中,形成<key, list(value)>对,传递给Reduce,这个由Hadoop自动完成。

(3)在Reduce阶段,有两个问题需要自己问问:

  • 当前的<key, list(value)>对是为了计算的哪个元素?

  • list中的每个value是来自表或表的哪个位置?

第一个问题可以从key中获知,因为我们在Map阶段已经将key构造为形式。第二个问题,也可以在value中直接读出,因为我们也在Map阶段做了标志。

接下来我们所要做的,就是把list(value)解析出来,来自的元素,单独放在一个数组中,来自的元素,放在另一个数组中,然后,我们计算两个数组(各自看成一个向量)的点积,即可算出的值。

示例矩阵相乘的计算过程如下图所示:

134456_8GH9_2010330.jpeg


其中map阶段:

public static class MatrixMap extends Mapper<Object, Text, Text, Text>{
        private int sum3 = 0;  //存放矩阵a的行数
        private int sum4 = 0;  //存放矩阵b的行数
        @Override
        protected void map(Object key, Text value, Context context)
                throws IOException, InterruptedException {
            String[] lines = value.toString().split(",");
            String url = ((FileSplit)context.getInputSplit()).getPath().toString();
            //取出文件路径名,判断数据来源分别增加其行数
            if(url.contains("matrix3")) sum3++;
            if(url.contains("matrix4")) sum4++;
            for(int m = 0; m < lines.length; m++){
                // 遍历矩阵列数,分别与行数组成key为(i,k),value为(a,j,v)的数据输出 
            if(url.contains("matrix3") && lines.length == matrix_j){
                for (int i = 1; i <= matrix_k; i++){
                    context.write(new Text(sum3+","+i), 
                            new Text("a,"+(m+1)+","+lines[m]));
                }    
            }else if(url.contains("matrix4") && lines.length == matrix_k){
                for (int i = 1; i <= matrix_i; i++){
                    context.write(new Text(i+","+(m+1)), 
                            new Text("b,"+sum4+","+lines[m]));
                }
            }
            }
        }
        
    }

reduce阶段:

public static class MatrixReduce extends Reducer<Text, Text, Text, Text>{
        private Map<Integer, Integer> matrix_a;
        private Map<Integer, Integer> matrix_b;
        @Override
        protected void reduce(Text key, Iterable<Text> values, Context context)
                throws IOException, InterruptedException {
            matrix_a = new HashMap<Integer, Integer>();
            matrix_b = new HashMap<Integer, Integer>();
            for(Text value : values){
                //循环分辨values中值是矩阵a或是b的,并存入map集合a和b中
                String line = value.toString();
                if(line.startsWith("a,")){
                    String[] lines = line.split(",");
                    if(lines.length == 3) 
                        matrix_a.put(Integer.parseInt(lines[1]), 
                                Integer.parseInt(lines[2]));
                }else{
                    String[] lines = line.split(",");
                    if(lines.length == 3) 
                        matrix_b.put(Integer.parseInt(lines[1]), 
                                Integer.parseInt(lines[2]));
                }
            }
            int a_value = 0;
            int b_value = 0;
            int result = 0;
            //分别取出a和b集合中,计算结果放入result中
            for(int i = 1; i <= matrix_j; i++){
                if(matrix_a.get(i) != null && matrix_b.get(i) != null){
                    a_value = matrix_a.get(i);
                    b_value = matrix_b.get(i);
                    result += a_value * b_value;
                }
            }
            context.write(key, new Text(result+""));
            
        }
        
    }

主程序:

public static void run(String time, Configuration conf) 
            throws IOException, ClassNotFoundException, InterruptedException{
        // 需求输出文件路径
        String outpath = VALUE_FSNAME+
                "/data/test_out/zk/matrix-"+time;
        // 需求输入文件路径
        String input1 = VALUE_FSNAME+"/data/test_in/matrix3";
        String input2 = VALUE_FSNAME+"/data/test_in/matrix4";
        File jarFile = EJob.createTempJar("bin");
        @SuppressWarnings("deprecation")
        Job job = new Job(conf, "Test-Matrix");
        job.setJarByClass(TestMatrix1.class);
        job.setMapperClass(MatrixMap.class);
        job.setReducerClass(MatrixReduce.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);
        job.setNumReduceTasks(1);
        job.setInputFormatClass(TextInputFormat.class);
        job.setOutputFormatClass(TextOutputFormat.class);

        FileInputFormat.addInputPaths(job, input1+","+input2);;
        FileOutputFormat.setOutputPath(job, new Path(outpath));

        // 提交job
        if (job.waitForCompletion(true)) {
            System.err.println("计算完成!");
        } else {
            System.err.println("error!请检查程序!");
        }
    
    }

最后,大家请看一下原始数据:

matrix1:

1,2,3
4,5,0
7,8,9
10,11,12

matrix2:

10,15
0,2
11,9


转载于:https://my.oschina.net/ssrs2202/blog/494516

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值