Por que o Big Data precisa ser funcional?


9

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?


5
A programação funcional facilita o paralelismo do seu código, portanto, mesmo que uma única operação leve mais tempo para ser executada em um encadeamento, o desempenho geral pode ser melhor devido ao paralelismo.
Giorgio

@Giorgio: Existem paradigmas diferentes, como a Modelagem de Atores, para obter o melhor desempenho para o paralelismo. Não acha?
user3047512

2
Eu acho que é simplesmente porque a abordagem de mapa / redução do hadoop é uma idéia da programação funcional.
Doc Brown

11
@ user3047512: Por exemplo, Erlang usa o modelo de ator e é, em grande parte, funcional.
Giorgio

2
A conexão entre a moda "big data" e o FP não é tão simples. Em "Big Data", está em moda uma abordagem chamada de redução de mapa , que, por sua vez, havia sido um pouco inspirada pelo ethos da programação funcional. É aqui que a semelhança termina; não vejo mais nenhuma conexão entre esses dois mundos.
SK-logic

Respostas:


13

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:

O MapReduce é um modelo de programação para processar grandes conjuntos de dados com um algoritmo distribuído paralelo em um cluster.

...

Um programa MapReduce é composto por um procedimento Map () que executa filtragem e classificação (como classificar os alunos pelo primeiro nome em filas, uma fila para cada nome) e um procedimento Reduce () que executa uma operação de resumo (como contar o número de alunos em cada fila, gerando frequências de nomes)

...

'MapReduce' é uma estrutura para processar problemas paralelamente felizes em enormes conjuntos de dados usando um grande número de computadores

Também nesta página, o Hadoop é descrito como

Hadoop, implementação gratuita e de código aberto do Apache do MapReduce.

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.


2
Você faz um excelente argumento sobre a JVM não oferecer suporte à otimização de chamada de cauda que prejudica os parâmetros de referência propostos pelo OP. Esta é uma resposta muito informativa, obrigado.
maple_shaft

11
Obrigado pela sua resposta, sim! A otimização da chamada de cauda é um dos recursos ocultos da escala. stackoverflow.com/questions/1025181/hidden-features-of-scala/… . Um dos problemas do "Big Data" é que toda empresa está tentando construir uma nova tecnologia de maneira diferente. Mas existem principalmente dois: tecnologia Hadoop e outros. Como você disse, é subjetivo e está relacionado aos problemas, devemos escolher o paradigma de programação correto com base em nossa experiência também. Por exemplo: Modelos preditivos em tempo real não funcionam muito bem nas plataformas Hadoop.
User3047512

9

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.


"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". - Eu não entendo que tipo de problema não pode AT ALL ser resolvidos usando uma máquina, e requer pelo menos N, onde N> 1 ...
Shivan Dragão

6
@ShivanDragon: O tipo de problema que inclui requisitos de desempenho que são absolutamente impossíveis de satisfazer em um único sistema. Ou onde o tamanho dos dados é tão grande que nenhum sistema pode armazenar tudo.
precisa

Me desculpe, eu entendo o seu ponto agora. É correto dizer que o que você está se referindo é, mais especificamente, o MapReduce, que vive sob a égide do BigData?
perfil completo de Shivan Dragon

Obrigado pela sua contribuição, eu concordo. Talvez não tenha conseguido encontrar um bom exemplo simples para demonstrar meu ponto de vista. "Big Data" ainda é uma maneira que os desenvolvedores usam dados para resolver nossos problemas diários, levando em consideração a definição de 3Vs. Vou esquecer o 3V por um tempo e falar sobre o aspecto muito simples, lidando com o Data. Se vemos que a análise de dados de uma maneira funcional é cara, por que dizemos que o "Big Data" precisa ser funcional? Este é o meu ponto.
user3047512

4
@ShivanDragon, por exemplo, o LHC está produzindo vários gigabytes de dados por segundo . Não tenho certeza se uma única máquina pode lidar com essa taxa de transferência.
SK-logic

4

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:

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

O caso especial padrão é:

f0 = 0
f1 = 1

A função recursiva geral é:

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);
}

Obrigado! Você levantou um bom argumento, mas não existe uma maneira eficiente de fazer isso de maneira iterativa. Este é um prob muito comum (pacote Fibonacci). e esse é o objetivo de resolver o mesmo problema usando três maneiras. Você pode sugerir uma maneira melhor de resolver esse problema usando qualquer linguagem de programação, posso reescrevê-lo usando o scala e fazer os mesmos testes?
precisa saber é o seguinte

@ user3047512 Para um idioma que suporta recursão de cauda, ​​você pode escrevê-lo com um acumulador. Exemplos
toasted_flakes

Scala também suportam recursão cauda como recurso escondido oldfashionedsoftware.com/2008/09/27/...
user3047512

11
@ user3047512 Como a solução recursiva é uma função pura (a saída depende apenas da função args e nada mais ), a memorização é uma boa solução. Simplificando, toda vez que ele retornaria um valor, armazene os argumentos e resultaria em um hash de chave / valor, e toda vez que a função for executada, procure lá primeiro. Essa é uma das vantagens das funções puras - uma chamada futura para essa função encontrará o valor de hash preexistente e fará cálculos nulos , porque sabemos que o resultado não será alterado.
Izkata

@ user3047512 A versão iterativa também se parece com uma função pura neste caso, mas que nem sempre é verdade - em uma linguagem funcional, eu acredito que é melhor executada pela linguagem ...
Izkata

0

Se a programação funcional é cara e consome memória para pequenos dados, por que precisamos dela para Big Data?

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.

Quais são as melhores práticas para usar a programação funcional (Scala) para Big Data?

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

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)
}

Usando fluxos / hof

val fibStream:Stream[Int] = 0 #:: 1 #:: (fibStream zip fibStream.tail).map{ t => t._1 + t._2 }
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.