Умножение матриц Hadoop - PullRequest
       20

Умножение матриц Hadoop

5 голосов
/ 14 марта 2012

Я запускал программу MapReduce Matrix Multiplication, найденную в http://www.norstad.org/matrix-multiply/index.html. Я обнаружил, что эта реализация не работает должным образом, когда во входных матрицах присутствуют 0.Но я не понимаю, почему и как мне изменить программу, чтобы она работала?Операция MapReduce завершается, но на выходе всегда есть матрица со всеми элементами 0.

Мои входные матрицы 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 как файлы последовательности, и выходные данные также являются файлом последовательности.Может кто-то пролить свет на проблему?Спасибо!

Код для класса Mapper приведен ниже:

/** 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 Ответ

3 голосов
/ 21 марта 2012

В 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.

Ваш маппер не читает 0s, потому что ваши входные файлы не содержат 0s.

Код разработан так, чтобы предполагать, чтовсе отсутствующие значения равны 0, и он выполняет дополнительные проверки, чтобы избежать выброса 0, чтобы попытаться минимизировать сетевой трафик.

Здесь все в основном неправильно, потому что я неправильно понял алгоритм
(хотя приведенная выше часть все еще полезна)

Изна связанной странице вы используете стратегию 3. Стратегия 3 основана на поведении разделителя и порядке сортировки.К сожалению, разделитель не так!Это отдельно от 0 не распечатывается.Разделитель здесь просто неверен, и вы получаете матрицы, полные 0, потому что он умножается на данные, которые ранее были инициализированы равными 0 и никогда не перезаписываются правильными данными для блока.Это скрыто при работе на 1 машине, поскольку разделитель является нулевой операцией, но в большинстве кластеров разрывается.

Разделитель отображает промежуточный ключ (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.Поскольку присвоение редуктору является циклическим, это гарантирует , что ключи A-матрицы будут , а не назначаться тому же редуктору, что и ключи B-матрицы.Поэтому алгоритм терпит неудачу, так как он предполагает что-то о назначении и упорядочении ключей, что доказуемо неверно.Это верно в отношении порядка ключей, если и только если существует один редуктор, которому назначены все ключи, но разделитель неверен!

Разделитель должен быть модифицирован для использования kb % numReducers для Стратегии 3. Это неочень хороший разделитель, но это единственный разделитель, который будет работать, потому что неидентичные ключи должны быть отсортированы по одному и тому же редуктору в определенном порядке.

Код, который вы фактически поместили в вопрос, не имеет отношениятуда, где ошибка действительно существует.

...