为什么大数据需要发挥作用?


9

我开始从事与大数据相关的新项目的实习。我的经理们建议开始学习函数式编程(他们强烈推荐Scala)。我使用F#的经验很卑鄙,但是我看不到使用这种编程范例的重要性,因为在某些情况下它很昂贵。

迪恩(Dean)在这个话题上做了有趣的演讲,并在这里分享了他对“大数据”为何的想法:http : //www.youtube.com/watch?v=DFAdLCqDbLQ 但这并不十分方便,因为大数据并不意味着只有Hadoop。

由于BigData是非常模糊的概念。我暂时忘记了。我尝试提出一个简单的示例,以便在处理数据时比较不同方面,以查看功能方式是昂贵的还是没有。如果小数据的功能编程昂贵且占用大量内存,那么为什么大数据需要它?

我远没有花哨的工具,而是尝试使用三种方法针对一个特定且普遍存在的问题构建解决方案:命令式和功能性方法(递归,使用集合)。我比较了时间和复杂性,以比较这三种方法。

我使用Scala编写这些函数,因为它是使用三种范式编写算法的最佳工具

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

功能方式:

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))(_ + _)
}

递归方式:

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

命令式:

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
}

我注意到函数式编程很重!它需要更长的时间并消耗更多的内存空间。我很困惑,每当我阅读文章或观看演讲时,他们都说我们应该在数据科学中使用函数式编程。没错,它更简单,更高效,特别是在数据世界中。但是它需要更多的时间和更多的存储空间。

那么,为什么我们需要在大数据中使用函数式编程?将函数式编程(Scala)用于大数据的最佳实践是什么?


5
通过函数式编程,可以更轻松地并行化代码,因此即使单个操作可能需要更多时间在一个线程中运行,但由于并行性,整体性能可能会更好。
Giorgio

@Giorgio:有多种不同的范例作为Actor Modeling来使并行性能达到最佳。不这样认为吗?
user3047512 2013年

2
我想这仅仅是因为hadoop的map / reduce方法是功能编程的一个主意。
布朗

1
@ user3047512:例如,Erlang使用actor模型,并且在大多数情况下是起作用的。
Giorgio

2
“大数据”时尚与FP之间的联系并不是那么简单。在“大数据”中,一种所谓的map-reduce方法很流行,而这反过来又在某种程度上受到了函数式编程思想的启发。这就是相似性结束的地方,我看不到这两个世界之间的任何进一步联系。
SK-logic

Answers:


13

这是我的看法:

  • 让我们暂时忽略“大数据”一词,因为它们是一个模糊的概念

  • 您提到了Hadoop。Hadoop做两件事:允许您将一种“虚拟”驱动器以冗余方式分布在多台计算机上,可以通过Hadoop的API对其进行访问,就好像它是一个单一的驱动器一样。在Hadoop分布式文件系统中,它称为HDFS 。Hadoop的另一件事是允许您执行Map-Reduce作业(这是Map-Reduce的框架)。如果我们查看MapReduce的Wikipedia页面则会看到:

MapReduce是一种编程模型,用于通过集群上的并行分布式算法处理大型数据集。

...

MapReduce程序由执行过滤和排序的Map()过程(例如,按名字将学生排序到队列中,每个名称一个队列)和执行摘要操作(例如对数字进行计数)的Reduce()过程组成每个队列中的学生人数,产生姓名频率)

...

“ MapReduce”是一个使用大量计算机处理庞大数据集中可并行化问题的框架

同样在此页面上,Hadoop被描述为

Hadoop,Apache的MapReduce的免费和开源实现。

现在,Hadoop是用Java编写的,这不是一种功能语言。另外,如果我们查看Hadoop的页面,我们还将找到一个示例,说明如何使用Java创建MapReduce作业并将其部署在Hadoop集群中

这是Fibonnaci MapReduce作业针对Hadoop的Java示例。

我希望这个答案能回答您的问题,即BigData(尤其是创建斐波那契的MapReduce作业)不需要“起作用”,也就是说,如果您愿意(例如),可以使用OO语言实现它。

当然,这也不意味着BigData也“仅”需要面向对象。您可以很好地使用功能语言来实现类似MapReduce的作业。例如,您可以通过Scalding将Scala与Hadoop一起使用。

我认为其他几点值得一提。

在Scala中进行递归时,如果您的代码允许,Scala会进行尾调用优化。但是,由于JVM还不支持尾调用优化,因此Scala通过在编译时用等效于循环的代码替换递归调用来实现这一点,如此处所述。这基本上意味着使用Scala进行递归与非递归代码基准测试是没有意义的,因为它们最终都在运行时执行相同的操作。


2
您对JVM不支持尾部调用优化(这破坏了OP提出的基准)提出了非常好的观点。这是一个非常有用的答案,谢谢。
maple_shaft

1
谢谢您的回答,是的!尾部呼叫优化是隐藏的scala功能之一。 stackoverflow.com/questions/1025181/hidden-features-of-scala/...。“大数据”的问题之一是每个公司都试图以不同的方式来构建新技术。但是主要有两个:Hadoop技术和其他。如您所说,它是主观的并且与它自身的问题有关,我们也应该根据我们的专业知识选择正确的编程范例。例如:实时预测模型在Hadoop平台上不能很好地工作。
user3047512 2013年

9

只要您可以在一台计算机上运行它,就不是“大数据”。您的示例问题完全不适合演示任何有关此问题的信息。

大数据意味着问题规模如此之大,以至于分配处理过程不是优化,而是一项基本要求。由于不可变的数据结构和无状态性,函数式编程使编写正确和高效的分布式代码变得更加容易。


“大数据意味着问题规模如此之大,以至于分配处理过程不是优化,而是基本要求。” -我不知道使用一台机器根本无法解决哪种问题,并且至少需要N个,其中N> 1 ...
Shivan Dragon 2013年

6
@ShivanDragon:这类问题包含了在单个系统上完全无法满足的性能要求。或者,由于数据量太大,甚至没有一个系统可以存储所有数据。
Michael Borgwardt 2013年

对不起,我现在明白你的意思了。正确地说,您指的是MapReduce,它生活在BigData的保护下吗?
Shivan Dragon 2013年

谢谢您的投入,我同意。也许我找不到一个简单的例子来说明我的观点。考虑到3V的定义,“大数据”仍然是开发人员使用数据来解决我们的日常问题的一种方式。我会暂时忘记3V,并谈论有关数据的非常简单的方面。如果我们发现以功能性方式分析数据非常昂贵,为什么我们要说“大数据”需要功能性?这是我的观点。
user3047512 2013年

4
以@ShivanDragon为例,LHC 每秒产生数GB的数据。不确定一台机器甚至可以处理这样的吞吐量。
SK-logic

4

我不了解scala,因此无法评论您的功能方法,但是您的代码看起来有些过分。

另一方面,您的递归函数效率很低。因为函数调用了两次,所以它的阶数为2 ^ n,效率非常低。如果要比较这三种方法,则需要比较三种最佳实现。

Fibonacci函数可以通过仅调用一次函数来递归实现。让我们采用更笼统的定义:

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

标准的特殊情况是:

f0 = 0
f1 = 1

一般的递归函数是:

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

谢谢!您提出了一个很好的观点,但是没有有效的方法可以迭代地实现。这是一个非常常见的问题(斐波那契套件)。这是使用三种方法解决同一问题的要点。您能否建议使用任何编程语言来解决此问题的更好方法,我都可以使用scala重写并进行相同的测试?
user3047512 2013年

@ user3047512对于支持尾递归的语言,可以使用累加器编写它。示例
toasted_flakes 2013年

斯卡拉还支持尾递归为隐藏功能oldfashionedsoftware.com/2008/09/27/...
user3047512

1
@ user3047512因为递归解决方案是一个纯函数(输出仅取决于函数args,而别无其他),所以记忆是一个很好的解决方案。简而言之,每次它将返回一个值,存储args并导致键/值哈希,并且每次运行该函数时,请首先查看那里。这是纯函数的优点之一-将来对该函数的调用将找到预先存在的哈希值并进行计算,因为我们知道结果不会改变。
Izkata 2013年

@ user3047512在这种情况下,迭代版本也看起来像是一个纯函数,但这并不总是正确的-在函数式语言中,我认为它最好由该语言来执行...
Izkata

0

如果小数据的功能编程昂贵且占用大量内存,那么为什么大数据需要它?

具体来说,我已经看到了一些非常有用的应用程序。例如 统计信息,即使用不同的参数或一组参数动态地计算高斯函数以进行数据分析。还有用于数值分析的插值等。

将函数式编程(Scala)用于大数据的最佳实践是什么?

为了回答效率问题,还有一些技巧可以帮助您提高时空效率,特别是递归,尾递归连续传递样式高阶函数等。某些语言各有利弊(例如,懒惰与渴望)。像Fibonnacci序列这样简单的东西,我可能只是用命令式的方式,有时我发现有些同事不愿意并且可能不喜欢函数式编程,因此占用了更多的开发时间...(我仍然喜欢我可以[我负责的应用程序]时使用函数式编程),因为我发现它快速,干净并且“易于阅读”(尽管我发现这是主观的)代码。

维基百科发布了斐波那契序列的“快速”版本。 https://zh.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)
}

使用溪流/霍夫

val fibStream:Stream[Int] = 0 #:: 1 #:: (fibStream zip fibStream.tail).map{ t => t._1 + t._2 }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.