• Spark算子讲解(一)


    1:Zip算子

    def zip[U](other: RDD[U])(implicit arg0: ClassTag[U]): RDD[(T, U)]

    将两个RDD做zip操作,如果当两个RDD分区数目不一样的话或每一个分区数目不一样的话则会异常。

    例如:

    val rdd1 = sc.parallelize(Array(1,2,3,4,5,6),2)
    val rdd2 = sc.parallelize(Array(1,2,3,4,5,6),3)
    rdd.zip(rdd1).collect

    异常信息:

    java.lang.IllegalArgumentException: Can't zip RDDs with unequal numbers of partitions: List(2, 3)
      at org.apache.spark.rdd.ZippedPartitionsBaseRDD.getPartitions(ZippedPartitionsRDD.scala:57)
      at org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:252)
      at org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:250)

    例如:

    val rdd1 = sc.parallelize(Array(1,2,3,4,5,6),2)
    val rdd2 = sc.parallelize(Array(1,2,3,4,5,6,7),2)
    rdd.zip(rdd1).collect

    异常信息:

    Caused by: org.apache.spark.SparkException: Can only zip RDDs with same number of elements in each partition

    2:zipPartitions

    以分区为单位进行zip操作,要求分区数目相等。否则异常。

    val rdd1 = sc.parallelize(Array(1,2,3,4,5,6),2)
    val rdd2 = sc.parallelize(Array(1,2,3,4,5,6,7),2)
    val func = (x:Iterator[Int], y:Iterator[Int])=>x.toSeq.++(y.toSeq).toIterator
    rdd1.zipPartitions(rdd2)(func).collect

    3:zipWithIndex

    给RDD中的每一个元素添加上索引号,组成二元组。索引号从0开始并且索引号类型是Long,当RDD分区大于1个时候需要出发一个Spark Job。

    4:zipWithUniqueId

    var rdd1 = sc.makeRDD(Seq("A","B","C","D","E","F"),2)
    //rdd1有两个分区,
    rdd1.zipWithUniqueId().collect
     Array[(String, Long)] = Array((A,0), (B,2), (C,4), (D,1), (E,3), (F,5))
    //总分区数为2
    //第一个分区第一个元素ID为0,第二个分区第一个元素ID为1
    //第一个分区第二个元素ID为0+2=2,第一个分区第三个元素ID为2+2=4
    //第二个分区第二个元素ID为1+2=3,第二个分区第三个元素ID为3+2=5

    其实就是按照每一个的分区的每一个元素的顺序进行编号。这个算子不需要出发作业到集群运行。

    5:union

    RDD求并集操作,不会自动去重。

    res31: Array[Int] = Array(1, 2, 3, 4, 5, 6)
    
    scala> rdd2.collect
    collect   collectAsync
    
    scala> rdd2.collect
    res32: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7)
    
    scala> rdd1.union(rdd2).collect
    collect   collectAsync
    
    scala> rdd1.union(rdd2).collect
    res34: Array[Int] = Array(1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7)//不去重

    6:distinct

    scala> unionRDD.collect
    res38: Array[Int] = Array(1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7)
    scala> unionRDD.distinct.collect
    res39: Array[Int] = Array(4, 1, 5, 6, 2, 3, 7)

    实现去重。

    7:treeReduce

    treeReduce有点类似于reduce函数,也不需要传入初始值,只不过这个算子使用一个多层树的形式来进行reduce操作。

    scala> rdd1.collect
    res42: Array[Int] = Array(1, 2, 3, 4, 5, 6)
    
    scala> rdd1.treeReduce((x,y)=>x+y)
    res43: Int = 21

    8:aggregate

    scala> rdd1.collect
    res53: Array[Int] = Array(1, 2, 3, 4, 5, 6)
    
    scala> rdd1.partitions.length
    res54: Int = 2
    
    scala> rdd1.aggregate(1)((x,y)=>x+y,(x,y)=>x+y)
    res56: Int = 24
    
    scala> rdd1.repartition(3).aggregate(1)((x,y)=>x+y,(x,y)=>x+y)
    res57: Int = 25

    我们设置的聚集函数的ZeroValue值是1,这个值会每一个分区聚集时候使用一次,最后在聚集所有分区时候在使用一次。

    我们这里面分区内部元素计算函数是:

    (x,y)=>x+y

    分区之间的聚集函数:

    (x,y)=>x+y

    由于rdd1默认是2个分区,所以在计算两个分区时候使用两次,相当于+1,最后合并两个分区时候有使用一次,相当于再加1.所以一共加3,,即:

    1+2+3+4+5+6=21,21+3 =24.另一个只因为多一个分区,所以多累加1.

    9:treeAggregate

    和8中聚集算子效果一样,只不过使用的是树的层次结构聚集。

    10:top

    返回前面n个最大元素,可以定义排序规则

    11:takeSample

    def takeSample(withReplacement: Boolean, num: Int, seed: Long = Utils.random.nextLong): Array[T]

    随机采样,抽取num个样例。可以指定是否重复抽取,随机数种子是一个生成随机数的初始条件,可以使用系统时间戳作为种子值。

    当不允许重复抽取时候,num数目大于rdd元素数目不会报错,此时只会抽取rdd的所有元素。

    12:takeOrdered

    def takeOrdered(num: Int)(implicit ord: Ordering[T]): Array[T]

    抽取出num个个最小的元素,唯一和top区别就是top抽取大的,takeOrdered抽取小的。

    13:take

    def take(num: Int): Array[T]

    返回num个数据,一般当数据较大的时候如果collect操作会导致Driver内存溢出,所以此时可以使用take携带少量数据到Driver。

    14:subtract

    def subtract(other: RDD[T]): RDD[T]

    返回一个在当前RDD中且不在other中的元素所生成的RDD

    15:sortBy

    def sortBy[K](f: (T) ⇒ K, ascending: Boolean = true, numPartitions: Int = this.partitions.length)(implicit ord: Ordering[K], ctag: ClassTag[K]): RDD[T]

    例如:

    scala> rdd1.collect
    res19: Array[Int] = Array(1, 2, 3, 4, 5)
    
    scala> val rdd2 = rdd1.map(x=>(x,scala.util.Random.nextInt(100),scala.util.Random.nextInt(100)))
    rdd2: org.apache.spark.rdd.RDD[(Int, Int, Int)] = MapPartitionsRDD[33] at map at <console>:26
    
    scala> rdd2.collect
    collect   collectAsync
    
    scala> rdd2.collect
    res20: Array[(Int, Int, Int)] = Array((1,87,34), (2,5,62), (3,51,60), (4,72,33), (5,33,23))
    
    scala> res13.sortBy(x=>x._3).collect
    res21: Array[(Int, Int, Int)] = Array((3,26,12), (4,45,28), (1,12,37), (2,71,67), (5,80,96))

    16:sample

    def sample(withReplacement: Boolean, fraction: Double, seed: Long = Utils.random.nextLong): RDD[T]

    随机采样,是否重复采样,抽取数据的百分比例。

    17:repartition

    def repartition(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T]

    重新创建一个只有numPartitions个分区的RDD,提高分区数或降低分区数会改变并行度,内部实现实现需要shuffle。如果需要降低RDD的分区数的话尽可能使用coalesce算子,它会避免shuffle的发生。

    18:coalesce

    def coalesce(numPartitions: Int, shuffle: Boolean = false, partitionCoalescer: Option[PartitionCoalescer] = Option.empty)(implicit ord: Ordering[T] = null): RDD[T]

    降低原来RDD的分区数目到numPartitions个分区。例如由1000个分区降到100个分区的话,这样是一个窄依赖,因此不需要shuffle过程。

    但是如果RDD原本有2个分区的话,当我们调用coalesce(5)的话,生成的RDD分区还将是2,不会增加,但是如果调用coalesce(1)的话,则会生成分区个数为1的RDD。(coalesce只会减少分区数,不会增加分区数)。

    拓展:如果我们的RDD分区数为1的话,我们可以传递shuffle=true,当计算时候会进行shuflle分布到多个节点进行计算。

    19:checkpoint

    def checkpoint(): Unit

    Mark this RDD for checkpointing. It will be saved to a file inside the checkpoint directory set with SparkContext#setCheckpointDir and all references to its parent RDDs will be removed. This function must be called before any job has been executed on this RDD. It is strongly recommended that this RDD is persisted in memory, otherwise saving it on a file will require recomputation.

    20:cartesian

    def cartesian[U](other: RDD[U])(implicit arg0: ClassTag[U]): RDD[(T, U)]

    两个RDD生成笛卡尔积。

    scala> rdd1.collect
    res37: Array[Int] = Array(1, 2, 3, 4, 5)
    
    scala> rdd2.collect
    res38: Array[Int] = Array(6, 7, 8, 9, 10)
    
    scala> rdd1.cartesian(rdd2).collect
    res39: Array[(Int, Int)] = Array((1,6), (1,7), (2,6), (2,7), (1,8), (1,9), (1,10), (2,8), (2,9), (2,10), (3,6), (3,7), (4,6), (4,7), (5,6), (5,7), (3,8), (3,9), (3,10), (4,8), (4,9), (4,10), (5,8), (5,9), (5,10))

    21:cache

    def cache(): RDD.this.type

    将RDD缓存,缓存级别为:MEMORY_ONLY

    22:persist

    def persist(): RDD.this.type

    将RDD缓存,缓存级别为:MEMORY_ONLY

    23:persist

    def persist(newLevel: StorageLevel): RDD.this.type

    指定缓存级别,在第一次被计算之后进行缓存。

    24:keyBy

    def keyBy[K](f: (T) ⇒ K): RDD[(K, T)]

    根据函数f进行选取key,例如:

    scala> rdd1.collect
    res43: Array[Int] = Array(1, 2, 3, 4, 5)
    
    scala> rdd1.keyBy(x=>x*x).collect
    res44: Array[(Int, Int)] = Array((1,1), (4,2), (9,3), (16,4), (25,5))

    25:intersection

    def intersection(other: RDD[T]): RDD[T]

    求两个RDD的交集

  • 相关阅读:
    钉钉outgoing机器人小项目开发
    js根据cookie判断,一天之内只弹出一次弹窗
    js倒计时功能
    jquery的$().each,$.each的区别
    VS代码提示自动高亮
    winform当前屏幕大小
    动态增删改控件
    datagridveiw样式
    sql 语句 提取中文的首字母
    按键监听及重写
  • 原文地址:https://www.cnblogs.com/leodaxin/p/7499094.html
Copyright © 2020-2023  润新知