SparkCore-RDD编程

SparkCore-RDD编程操作

0. 大纲

  • Spark程序的执行过程
  • RDD的操作
    • RDD的转换操作
    • 共享变量
  • 高级排序

1. Spark程序执行过程

1.1. WordCount案例程序的执行过程

图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ar7k9Q5x-1587102271050)(assets/01Spark作业运行原理剖析.png)]

1.2. Spark程序执行流程

在这里插入图片描述

2. RDD的操作

​ At a high level, every Spark application consists of a driver program that runs the user’s main function and executes various parallel operations on a cluster. The main abstraction Spark provides is a resilient distributed dataset (RDD), which is a collection of elements partitioned across the nodes of the cluster that can be operated on in parallel. RDDs are created by starting with a file in the Hadoop file system (or any other Hadoop-supported file system), or an existing Scala collection in the driver program, and transforming it. Users may also ask Spark to persist an RDD in memory, allowing it to be reused efficiently across parallel operations. Finally, RDDs automatically recover from node failures.

​ A second abstraction in Spark is shared variables that can be used in parallel operations. By default, when Spark runs a function in parallel as a set of tasks on different nodes, it ships a copy of each variable used in the function to each task. Sometimes, a variable needs to be shared across tasks, or between tasks and the driver program. Spark supports two types of shared variables: broadcast variables, which can be used to cache a value in memory on all nodes, and accumulators, which are variables that are only “added” to, such as counters and sums.

2.1. RDD的初始化

​ RDD的初始化,原生api提供的2中创建方式,一种就是读取文件textFile,还有一种就是加载一个scala集合parallelize。当然,也可以通过transformation算子来创建的RDD。

2.2. RDD的操作

​ 需要知道RDD操作算子的分类,基本上分为两类:transformation和action,当然更加细致的分,可以分为输入算子,转换算子,缓存算子,行动算子。

在这里插入图片描述

输入:在Spark程序运行中,数据从外部数据空间(如分布式存储:textFile读取HDFS等,parallelize方法输入Scala集合或数据)输入Spark,数据进入Spark运行时数据空间,转化为Spark中的数据块,通过BlockManager进行管理。
运行:在Spark数据输入形成RDD后便可以通过变换算子,如filter等,对数据进行操作并将RDD转化为新的RDD,通过Action算子,触发Spark提交作业。 如果数据需要复用,可以通过Cache算子,将数据缓存到内存。
输出:程序运行结束数据会输出Spark运行时空间,存储到分布式存储中(如saveAsTextFile输出到HDFS),或Scala数据或集合中(collect输出到Scala集合,count返回Scala int型数据)。

2.2.1. transformation转换算子

  • map

    1. 说明

      rdd.map(func):RDD,对rdd集合中的每一个元素,都作用一次该func函数,之后返回值为生成元素构成的一个新的RDD。

    2. 编码

      对rdd中的每一个元素×7

      object _01RDDOps {
          def main(args: Array[String]): Unit = {
              val conf = new SparkConf()
                          .setAppName(s"${_01RDDOps.getClass.getSimpleName}")
                          .setMaster("local[*]")
      
              val sc = new SparkContext(conf)
              //map 原集合*7
              val list = 1 to 7
              //构建一个rdd
              val listRDD:RDD[Int] = sc.parallelize(list)
      
      //        listRDD.map((num:Int) => num * 7)
      //        listRDD.map(num => num * 7)
              val ret = listRDD.map(_ * 7)
              ret.foreach(println)
      
              sc.stop()
          }
      }
      
  • flatMap

    1. 说明

      rdd.flatMap(func):RDD ==>rdd集合中的每一个元素,都要作用func函数,返回0到多个新的元素,这些新的元素共同构成一个新的RDD。所以和上述map算子进行总结:

      map操作是一个one-2-one的操作

      flatMap操作是一个one-2-many的操作

    2. 编码

      案例:将每行字符串,拆分成一个个的单词

      def  flatMapOps(sc:SparkContext): Unit = {
          val list = List(
              "jia jing kan kan kan",
              "gao di di  di di",
              "zhan yuan qi qi"
          )
          val listRDD = sc.parallelize(list)
          listRDD.flatMap(line => line.split("\\s+"))
          .foreach(println)
      }
      
  • filter

    1. 说明

      rdd.filter(func):RDD ==> 对rdd中的每一个元素操作func函数,该函数的返回值为Boolean类型,保留返回值为true的元素,共同构成一个新的RDD,过滤掉哪些返回值为false的元素。

    2. 编程

      案例:保留集合中的偶数

      def filterMapOps(sc:SparkContext): Unit = {
          val list = 1 to 10
          sc.parallelize(list)
          .filter(_ % 2 == 0)
          .foreach(println)
      }
      
  • sample

    1. 说明

      rdd.sample(withReplacement:Boolean, fraction:Double [, seed:Long]):RDD ===> 抽样,需要注意的是spark的sample抽样不是一个精确的抽样。一个非常重要的作用,就是来看rdd中数据的分布情况,根据数据分布的情况,进行各种调优与优化。—>数据倾斜。

      首先得要知道这三个参数是啥意思

      withReplacement:抽样的方式,true有放回抽样, false为无返回抽样

      fraction: 抽样比例,取值范围就是0~1

      seed: 抽样的随机数种子,有默认值,通常也不需要传值

    2. 编程

      案例:从10w个数中抽取千分之一进行样本评估

      def sampleMapOps(sc:SparkContext): Unit = {
          val listRDD = sc.parallelize(1 to 100000)
      
          var sampledRDD = listRDD.sample(true, 0.001)
          println("样本空间的元素个数:" + sampledRDD.count())
          sampledRDD = listRDD.sample(false, 0.001)
          println("样本空间的元素个数:" + sampledRDD.count())
      }
      
  • union

    1. 说明

      rdd1.union(rdd2),联合rdd1和rdd2中的数据,形成一个新的rdd,其作用相当于sql中的union all。

    2. 编程

      案例:合并两个rdd中的数据,生成一个新的rdd,做后续统一的处理

      def unionMapOps(sc:SparkContext): Unit = {
          val listRDD1 = sc.parallelize(List(1, 3, 5, 7, 9))
          val listRDD2 = sc.parallelize(List(2, 4, 5, 8, 10))
          val unionedRDD:RDD[Int] = listRDD1.union(listRDD2)
      
          unionedRDD.foreach(println)
      }
      
  • join

    1. 说明

      join就是sql中的inner join,join的效果工作7种。

    在这里插入图片描述

      从具体的写法上面有如下几种
    
      - 交叉连接
    
          A a accross join B b;这种操作方式会产生笛卡尔积,在工作中一定要避免。
    
      - 内连接
    
          A a [inner] join B b [where|on a.id = b.id]; 有时候也写成:A a, B b(自连接) 是一种等值连接。所谓等值连接,就是获取A和B的交集。
    
      - 外连接
    
          - 左外连接
    
              以左表为主体,查找右表中能够关联上的数据,如果管理不上,显示null。
    
              A a left outer join B b on a.id = b.id。
    
          - 右外连接
    
              是以右表为主体,查找左表中能够关联上的数据,如果关联不上,显示null。
    
              A a right outer join B b on a.id = b.id。
    
          - 全连接
    
              就是左外连接+右外连接
    
              A a full outer join B b on a.id = b.id。
    
          - 半连接 
    
              一般在工作很少用
    
          sparkcore中支持的连接有:笛卡尔积、内连接join,外连接(左、右、全)
    
      - spark连接
    
           要想两个RDD进行连接,那么这两个rdd的数据格式,必须是k-v键值对的,其中的k就是关联的条件,也就是sql中的on连接条件。
    
            假设,RDD1的类型[K, V], RDD2的类型[K, W]
    
          - 内连接
    
              val joinedRDD:RDD[(K, (V, W))] = rdd1.join(rdd2)
    
          - 左外连接
    
              val leftJoinedRDD:RDD[(K, (V, Option[W]))] = rdd1.leftOuterJoin(rdd2)
    
          - 右外连接
    
              val rightJoinedRDD:RDD[(K, (Option[V], W))] = rdd1.rightOuterJoin(rdd2)
    
          - 全连接
    
              val fullJoinedRDD:RDD[(K, (Option[V], Option[W]))] = rdd1.fullOuterJoin(rdd2)
    
    1. 编程

      案例:关联学生信息

      def joinedMapOps(sc:SparkContext): Unit = {
          //stu表:id,name,gender,age
          //score表:stuid,course, score
          val stuList = List(
              "1 严文青 女 18",
              "2 王大伟 男 55",
              "3 贾静凯 男 33",
              "4 old李 ladyBoy 31"
          )
      
          val scoreList = List(
              "1 语文 59",
              "3 数学 0",
              "2 英语 60",
              "5 体育 99"
          )
      
          val stuListRDD = sc.parallelize(stuList)
          val sid2StuInfoRDD:RDD[(Int, String)] = stuListRDD.map(line => {
              val sid = line.substring(0, line.indexOf(" ")).toInt
              val info = line.substring(line.indexOf(" ") + 1)
              (sid, info)
          })
          val scoreListRDD = sc.parallelize(scoreList)
          val sid2ScoreInfoRDD:RDD[(Int, String)] = scoreListRDD.map(line => {
              val sid = line.substring(0, line.indexOf(" ")).toInt
              val scoreInfo = line.substring(line.indexOf(" ") + 1)
              (sid, scoreInfo)
          })
          //查询有成绩的学生信息 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值