Einfache Erklärung von MapReduce?

166

Bezogen auf meine CouchDB- Frage.

Kann jemand MapReduce mit Begriffen erklären, die eine Nummer verstehen könnte?

reefnet_alex
quelle
3
Und hier ist meine Meinung dazu: MapReduce für und mit den Kindern .
Michael Hausenblas
@MichaelHausenblas - Ich liebe dein Beispiel: leicht verständlich und lustig für die ganze Familie.
Lee
Joel Spolsky hat eine gute Erklärung für Anfänger - joelonsoftware.com/items/2006/08/01.html
user2314737

Antworten:

187

Gehen Sie bis zu den Grundlagen für Map und Reduce.


Map ist eine Funktion, die Elemente in einer Art Liste in eine andere Art von Element "umwandelt" und sie wieder in dieselbe Art von Liste einfügt.

Angenommen, ich habe eine Liste von Zahlen: [1,2,3] und ich möchte jede Zahl verdoppeln. In diesem Fall ist die Funktion "jede Zahl verdoppeln" die Funktion x = x * 2. Und ohne Zuordnungen könnte ich schreiben eine einfache Schleife, sagen wir

A = [1, 2, 3]
foreach (item in A) A[item] = A[item] * 2

und ich hätte A = [2, 4, 6], aber anstatt Schleifen zu schreiben, könnte ich schreiben, wenn ich eine Kartenfunktion hätte

A = [1, 2, 3].Map(x => x * 2)

x => x * 2 ist eine Funktion, die für die Elemente in [1,2,3] ausgeführt werden soll. Was passiert ist, dass das Programm jedes Element nimmt, es ausführt (x => x * 2), indem es x gleich jedem Element macht und eine Liste der Ergebnisse erstellt.

1 : 1 => 1 * 2 : 2  
2 : 2 => 2 * 2 : 4  
3 : 3 => 3 * 2 : 6  

Nach dem Ausführen der Kartenfunktion mit (x => x * 2) hätten Sie also [2, 4, 6].


Reduzieren ist eine Funktion, die die Elemente in Listen "sammelt" und für alle Berechnungen durchführt , um sie auf einen einzigen Wert zu reduzieren.

Das Finden einer Summe oder das Finden von Durchschnittswerten sind alle Fälle einer Reduktionsfunktion. Wenn Sie beispielsweise eine Liste mit Zahlen haben, z. B. [7, 8, 9], und möchten, dass diese zusammengefasst werden, schreiben Sie eine Schleife wie diese

A = [7, 8, 9]
sum = 0
foreach (item in A) sum = sum + A[item]

Wenn Sie jedoch Zugriff auf eine Reduzierungsfunktion haben, können Sie diese so schreiben

A = [7, 8, 9]
sum = A.reduce( 0, (x, y) => x + y )

Jetzt ist es etwas verwirrend, warum 2 Argumente (0 und die Funktion mit x und y) übergeben wurden. Damit eine Reduzierungsfunktion nützlich ist, muss sie in der Lage sein, 2 Elemente zu nehmen, etwas zu berechnen und diese 2 Elemente auf nur einen einzigen Wert zu "reduzieren". Daher kann das Programm jedes Paar reduzieren, bis wir einen einzelnen Wert haben.

Die Ausführung würde folgen:

result = 0
7 : result = result + 7 = 0 + 7 = 7
8 : result = result + 8 = 7 + 8 = 15
9 : result = result + 9 = 15 + 9 = 24

Sie möchten jedoch nicht immer mit Nullen beginnen. Mit dem ersten Argument können Sie einen Startwert angeben, insbesondere den Wert in der ersten result =Zeile.

Angenommen, Sie möchten 2 Listen zusammenfassen, es könnte folgendermaßen aussehen:

A = [7, 8, 9]
B = [1, 2, 3]
sum = 0
sum = A.reduce( sum, (x, y) => x + y )
sum = B.reduce( sum, (x, y) => x + y )

oder eine Version, die Sie in der realen Welt eher finden würden:

A = [7, 8, 9]
B = [1, 2, 3]

sum_func = (x, y) => x + y
sum = A.reduce( B.reduce( 0, sum_func ), sum_func )

Dies ist eine gute Sache in einer DB-Software, da Sie mit der Unterstützung von Map \ Reduce mit der Datenbank arbeiten können, ohne wissen zu müssen, wie die Daten in einer DB gespeichert sind, um sie zu verwenden. Dafür ist eine DB-Engine gedacht.

Sie müssen nur in der Lage sein, der Engine zu "sagen", was Sie wollen, indem Sie ihnen entweder eine Map- oder eine Reduce-Funktion zur Verfügung stellen. Dann kann die DB-Engine die Daten umgehen, Ihre Funktion anwenden und die gewünschten Ergebnisse erzielen Ich möchte alles, ohne dass Sie wissen, wie es alle Datensätze durchläuft.

Es gibt Indizes und Schlüssel sowie Verknüpfungen und Ansichten und viele Dinge, die eine einzelne Datenbank enthalten könnte. Indem Sie sich also vor der tatsächlichen Speicherung der Daten schützen, wird das Schreiben und Verwalten Ihres Codes erleichtert.

Gleiches gilt für die parallele Programmierung. Wenn Sie nur angeben, was Sie mit den Daten tun möchten, anstatt den Schleifencode tatsächlich zu implementieren, kann die zugrunde liegende Infrastruktur Ihre Funktion "parallelisieren" und in einer simultanen parallelen Schleife für Sie ausführen.

Chakrit
quelle
Ok, ich verstehe die Karte und reduziere individuell genommen. Aber welche Anwendungen könnte ich von der Reduzierung haben? Würden sie es in einem Google-Szenario beispielsweise zum Summieren einer Reihe von Parametern verwenden, die ihnen das Ranking einer Seite für ein bestimmtes Keyword geben?
Lorenzo
@lbolognini var total = orderes.Sum (o => o.UnitPrice * o.Quantity)
Chakrit
@lbolognini Es gibt viele Verwendungszwecke, wenn Sie das Konzept der Schleife abstrahieren. In Googles Szenario haben sie wahrscheinlich Tausende von Maschinen zum Berechnen von Pageranks, Links und so weiter. Was tun sie, wenn sie ein paar weitere Server hinzufügen müssen? Das Ändern jedes einzelnen Schleifencodes ist wahrscheinlich keine Option. Sie haben also stattdessen ihren Berechnungscode für eine "Reduzieren" -Funktion geschrieben ... Und wenn sich die Liste der Server ändert, muss nur die "Reduzieren" -Funktion geändert werden. Verstanden?
Chakrit
Wie würde sich die Berechnung des Durchschnitts verringern? Nach allem, was ich sehe, schätze ich, dass du es nicht konntest? Vielleicht den Zähler und den Nenner abbilden und am Ende der Summierung beider teilen?
andyczerwonka
@arcticpenguin Ich bin dort etwas zu generisch. Eigentlich Average()ist angeblich Sahnehäubchen auf Sum(). Aber ich habe darüber gesprochen, um zu veranschaulichen, warum die Funktion "Reduzieren" heißt ... Eine Durchschnittsfunktion ist etwas, das eine Liste von Zahlen auf eine einzelne Zahl (die der Durchschnitt ist) reduziert .
Chakrit
60

MapReduce ist eine Methode, um große Datenmengen parallel zu verarbeiten, ohne dass der Entwickler einen anderen Code als den Mapper schreiben und Funktionen reduzieren muss.

Die Kartenfunktion nimmt Daten auf und gibt ein Ergebnis aus, das in einer Barriere gehalten wird. Diese Funktion kann parallel zu einer großen Anzahl derselben Kartenaufgabe ausgeführt werden . Der Datensatz kann dann auf einen Skalarwert reduziert werden.

Wenn Sie es sich also wie eine SQL-Anweisung vorstellen

SELECT SUM(salary)
FROM employees
WHERE salary > 1000
GROUP by deptname

Wir können die Karte verwenden , um unsere Untergruppe von Mitarbeitern mit einem Gehalt> 1000 zu erhalten, die die Karte in Gruppengrößen-Eimern an die Barriere abgibt.

Reduzieren summiert jede dieser Gruppen. Geben Sie Ihre Ergebnismenge.

nur gepflückt aus meiner Universität Studie stellt fest von dem Google - Papier

Johnno Nolan
quelle
33
  1. Nehmen Sie eine Menge Daten
  2. Führen Sie eine Transformation durch, die jedes Datum in eine andere Art von Datum konvertiert
  3. Kombinieren Sie diese neuen Daten zu noch einfacheren Daten

Schritt 2 ist Karte. Schritt 3 ist Reduzieren.

Beispielsweise,

  1. Holen Sie sich Zeit zwischen zwei Impulsen auf einem Paar Druckmesser auf der Straße
  2. Ordnen Sie diese Zeiten basierend auf der Entfernung der Meter Geschwindigkeiten zu
  3. Reduzieren Sie diese Geschwindigkeiten auf eine Durchschnittsgeschwindigkeit

Der Grund, warum MapReduce zwischen Map und Reduce aufgeteilt wird, liegt darin, dass verschiedene Teile problemlos parallel ausgeführt werden können. (Besonders wenn Reduzieren bestimmte mathematische Eigenschaften hat.)

Eine komplexe, aber gute Beschreibung von MapReduce finden Sie unter: Google MapReduce-Programmiermodell - überarbeitet (PDF) .

Frank Krueger
quelle
1
Ich würde für Schritt 3 sagen, "kombinieren" statt "transformieren"
TraumaPony
Zum ersten Mal sind drei Antworten zusammen die BESTE Antwort. Lesen Sie zuerst Nassers Artikel-Link (theoretisches Hi-Level) Dann Chakrits Antwort (individuelle Erklärung der Kartenreduzierung) Jetzt Franks Antwort (Was ist die berühmte MapReduce-Redewendung.) Vielen Dank an Sie drei. :)
Ajeet Ganga
20

MAP und REDUCE sind alte Lisp-Funktionen aus einer Zeit, als der Mensch die letzten Dinosaurier getötet hat.

Stellen Sie sich vor, Sie haben eine Liste von Städten mit Informationen über den Namen, die Anzahl der dort lebenden Personen und die Größe der Stadt:

(defparameter *cities*
  '((a :people 100000 :size 200)
    (b :people 200000 :size 300)
    (c :people 150000 :size 210)))

Jetzt möchten Sie vielleicht die Stadt mit der höchsten Bevölkerungsdichte finden.

Zuerst erstellen wir mit MAP eine Liste der Städtenamen und der Bevölkerungsdichte:

(map 'list
     (lambda (city)
         (list (first city)
               (/ (getf (rest city) :people)
                  (getf (rest city) :size))))
     *cities*)

=>   ((A 500) (B 2000/3) (C 5000/7))

Mit REDUCE können wir nun die Stadt mit der größten Bevölkerungsdichte finden.

(reduce (lambda (a b)
          (if (> (second a) (second b))
             a
             b))
        '((A 500) (B 2000/3) (C 5000/7)))

 =>   (C 5000/7)

Wenn wir beide Teile kombinieren, erhalten wir den folgenden Code:

(reduce (lambda (a b)
          (if (> (second a) (second b))
             a
             b))
        (map 'list
             (lambda (city)
                (list (first city)
                   (/ (getf (rest city) :people)
                      (getf (rest city) :size))))
             *cities*))

Lassen Sie uns Funktionen einführen:

(defun density (city)
   (list (first city)
         (/ (getf (rest city) :people)
            (getf (rest city) :size))))

(defun max-density (a b)
   (if (> (second a) (second b))
          a
          b))

Dann können wir unseren MAP REDUCE-Code wie folgt schreiben:

(reduce 'max-density
        (map 'list 'density *cities*))

 =>   (C 5000/7)

Es ruft auf MAPund REDUCE(Auswertung ist von innen nach außen), daher heißt es Kartenreduzierung .

Rainer Joswig
quelle
@MoMolog: Die Funktion MAX existiert bereits und macht etwas anderes. Auch: man sollte MAX nicht neu definieren.
Rainer Joswig
max-densityvergleicht das zweite Element der übergebenen Argumente, richtig? Entschuldigung für die dumme Bearbeitung.
Alexander Presber
@ MoMolog: Ja, es ist das zweite Element und das ist nur im Kontext dieses kleinen Beispiels nützlich. Der Code ist auch absichtlich in etwas altmodischem Lisp mit Listen als Datenstrukturen geschrieben ...
Rainer Joswig
17

Nehmen wir das Beispiel aus dem Google-Artikel . Das Ziel von MapReduce ist es, eine Vielzahl von Prozessoreinheiten, die parallel zu einer Art von Algorithmen arbeiten, effizient nutzen zu können. Das Beispiel lautet wie folgt: Sie möchten alle Wörter und ihre Anzahl in einer Reihe von Dokumenten extrahieren.

Typische Implementierung:

for each document
    for each word in the document
        get the counter associated to the word for the document
        increment that counter 
    end for
end for

MapReduce-Implementierung:

Map phase (input: document key, document)
for each word in the document
    emit an event with the word as the key and the value "1"
end for

Reduce phase (input: key (a word), an iterator going through the emitted values)
for each value in the iterator
    sum up the value in a counter
end for

Um das herum haben Sie ein Master-Programm, das den Satz von Dokumenten in "Splits" unterteilt, die für die Map-Phase parallel behandelt werden. Die ausgegebenen Werte werden vom Worker in einen für den Worker spezifischen Puffer geschrieben. Das Master-Programm delegiert dann andere Mitarbeiter an die Durchführung der Reduzierungsphase, sobald benachrichtigt wird, dass der Puffer zur Bearbeitung bereit ist.

Jede Worker-Ausgabe (als Map- oder Reduce-Worker) ist eine Datei, die im verteilten Dateisystem (GFS für Google) oder in der verteilten Datenbank für CouchDB gespeichert ist.

Damien B.
quelle
10

Eine wirklich einfache , schnelle und "für Dummies" Einführung in MapReduce finden Sie unter: http://www.marcolotz.com/?p=67

Einige Inhalte veröffentlichen:

Warum wurde MapReduce ursprünglich erstellt?

Grundsätzlich benötigte Google eine Lösung, mit der große Rechenaufträge einfach parallelisiert werden können, sodass Daten auf mehreren Computern verteilt werden können, die über ein Netzwerk verbunden sind. Abgesehen davon musste es den Maschinenausfall auf transparente Weise behandeln und Lastausgleichsprobleme verwalten.

Was sind die wahren Stärken von MapReduce?

Man kann sagen, dass MapReduce Magic auf der Map and Reduce-Funktionsanwendung basiert. Ich muss Kumpel gestehen, dass ich überhaupt nicht einverstanden bin. Das Hauptmerkmal, das MapReduce so beliebt gemacht hat, ist die Fähigkeit zur automatischen Parallelisierung und Verteilung in Kombination mit der einfachen Benutzeroberfläche. Dieser Faktor, summiert mit einer transparenten Fehlerbehandlung für die meisten Fehler, machte dieses Framework so beliebt.

Etwas mehr Tiefe auf dem Papier:

MapReduce wurde ursprünglich in einem Google-Artikel (Dean & Ghemawat, 2004 - Link hier) als Lösung für Berechnungen in Big Data unter Verwendung eines parallelen Ansatzes und von Commodity-Computer-Clustern erwähnt. Im Gegensatz zu Hadoop, das in Java geschrieben ist, ist das Google-Framework in C ++ geschrieben. Das Dokument beschreibt, wie sich ein paralleles Framework unter Verwendung der Map- und Reduce-Funktionen aus der funktionalen Programmierung über große Datenmengen verhalten würde.

In dieser Lösung gibt es zwei Hauptschritte - Map und Reduce - mit einem optionalen Schritt zwischen dem ersten und dem zweiten - Combine. Der Map-Schritt wird zuerst ausgeführt, Berechnungen im Eingabe-Schlüssel-Wert-Paar durchgeführt und ein neuer Ausgabeschlüssel-Wert generiert. Es ist zu beachten, dass das Format der Eingabe-Schlüssel-Wert-Paare nicht unbedingt mit dem Ausgabeformat-Paar übereinstimmen muss. Der Schritt "Reduzieren" würde alle Werte desselben Schlüssels zusammensetzen und andere Berechnungen darüber durchführen. Infolgedessen würde dieser letzte Schritt Schlüssel-Wert-Paare ausgeben. Eine der trivialsten Anwendungen von MapReduce ist die Implementierung von Wortzahlen.

Der Pseudocode für diese Anwendung ist unten angegeben:

map(String key, String value):

// key: document name
// value: document contents
for each word w in value:
EmitIntermediate(w, “1”);

reduce(String key, Iterator values):

// key: a word
// values: a list of counts
int result = 0;
for each v in values:
    result += ParseInt(v);
Emit(AsString(result));

Wie man sehen kann, liest die Karte alle Wörter in einem Datensatz (in diesem Fall kann ein Datensatz eine Zeile sein) und gibt das Wort als Schlüssel und die Nummer 1 als Wert aus. Später gruppiert die Reduzierung alle Werte desselben Schlüssels. Geben wir ein Beispiel: Stellen Sie sich vor, das Wort "Haus" kommt dreimal in der Aufzeichnung vor. Der Eingang des Reduzierers wäre [Haus, [1,1,1]]. Im Reduzierer werden alle Werte für das Schlüsselhaus summiert und als Ausgabe der folgende Schlüsselwert angegeben: [Haus, [3]].

Hier ist ein Bild davon, wie dies in einem MapReduce-Framework aussehen würde:

Bild aus dem Original MapReduce Google-Papier

Als einige andere klassische Beispiele für MapReduce-Anwendungen kann man sagen:

• Anzahl der URL-Zugriffshäufigkeiten

• Weblink-Diagramm umkehren

• Verteiltes Grep

• Termvektor pro Host

Um zu viel Netzwerkverkehr zu vermeiden, wird in diesem Dokument beschrieben, wie das Framework versuchen sollte, die Datenlokalität beizubehalten. Dies bedeutet, dass immer versucht werden sollte, sicherzustellen, dass auf einem Computer, auf dem Map-Jobs ausgeführt werden, die Daten in seinem Speicher / lokalen Speicher gespeichert sind, um zu vermeiden, dass sie aus dem Netzwerk abgerufen werden. Mit dem Ziel, das Netzwerk durch Setzen eines Mappers zu reduzieren, wird der zuvor beschriebene optionale Kombinationsschritt verwendet. Der Combiner führt Berechnungen für die Ausgabe der Mapper in einer bestimmten Maschine durch, bevor er sie an die Reduzierer sendet - möglicherweise in einer anderen Maschine.

Das Dokument beschreibt auch, wie sich die Elemente des Frameworks im Fehlerfall verhalten sollen. Diese Elemente werden im Papier als Arbeiter und Meister bezeichnet. Sie werden in Open-Source-Implementierungen in spezifischere Elemente unterteilt. Da Google den Ansatz nur in dem Artikel beschrieben und seine proprietäre Software nicht veröffentlicht hat, wurden viele Open-Source-Frameworks erstellt, um das Modell zu implementieren. Als Beispiele kann man Hadoop oder die eingeschränkte MapReduce-Funktion in MongoDB nennen.

Die Laufzeit sollte sich um Details von Nicht-Experten-Programmierern kümmern, wie das Partitionieren der Eingabedaten, das Planen der Programmausführung auf eine große Anzahl von Maschinen, das Behandeln von Maschinenfehlern (natürlich auf transparente Weise) und das Verwalten der Kommunikation zwischen Maschinen . Ein erfahrener Benutzer kann diese Parameter so einstellen, wie die Eingabedaten zwischen Arbeitern aufgeteilt werden.

Schlüssel Konzepte:

Fehlertoleranz:Es muss einen Maschinenausfall ordnungsgemäß tolerieren. Um dies durchzuführen, pingt der Meister die Arbeiter regelmäßig an. Wenn der Master in einem bestimmten Zeitraum keine Antworten von einem bestimmten Mitarbeiter erhält, definiert der Master die Arbeit als in diesem Mitarbeiter fehlgeschlagen. In diesem Fall werden alle vom fehlerhaften Arbeiter ausgeführten Kartenaufgaben weggeworfen und an einen anderen verfügbaren Arbeiter übergeben. Ähnliches passiert, wenn der Worker noch eine Karte oder eine Reduzierungsaufgabe verarbeitet hat. Beachten Sie, dass, wenn der Worker seinen Reduktionsteil bereits abgeschlossen hat, die gesamte Berechnung zum Zeitpunkt des Fehlschlags bereits abgeschlossen war und nicht zurückgesetzt werden muss. Als primärer Fehlerpunkt schlägt der gesamte Job fehl, wenn der Master ausfällt. Aus diesem Grund kann man periodische Prüfpunkte für den Master definieren, um dessen Datenstruktur zu speichern.

Lokalität: Um Netzwerkverkehr zu vermeiden, versucht das Framework sicherzustellen, dass alle Eingabedaten lokal für die Computer verfügbar sind, die Berechnungen auf ihnen durchführen werden. In der ursprünglichen Beschreibung wird Google File System (GFS) mit einem Replikationsfaktor von 3 und einer Blockgröße von 64 MB verwendet. Dies bedeutet, dass derselbe Block von 64 MB (der eine Datei im Dateisystem erstellt) identische Kopien auf drei verschiedenen Computern enthält. Der Master weiß, wo sich die Blöcke befinden, und versucht, Kartenjobs auf diesem Computer zu planen. Wenn dies fehlschlägt, versucht der Master, einen Computer in der Nähe eines Replikats der Eingabedaten für Aufgaben zuzuweisen (dh einen Arbeitscomputer im selben Rack des Datencomputers).

Aufgabengranularität: Unter der Annahme, dass jede Kartenphase in M ​​Teile und jede Reduzierungsphase in R Teile unterteilt ist, wäre das Ideal, dass M und R viel größer sind als die Anzahl der Arbeitsmaschinen. Dies liegt an der Tatsache, dass ein Mitarbeiter, der viele verschiedene Aufgaben ausführt, den dynamischen Lastausgleich verbessert. Abgesehen davon erhöht es die Wiederherstellungsgeschwindigkeit im Falle eines Worker-Ausfalls (da die vielen Map-Aufgaben, die es ausgeführt hat, auf alle anderen Computer verteilt werden können).

Sicherungsaufgaben: Manchmal verhält sich ein Map- oder Reducer-Worker viel langsamer als die anderen im Cluster. Dies kann die Gesamtverarbeitungszeit halten und sie gleich der Verarbeitungszeit dieser einzelnen langsamen Maschine machen. Das Originalpapier beschreibt eine Alternative namens Sicherungsaufgaben, die vom Master geplant werden, wenn ein MapReduce-Vorgang kurz vor dem Abschluss steht. Dies sind Aufgaben, die vom Master der laufenden Aufgaben geplant werden. Somit wird der MapReduce-Vorgang abgeschlossen, wenn die primäre oder die Sicherung abgeschlossen ist.

Zähler: Manchmal möchte man Ereignisse zählen. Aus diesem Grund wird gezählt, wo erstellt. Die Zählerwerte in jedem Arbeiter werden regelmäßig an den Master weitergegeben. Der Master aggregiert dann die Zählerwerte einer erfolgreichen Karte und reduziert sie und gibt sie an den Benutzercode zurück, wenn der MapReduce-Vorgang abgeschlossen ist. Im Master-Status ist auch ein aktueller Zählerwert verfügbar, sodass ein Mensch, der den Prozess beobachtet, verfolgen kann, wie er sich verhält.

Nun, ich denke, mit all den oben genannten Konzepten wird Hadoop ein Kinderspiel für Sie sein. Wenn Sie Fragen zum ursprünglichen MapReduce-Artikel oder zu verwandten Themen haben, lassen Sie es mich bitte wissen.

Prometheus
quelle
4

Ich möchte nicht banal klingen, aber das hat mir sehr geholfen und es ist ziemlich einfach:

cat input | map | reduce > output
Mike Dewar
quelle
4

Wenn Sie mit Python vertraut sind, finden Sie im Folgenden die einfachste Erklärung für MapReduce:

In [2]: data = [1, 2, 3, 4, 5, 6]
In [3]: mapped_result = map(lambda x: x*2, data)

In [4]: mapped_result
Out[4]: [2, 4, 6, 8, 10, 12]

In [10]: final_result = reduce(lambda x, y: x+y, mapped_result)

In [11]: final_result
Out[11]: 42

Sehen Sie, wie jedes Segment der Rohdaten einzeln verarbeitet wurde, in diesem Fall multipliziert mit 2 (der Kartenteil von MapReduce). Basierend auf dem mapped_resultkamen wir zu dem Schluss, dass das Ergebnis 42(der reduzierte Teil von MapReduce) sein würde.

Eine wichtige Schlussfolgerung aus diesem Beispiel ist die Tatsache, dass jeder Verarbeitungsblock nicht von einem anderen Block abhängt. Wenn beispielsweise thread_1Maps [1, 2, 3]und thread_2Maps [4, 5, 6]das endgültige Ergebnis beider Threads sind, ist dies immer noch der Fall, [2, 4, 6, 8, 10, 12]aber wir haben die Verarbeitungszeit dafür halbiert . Das Gleiche gilt für den Reduktionsvorgang und ist die Essenz der Funktionsweise von MapReduce beim parallelen Rechnen.

Rafay
quelle