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?
quelle
Antworten:
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:
...
...
Auch auf dieser Seite wird Hadoop als beschrieben
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.
quelle
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.
quelle
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:
Der Standard-Sonderfall ist:
Die allgemeine rekursive Funktion lautet:
quelle
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.
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
Streams / hof verwenden
quelle