J'ai commencé à travailler sur un nouveau projet récemment lié au Big Data pour mon stage. Mes gestionnaires ont recommandé de commencer à apprendre la programmation fonctionnelle (ils ont fortement recommandé Scala). J'ai eu une expérience humble en utilisant F #, mais je ne voyais pas l'importance d'utiliser ce paradigme de programmation car il est cher dans certains cas.
Dean a donné une conférence intéressante sur ce sujet et a partagé ses réflexions sur la raison pour laquelle les "Big Data" ici: http://www.youtube.com/watch?v=DFAdLCqDbLQ Mais ce n'était pas très pratique car les Big Data ne signifient pas seulement Hadoop.
Comme BigData est un concept très vague. Je l'oublie un moment. J'ai essayé de trouver un exemple simple pour comparer les différents aspects lorsque nous traitons des données, pour voir si la méthode fonctionnelle est coûteuse ou non. Si la programmation fonctionnelle coûte cher et consomme beaucoup de mémoire pour les petites données, pourquoi en avons-nous besoin pour les Big Data?
Loin des outils sophistiqués, j'ai essayé de construire une solution pour un problème spécifique et populaire en utilisant trois approches: voie impérative et voie fonctionnelle (récursivité, utilisation de collections). J'ai comparé le temps et la complexité, pour comparer entre les trois approches.
J'ai utilisé Scala pour écrire ces fonctions car c'est le meilleur outil pour écrire un algorithme en utilisant trois paradigmes
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))
}
Manière fonctionnelle:
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))(_ + _)
}
Manière récursive:
def Fibonacci_R(n: Int): BigInt = n match {
case 1 | 2 = > 1
case _ = > Fibonacci_R(n - 1) + Fibonacci_R(n - 2)
}
Manière impérative:
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
}
J'ai remarqué que la programmation fonctionnelle est lourde! cela prend plus de temps et consomme plus d'espace en mémoire. Je suis confus, chaque fois que je lis un article ou regarde une conférence, ils disent que nous devrions utiliser la programmation fonctionnelle en science des données. C'est vrai, c'est plus facile et plus productif, spécialement dans le monde des données. mais cela prend plus de temps et plus d'espace mémoire.
Alors, pourquoi avons-nous besoin d'utiliser la programmation fonctionnelle dans le Big Data? Quelles sont les meilleures pratiques pour utiliser la programmation fonctionnelle (Scala) pour le Big Data?
la source
Réponses:
Voici comment je le vois:
Ignorons les mots «big data» pendant un certain temps, car ils sont une notion assez vague
Vous avez mentionné Hadoop. Hadoop fait 2 choses: vous permet d'avoir une sorte de lecteur "virtuel" qui est distribué sur plusieurs machines, avec redondance, accessible via l'API Hadoop comme s'il s'agissait d'un seul lecteur unitaire. Cela s'appelle HDFS comme dans Hadoop Distributed File System . L'autre chose que fait Hadoop est de vous permettre d'exécuter des travaux Map-Reduce (c'est un framework pour Map-Reduce). Si nous vérifions la page Wikipedia de MapReduce , nous voyons que:
...
...
Également sur cette page, Hadoop est décrit comme
Maintenant, Hadoop est écrit en Java, qui n'est pas un langage fonctionnel. En outre, si nous regardons la page de Hadoop, nous trouvons également un exemple de la façon de créer un travail MapReduce en Java et de le déployer dans un cluster Hadoop .
Voici un exemple Java d'un travail Fibonnaci MapReduce pour Hadoop.
J'espère que cela répond à votre question, à savoir que BigData, et en particulier un travail MapReduce créant Fibonacci n'a pas "besoin" d'être fonctionnel, c'est-à-dire que vous pouvez l'implémenter dans les langages OO si vous le souhaitez (par exemple).
Bien sûr, cela ne signifie pas non plus que "BigData" doit être uniquement OO. Vous pouvez très bien utiliser un langage fonctionnel pour implémenter un travail similaire à MapReduce. Vous pouvez, par exemple, utiliser Scala avec Hadoop si vous le souhaitez, via Scalding .
Je pense que d'autres points méritent d'être mentionnés.
Lorsque vous effectuez une récursivité dans Scala, si votre code le permet, Scala fera une optimisation de l'appel de queue . Cependant, étant donné que la JVM ne prend pas (encore) en charge l'optimisation des appels de queue , Scala y parvient en remplaçant, au moment de la compilation, vos appels récursifs par du code équivalent aux boucles, comme expliqué ici . Cela signifie essentiellement que faire des tests de code récursifs vs non récursifs en utilisant Scala est inutile, car ils finissent tous les deux par faire la même chose au moment de l'exécution.
la source
Tant que vous pouvez l'exécuter sur une seule machine, ce n'est pas du "Big Data". Votre exemple de problème est totalement inapproprié pour démontrer quoi que ce soit à ce sujet.
Le Big Data signifie que la taille des problèmes est si grande que la distribution du traitement n'est pas une optimisation mais une exigence fondamentale. Et la programmation fonctionnelle facilite l'écriture de code distribué correct et efficace en raison de structures de données immuables et de l'apatridie.
la source
Je ne connais pas scala et donc je ne peux pas commenter votre approche fonctionnelle, mais votre code ressemble à exagéré.
En revanche, votre fonction récursive est inefficace. Parce que la fonction s'appelle deux fois, elle est d'ordre 2 ^ n, ce qui est très inefficace. Si vous souhaitez comparer les trois approches, vous devez comparer trois implémentations optimales.
La fonction Fibonacci peut être implémentée récursivement en appelant la fonction une seule fois. Prenons une définition plus généralisée:
Le cas spécial standard est:
La fonction récursive générale est:
la source
Plus précisément, je peux déjà voir quelques applications où cela est extrêmement utile. ex. Statistiques, c'est-à-dire calcul d'une fonction gaussienne à la volée avec différents paramètres ou un ensemble de paramètres pour l'analyse de données. Il existe également une interpolation pour l'analyse numérique, etc.
Pour répondre à l'efficacité, il existe également des techniques pour aider à augmenter votre efficacité dans l'espace ou le temps, en particulier la récursivité, la récursivité de la queue , le style de passage de continuation , les fonctions d'ordre supérieur , etc. quelque chose de simple comme la séquence de Fibonnacci, je pourrais simplement utiliser la manière impérative car je trouve parfois que certains de mes collègues sont réticents et peuvent ne pas être aussi à l'aise avec la programmation fonctionnelle et donc prendre plus de temps de développement ... (je préfère toujours utiliser la programmation fonctionnelle quand je peux [les applications dont je suis responsable]) car je le trouve rapide, propre et "facile à lire" (bien que je trouve ce code subjectif).
Wikipédia a publié une version "rapide" de la séquence des fibonnacci. https://en.wikipedia.org/wiki/Functional_programming#Scala
Utilisation de streams / hof
la source