spark05

spark05

def main(args: Array[String]): Unit = {
    //每个用户最喜欢得电影类型
    //观看量   评分得平均值
  val conf = new SparkConf()
  conf.setMaster("local[*]")
  conf.setAppName("movie")
  val sc = new SparkContext(conf)
  val ratRDD:RDD[String] = sc.textFile("ratings.txt")
  val mRDD:RDD[String] = sc.textFile("movies.txt")
  val ratRDD1:RDD[(String,String)] = ratRDD.map(t=>{
    var strs = t.split(",")
    (strs(1),strs(0))
    //mId   userId
  })

  val mRDD1:RDD[(String,String)] = mRDD.flatMap(t=>{
    val strs = t.split(",")
    val mid = strs(0)
    val types = strs(strs.length-1).split("\\|")
    val mtype = types.map(tp=>{
      (mid,tp)
    })
    mtype
  })

 val joinRDD:RDD[(String,(String,String))] = ratRDD1 join mRDD1
  val joinRDD1:RDD[((String,String),Int)] = joinRDD.map(t=>{
    (t._2,1)
  })
  val userTypeCount:RDD[((String,String),Int)] = joinRDD1.reduceByKey(_+_)
  //用户  类型  观看量
  val userTypeCount2:RDD[(String,(String,Int))] = userTypeCount.map(t=>{
    (t._1._1,(t._1._2,t._2))
  })

  val result: RDD[(String, Iterable[(String, Int)])] = userTypeCount2.groupByKey()

  val finalResult:RDD[(String,(String,Int))] = result.mapValues(t=>{
    val list = t.toList.sortBy(-_._2)
    list(0)
  })

  finalResult.foreach(println)
}

作业题

 

object MoviesTest {
  def main(args: Array[String]): Unit = {
      //每个用户最喜欢得电影类型
      //观看量   评分得平均值
    val conf = new SparkConf()
    conf.setMaster("local[*]")
    conf.setAppName("movie")
    val sc = new SparkContext(conf)
    val ratRDD:RDD[String] = sc.textFile("ratings.txt")
    val mRDD:RDD[String] = sc.textFile("movies.txt")
    val ratRDD1:RDD[(String,String)] = ratRDD.map(t=>{
      var strs = t.split(",")
      (strs(1),strs(0))
      //mId   userId
    })

    val mRDD1:RDD[(String,String)] = mRDD.flatMap(t=>{
      val strs = t.split(",")
      val mid = strs(0)
      val types = strs(strs.length-1).split("\\|")
      val mtype = types.map(tp=>{
        (mid,tp)
      })
      mtype
    })

   val joinRDD:RDD[(String,(String,String))] = ratRDD1 join mRDD1
    val joinRDD1:RDD[((String,String),Int)] = joinRDD.map(t=>{
      (t._2,1)
    })
    val userTypeCount:RDD[((String,String),Int)] = joinRDD1.reduceByKey(_+_)
    //用户  类型  观看量

    val userArr = userTypeCount.map(_._1._1).distinct().collect()
    val map:Map[String,Int] = userArr.zipWithIndex.toMap

    val partitionedRDD:RDD[((String,String),Int)] = userTypeCount.partitionBy(new MPartitioner(map))

    val result: RDD[((String, String), Int)] = partitionedRDD.mapPartitions(t => {
      val topOne = t.toList.sortBy(-_._2).take(1)
      topOne.toIterator
    })

    result.foreach(println)
  }
}

class  MPartitioner(val map:Map[String,Int]) extends Partitioner {
  override def numPartitions: Int = map.size

  override def getPartition(key: Any): Int = {
   val user =  key.asInstanceOf[(String,String)]._1
    map(user)
  }
}

 

 

wordcount中得rdd数量

 

 

 

 

 

textFile算子中产生了两个rdd,第一个是hadoopRDD用于读取hdfs中得文件,这个读取使用得是hadoop得原生apikey longWritable  value  text

 

通过map方法将读取后得文件取value值,不取key

 

mapPartitionsRDDflatMap算子中产生

 

 

 

map算子中产生得mapPartitionsRdd

 

 

 

reduceByKey这个算子中产生了shuffledRDD

 

 

 

 

saveAsTextFile存储数据产生得MapPartitionsRDD

 

一个wordcount应用程序中产生了6rdd

hadoopRDD  mapPartitionsRDD mapPartitionsRDD  mapPartitionsRDD shuffledRDD mapPartitionsRDD

 

wordcount中得数据流向图

 

 

 

 

spark任务得调用流程

任务得层次

application  job   stage  task任务数量

 

spark任务得物理执行流程

spark任务在执行main方法得时候,并没有真正得执行

 

 

 

 

 

spark中的原理

RDD之间的依赖关系,父子关系,RDD之间存在血统血缘关系lineage

算子就是两个rdd之间的关系,这个关系又称之为依赖

dependency : shuffleDependency  narrowDependency:OneToOne RangeDependency

宽窄依赖

依赖的划分

rdd和子rdd之间存在依赖关系,宽依赖和窄依赖

  1. 从计算过程中:窄依赖是管道形式运算的,上一个rdd和下一个rdd之间的数据不会产生变化,数据在一个节点上不会流动,如果产生了节点之间的数据转移,宽依赖(shuffle
  2. 从失败恢复的角度:窄依赖的失败恢复比较快,rdd对应分区中的数据丢失就去上一个rdd上面的对应分区中寻找,如果是宽依赖,去上一个rdd上面的所有分区中去寻找
  3. 综上所述引入一个新的概念,stage,宽依赖会切分stage,窄依赖不会切分stage

管道形式的任务都属于一个stage

 

宽依赖和窄依赖的理解

上一个rdd的数据到下一个rdd中的时候对应分区中的数据不会发生改变,窄依赖

上一个rdd上面的数据不同分区中的数据到下一个rdd的分区中 宽依赖

窄依赖是一对一的 map  flatMap  union  filter  coalesce

以上的算子都是窄依赖,在窄依赖中算子产生的DAG图是一条线

窄依赖的算子都是pipeline形式的任务

 

 

 

 

宽依赖

reduceByKey  groupBykey  distinct  groupBy  repartition

以上都是宽依赖,他们的分区器都是hashPartitioner

shuffleDependency宽依赖

 

 

 

repartition是宽依赖,但是可以变为窄依赖repartition == coalesce(false)

 

join算子是一个特殊的算子(重点)

join算子是宽依赖还窄依赖????

 

 

join算子的底层使用的就是cogroup算子

 

 

 

 

根据源码得出两个rdd的分区其是一样的那么就是窄依赖,如果是不一样的就是宽依赖

怎么判断分区器是不是一样的?

 

 

 

分区器中含有一个equals方法,这个方法中判定逻辑,如果两个分区器都是hash分区器,并且分区数量一致,那么两个分区器就一样,那么就是窄依赖,不然就是宽依赖

 

scala> var arr = Array(("zhangsan",200),("lisi",700),("xiaohong",20000))

arr: Array[(String, Int)] = Array((zhangsan,200), (lisi,700), (xiaohong,20000))

 

scala> var arr1 = Array(("zhangsan",20),("lisi",30),("xiaohong",1))

arr1: Array[(String, Int)] = Array((zhangsan,20), (lisi,30), (xiaohong,1))

 

scala> sc.makeRDD(arr,3)

res7: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[8] at makeRDD at <console>:27

 

scala> sc.makeRDD(arr1,3)

res8: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[9] at makeRDD at <console>:27

 

scala> res7 join res8

res9: org.apache.spark.rdd.RDD[(String, (Int, Int))] = MapPartitionsRDD[12] at join at <console>:33

 

scala> res9.collect

res10: Array[(String, (Int, Int))] = Array((zhangsan,(200,20)), (xiaohong,(20000,1)), (lisi,(700,30)))

 

 

 

分区器都没有,分区数量一致就是宽依赖

scala> res7.reduceByKey(_+_)

res11: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[13] at reduceByKey at <console>:29

 

scala> res8.reduceByKey(_+_)

res12: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[14] at reduceByKey at <console>:29

 

scala>

 

scala> res11 join res12

res13: org.apache.spark.rdd.RDD[(String, (Int, Int))] = MapPartitionsRDD[17] at join at <console>:37

 

scala> res13.collect

res14: Array[(String, (Int, Int))] = Array((zhangsan,(200,20)), (xiaohong,(20000,1)), (lisi,(700,30)))

 

 

 

 

 

算子是不是宽依赖,看这个算子的上一个rdd和下一个rdd是不是在一个stage中存在

 

 

 

 

join之后的rdd分区数量

  1. 如果两个rdd都是普通的rdd

scala> sc.makeRDD(arr,3)

res15: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[18] at makeRDD at <console>:27

 

scala> sc.makeRDD(arr1,4)

res16: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[19] at makeRDD at <console>:27

 

scala> res15 join res16

res17: org.apache.spark.rdd.RDD[(String, (Int, Int))] = MapPartitionsRDD[22] at join at <console>:33

 

scala> res17.partitions.size

res18: Int = 4

如果两个rdd都是普通的rdd,而且分区数量不一样,那么以数量多的rdd为主

 

如果一个含有分区器的,一个是普通的rdd,以含有分区器的为主

 

scala> res15.reduceByKey(_+_)

res19: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[23] at reduceByKey at <console>:29

 

scala> res19 join res16

res20: org.apache.spark.rdd.RDD[(String, (Int, Int))] = MapPartitionsRDD[26] at join at <console>:35

 

scala> res20.partitions.size

res21: Int = 3

 

两个都是含有分区器的,以多的为主

scala> res16.reduceByKey(_+_)

res23: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[27] at reduceByKey at <console>:29

 

scala> res23 join res19

res24: org.apache.spark.rdd.RDD[(String, (Int, Int))] = MapPartitionsRDD[30] at join at <console>:37

 

scala> res24.partitions.size

res25: Int = 4

 

依赖和stage

依赖会进行切分stage,宽依赖会切分stage,一旦产生了shuffle流程那么就会切分stage

一个job中存在多少个stageshuffle算子的个数,shuffle算子的个数+1就是stage的个数

什么是stage呢?

 

 

 

 

 

 

shuffleMapStage是处理阶段,一个任务中存在多个shuffleMapStage,存在一个resultStage

一个任务中肯定存在一个resultStage,存在多个shuffleMapStage

 

依赖和容错

rdd的数据丢失后会从上一个rdd中进行数据的恢复

窄依赖会从上一个rdd对应的分区中找到相应的数据

宽依赖会从上一个rdd的所有分区中找到对应的数据,这些数据多个分区中的数据

rdd数据丢失以后会从哪个RDD找到?

Driver是任务运行的老大,这个driver相当于mr中的appMaster,属于整个任务的管理,driver端在任务提交以后会对任务进行解析,在解析的过程中会将任务的处理过程进行记录,失败的恢复的时候会在driver端找寻相应的业务逻辑。driver端是一次性的针对于每个应用都会产生一个新的driver,那么executorsdriver也是一套,所以executor也是一次性的。

driver还会进行故障重试,如果任务在executor中运行失败,那么会重启3次,会将失败的任务转移到另外的executor

 

DAG有向无环图

对于整个任务运行执行过程的一个优化

DAG有向无环图的开头 第一个rdd

DAG的终点:action

点(rdd+ 线(算子) 组成一个DAG图,切分阶段 按照shuffle流程切分阶段

可以清晰的体现出来缓存的概念

 

 

 

在一个任务中,如果运行两次一样的业务逻辑,数据会存在缓存,前面的部分业务逻辑会跳过,但是业务逻辑会执行两次。依赖关系和业务逻辑没有发生任何改变

 

 

spark任务的运行机制

 

 

posted @ 2019-09-16 15:04  lilixia  阅读(208)  评论(0编辑  收藏  举报