Donnerstag , 21 März 2019

MapReduce Entwurfsmuster – Numerische Aggregation (Min/Max/Count)

MapReduce Entwurfsmuster - Einfache AggregationIn den letzten Monaten ist es leider etwas ruhig auf meinem Blog geworden, was zum größten Teil an meinem neuen Freizeitprojekt – den Azure Management Apps – lag.
Um diese Stille zu durchbrechen, möchte ich eine kleine Serie mit MapReduce Entwurfsmustern für Microsoft HDInsight starten…

Beginnen möchte ich mit einem sehr einfachen Entwurfsmustern aus dem Bereich "Numerische Aggregation".

Hierbei werden die Datensätze nach einem bestimmtem Feld gruppiert und Aggregate von einem oder mehreren anderen Feldern gebildet.
Beispiele für diese Aggregate sind Summen, Standardabweichungen, das Zählen von Datensätzen, Mindest-, Maximal-, Median- oder Durchschnittswerte.

 

Voraussetzungen

Das hier vorgestellt Entwurfsmuster kann genutzt werden, wenn folgende Voraussetzungen erfüllt sind:

  • Es handelt sich um numerische Daten
  • Die Daten können nach einem bestimmten Feld gruppiert werden

 

Musterstruktur

  • Mapper
    Die Mapper-Funktion gibt bei diesem Entwurfsmuster als Key das Feld zurück, nachdem gruppiert werden soll, und als Value eine Liste der zu aggregierenden Felder.
  • Combiner
    Die Combiner-Funktion stellt hier eine ideale Möglichkeit bereit die gesammelten Werte vorzuaggregieren. Somit wird der Datentransfer zwischen den Clusterknoten minimiert.
  • Partitioner
    Bei besonders riesigen, unausgewogenen Datenmengen können Numerische Aggregationen durch den Einsatz eines benutzerdefinierten Partitioners profitieren.
    Dieser muss dann die Daten möglichst gleichmäßig auf die Reducer verteilen.
    Da diese Art von Datenquellen allerdings recht selten vorkommen, ist in den meisten Fällen der damit erreichte Zeitvorteil sehr gering.
  • Reducer
    Die Reducer-Funktion führt dann die eigentlichen Aggregationen durch und gibt als Key das Feld nachdem gruppiert wurde, und als Value die Liste der aggregierten Felder zurück.

 

Mögliche Einsatzszenarien

  • Wörter Zählen
    Wörter Zählen – das "Hello World"-Beispiel von MapReduce – ist eine Numerische Aggregation.
    Hier splittet die Mapper-Funktion die vorhandenen Texte in ihre einzelnen Wörter auf und gibt jedes Wort als Key und eine "1" als Value zurück.
    Die Combiner- und Reducer-Funktion summiert diese Values anschließend auf.
  • Anzahl von Datensätzen 
    Ein oft genutztes Verfahren, um ein besseres Verständnis für die Datenmengen in einem bestimmten Intervall zu erhalten, wie beispielsweise Wöchentlich, Täglich, Stündlich, etc..
  • Min. / Max. / Anzahl
    Mit dem zusätzlichen Mindest- und Maximalwert können auch dynamische Intervalle dargestellt werden, wie beispielsweise das Datum des erster und letzten Forumbeitrags eines Benutzers und die Gesamtzahl der Beiträge in diesem Zeitfenster.
  • Durchschnitt / Medianwert / Standardabweichung
    Die Implementierung dieser drei Werteberechnungen ist nicht ganz so trivial wie bei den vorangegangenen Beispielen.
    Der Einsatz einer Combiner-Funktion ist zwar möglich, macht allerdings der Algorithmus komplexer.
    Dazu mehr in den kommenden Blog Posts. 

 

Hinweise zu den Beispielen dieser Artikelserie

Wenn immer möglich nutze ich Visual Studio und C# für die Beispiele dieser Artikelserie.
In besonderen Fällen, wie beispielsweise bei der Erstellung von benutzerdefinierten Partitionern oder der Nutzung von besonderen Hadoop-Eigenschaften, werde ich auf Java zurückgreifen.

Als Datenbasis verwende ich einen Auszug von Stack Overflow der hier heruntergeladen werden kann.
Diese Daten stehen unter der Creative Commons BY-SA 3.0 Lizenz.

Zur Vereinfachung habe ich die Algorithmen zusammen mit der jeweiligen Job-Konfiguration in gemeinsame Konsolenprojekte gepackt.
In der Praxis sollten die Algorithmen in separate Klassenbibliotheken eingebettet werden.

Um Boilerplate-Code für die Nutzung des Hadoop-Streaming-APIs zu vermeiden, nutze ich das NuGet Package Microsoft .NET Map Reduce API For Hadoop.

Den Source Code werde ich auf hier auf GitHub veröffentlichen.

 

Beispiel "Min / Max / Count"

Das erste Code-Beispiele berechnet die Anzahl der Kommentare pro Benutzer in einem dynamischen Zeitintervall.

Hierzu extrahiert die Mapper-Funktion die Werte für UserId und CreationDate aus der XML-Quelle und gibt diese als Key/Value-Paare zurück:

Um einen eleganten Weg aufzuzeigen, wie man mit dem NuGet Package Microsoft .NET Map Reduce API For Hadoop auch komplexe Datenstrukturen übertragen kann, habe ich statt der üblichen MapperBase-Klasse diesmal von der JsonOutMapperBase-Klasse abgeleitet.

Diese bietet eine automatische Serialisierung ins JSON-Format an (Üblich wäre eine einfache Wertetrennung mittels Tabs).

Die hierbei verwendete Datenklasse sieht dabei wie folgt aus:

Die Combiner- und Reducer-Funktionen aggregieren anschließend die entsprechenden Werte.

Um die Daten später weiterverarbeiten zu können, gebe ich die Werte beim Reducer wieder im üblichen Tab-getrennten Format zurück.

Ausführen im Hadoop Emulator

Um jetzt den Code im lokalen Hadoop Emulator auszuführen, kann zum Einen die im NuGet-Package mitgelieferte MRRunner.exe genutzt oder zum Anderen eine Konsolenapplikation erstellt werden: