2012-03-14 245 views
5

我正在运行在http://www.norstad.org/matrix-multiply/index.html处找到的MapReduce矩阵乘法程序。 我发现这个实现在输入矩阵中有0时无法正常工作。但我不明白为什么,我该如何修改该程序才能使其工作? MapReduce的操作完成,但输出始终与所有元素的矩阵0Hadoop矩阵乘法

我的输入矩阵A & B是:

Matrix A  Matrix B 
0 0 0  6 7 4 
0 1 6  9 1 3 
7 8 9  7 6 2 

输出矩阵:

0 0 0 
0 0 0 
0 0 0 

以下是取自作业的日志文件:

矩阵B的映射输出:

##### Map setup: matrixA = false for hdfs://localhost/user/hadoop-user/B 
strategy = 4 
R1 = 4 
I = 3 
K = 3 
J = 3 
IB = 3 
KB = 3 
JB = 3 
##### Map input: (0,0) 6 
##### Map output: (0,0,0,1) (0,0,6) 
##### Map input: (0,1) 7 
##### Map output: (0,0,0,1) (0,1,7) 
##### Map input: (0,2) 4 
##### Map output: (0,0,0,1) (0,2,4) 
##### Map input: (1,0) 9 
##### Map output: (0,0,0,1) (1,0,9) 
##### Map input: (1,1) 1 
##### Map output: (0,0,0,1) (1,1,1) 
##### Map input: (1,2) 3 
##### Map output: (0,0,0,1) (1,2,3) 
##### Map input: (2,0) 7 
##### Map output: (0,0,0,1) (2,0,7) 
##### Map input: (2,1) 6 
##### Map output: (0,0,0,1) (2,1,6) 
##### Map input: (2,2) 2 
##### Map output: (0,0,0,1) (2,2,2) 

地图输出为基质A:

##### Map setup: matrixA = true for hdfs://localhost/user/hadoop-user/A 
strategy = 4 
R1 = 4 
I = 3 
K = 3 
J = 3 
IB = 3 
KB = 3 
JB = 3 
##### Map input: (1,1) 1 
##### Map output: (0,0,0,0) (1,1,1) 
##### Map input: (1,2) 6 
##### Map output: (0,0,0,0) (1,2,6) 
##### Map input: (2,0) 7 
##### Map output: (0,0,0,0) (2,0,7) 
##### Map input: (2,1) 8 
##### Map output: (0,0,0,0) (2,1,8) 
##### Map input: (2,2) 9 
##### Map output: (0,0,0,0) (2,2,9) 

注意到地图为矩阵A不从输入文件中读取的零。 注意:两个输入文件都作为序列文件存储在HDFS中,输出也是序列文件。有人可以解释一下问题是什么?谢谢!

的映射器类的代码下面给出:

/** The job 1 mapper class. */ 

private static class Job1Mapper 
    extends Mapper<IndexPair, IntWritable, Key, Value> 
{ 
    private Path path; 
    private boolean matrixA; 
    private Key key = new Key(); 
    private Value value = new Value(); 

    public void setup (Context context) { 
     init(context); 
     FileSplit split = (FileSplit)context.getInputSplit(); 
     path = split.getPath(); 
     matrixA = path.toString().startsWith(inputPathA); 
     if (DEBUG) { 
      System.out.println("##### Map setup: matrixA = " + matrixA + " for " + path); 
      System.out.println(" strategy = " + strategy); 
      System.out.println(" R1 = " + R1); 
      System.out.println(" I = " + I); 
      System.out.println(" K = " + K); 
      System.out.println(" J = " + J); 
      System.out.println(" IB = " + IB); 
      System.out.println(" KB = " + KB); 
      System.out.println(" JB = " + JB); 
     } 
    } 

    private void printMapInput (IndexPair indexPair, IntWritable el) { 
     System.out.println("##### Map input: (" + indexPair.index1 + "," + 
      indexPair.index2 + ") " + el.get()); 
    } 

    private void printMapOutput (Key key, Value value) { 
     System.out.println("##### Map output: (" + key.index1 + "," + 
      key.index2 + "," + key.index3 + "," + key.m + ") (" + 
      value.index1 + "," + value.index2 + "," + value.v + ") "); 
    } 

    private void badIndex (int index, int dim, String msg) { 
     System.err.println("Invalid " + msg + " in " + path + ": " + index + " " + dim); 
     System.exit(1); 
    } 

    public void map (IndexPair indexPair, IntWritable el, Context context) 
     throws IOException, InterruptedException 
    { 
     if (DEBUG) printMapInput(indexPair, el); 
     int i = 0; 
     int k = 0; 
     int j = 0; 
     if (matrixA) { 
      i = indexPair.index1; 
      if (i < 0 || i >= I) badIndex(i, I, "A row index"); 
      k = indexPair.index2; 
      if (k < 0 || k >= K) badIndex(k, K, "A column index"); 
     } else { 
      k = indexPair.index1; 
      if (k < 0 || k >= K) badIndex(k, K, "B row index"); 
      j = indexPair.index2; 
      if (j < 0 || j >= J) badIndex(j, J, "B column index"); 
     } 
     value.v = el.get(); 
       if (matrixA) { 
        key.index1 = i/IB; 
        key.index3 = k/KB; 
        key.m = 0; 
        value.index1 = i % IB; 
        value.index2 = k % KB; 
        for (int jb = 0; jb < NJB; jb++) { 
         key.index2 = jb; 
         context.write(key, value); 
         if (DEBUG) printMapOutput(key, value); 
        } 
       } else { 
        key.index2 = j/JB; 
        key.index3 = k/KB; 
        key.m = 1; 
        value.index1 = k % KB; 
        value.index2 = j % JB; 
        for (int ib = 0; ib < NIB; ib++) { 
         key.index1 = ib; 
         context.write(key, value); 
         if (DEBUG) printMapOutput(key, value); 
        } 
     } 
    } 
} 

如果有任何语法错误,那只是因为我复制粘贴代码,并在这里修改了它,所以我可能忽略了一些东西。

我需要帮助Map函数的逻辑,它不会从输入文件读取0,谁能告诉我为什么?

+1

这些超过700行代码。你认为有人会为你调试吗? – 2012-03-15 06:55:09

+0

我修改了我的帖子以仅包含映射器类代码。我需要关于逻辑的帮助,在某种意义上,我无法解释为什么0不会被Map函数读入输入文件。 – Chaos 2012-03-15 17:40:03

+0

@ThomasJungblut - 我以为你会促进哈马矩阵乘法:) – 2012-03-16 02:33:40

回答

3

在TestMatrixMultiply.java,从网站链接你,这大概包含了你正在使用你的矩阵编码到预期的IndexPair支持的文件格式的代码,有功能writeMatrix:

public static void writeMatrix (int[][] matrix, int rowDim, int colDim, String pathStr) 
    throws IOException 
{ 
    Path path = new Path(pathStr); 
    SequenceFile.Writer writer = SequenceFile.createWriter(fs, conf, path, 
     MatrixMultiply.IndexPair.class, IntWritable.class, 
     SequenceFile.CompressionType.NONE); 
    MatrixMultiply.IndexPair indexPair = new MatrixMultiply.IndexPair(); 
    IntWritable el = new IntWritable(); 
    for (int i = 0; i < rowDim; i++) { 
     for (int j = 0; j < colDim; j++) { 
      int v = matrix[i][j]; 
      if (v != 0) { // !!! well, that would be why we aren't writing 0s 
       indexPair.index1 = i; 
       indexPair.index2 = j; 
       el.set(v); 
       writer.append(indexPair, el); 
      } 
     } 
    } 
    writer.close(); 
} 

将注释插入内部for循环的第二行。

由于输入文件不包含0,因此您的映射器读取的编号为0。

该代码的重点在于假定所有缺失值都为0,并且执行额外的检查以避免发射0,以尝试最小化网络流量。

下面的一切这里大多是错误的,因为我误解了算法
(以上部分仍然是有用的,虽然)

从链接页面,您正在使用的策略3.策略3依赖关于分区行为和排序顺序。不幸的是,分区是错误的!这与0不打印出来是分开的。分区器在这里只是简单的错误,而且你得到的矩阵是满了0的,因为它乘以之前被初始化为0的数据,并且从未被该块的正确数据覆盖。这在单机操作中是隐藏的,因为分区器是空操作,但在大多数集群中都会中断。

分区器映射中间密钥(KB,JB,IB)的减速器R作为如下:

r = (jb*KB + kb) mod R

它需要保证对于相同块中的所有按键被分配给相同的减速器。不幸的是,它保证这不会发生,除非KB % numReducers == 0

map (key, value) 
    if from matrix A with key=(i,k) and value=a(i,k) 
     for 0 <= jb < NJB 
     emit (k/KB, jb, i/IB), (i mod IB, k mod KB, a(k,j)) // compare this... 
    if from matrix B with key=(k,j) and value=b(k,j) 
     emit (k/KB, j/JB, -1), (k mod KB, j mod KB, b(k,j)) // ...to this 

对于矩阵A,关键JB被重复。对于矩阵B,正在计算密钥jb。由于对reducer的赋值是round-robin,因此保证将A矩阵键将而不是分配给与B矩阵键相同的reducer。因此,该算法失败了,因为它假设了关于密钥分配和排序的一些证明是不正确的。关键顺序是正确的,当且仅当有一个reducer分配了所有的键,但分区错误!

的分区必须修改为使用kb % numReducers的战略3.这是不是一个很好的分区,但它仅仅是将工作,因为需要不相同的密钥在一个特定的被分拣到相同的减速分区程序订购。

您实际上将问题放在问题中的代码与错误实际存在的位置无关。

+0

非常感谢你的回复。我明天会去实验室,看看它是否有效,我会让你知道:) – Chaos 2012-03-21 04:37:52

+1

@shailesh,不要花太多时间在上面 - 我只是意识到我错了。关键参数是块,并且需要将A矩阵块分配给每个对应的B矩阵块,因此迭代是适当的;它是1:1的关系,而不是范围关系。我现在怀疑这与行初始化由于在预期位置没有块而被跳过有关,但我必须再试一次。我对分区器的回答是错误的,尽管0检测站立了。尝试删除非零检查并找出会发生什么? – 2012-03-21 06:07:40

+0

是的,你是对的非零检查是正确的,我删除了它,它工作得很好!我不敢相信我忽略了这样一个简单的错误!非常感谢您指出:)。 – Chaos 2012-03-21 19:34:38