• MR实现--矩阵乘法


      1 import java.io.IOException;
      2 import org.apache.hadoop.conf.Configuration;
      3 import org.apache.hadoop.io.*;
      4 import org.apache.hadoop.mapreduce.Job;
      5 import org.apache.hadoop.mapreduce.Mapper;
      6 import org.apache.hadoop.mapreduce.Reducer;
      7 import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
      8 import org.apache.hadoop.mapreduce.lib.input.FileSplit;
      9 import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
     10 import org.apache.hadoop.fs.Path;
     11 public class matrix {
     12     public static int rowM=0;
     13     public static int columnM=0;
     14     public static int columnN=0;
     15     public static class MyMapper extends Mapper<Object, Text, Text, Text>{
     16         private Text map_key=new Text();
     17         private Text map_value=new Text();        
     18         public void setup(Context context){
     19             Configuration conf=context.getConfiguration();
     20             columnN=Integer.parseInt(conf.get("columnN"));
     21             rowM=Integer.parseInt(conf.get("rowM"));
     22         }
     23         public void map(Object key,Text value,Context context) throws IOException, InterruptedException{
     24             FileSplit fileSplit=(FileSplit)context.getInputSplit();
     25             String filename=fileSplit.getPath().getName();            
     26             System.out.println("map的数据分片长度是:"+fileSplit.getLength());
     27             System.out.println("数据分片的起始位置是:"+fileSplit.getStart());
     28             String[] tempLocation=fileSplit.getLocations();
     29             for (String string : tempLocation) {
     30                 System.out.println("数据分片所在的主机是:"+string);
     31             }
     32             if(filename.contains("M")){            
     33             String[] tuple=value.toString().split(",");
     34             int i=Integer.parseInt(tuple[0]);
     35             String[] tupleS=tuple[1].split("	");
     36             int j=Integer.parseInt(tupleS[0]);
     37             int Mij=Integer.parseInt(tupleS[1]);
     38             for (int k = 1; k <columnN+1 ; k++) {
     39                 map_key.set(i+","+k);
     40                 map_value.set("M"+","+j+","+Mij);
     41                 context.write(map_key, map_value);                
     42             }
     43             }
     44             else if(filename.contains("N")){            
     45                 String[] tuple=value.toString().split(",");
     46                 int j=Integer.parseInt(tuple[0]);
     47                 String[] tupleS=tuple[1].split("	");
     48                 int k=Integer.parseInt(tupleS[0]);
     49                 int Njk=Integer.parseInt(tupleS[1]);
     50                 for (int i = 1; i <rowM+1 ; i++) {
     51                     map_key.set(i+","+k);
     52                     map_value.set("N"+","+j+","+Njk);
     53                     context.write(map_key, map_value);                
     54                 }                
     55             }
     56         }
     57     }
     58     public static class MyReducer extends Reducer<Text, Text, Text, Text>{
     59         private int sum=0;
     60         public void setup(Context context) throws IOException{
     61             Configuration conf=context.getConfiguration();
     62             columnM=Integer.parseInt(conf.get("columnM"));    
     63         }
     64     public void reduce(Text key,Iterable<Text> value,Context context)throws IOException,InterruptedException{
     65         int[] M=new int[columnM+1];
     66         int[] N=new int[columnM+1];
     67         System.out.println(key.toString()+"对应的value列表所有值是:");
     68         for (Text val : value){
     69             System.out.println(val.toString());
     70             String[] tuple=val.toString().split(",");
     71             if(tuple[0].equals("M")){
     72                 M[Integer.parseInt(tuple[1])]=Integer.parseInt(tuple[2]);                
     73             }else {
     74                 N[Integer.parseInt(tuple[1])]=Integer.parseInt(tuple[2]);        
     75             }
     76         }
     77         for (int j=1;j<columnM+1;++j) {
     78             sum+=M[j]*N[j];
     79         }
     80         context.write(key, new Text(Integer.toString(sum)));
     81         sum=0;        
     82     }        
     83     }
     84     public static void main(String[] args)throws Exception {
     85         if(args.length!=3){
     86             System.err.println("Usage: MatrixMultiply <inputPathM> <inputPathN> <outputPath>");
     87         System.exit(2);
     88         }
     89         else{
     90             System.out.println("M文件路径:"+args[0]);
     91             String[] infoTupleM=args[0].split("_");
     92             rowM=Integer.parseInt(infoTupleM[1]);
     93             columnM=Integer.parseInt(infoTupleM[2]);
     94             String[] infoTupleN=args[1].split("_");
     95             columnN=Integer.parseInt(infoTupleN[2]);                
     96         }
     97         Configuration conf=new Configuration();
     98         conf.set("columnM", Integer.toString(columnM));
     99         conf.set("rowM", Integer.toString(rowM));
    100         conf.set("columnN", Integer.toString(columnN));
    101         Job job=new Job(conf, "Matrix");
    102         job.setJarByClass(matrix.class);
    103         job.setMapperClass(MyMapper.class);
    104         job.setReducerClass(MyReducer.class);
    105         job.setOutputKeyClass(Text.class);
    106         job.setOutputValueClass(Text.class);
    107         FileInputFormat.setInputPaths(job, new Path(args[0]),new Path(args[1]));
    108         FileOutputFormat.setOutputPath(job, new Path(args[2]));
    109         System.exit(job.waitForCompletion(true)?0:1);        
    110     }
    111 }

         以上是j计算矩阵M*N结果的源码,总共需要三个输入参数,分别是:M矩阵的路径、N矩阵的路径以及结果的输入路径。其中M存放在文件中,文件的格式是"M_rows_columns",实验的矩阵文件是M_300_500。实验中N的文件是N_500_700。并且M和N文件中的格式都是相同的,都是"i,j Mij"的形式,其中i表示元素所在矩阵的行数,j表示元素所在矩阵的列数,Mij表示矩阵元素。如下图所示(N_500_700中形式也是如此):

    矩阵内都是随机数,矩阵文件由以下shell脚本生成:

    #!/bin/bash
    for i in `seq 1 $1`
    do
        for j in `seq 1 $2`
        do 
            s=$(($RANDOM%100))
                echo -e "$i,$j	$s" >>M_$1_$2
        done
    done

    2)map的输出形式:

    假设M是i*j的矩阵,N是j*k的矩阵。

    对于M矩阵:map的输出形式是(<i,k>,<"M",j,Mij>),其中<i,k>是key,<"M",j,Mij>是value。

    M表示此键值对是M矩阵的内容

    Mij是M矩阵中的一个元素

    i和j是这个元素在矩阵中的位置

    k是矩阵N的列数

    对于N矩阵:map的输出形式是(<i,k>,<"N",j,Njk>),其中<i,k>是key,<"N",j,Njk>是value。

    可以看到M和N经过map处理之后输出形式类似,key完全一样,其实key就表示结果矩阵中的第i行第k列,而reduce就是将<"M",j,Mij>和<"N",j,Njk>对应的元素相乘。

    3)而map的输入形式是“1,1  87 ”(也就是i,j,Mij),而map的输出形式是(<i,k>,<"M",j,Mij>),只有k是未知的,其实k就是N的列数,也是结果矩阵的列数,

    从M中读取的数据就只有i,j,Mij,k就是N的列数,所以:

     1     if(filename.contains("M")){            
     2             String[] tuple=value.toString().split(",");
     3             int i=Integer.parseInt(tuple[0]);
     4             String[] tupleS=tuple[1].split("	");
     5             int j=Integer.parseInt(tupleS[0]);
     6             int Mij=Integer.parseInt(tupleS[1]);
     7             for (int k = 1; k <columnN+1 ; k++) {
     8                 map_key.set(i+","+k);
     9                 map_value.set("M"+","+j+","+Mij);
    10                 context.write(map_key, map_value);                
    11             }
    12             }

    从N矩阵中读取到j,k,Njk,所以i就是M的行数,对于N是:

     1 else if(filename.contains("N")){            
     2                 String[] tuple=value.toString().split(",");
     3                 int j=Integer.parseInt(tuple[0]);
     4                 String[] tupleS=tuple[1].split("	");
     5                 int k=Integer.parseInt(tupleS[0]);
     6                 int Njk=Integer.parseInt(tupleS[1]);
     7                 for (int i = 1; i <rowM+1 ; i++) {
     8                     map_key.set(i+","+k);
     9                     map_value.set("N"+","+j+","+Njk);
    10                     context.write(map_key, map_value);                
    11                 }                
    12             }

    4)作业的配置,有个地方需要注意,就是设置了每个Map和Reduce节点都可以共享的三个变量:

    1     conf.set("columnM", Integer.toString(columnM));
    2     conf.set("rowM", Integer.toString(rowM));
    3     conf.set("columnN", Integer.toString(columnN));

    5)为了获得columnN和rowM,重载了Mapper的setup函数:

    1 public void setup(Context context){
    2             Configuration conf=context.getConfiguration();
    3             columnN=Integer.parseInt(conf.get("columnN"));
    4             rowM=Integer.parseInt(conf.get("rowM"));
    5         }

    通过conf的get函数获得。同样的,为获得columnM,也重载了Reducer的setup函数。

    1     public void setup(Context context) throws IOException{
    2             Configuration conf=context.getConfiguration();
    3             columnM=Integer.parseInt(conf.get("columnM"));    
    4         }

     6)由于定义的reduce数量是5,所以最终生成了5个结果文件。

  • 相关阅读:
    ES6中的新特性
    怎样优化CPU
    es6 一些小知识
    ECMAScript有6种继承方式(实现继承)
    angula的factory service provider
    angular的继承作用域通信
    MVP和MVC的区别
    判断浏览器版本语句大全
    IScroll5+在ios、android点击(click)事件不兼容解决方法
    css中单位px和em,rem的区别
  • 原文地址:https://www.cnblogs.com/lz3018/p/4949987.html
Copyright © 2020-2023  润新知