Comecei a trabalhar em um novo projeto recentemente relacionado ao Big Data para meu estágio. Meus gerentes recomendaram começar a aprender programação funcional (eles recomendaram muito Scala). Tive uma experiência humilde no uso de F #, mas não pude ver a importância de usar esse paradigma de programação, pois, em alguns casos, é caro.
Dean fez uma palestra interessante sobre esse tópico e compartilhou seus pensamentos sobre o porquê de "Big Data" aqui: http://www.youtube.com/watch?v=DFAdLCqDbLQ Mas não foi muito conveniente, pois Big Data não significa somente Hadoop.
Como BigData é um conceito muito vago. Eu esqueço isso por um tempo. Tentei criar um exemplo simples para comparar os diferentes aspectos quando lidamos com dados, para ver se a maneira funcional é cara ou não. Se a programação funcional é cara e consome memória para pequenos dados, por que precisamos dela para Big Data?
Longe de ferramentas sofisticadas, tentei criar uma solução para um problema específico e popular usando três abordagens: maneira imperativa e forma funcional (recursão, usando coleções). Comparei tempo e complexidade, para comparar entre as três abordagens.
Usei o Scala para escrever essas funções, pois é a melhor ferramenta para escrever um algoritmo usando três paradigmas
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))
}
Maneira funcional:
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))(_ + _)
}
Maneira recursiva:
def Fibonacci_R(n: Int): BigInt = n match {
case 1 | 2 = > 1
case _ = > Fibonacci_R(n - 1) + Fibonacci_R(n - 2)
}
Maneira imperativa:
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
}
Notei que a programação funcional é pesada! leva mais tempo e consome mais espaço na memória. Estou confuso, sempre que leio um artigo ou assisto a uma conversa, eles dizem que devemos usar a programação funcional na ciência de dados. É verdade que é mais fácil e produtivo, especialmente no mundo dos dados. mas leva mais tempo e mais espaço de memória.
Então, por que precisamos usar a programação funcional no Big Data? Quais são as melhores práticas para usar a programação funcional (Scala) para Big Data?
fonte
Respostas:
Aqui está como eu o vejo:
Vamos ignorar as palavras "big data" por um tempo, pois elas são uma noção bastante vaga
Você mencionou o Hadoop. O Hadoop faz duas coisas: permite que você tenha uma espécie de unidade "virtual" distribuída em várias máquinas, com redundância, que pode ser acessada pela API do Hadoop como se fosse uma unidade única e unitária. É chamado HDFS como no Hadoop Distributed File System . A outra coisa que o Hadoop faz é permitir que você execute tarefas de redução de mapa (é uma estrutura para redução de mapa). Se verificarmos a página da Wikipedia do MapReduce , veremos que:
...
...
Também nesta página, o Hadoop é descrito como
Agora, o Hadoop é escrito em Java, que não é uma linguagem funcional. Além disso, se olharmos na página do Hadoop, também encontramos um exemplo de como criar uma tarefa MapReduce em Java e implantá-la em um cluster Hadoop .
Aqui está um exemplo de Java de um trabalho do Fibonnaci MapReduce para o Hadoop.
Espero que isso responda à sua pergunta, a saber, que o BigData e, em particular, um trabalho MapReduce que cria Fibonacci "não" precisam ser funcionais, ou seja, você pode implementá-lo nas linguagens OO, se quiser (por exemplo).
Obviamente, isso não significa que o BigData "precise" ser apenas de OO também. Você pode muito bem usar uma linguagem funcional para implementar um trabalho semelhante ao MapReduce. Você pode, por exemplo, usar o Scala com o Hadoop, se desejar, via Scalding .
Eu acho que vale a pena mencionar outros pontos.
Ao fazer recursão no Scala, se o seu código permitir, o Scala fará otimização de chamada de cauda . No entanto, como a JVM (ainda) não suporta otimização de chamada de cauda , a Scala consegue isso substituindo, em tempo de compilação, suas chamadas recursivas por código equivalente a loops, conforme explicado aqui . O que isso significa basicamente é que fazer benchmarks de código recursivos vs não recursivos usando o Scala é inútil, pois ambos acabam fazendo a mesma coisa em tempo de execução.
fonte
Contanto que você possa executá-lo em uma única máquina, não é "Big Data". Seu exemplo de problema é completamente inapropriado para demonstrar algo sobre ele.
Big Data significa que os tamanhos dos problemas são tão grandes que distribuir o processamento não é uma otimização, mas um requisito fundamental. E a programação funcional facilita muito a gravação de código distribuído correto e eficiente devido a estruturas de dados imutáveis e ausência de estado.
fonte
Não conheço scala e, portanto, não posso comentar sobre sua abordagem funcional, mas seu código parece um exagero.
Sua função recursiva, por outro lado, é ineficiente. Como a função se chama duas vezes, é da ordem 2 ^ n, o que é altamente ineficiente. Se você quiser comparar as três abordagens, precisará comparar três implementações ideais.
A função Fibonacci pode ser implementada recursivamente chamando a função apenas uma vez. Vamos dar uma definição mais generalizada:
O caso especial padrão é:
A função recursiva geral é:
fonte
Especificamente, já posso ver alguns aplicativos em que isso é extremamente útil. ex. Estatística, isto é, cálculo de uma função gaussiana em tempo real com diferentes parâmetros ou um conjunto de parâmetros para análise de dados. Também há interpolação para análise numérica, etc.
Para responder à eficiência, também existem técnicas para ajudar a aumentar sua eficiência no espaço ou no tempo, especificamente recursão, recursão de cauda , estilo de passagem de continuação , funções de ordem superior , etc. Alguns idiomas têm seus prós e contras (por exemplo, preguiçoso ou ansioso.) algo simples como a sequência de Fibonnacci, eu poderia apenas usar a maneira imperativa, pois às vezes acho que alguns de meus colegas de trabalho relutam e podem não se sentir tão à vontade com a programação funcional e, portanto, ocupar mais tempo de desenvolvimento ... (eu ainda prefiro usar programação funcional quando puder [aplicativos dos quais sou responsável], pois acho que é rápido, limpo e "fácil de ler" (embora eu ache esse subjetivo) código.
A Wikipedia tem uma versão "rápida" da sequência de fibonnacci publicada. https://en.wikipedia.org/wiki/Functional_programming#Scala
Usando fluxos / hof
fonte