为了账号安全,请及时绑定邮箱和手机立即绑定

Spark函数详解系列之RDD基本转换

标签:
Premiere

摘要:

 RDD:弹性分布式数据集,是一种特殊集合 ‚ 支持多种来源 ‚ 有容错机制 ‚ 可以被缓存 ‚ 支持并行操作,一个RDD代表一个分区里的数据集

 RDD有两种操作算子:

     Transformation(转换):Transformation属于延迟计算,当一个RDD转换成另一个RDD时并没有立即进行转换,仅仅是记住了数据集的逻辑操作

     Ation(执行):触发Spark作业的运行,真正触发转换算子的计算

基础转换操作:

1.map(func):数据集中的每个元素经过用户自定义的函数转换形成一个新的RDD,新的RDD叫MappedRDD

(例1)

object Map {

  def main(args: Array[String]) {

    val conf = new SparkConf().setMaster("local").setAppName("map")

    val sc = new SparkContext(conf)

    val rdd = sc.parallelize(1 to 10)  //创建RDD

    val map = rdd.map(_*2)             //对RDD中的每个元素都乘于2

    map.foreach(x => print(x+" "))

    sc.stop()

  }

}

输出:

2 4 6 8 10 12 14 16 18 20

webp

(RDD依赖图:红色块表示一个RDD区,黑色块表示该分区集合,下同)

webp


2.flatMap(func):与map类似,但每个元素输入项都可以被映射到0个或多个的输出项,最终将结果”扁平化“后输出

(例2)

//...省略sc

   val rdd = sc.parallelize(1 to 5)

   val fm = rdd.flatMap(x => (1 to x)).collect()

   fm.foreach( x => print(x + " "))

输出:

1 1 2 1 2 3 1 2 3 4 1 2 3 4 5

如果是map函数其输出如下:

Range(1) Range(1, 2) Range(1, 2, 3) Range(1, 2, 3, 4) Range(1, 2, 3, 4, 5)

(RDD依赖图)

webp


3.mapPartitions(func):类似与map,map作用于每个分区的每个元素,但mapPartitions作用于每个分区工

func的类型:Iterator[T] => Iterator[U]

假设有N个元素,有M个分区,那么map的函数的将被调用N次,而mapPartitions被调用M次,当在映射的过程中不断的创建对象时就可以使用mapPartitions比map的效率要高很多,比如当向数据库写入数据时,如果使用map就需要为每个元素创建connection对象,但使用mapPartitions的话就需要为每个分区创建connetcion对象

(例3):输出有女性的名字:

object MapPartitions {

//定义函数

  def partitionsFun(/*index : Int,*/iter : Iterator[(String,String)]) : Iterator[String] = {

    var woman = List[String]()

    while (iter.hasNext){

      val next = iter.next()

      next match {

        case (_,"female") => woman = /*"["+index+"]"+*/next._1 :: woman

        case _ =>

      }

    }

    return  woman.iterator

  }


  def main(args: Array[String]) {

    val conf = new SparkConf().setMaster("local").setAppName("mappartitions")

    val sc = new SparkContext(conf)

    val l = List(("kpop","female"),("zorro","male"),("mobin","male"),("lucy","female"))

    val rdd = sc.parallelize(l,2)

    val mp = rdd.mapPartitions(partitionsFun)

    /*val mp = rdd.mapPartitionsWithIndex(partitionsFun)*/

    mp.collect.foreach(x => (print(x +" ")))   //将分区中的元素转换成Aarray再输出

  }

}

输出:

kpop lucy

其实这个效果可以用一条语句完成

1

val mp = rdd.mapPartitions(x => x.filter(_._2 == "female")).map(x => x._1)

之所以不那么做是为了演示函数的定义

  (RDD依赖图)

webp


4.mapPartitionsWithIndex(func):与mapPartitions类似,不同的时函数多了个分区索引的参数

func类型:(Int, Iterator[T]) => Iterator[U]

(例4):将例3橙色的注释部分去掉即是

输出:(带了分区索引)

[0]kpop [1]lucy


5.sample(withReplacement,fraction,seed):以指定的随机种子随机抽样出数量为fraction的数据,withReplacement表示是抽出的数据是否放回,true为有放回的抽样,false为无放回的抽样

(例5):从RDD中随机且有放回的抽出50%的数据,随机种子值为3(即可能以1 2 3的其中一个起始值)

//省略

    val rdd = sc.parallelize(1 to 10)

    val sample1 = rdd.sample(true,0.5,3)

    sample1.collect.foreach(x => print(x + " "))

    sc.stop


6.union(ortherDataset):将两个RDD中的数据集进行合并,最终返回两个RDD的并集,若RDD中存在相同的元素也不会去重

//省略sc

   val rdd1 = sc.parallelize(1 to 3)

   val rdd2 = sc.parallelize(3 to 5)

   val unionRDD = rdd1.union(rdd2)

   unionRDD.collect.foreach(x => print(x + " "))

   sc.stop

输出:

1 2 3 3 4 5

7.intersection(otherDataset):返回两个RDD的交集

//省略sc

val rdd1 = sc.parallelize(1 to 3)

val rdd2 = sc.parallelize(3 to 5)

val unionRDD = rdd1.intersection(rdd2)

unionRDD.collect.foreach(x => print(x + " "))

sc.stop

输出:

3 4


8.distinct([numTasks]):对RDD中的元素进行去重

//省略sc

val list = List(1,1,2,5,2,9,6,1)

val distinctRDD = sc.parallelize(list)

val unionRDD = distinctRDD.distinct()

unionRDD.collect.foreach(x => print(x + " "))

输出:

1 6 9 5 2



作者:Java大生
链接:https://www.jianshu.com/p/a035d937c31b


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消