算子

本文详细解析了Spark中MapPartitionsRDD算子的底层执行流程,包括连接配置、RDD创建与分区处理,对比map与mapPartitions的效率差异,并深入探讨flatMap算子的工作原理及其在数据处理中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MapPartitionsRDD 算子的程序与应用

程序底层执行流程,

1.连接Spark配置文件,设置项目名称,和创建本地地址,

2.创建连接,创建RDD,分三个去,把9个数字均匀的分配到三个去里面,调用RDD,对RDD操作,本质上是对RDD里面的每一个分      区进行操作,每一个分区有对应一个Task,Task里面的逻辑也就是分区对应的计算逻辑,

3.调用map,从下面的程序中可以得知,每一条数据都会调用一次map函数,这样就降低数据处理的效率,

4.分析一下map底层的实现逻辑,在调用map方法的时候,先看这个函数是否可以序列化,在new  MapPartitionsRDD[] ,把上次的partition传进去,也就是新的RDD持有老的RDD的引用,并传入新的迭代器里面,在mapPartitoinRDD里面传的是,上下文,分区编号,迭代器(TaskContext,Int,Iterator) ,通过迭代器实现对里面数据的处理,

5.同时里面有一个方法叫做computer,computer会应用传进来的函数,分别传进上下文,分区编号,因为要对数据进行运算, // 所以要到上一个迭代器拿数据,所以传进去一个父类的迭代器 // (context,split.index,firstParent[T].iterator(split,context)) ,而这个iterator看缓存是否存在数据, // 如果缓存有数据,那么直接到缓存里面直接取,如果没缓存.那么直接从源头拿过来

  def main(args: Array[String]): Unit = {
    //上传连接机器的名字,和主机地址为本地地址
    val conf = new SparkConf().setAppName("MapPartitionsDemo").setMaster("local[*]")
    val sc = new SparkContext(conf)

    //创建RDD,并分三个分区
    //会把9个数据均匀的分配到中三个区域里面
    val words = sc.makeRDD(List(1, 2, 3, 4, 5, 6, 7, 8, 9), 3)

    //调用RDD,对RDD进行操作本质上是对RDD里面的每一个分区进行操作,一个分区对应一个Task,Task里面的逻辑
    //也就是对分区进行计算的逻辑
    //调用map方法
    //val re = words.map(_ * 100)
    val result = words.map(x => {  //这种模式就要一条数据调用一次map,相对来说效率比较低
      //可以直接取TaskContext,然后调用partition的Id
      val index = TaskContext.getPartitionId()
      (index,x*100)
    })
    //写一个相对路径
    result.saveAsTextFile("map-out")
    sc.stop()

    //调用map方法本质上是看这个函数是不是可以序列化的,在new MapPartitionsRDD[],把上一次的partition
    //传进去,也就是新的RDD持有老的RDD得引用,在新的迭代器里面,
    //在mapPartitionsRDD里面传进去的是上下文,分区编号,迭代器(TaskContext,Int,Iterator),对立面的数据进行处理
    //输出一个新的迭代器Iterator,(当Task在executor里面被执行的时候会产生新的iterator)
    //同时里面有一个方法叫做computer,computer会应用传进来的函数,分别传进上下文,分区编号,因为要对数据进行运算,
    // 所以要到上一个迭代器拿数据,所以传进去一个父类的迭代器
    // (context,split.index,firstParent[T].iterator(split,context)) ,而这个iterator看缓存是否存在数据,
    // 如果缓存有数据,那么直接到缓存里面直接取,如果没缓存.那么直接从源头拿过来
  }

第二段代码,是通过调用mapPartitions,实现将数据以分区单位的方式取出来,一个分区就是一个迭代器,然后再迭代器里面通过调用map方法对数据进行处理,这样

底层代码实现

1.查看程序是否可执行,

2.创建一个新的迭代器,传入TaskContext,Int,Iterator,这不是对迭代器进行map操作,而是把把所写的函数写到迭代器里面

然后传到新的迭代器里面,所以后面传入的是一个分区的迭代器,这样就可以操作一个分区的数据了(实在不懂可以多看源码)

 

 //调用mapPatitions方法,可将数据以分区单位取出来,一个分区就是一个迭代器
    //底层代码,先new一个新的MapPartitionsRDD,里面传,上下文,分区编号,应用传入的参数放进迭代器里面,
    // 也就是传入的函数得到的是一个迭代器,

    //it的迭代器,对mapPartitons的要求是输入的是迭代器,返回的也是迭代器
    val result2 = words.mapPartitions(it=>{
      //这个是得到每个分区的分区编号
      val index = TaskContext.getPartitionId()   //这个以后有几个分区就调用几次,调用一个分区后,
      //开始执行分区里面的相关逻辑
//调用map,这个map是迭代器里面的方法,返回一个新的迭代器,第一个int是分区编号,
val Iterator1: Iterator[(Int, Int)] = it.map(x => { //注意x是局部变量,输入一个x  输出x*100
(index, x * 100)
})
Iterator1
    })
    result2.saveAsTextFile("map-out02")
    sc.stop()
  }

 这个也是对先分区,然后再对个区里面的内容进行操作,有多少分区调用几次map

//输入的是一个迭代器,返回的也是一个迭代器
    val result4 = words.mapPartitionsWithIndex((index: Int, it: Iterator[Int]) => {
      it.map(e => {
        s"partitionIndex:$index,element:$e"
      })
    })


    /*val r = result4.collect()
    println(r)
    sc.stop()*/
    result4.saveAsTextFile("map-out03")
    sc.stop()
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

 

mapPartition和mapPartitionsWithIndex在什么情况下使用,都可以实现map方法,filter方法,但最终要返回新的map迭代器,而mapPartitionsWithIndex,在底层比mapPartition多传入了一个index,

 

4.flatMap算子(注意:前面几个都是窄依赖算子,这些算子都是只需要在同一个task里面执行就可以了,不需要考虑shuffle)

 //分析通过RDD调用flatMap方法,就是通过迭代器调用flatMap方法,然后把迭代器调用flatm=Map 方法
    val conf = new SparkConf().setAppName("flatMapDemo").setMaster("local[*]")
    //创建连接
    val sc = new SparkContext(conf)

    //在driver定义数组
    val words = Array("hadoop,flink,hive,hadoop", "hive,hbase,hive,hbase,spark", "spark,hive,flink,hadoop,scala")

    //调用RDD,然后把数组的应用传入到parallelize方法里面,得到一个新的RDD
    val lines: RDD[String] = sc.parallelize(words)  //RDD未来里面要装的是未来要处理的string类型的数据
    //flatMap底层输入的是输入可以是任意类型,返回必须是TraversableOnce,也就是可以返回List,set,等都行,只要是能够压平的就行


    //可以看出输入的是String类型,但是输出是被压平的char类型
    //val flat: RDD[Char] = lines.flatMap(x => x)
    //一个个大的数组压成一个个小的数组
    val flat: RDD[String] = lines.flatMap(x => x.split(" "))
    val r = flat.collect()
    println(r.toBuffer)//这样的结构都变成char类型的数据

    /**
     * 源代码,
     * 1.检查传入的数据是否可以序列化,
     * 2.new MapPartitionsRDD 就是对每一个 分区进行操作的一个RDD
     * 3.对RDD调用flatMap,本质上是对RDD上每一个分区调用flatMap,第一个是RDD上调用faltmap,第二个是迭代器上调用flatMap
     * 4.然后把传入迭代器的数据进行压平
     */

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值