Warum müssen Big Data funktionsfähig sein?


9

Ich habe kürzlich angefangen, an einem neuen Projekt für Big Data für mein Praktikum zu arbeiten. Meine Manager empfahlen, mit dem Erlernen der funktionalen Programmierung zu beginnen (sie empfahlen Scala dringend). Ich hatte eine bescheidene Erfahrung mit F #, aber ich konnte nicht erkennen, wie wichtig es ist, dieses Paradigma der Programmierung zu verwenden, da es in einigen Fällen teuer ist.

Dean hielt einen interessanten Vortrag zu diesem Thema und teilte seine Gedanken darüber mit, warum "Big Data" hier ist: http://www.youtube.com/watch?v=DFAdLCqDbLQ Aber es war nicht sehr praktisch, da Big Data nicht bedeutet nur Hadoop.

Als BigData ist das Konzept sehr vage. Ich vergesse es für eine Weile. Ich habe versucht, ein einfaches Beispiel zu finden, um die verschiedenen Aspekte beim Umgang mit Daten zu vergleichen und festzustellen, ob funktionale Methoden teuer sind oder nicht. Wenn funktionale Programmierung für kleine Datenmengen teuer und speicherintensiv ist, warum benötigen wir sie für Big Data?

Weit entfernt von ausgefallenen Werkzeugen habe ich versucht, eine Lösung für ein bestimmtes und beliebtes Problem mit drei Ansätzen zu finden: Imperativer Weg und funktionaler Weg (Rekursion, Verwendung von Sammlungen). Ich habe Zeit und Komplexität verglichen, um die drei Ansätze zu vergleichen.

Ich habe Scala verwendet, um diese Funktionen zu schreiben, da es das beste Werkzeug ist, um einen Algorithmus unter Verwendung von drei Paradigmen zu schreiben

def main(args: Array[String]) {
    val start = System.currentTimeMillis()
    // Fibonacci_P
    val s = Fibonacci_P(400000000)
    val end = System.currentTimeMillis()
    println("Functional way: \n the Fibonacci sequence whose values do not exceed four million : %d \n Time : %d ".format(s, end - start))
    val start2 = System.currentTimeMillis()

    // Fibonacci_I
    val s2 = Fibonacci_I(40000000 0)
    val end2 = System.currentTimeMillis();
    println("Imperative way: \n the Fibonacci sequence whose values do not exceed four million : %d \n Time : %d ".format(s2, end2 - start2))
}

Funktionsweise:

def Fibonacci_P(max: BigInt): BigInt = {
    //http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Stream
    //lazy val Fibonaccis: Stream[Long] = 0 #:: 1 #:: Fibonaccis.zip(Fibonaccis.tail).map { case (a, b) => a + b }
    lazy val fibs: Stream[BigInt] = BigInt(0)#::BigInt(1)#::fibs.zip(fibs.tail).map {
        n = > n._1 + n._2
    }
    // println(fibs.takeWhile(p => p < max).toList)
    fibs.takeWhile(p = > p < max).foldLeft(BigInt(0))(_ + _)
}

Rekursiver Weg:

def Fibonacci_R(n: Int): BigInt = n match {
    case 1 | 2 = > 1
    case _ = > Fibonacci_R(n - 1) + Fibonacci_R(n - 2)
}

Imperativer Weg:

def Fibonacci_I(max: BigInt): BigInt = {
    var first_element: BigInt = 0
    var second_element: BigInt = 1
    var sum: BigInt = 0

    while (second_element < max) {
        sum += second_element

        second_element = first_element + second_element
        first_element = second_element - first_element
    }

    //Return 
    sum
}

Mir ist aufgefallen, dass die funktionale Programmierung schwer ist! Es dauert länger und verbraucht mehr Speicherplatz. Ich bin verwirrt, wenn ich einen Artikel lese oder einen Vortrag sehe, sagen sie, dass wir funktionale Programmierung in der Datenwissenschaft verwenden sollten. Es ist wahr, es ist einfacher und produktiver, insbesondere in der Datenwelt. Aber es braucht mehr Zeit und mehr Speicherplatz.

Warum müssen wir also die funktionale Programmierung in Big Data verwenden? Was sind die Best Practices für die Verwendung der funktionalen Programmierung (Scala) für Big Data?


5
Die funktionale Programmierung erleichtert die Parallelisierung Ihres Codes. Selbst wenn die Ausführung eines einzelnen Vorgangs in einem Thread länger dauert, kann die Gesamtleistung aufgrund der Parallelität besser sein.
Giorgio

@Giorgio: Es gibt verschiedene Paradigmen als Actor Modeling, um die beste Leistung für Parallelität zu erzielen. Glaubst du nicht?
user3047512

2
Ich denke, es liegt einfach daran, dass der Map / Reduce-Ansatz von hadoop eine Idee aus der funktionalen Programmierung ist.
Doc Brown

1
@ user3047512: Erlang verwendet beispielsweise das Akteurmodell und ist größtenteils funktionsfähig.
Giorgio

2
Die Verbindung zwischen "Big Data" und FP ist nicht so einfach. In "Big Data" ist ein sogenannter Map-Reduction- Ansatz in Mode, der wiederum etwas vom funktionalen Programmierethos inspiriert war. Hier endet die Ähnlichkeit, ich kann keine weitere Verbindung zwischen diesen beiden Welten erkennen.
SK-Logik

Antworten:


13

So sehe ich das:

  • Lassen Sie uns die Wörter "Big Data" für eine Weile ignorieren, da sie eine ziemlich vage Vorstellung sind

  • Sie haben Hadoop erwähnt. Hadoop macht zwei Dinge: Ermöglicht Ihnen eine Art "virtuelles" Laufwerk, das auf mehrere Computer mit Redundanz verteilt ist und auf das über die Hadoop-API zugegriffen werden kann, als wäre es ein einzelnes, einheitliches Laufwerk. Es heißt HDFS wie im Hadoop Distributed File System . Mit Hadoop können Sie auch Map-Reduce-Jobs ausführen (dies ist ein Framework für Map-Reduce). Wenn wir uns die Wikipedia-Seite von MapReduce ansehen, sehen wir Folgendes:

MapReduce ist ein Programmiermodell zur Verarbeitung großer Datenmengen mit einem parallelen, verteilten Algorithmus in einem Cluster.

...

Ein MapReduce-Programm besteht aus einer Map () - Prozedur, die das Filtern und Sortieren ausführt (z. B. das Sortieren von Schülern nach Vornamen in Warteschlangen, eine Warteschlange für jeden Namen), und einer Reduce () - Prozedur, die eine Zusammenfassungsoperation ausführt (z. B. das Zählen der Nummer) von Schülern in jeder Warteschlange, die Namenshäufigkeiten ergeben)

...

'MapReduce' ist ein Framework für die Verarbeitung parallelisierbarer Probleme über große Datenmengen hinweg mit einer großen Anzahl von Computern

Auch auf dieser Seite wird Hadoop als beschrieben

Hadoop, Apaches kostenlose und Open Source-Implementierung von MapReduce.

Jetzt ist Hadoop in Java geschrieben, das keine funktionale Sprache ist. Wenn wir uns die Seite von Hadoop ansehen, finden wir auch ein Beispiel dafür, wie ein MapReduce-Job in Java erstellt und in einem Hadoop-Cluster bereitgestellt wird .

Hier ist ein Java-Beispiel für einen Fibonnaci MapReduce-Job für Hadoop.

Ich hoffe, dies beantwortet Ihre Frage, nämlich dass BigData und insbesondere ein Fibonacci-erstellender MapReduce-Job nicht "funktionsfähig" sein müssen, auch bekannt als "Sie können ihn in OO-Sprachen implementieren, wenn Sie möchten" (zum Beispiel).

Das bedeutet natürlich nicht, dass BigData auch nur OO sein muss. Sie können sehr gut eine funktionale Sprache verwenden, um einen MapReduce-ähnlichen Job zu implementieren. Sie können Scala beispielsweise mit Hadoop über Scalding verwenden, wenn Sie möchten .

Andere Punkte sind meiner Meinung nach erwähnenswert.

Wenn Sie in Scala eine Rekursion durchführen und Ihr Code dies zulässt, führt Scala eine Tail-Call-Optimierung durch . Da die JVM die Tail-Call-Optimierung (noch) nicht unterstützt , erreicht Scala dies, indem Ihre rekursiven Aufrufe zur Kompilierungszeit durch Code ersetzt werden, der Schleifen entspricht, wie hier erläutert . Dies bedeutet im Grunde, dass das Ausführen von rekursiven und nicht rekursiven Code-Benchmarks mit Scala sinnlos ist, da beide zur Laufzeit dasselbe tun.


2
Sie machen einen hervorragenden Punkt darüber, dass die JVM die Tail-Call-Optimierung nicht unterstützt, was die vom OP vorgeschlagenen Benchmarks untergräbt. Dies ist eine sehr informative Antwort, danke.
maple_shaft

1
Vielen Dank für Ihre Antwort: Ja! Die Tail-Call-Optimierung ist eine der versteckten Scala-Funktionen. stackoverflow.com/questions/1025181/hidden-features-of-scala/… . Eines der Probleme von "Big Data" ist, dass jedes Unternehmen versucht, eine neue Technologie auf unterschiedliche Weise aufzubauen. Aber es gibt hauptsächlich zwei: Hadoop Tech und andere. Wie Sie sagten, es ist subjektiv und hängt mit den Problemen selbst zusammen. Wir sollten das richtige Programmierparadigma auch basierend auf unserem Fachwissen auswählen. Beispiel: Echtzeit-Vorhersagemodelle funktionieren auf Hadoop-Plattformen nicht sehr gut.
user3047512

9

Solange Sie es auf einem einzelnen Computer ausführen können, handelt es sich nicht um "Big Data". Ihr Beispielproblem ist völlig unangemessen, um etwas darüber zu demonstrieren.

Big Data bedeutet, dass die Problemgrößen so groß sind, dass die Verteilung der Verarbeitung keine Optimierung, sondern eine grundlegende Anforderung darstellt. Die funktionale Programmierung erleichtert das Schreiben von korrektem und effizientem verteiltem Code aufgrund unveränderlicher Datenstrukturen und Zustandslosigkeit erheblich.


"Big Data bedeutet, dass die Problemgrößen so groß sind, dass die Verteilung der Verarbeitung keine Optimierung, sondern eine grundlegende Anforderung darstellt." - Ich verstehe nicht, welche Art von Problem überhaupt nicht mit einer Maschine gelöst werden kann, und erfordert mindestens N, wobei N> 1 ...
Shivan Dragon

6
@ShivanDragon: Die Art von Problem, das Leistungsanforderungen umfasst, die auf einem einzelnen System überhaupt nicht zu erfüllen sind. Oder wo die Datengröße so groß ist, dass kein einzelnes System alles speichern kann.
Michael Borgwardt

Es tut mir leid, ich verstehe Ihren Standpunkt jetzt. Ist es richtig zu sagen, dass Sie sich speziell auf MapReduce beziehen, das unter dem Dach von BigData lebt?
Shivan Dragon

Vielen Dank für Ihre Eingabe, ich stimme zu. Vielleicht konnte ich kein gutes einfaches Beispiel finden, um meinen Standpunkt zu demonstrieren. "Big Data" ist immer noch eine Möglichkeit, mit der Entwickler Daten verwenden, um unsere täglichen Probleme unter Berücksichtigung der 3V-Definition zu lösen. Ich werde die 3V für eine Weile vergessen und über den sehr einfachen Aspekt sprechen, den Umgang mit Daten. Wenn wir sehen, dass eine funktionale Analyse von Daten teuer ist, warum sagen wir dann, dass "Big Data" funktionsfähig sein muss? Das ist mein Punkt.
user3047512

4
Bei ShivanDragon beispielsweise produziert LHC mehrere Gigabyte Daten pro Sekunde . Ich bin mir nicht sicher, ob eine einzelne Maschine einen solchen Durchsatz überhaupt verarbeiten kann.
SK-Logik

4

Ich kenne Scala nicht und kann daher Ihren funktionalen Ansatz nicht kommentieren, aber Ihr Code sieht nach Overkill aus.

Ihre rekursive Funktion ist dagegen ineffizient. Da sich die Funktion zweimal selbst aufruft, liegt sie in der Größenordnung von 2 ^ n, was sehr ineffizient ist. Wenn Sie die drei Ansätze vergleichen möchten, müssen Sie drei optimale Implementierungen vergleichen.

Die Fibonacci-Funktion kann rekursiv implementiert werden, indem die Funktion nur einmal aufgerufen wird. Nehmen wir eine allgemeinere Definition:

F(0) = f0
F(1) = f1
F(n) = F(n-1) + F(n-2)

Der Standard-Sonderfall ist:

f0 = 0
f1 = 1

Die allgemeine rekursive Funktion lautet:

function fibonacci($f0, $f1, $n){
    if($n < 0 || !isInt($n)) return false;
    if($n = 0) return $f0;
    if($n = 1) return $f1;
    return fibonacci($f1, $f0 + $f1, $n - 1);
}

Vielen Dank! Sie haben einen guten Punkt angesprochen, aber es gibt keinen effizienten Weg, dies iterativ zu tun. Dies ist ein sehr häufiges Problem (Fibonacci-Suite). und dies ist der Punkt, um das gleiche Problem auf drei Arten anzugehen. Können Sie einen besseren Weg vorschlagen, um dieses Problem mit einer beliebigen Programmiersprache zu lösen? Ich kann das mit Scala neu schreiben und die gleichen Tests durchführen.
user3047512

@ user3047512 Für eine Sprache, die die Schwanzrekursion unterstützt, können Sie sie mit einem Akkumulator schreiben. Beispiele
toasted_flakes

Scala unterstützt auch die Schwanzrekursion als verstecktes Feature oldfashionedsoftware.com/2008/09/27/…
user3047512

1
@ user3047512 Da die rekursive Lösung eine reine Funktion ist (die Ausgabe hängt ausschließlich von Funktionsargumenten und nichts anderem ab ), ist das Auswendiglernen eine gute Lösung. Einfach ausgedrückt, jedes Mal, wenn ein Wert zurückgegeben wird, speichern Sie die Argumente und führen zu einem Schlüssel / Wert-Hash. Jedes Mal, wenn die Funktion ausgeführt wird, schauen Sie zuerst dort nach. Dies ist einer der Vorteile von reinen Funktionen - ein zukünftiger Aufruf dieser Funktion findet den bereits vorhandenen Hash-Wert und führt Nullberechnungen durch , da wir wissen, dass sich das Ergebnis nicht geändert hat.
Izkata

@ user3047512 Die iterative Version sieht in diesem Fall auch wie eine reine Funktion aus, aber das ist nicht immer wahr - in einer funktionalen Sprache glaube ich, dass es durch die Sprache besser erzwungen wird ...
Izkata

0

Wenn funktionale Programmierung für kleine Datenmengen teuer und speicherintensiv ist, warum benötigen wir sie für Big Data?

Insbesondere kann ich bereits einige Anwendungen sehen, bei denen dies äußerst nützlich ist. Ex. Statistik, dh Berechnung einer Gaußschen Funktion im laufenden Betrieb mit verschiedenen Parametern oder einer Reihe von Parametern für die Datenanalyse. Es gibt auch eine Interpolation für die numerische Analyse usw.

Was sind die Best Practices für die Verwendung der funktionalen Programmierung (Scala) für Big Data?

Um auf die Effizienz zu antworten, gibt es auch Techniken, mit denen Sie Ihre räumliche oder zeitliche Effizienz steigern können, insbesondere Rekursion, Schwanzrekursion , Weitergabestil , Funktionen höherer Ordnung usw. Einige Sprachen haben ihre Vor- und Nachteile (z. B. faul oder eifrig) Etwas Einfaches wie die Fibonnacci-Sequenz, die ich möglicherweise nur auf die zwingende Weise verwende, da ich manchmal finde, dass einige meiner Mitarbeiter zögern und möglicherweise nicht so gut mit funktionaler Programmierung vertraut sind und daher mehr Entwicklungszeit in Anspruch nehmen ... (Ich bevorzuge es immer noch Verwenden Sie funktionale Programmierung, wenn ich kann [Anwendungen, für die ich verantwortlich bin]), da ich sie schnell, sauber und "leicht lesbar" finde (obwohl ich diesen subjektiven Code finde).

Wikipedia hat eine "schnelle" Version der Fibonnacci-Sequenz veröffentlicht. https://en.wikipedia.org/wiki/Functional_programming#Scala

def fibTailRec(n: Int): Int = {
  @tailrec def f(a: Int, b: Int, c: Int): Int = if (a == 0) 0 else if(a < 2) c else f(a-1, c, b + c)
  f(n, 0, 1)
}

Streams / hof verwenden

val fibStream:Stream[Int] = 0 #:: 1 #:: (fibStream zip fibStream.tail).map{ t => t._1 + t._2 }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.