Freitag, 18. Dezember 2015

Akka.NET Adventskalender – Tür 18

Wenn's mal ganz heftig wird

Sicher hast Du schon einmal von "Map/Reduce" gehört – mir ist der Begriff auch vor ein paar Tagen rausgerutscht. Erfunden wurde der Algorithmus von Google mit dem Ziel, große Datenmengen auf verteilten Systemen verarbeiten zu können. Eine zentrale Instanz kümmert sich um die Partitionierung und Verteilung der Daten sowie der Sammlung der Ergebnisse sowie um die Überwachung aller Beteiligten.

Wie funktioniert Map/Reduce?

Der erste Schritt, "Map" genannt, erzeugt aus den Rohdaten eine Liste mit Schlüsseln und einem Wert, der später von Bedeutung ist. Der Wert kann im einfachsten Fall die Zahl "1" sein. Die Mächtigkeit der Liste kann hierbei sehr groß sein. Unter Umständen kann sogar ein Rohdatensatz mehrere Werte erzeugen (z.B. wenn man sich für Vokale in Worten interessiert könnte das Wort "Eisenbahnschiene" die Liste {e,4}, {i,2}, {a,1} produzieren).

Diese Liste wird dann im "Reduce" Schritt nach den Schlüsseln der ersten Liste gruppiert und mit den Werten eine vorher festgelegte Operation ausgeführt (z.B. Summierung). Das Ergebnis ist wieder eine Liste mit so vielen Einträgen, wie es unterschiedliche Schlüssel gibt. Aus unserem obigen Vokal-Beispiel würde dann eine Liste mit nur den 5 Schlüsseln "a,e,i,o,u" und der entsprechenden Summe der Anzahlen werden.

Sowohl der "Map", als auch der "Reduce" Schritt kann auf Teilmengen der (großen) Original-Daten operieren und auf beliebig viele Systeme verteilt werden. Auf diese Weise lassen sich solche Aufgaben trotz der großen Datenmengen im Vergleich zu iterativen Ansätzen, die nur auf einer Maschine laufen, in deutlich kürzeren Zeiten abwickeln.

Was wollen wir analysieren?

Das kleine Map/Reduce Projekt, das wir anlegen werden, soll folgende Aufgaben erfüllen:

  • Aus einer großen Anzahl von Text Dokumenten (wir haben ein Dokument pro Stadt) extrahieren wir Zeilen, die aus Werten für Firmen-Name, Name eines Entwicklers und der von ihm benutzbaren Programmiersprache. Spricht ein Entwickler mehrere Sprachen, existieren mehrere Zeilen für ihn. Und besitzt eine Firma mehrere Entwickler, wiederholen sich die Zeilen ebenfalls.
  • Der "Map" Schritt bekommt diese Zeilen und erzeugt eine Liste aus {Sprache, 1} Tupeln.
  • Der "Reduce" Schritt gruppiert die Liste nach Sprache und summiert die Zahlen hoch.
  • Der Aggregator (unsere zentrale Instanz) erhält die Liste, die der Reduce-Schritt erzeugt hat und fasst beliebig viele davon zu einer Liste zusammen.
  • Das Ergebnis ist eine Übersicht, welche Programmiersprachen von wie vielen Entwicklern gesprochen wird.
Heute werden wir unsere Umgebung aufsetzen und das Gerüst unserer Kommandozeilen Applikation erstellen. (Pssst: Du kannst aber auch bis übermorgen warten, dann gibt es wieder ein git Repository).

Damit die Anwendung einfach und ohne problematische Pfad Handhabung zwischen Windows und *nix portierbar wird, habe ich die "Dateien" als statische Methoden in die Applikation eingebaut. die viel gepriesenen großen Datenmengen werden zum Zwecke der Demonstration auch etwas übersichtlicher ausfallen.

using System;
using Akka.Actor;
using MapReduce.Actors;

namespace MapReduce
{
    class MainClass
    {
        public static void Main(string[] args)
        {
            var system = ActorSystem.Create("MapReduce");
            var master = system.ActorOf(Props.Create<Master>());

            master.Tell(Sample1());
            master.Tell(Sample2());

            Console.WriteLine("Press [enter] to continue");
            Console.ReadLine();

            system.Shutdown();
            system.AwaitTermination();
        }

        private static string Sample1()
        {
            return @"
ACME, Inc | Mr. Green | C#
ACME, Inc | Mr. Blue | JavaScript

Facilities | Coolman | Ruby

FastCoders | Speedy | C#

SlowCoders | Snail | Java
";
        }

        private static string Sample2()
        {
            return @"
Foo | Mr. Green | C#
Foo | Mr. Blue | Java
Foo | Mr. Black | C#
Foo | Mr. White | F#

Bla | Coolman | Python
Bla | Catwoman | C#

SlowMovers | Snail | C#
SlowMovers | Snail | F#
";
        }
    }
}

Morgen werden wir die Aktoren für die beiden Haupt-Aufgaben hinzufügen.

Keine Kommentare:

Kommentar veröffentlichen