• spark rdd Transformation和Action 剖析


      1.看到 这篇总结的这么好, 就悄悄的转过来,供学习

    wordcount.toDebugString查看RDD的继承链条


    所以广义的讲,对任何函数进行某一项操作都可以认为是一个算子,甚至包括求幂次,开方都可以认为是一个算子,只是有的算子我们用了一个符号来代替他所要进行的运算罢了,所以大家看到算子就不要纠结,他和f(x)的f没区别,它甚至和加减乘除的基本运算符号都没有区别,只是他可以对单对象操作罢了(有的符号比如大于、小于号要对多对象操作)。又比如取概率P{X<x},概率是集合{X<x}(他是属于实数集的子集)对[0,1]区间的一个映射,我们知道实数域和[0,1]区间是可以一一映射的(这个后面再说),所以取概率符号P,我们认为也是一个算子,和微分,积分算子算子没区别。

    总而言之,算子就是映射,就是关系,就是**变换**!



    **mapPartitions(f)**
    f函数的输入输出都是每个分区集合的迭代器Iterator

    def mapPartitions[U](f: (Iterator[T]) => Iterator[U], preservesPartitioning: Boolean = false)(implicit arg0: ClassTag[U]): RDD[U]
    该函数和map函数类似,只不过映射函数的参数由RDD中的每一个元素变成了RDD中每一个分区的迭代器。如果在映射的过程中需要频繁创建额外的对象,使用mapPartitions要比map高效的过。
    比如,将RDD中的所有数据通过JDBC连接写入数据库,如果使用map函数,可能要为每一个元素都创建一个connection,这样开销很大,如果使用mapPartitions,那么只需要针对每一个分区建立一个connection。
    参数preservesPartitioning表示是否保留父RDD的partitioner分区信息。
    参考文章:
    http://lxw1234.com/archives/2015/07/348.htm



    union(other: RDD[T])操作不去重,去重需要distinct()


    subtract取两个RDD中非公共的元素

    sample返回RDD,takeSample直接返回数组(数组里面的元素为RDD中元素,类似于collect)


    keyvalue之类的操作都在**PairRDDFunctions.scala**中

    mapValues只对value进行运算


    groupBy相同key的元素的value组成集合

    coGroup是在groupBy的基础上

    coGroup操作多个RDD,是两个RDD里相同key的两个value集合组成的元组

    wKioL1ZqaEOTbSUMAAK8H8ZgjwQ107.png

    参考文章:
    http://www.iteblog.com/archives/1280



    **combineByKey和reduceByKey,groupByKey(内部都是通过combineByKey)**

    源码分析:

        reduceByKey  mapSideCombine: Boolean = true
        
        groupByKey  mapSideCombine=false

    所以优先使用reduceByKey,参考文章:http://www.iteblog.com/archives/1357


    **join操作**

    本质是先coGroup再笛卡尔积
        
          def join[W](other: RDD[(K, W)], partitioner: Partitioner): RDD[(K, (V, W))] = {
        this.cogroup(other, partitioner).flatMapValues( pair =>
          for (v <- pair._1.iterator; w <- pair._2.iterator) yield (v, w)
        )
          }

    wKioL1ZqZSiyNF3AAASD75GrFR8284.png  

    **yield** 关键字的简短总结:

        针对每一次 for 循环的迭代, yield 会产生一个值,被循环记录下来 (内部实现上,像是一个缓冲区).
        当循环结束后, 会返回所有 yield 的值组成的集合.
        返回集合的类型与被遍历的集合类型是一致的.

    参考文章:
    http://unmi.cc/scala-yield-samples-for-loop/



    cache persist也是lazy级别的


    Action本质sc.runJob

    foreach

    collect()相当于toArray返回一个数组

    collectAsMap()对keyvalue类型的RDD操作返回一个HashMap,key重复后面的元素会覆盖前面的元素reduce

    源码解析:先调用collect()再放到HashMap[K, V]中

         def collectAsMap(): Map[K, V] = {
        val data = self.collect()
        val map = new mutable.HashMap[K, V]
        map.sizeHint(data.length)
        data.foreach { pair => map.put(pair._1, pair._2) }
        map
          }
        
    **reduceByKeyLocally**相当于reduceByKey+collectAsMap()

    该函数将RDD[K,V]中每个K对应的V值根据映射函数来运算,运算结果映射到一个Map[K,V]中,而不是RDD[K,V]。

    参考文章:
    http://lxw1234.com/archives/2015/07/360.htm



    **lookup**也是针对keyvalue返回指定key对应的value形成的seq


        def lookup(key: K): Seq[V] 


    **reduce fold(每个分区是串行,有个初始值) aggregate(并行,与fold类似)**

    前两个元素作用的结果与第三元素作用依次类推


    **SequenceFile**文件是Hadoop用来存储二进制形式的key-value对而设计的一种平面文件(Flat File)。目前,也有不少人在该文件的基础之上提出了一些HDFS中小文件存储的解决方案,他们的基本思路就是将小文件进行合并成一个大文件,同时对这些小文件的位置信息构建索引。不过,这类解决方案还涉及到Hadoop的另一种文件格式——**MapFile**文件。SequenceFile文件并不保证其存储的key-value数据是按照key的某个顺序存储的,同时不支持append操作。

    参考文章:http://blog.csdn.net/xhh198781/article/details/7693358




    **saveAsTextFile**->TextOutputFormat  (key为null,value为元素toString)

    **saveAsObjectFile**(二进制)->saveAsSequenceFile->SequenceFileOutputFormat(key为null,value为BytesWritable)


    cachepersist   


    **checkpoint()**机制避免缓存丢失(内存不足)要重新计算带来的性能开销,会导致另外一个作业,比缓存更可靠

    SparkContex.setCheckpointDir设置目录位置

  • 相关阅读:
    d
    今天刚注册,测试下
    关于Hadoop的简单介绍
    leveldb 阅读笔记 (2) 简易测试框架
    leveldb 阅读笔记(1) 内存分配器 Arena
    数论
    伴随网站
    convenience website
    大佬独特的骗分技巧
    动态规划
  • 原文地址:https://www.cnblogs.com/nucdy/p/8029220.html
Copyright © 2020-2023  润新知