2012-03-14 13 views
5

Uruchomiłem program MapReduce Matrix Multiplication pod adresem http://www.norstad.org/matrix-multiply/index.html. Dowiedziałem się, że ta implementacja nie działa poprawnie, gdy w macierzy wejściowej są 0. Ale nie rozumiem, dlaczego i jak mogę zmodyfikować program, aby działał? Operacja MapReduce kończy, ale wyjście jest zawsze macierzą ze wszystkimi elementami 0.Mnożenie macierzy Hadoop

Moja wejściowe macierzy A & B są: Matrix

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

wyjściowa:

0 0 0 
0 0 0 
0 0 0 

są następujące pobrane z plików dziennika dla zadania:

Dane wyjściowe mapy dla macierzyB:

##### 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) 

wyjście Mapa dla macierzy 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) 

Należy zauważyć, że mapa dla macierzy A nie czytać zer z pliku wejściowego. Uwaga: oba pliki wejściowe są przechowywane w HDFS jako pliki sekwencji, a dane wyjściowe są również plikami sekwencji. Czy ktoś może rzucić nieco światła na problem? Dzięki!

Kod dla klasy Mapper jest podany poniżej:

/** 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); 
        } 
     } 
    } 
} 

Jeśli są jakieś błędy składniowe, to tylko dlatego, że kopia wklejony kod i modyfikować go tutaj, więc może ja coś przeoczyłem.

Potrzebuję pomocy z logiką funkcji Mapa, która nie odczytuje 0 z pliku wejściowego, czy ktoś może mi powiedzieć, dlaczego?

+1

To więcej niż 700 linii kodu. Czy myślisz, że ktoś będzie przez to debugował? –

+0

Zmodyfikowałem mój post, aby uwzględnić tylko kod klasy mappera. Potrzebuję pomocy z logiką, w tym sensie, że nie jestem w stanie wymyślić wyjaśnienia, dlaczego 0 nie są odczytywane przez plik wejściowy przez funkcję Mapa. – Chaos

+0

@ThomasJungblut - Myślałem, że będziesz promował Hama do mnożenia Matrycy :) –

Odpowiedz

3

W TestMatrixMultiply.java, ze strony internetowej powiązane, który przypuszczalnie zawiera kod używasz zakodować swoje matryce do oczekiwanego IndexPair-backed formacie, jest writeMatrix funkcja:

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(); 
} 

Komentarz wstawiony w drugiej linii wewnętrznej pętli for.

Twój program odwzorowujący nie czyta 0, ponieważ twoje pliki wejściowe nie zawierają wartości 0.

Kod jest mocno zaprojektowany, aby założyć, że wszystkie brakujące wartości wynoszą 0, i wykonuje dodatkowe kontrole w celu uniknięcia emisji 0, aby zminimalizować ruch w sieci.

Wszystko poniżej jest tu przeważnie źle, bo źle algorytmu
(część powyżej jest nadal przydatny, choć)

Od połączonego stronie używasz strategii 3. Strategia opiera 3 na zachowanie partycji i kolejność sortowania. Niestety, partycja jest błędna! Jest to oddzielne od braku drukowania zer. Partycjoner jest tutaj po prostu niepoprawnie błędny, a otrzymujesz macierze pełne 0, ponieważ mnoży się przez dane, które zostały wcześniej zainicjowane na 0 i nigdy nie zostały nadpisane poprawnymi danymi bloku.Jest to ukryte w operacji na 1 komputerze, ponieważ partycja jest operacją pustą, ale zrywa się w większości klastrów.

partycjoner odwzorowuje kluczowy związek pośredni (kb, jb, IB) do reduktora R, jak następuje:

r = (jb*KB + kb) mod R

Wymaga to, aby zagwarantować, że wszystkie klucze o tym samym bloku są przypisane ten sam reduktor. Niestety, to gwarantuje, że tak się nie stanie, chyba 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 

Dla macierzy A, klucz jb jest powtórzyć. Dla macierzy B obliczany jest klucz jb. Ponieważ przypisanie do reduktora odbywa się cyklicznie, to gwarantuje, że klawisze macierzy A będą , a nie przypisane do tego samego reduktora, co klawisze B-macierzy. W związku z tym algorytm się nie powiedzie, ponieważ zakłada coś na temat przydziału i zamawiania kluczy, które są niepoprawnie poprawne. To jest poprawne w odniesieniu do kluczowej kolejności wtedy i tylko wtedy, gdy jest jeden reduktor, do którego przypisane są wszystkie klucze, ale partycja jest błędna!

Partycjoner musi zostać zmodyfikowany, aby używać kb % numReducers dla Strategii 3. Nie jest to dobry partycjonator, ale jest jedynym partycjonerem, który będzie działał, ponieważ nieidentyczne klucze muszą być posortowane do tego samego reduktora w konkretnej partycji. zamówienie.

Kod, który umieściłeś w pytaniu, nie ma związku z miejscem, w którym rzeczywiście istnieje błąd.

+0

Dziękuję bardzo za odpowiedź. Pójdę jutro do laboratorium i sprawdzę, czy to zadziała, a dam ci znać :) – Chaos

+1

@shailesh, nie poświęcajcie na to zbyt dużo czasu - po prostu zdałem sobie sprawę, że się mylę. Kluczowymi parametrami są bloki, a bloki macierzy A muszą być przypisane do każdego odpowiedniego bloku macierzy B, więc iteracja jest właściwa; jest to relacja 1: 1, a nie relacja zasięgu. Teraz podejrzewam, że jest to bardziej związane z inicjalizacją wiersza pomijaną z powodu braku bloku w oczekiwanym miejscu, ale będę musiał spróbować jeszcze raz. Moja odpowiedź na temat partycjonera jest błędna, chociaż wykrywanie 0 stoi. Spróbuj usunąć kontrolę niezerową i dowiedzieć się, co się dzieje? –

+0

Tak, masz rację co do niezerowej kontroli, usunąłem to i działa dobrze! Nie mogę uwierzyć, że przeoczyłem tak prosty błąd! Wielkie dzięki za wskazanie :). – Chaos

Powiązane problemy