zoukankan      html  css  js  c++  java
  • Spark RDD的fold和aggregate为什么是两个API?为什么不是一个foldLeft?

    欢迎关注我的新博客地址:http://cuipengfei.me/blog/2014/10/31/spark-fold-aggregate-why-not-foldleft/

    大家都知道Scala标准库的List有一个用来做聚合操作的foldLeft方法。

    比方我定义一个公司类:

    1
    
    case class Company(name:String, children:Seq[Company]=Nil)
    

    它有名字和子公司。 然后定义几个公司:

    1
    
    val companies = List(Company("B"),Company("A"),Company("T"))
    

    三家大公司,然后呢,我如果有一家超牛逼的公司把它们给合并了:

    1
    
    companies.foldLeft(Company("King"))((king,company)=>Company(name=king.name,king.children:+company))
    

    这个运行的结果是这种:

    1
    2
    
    scala> companies.foldLeft(Company("King"))((king,company)=>Company(name=king.name,king.children:+company))
    res6: Company = Company(King,List(Company(B,List()), Company(A,List()), Company(T,List())))
    

    可见foldLeft的结果是一家包括了BAT三大家得新公司。

    由List[Company]聚合出一个新的Company,这样的属于foldLeft的同构聚合操作。

    同一时候,foldLeft也能够做异构的聚合操作:

    1
    
    companies.foldLeft("")((acc,company)=>acc+company.name)
    

    它的运行结果是这种:

    1
    2
    
    scala> companies.foldLeft("")((acc,company)=>acc+company.name)
    res7: String = BAT
    

    由List[Company]聚合出一个String。

    这种API感觉非常方便。仅仅要是聚合。不管同构异构。都能够用它来做。

    近期接触了Spark,当中的RDD是做分布式计算时最经常使用的一个类。

    RDD有一个叫做fold的API,它和foldLeft的签名非常像,唯一差别是它仅仅能做同构聚合操作。

    也就是说假设你有一个RDD[X],通过fold,你仅仅能构造出一个X。

    假设我想通过一个RDD[X]构造一个Y出来呢?

    那就得用aggregate这个API了,aggregate的签名是这种:

    1
    
    aggregate[U](zeroValue: U)(seqOp: (U, T)  U, combOp: (U, U)  U)(implicit arg0: ClassTag[U]): U
    

    它比fold和foldLeft多须要一个combOp做參数。

    这让我非常不解,同构和异构的API干嘛非得拆成两个呢?怎么不能学Scala的标准库,把它做成类似foldLeft的样子呢?

    后来想明确了,这是因为Spark须要分布运算造成的。

    先想一下Scala List的foldLeft是怎么工作的?

    1
    
    companies.foldLeft(Company("King"))((king,company)=>Company(name=king.name,king.children:+company))
    
    1. 拿到初始值,即名字为king的公司,把它和list中的第一个公司合并,成为一个包括一家子公司的新公司
    2. 把上一步中的新公司拿来和list中的第二个公司合并,成为一个包括两家子公司的新公司
    3. 把上一步中的新公司拿来和list中的第三个公司合并,成为一个包括三家子公司的新公司

    这是同构的过程。

    1
    
    companies.foldLeft("")((acc,company)=>acc+company.name)
    
    1. 拿到初始值,即空字符串。把它和list中的第一个公司的名字拼在一起,成为B
    2. 把上一步中的B第二个公司名字拼一起。成为BA
    3. 把上一步中的BA拿来和list中的第三个公司的名字拼一起,成为BAT

    这是异构的过程。

    像多米诺骨牌一样,从左到右依次把list中的元素吸收入结果中。

    如今如果RDD[X]中有一个类似foldLeft的API,其签名和foldLeft一致,我如今调用foldLeft,给它一个f:(Y,X)=>Y,接下来该发生什么呢?

    1. 由于要分布计算,所以我先要把手里的非常多个X分成几份。分发到不同的节点上去
    2. 每一个节点把拿到的非常多个X计算出一个Y出来
    3. 把全部节点的结果拿来,这时我手里就有了非常多个Y
    4. 啊。。。我不知道怎么把非常多个Y变成一个Y啊。。。

    因为Spark的RDD不像Scala的List一样仅仅须要推倒一副多米诺骨牌。而是要推倒非常多副。最后再对非常多副多米诺骨牌的结果做聚合。

    这时假设是同构还好,我仅仅须要再用f:(X,X)=>X做一遍就ok了。

    可是假设是异构的,那我就必须得再须要一个f:(Y,Y)=>Y了。

  • 相关阅读:
    SCOPE_IDENTITY和@@identity的区别
    IE6.0、IE7.0 与FireFox CSS兼容的解决方法
    DivCSS布局基础:CSS中控制换行的四种属性
    load的用法(问题未解决)
    设置每个li的margin距离(巧设计)
    IE6下设置float和margin的问题
    在IE7下设置zindex没有反应
    做css页面时,注意的地方
    专题页
    IE8下margintop问题
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5405938.html
Copyright © 2011-2022 走看看