Spark Core(六)创建RDD、Transformation与Action、RDD的持久化

  1. 创建RDD什么是RDD请点击该链接

    1. 基于已有的数据集合并行化创建RDD

      val conf = new SparkConf().setAppName("").setMaster("local")
      val sc = new SparkContext(conf)
      val array = Array(1, 2, 3, 4, 5)
      //并行化创建RDD,并且指定该RDD的分区数量为3
      val rdd: RDD[Int] = sc.parallelize(array,3)
          val sparkConf = new SparkConf().setMaster("local").setAppName("RDDTest")
          val sc = new SparkContext(sparkConf)
          //调动SparkContext的makeRDD方法,该方法底层其实就是调用并行化创建RDD
          //的方法parallelize。该方创建RDD并且指定分区位置索引
          val mRDD: RDD[(Int, Array[String])] = sc.makeRDD(List((1, Array("a", "b", "c")), (2, Array("d", "e", "f"))))
            mRDD.foreach(x =>{
              val index: Int = x._1
              for (elem <- x._2) {
                print(index,elem)
              }
            })
    2. 基于外部文件创建RDD

      val conf = new SparkConf().setAppName("").setMaster("local")
      val sc = new SparkContext(conf)
      //基于本地文件创建RDD,并且指定该RDD的分区数量为3
      val rdd: RDD[String] = sc.textFile("C:\\a.txt"3)
    3. 基于Hadoop文件系统创建RDD

      val conf = new SparkConf().setAppName("").setMaster("local")
      val sc = new SparkContext(conf)
      //基于Hdfs文件创建RDD,格式一定是hdfs://....,并且指定该RDD的分区数量为3
      val rdd: RDD[String] = sc.textFile("hdfs://hadoop001:8020/spark.txt"3)
    4. 其他

      1. SparkContextwholeTextFiles()方法,可以针对一个目录中的大量小文件,返回由(fileName,fileContent)组成的Tuple。该方法返回的是文件名字和文件中的具体内容;而普通的textFile()方法返回的RDD中,每个元素就是文本中一行文本。

        val conf = new SparkConf().setAppName("").setMaster("local")
        val sc = new SparkContext(conf)
        //(String,String):第一个是文件名,第二个是文件的具体内容,并且指定该RDD分区数量为3
        val pairRDD: RDD[(String, String)] = sc.wholeTextFiles("xxxx"3)
      2. SparkContextsequenceFileK,V方法,可以针对SequenceFile创建RDDKV泛型类型就是SequenceFilekeyvalue的类型。KV要求必须是Hadoop的序列化机制,比如IntWritableText等。

        val conf = new SparkConf().setAppName("").setMaster("local")
        val sc = new SparkContext(conf)     
        //基于sequenceFile常见RDD,并指定分区数目为3
        sc.sequenceFile("hdfs://hadoop001:8020/squence.txt", classOf[IntWritable], classOf[Text],3)
      3. SparkContexthadoopRDD()方法,对于Hadoop的自定义输入类型,可以创建RDD。该方法接收JobConfInputFormatClassKeyValueClass
      4. SparkContextobjectFile()方法,可以针对之前调用的RDDsaveAsObjectFile()创建的对象序列化的文件,反序列化文件中的数据,并创建一个RDD
  2. Transformation(转换)

    1. 定义:Transformation是一种RDD的转换算子,它利用一个RDD经过转换算子生成一个新的RDD,该转换是一种延迟算子,当从一个RDD转换成新的RDD的时候,具体的转换算子不会立即执行,而是知识记录了由旧的RDD转换成新的RDD的逻辑操作。
    2. 方法

      方法名 方法解释
      map(func) 通过func函数作用在每个元素上从而返回一个新的数据集
      filter(func) 通过func函数对每个元素进行过滤,然后返回一个新的数据集
      flatMap(func) 类似于Map,只不过是利用func函数将每个单一的元素映射成多个区段,返回的是Seq
      mapPartitions(func) 类似于Map,只不过是在RDD的每个分区上运行,所以在T类型的RDD上运行时,func必须是Iterator => Iterator
      mapPartitionsWithIndex(func) 类似于mapPartitions,但也为func提供了一个表示分区索引的整数值,因此当运行在类型为TRDD上时。func类型必须是(Int, Iterator) => Iterator
      sample(withReplacement, fraction, seed)
      union(otherDataset) 将两个数据集合并成一个数据集
      intersection(otherDataset) 返回一个新的数据集,该数据己是两个数据集的交集
      distinct([numPartitions])) 对RDD中的数据去重
      sortByKey([ascending], [numPartitions]) 返回以Key排序的(K,V)键值对组成的RDDaccendingtrue时表示升序,为false时表示降序,numPartitions设置分区数,提高作业并行度
      groupByKey([numPartitions]) 对于K,V类型的数据集,按照K分组,将相同的Key合并,返回Key对应值集合的数据类型,(key,Iterabel)
      reduceByKey(func, [numPartitions]) Key进行分组,使用给定的func函数聚合value值, numPartitions设置分区数,提高作业并行度例
      aggregateByKey(zeroValue)(seqOp, combOp, [numPartitions]) aggregateByKey算子其实相当于是针对不同“key”数据做一个map+reduce规约的操作.seqOp操作会聚合各分区中的元素,然后combOp操作把所有分区的聚合结果再次聚合,两个操作的初始值都是zeroValue. seqOp的操作是遍历分区中的所有元素(T),第一个TzeroValue做操作,结果再作为与第二个T做操作的zeroValue,直到遍历完整个分区。combOp操作是把各分区聚合的结果,再聚合。aggregate函数返回一个跟RDD不同类型的值。因此,需要一个操作seqOp来把分区中的元素T合并成一个U,另外一个操作combOp把所有U聚合。
      sortByKey([ascending], [numPartitions]) 数据集类型为K,V,那么该算子就是根据Key对数据集里的每个元素进行排序
      join(otherDataset, [numPartitions]) 对两个RDD先进行cogroup操作形成新的RDD,再对每个Key下的元素进行笛卡尔积,numPartitions设置分区数,提高作业并行度
      cogroup(otherDataset, [numPartitions]) 对两个RDD(如:(K,V)和(K,W))相同Key的元素先分别做聚合,最后返回(K,Iterator,Iterator)形式的RDD,numPartitions`设置分区数,提高作业并行度
      cartesian(otherDataset) 对两个RDD中的所有元素进行笛卡尔积操作
      coalesce(numPartitions) RDD的分区进行重新分区,shuffle默认值为false,当shuffle=false时,不能增加分区数目,但不会报错,只是分区个数还是原来的
      repartition(numPartitions) 重新分区 必须shuffle 参数是要分多少区 少变多
      repartitionAndSortWithinPartitions(partitioner) 重新分区,并且在分区中进行排序
    3. 转换例子

      1. mapPartitions(func):传入一个func函数,然后在分区上执行RDD转换操作

        package com.lyz
        
        import org.apache.spark.rdd.RDD
        import org.apache.spark.{SparkConf, SparkContext}
        
        object RDDTest {
          def main(args: Array[String]): Unit = {
            val sparkConf = new SparkConf().setMaster("local").setAppName("RDDTest")
            val sc = new SparkContext(sparkConf)
            val rdd: RDD[(String, String)] = sc.makeRDD(List(("1", "x"), ("2", "y"), ("3", "y"), ("4", "x")))
            rdd.mapPartitions(partitionFunction).foreach(print(_))
          }
        
          def partitionFunction(iter: Iterator[(String, String)]): Iterator[String] = {
            var list = List[String]()
            while (iter.hasNext) {
              val value: (String, String) = iter.next()
              value match {
                case (_, "y") => list = value._1 :: list
                case _ =>
              }
            }
            list.iterator
          }
        }
        
      2. Simple(withReplacement, fraction, seed):抽样,来估计应用数据分布。

        1. withReplacement:抽样以后是否放回。
        2. fraction:格式为小数,抽象占数据的比例。
         def main(args: Array[String]): Unit = {
            val sparkConf = new SparkConf().setMaster("local").setAppName("RDDTest")
            val sc = new SparkContext(sparkConf)
            val rdd: RDD[Int] = sc.makeRDD(Array(1,2,3,4,5,6,7,8,10))
            //true:是否放回,0.5抽取元素的比例,4:随便填
            rdd.sample(true,0.5,4).foreach(print(_))
          }
          //打印结果为136810
      3. union(otherDateSet):将两个RDD合并成一个RDDotherDataSet:其他集合形式数据集

          def unionTest(sc: SparkContext): Unit = {
            val rdd_1: RDD[Int] = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7, 8, 10))
            val rdd_2: RDD[Int] = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7, 8, 10))
            rdd_1.union(rdd_2).foreach(print(_))
            //打印结果为两个RDD的所有元素
          }
      4. intersection(otherDataSet):求两个集合的交集。otherDataSet:其他形式的数据集。

        //求两个RDD的交际
          def intersectionTest(sc: SparkContext): Unit = {
            val rdd_1: RDD[Int] = sc.makeRDD(Array(1, 2, 3, 4))
            val rdd_2: RDD[Int] = sc.makeRDD(Array(3, 4, 5, 6))
            rdd_1.intersection(rdd_2).foreach(println(_))
            //运行结果为:34
          }
      5. distinct([numPartitions]):对数据集进行去重。numPartitions是一个可选参数,标识分区数,提高并行度。

          def distinctTest(sc: SparkContext): Unit = {
            val rdd_1: RDD[Int] = sc.makeRDD(Array(1, 2, 3, 4, 1))
            rdd_1.distinct().foreach(println(_))
            //执行结果为 1,23,4
          }
      6. sortByKey([ascending],[numPartition]):对k-v结构的数据集的元素进行排序。

        1. ascending:设置排序的方式,默认是true,表示升序,反之表示降序。
        2. numPartiton是可选参数,标识分区数,提高并行度。
        //对k-v结构的数据集的元素进行排序
          def sortByKey(sc: SparkContext): Unit = {
            val rdd_1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "c"), (4, "d")))
            //以key对键值对的数据集进行排序,第一个参数默认是true,表示升序排列,第二个参数是分区书,提供计算的并行度
            val sortRDD: RDD[(Int, String)] = rdd_1.sortByKey(true, 2)
            //打印结果为(1, "a"), (2, "b"), (3, "c"), (4, "d")
          }
      7. groupByKey([numPartitions]):对key-value结构的数据集按照key分组,然后把相同keyvalue放入一个迭代器里,并且返回key对应value的迭代器。

        1. numPartitions:是一个可选参数,标识分区数,提高并行度。
        def groupByKey(sc: SparkContext): Unit = {
           val rdd_1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (1, "c"), (2, "d")))
           //对k-v的数据集的元素按照key来分组,返回key对应value的Iterable迭代器,迭代器可以迭代出key对应的所有value
           val groupRDD: RDD[(Int, Iterable[String])] = rdd_1.groupByKey()
           groupRDD.foreach(println(_))
        
           /** 打印结果为,元素第二个元素为value的Iterable
             * (1,CompactBuffer(a, c))
             * (2,CompactBuffer(b, d))
             */
         }
      8. reduceByKey(func,[numParitions]):对k-v结构的数据集按照相同key进行分组,然后按照给定的func函数对value进行操作。func:对value操作的函数。

        1. numPartitions:分区数,提高作业并行度。
        def reduceByKeyTest(sc: SparkContext) {
            val rdd_1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (1, "c"), (2, "d")))
            rdd_1.reduceByKey(_ + _).foreach(println(_))
        
            /**
              * 打印结果为:
              * 
              * (1,ac)
              * (2,bd)
              */
          }
      9. aggregateByKey(zeroValue)(seqOp, combOp, [numPartitions]):相当于是针对不同"key"数据做一个map+reduce操作。

        1. zeroValue:按照业务需求初始化任意类型的值。
        2. seqOp:它是一个函数,这个函数功能就是能够遍历各个分区上的所有元素,它有两个参数,一个参数是zeroValue类型,一个是k-v元素中v元素的类型,它的返回值为zeroValue类型值,它的功能就是利用zeroValue与各个分区上k-v中的v进行不同的操作。
        3. combOp:通过seqOp操作每个分区得出的结果再次进行处理操作,它的做操对象就是相同key对应的value
        4. numPartitions:分区数,提高作业并行度。
        def aggregateByKeyTest(sc: SparkContext): Unit = {
           //所有元素放在一个分区上,来验证zeroValue与value相加的规则
           val rdd_1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (1, "c"), (2, "d")), 1)
           rdd_1.aggregateByKey("a")(seqOp, comOp).foreach(println(_))
        
           /**
             * 打印结果为
             *
             *(1,0ace)
             *(2,0bd)
             *由此得出结论就是 相同key的情况下zeroValue只会与value相加一次,也就是说遇到相同的key,不会从初始值开始相加,而是与上一次该key的计算结果相加
             */
         }
        
         /**
            * 这个函数作用就是遍历当前分区的所有的元素,在遍历过程中,将初始值"a"与分区上的元素的value进行相加
            * 相加的规则就是遇到相同的key累加这个key之前加过后得到的值,如果遇到不同的key就再次从初始值开始相加,
            * 我们把所以元素都放在一个分区中就可以看到zeroValue与value相加的规则。
            *
            * @param value1 : "a"
            * @param value2 : 分区上元素key对应的value
            * @return
            */
         def seqOp(value1: String, value2: String): String = {
           value1 + value2
         }
        
         /**
           * 这个函数时把各个分区处理后的结果再次进行处理,处理方式就是将相同key的value加在一起
           *
           * @param value1 : 各个分区处理过后的结果,结果中相同key对应的value
           * @param value2 : 各个分区处理过后的结果,结果中相同key对应的value
           * @return
           */
         def comOp(value1: String, value2: String): String = {
           value1 + value2
         }
      10. join(otherDataset,[numPartitions]):将两个RDD利用cogroup算子处理,将相同key的元素放入一个分区,然后返回一个新的RDD。再将新的RDD里元素的value进行笛卡尔积生成多个元组,每一个key都对应多个元组。然后返回由(k,(value1,valu2))结构的组成的RDD需要注意的是,join算子的处理规则就是只会处理两个RDD中都具有相同key的数据,如果一个RDD的key在另个RDD中没有。join算子是不会处理这种数据的。

         def joinTest(sc:SparkContext): Unit ={
           val rdd_1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"),(1, "e")))
           val rdd_2: RDD[(Int, String)] = sc.makeRDD(Array((1, "d"), (2, "f")))
           val joinRDD: RDD[(Int, (String, String))] = rdd_1.join(rdd_2)
        
           println(joinRDD.collect().toList)
        
           /**
             * 打印结果为:
             * (1,(a,f)), (1,(e,f)), (2,(b,d))
             */
         }

        Spark Core(六)创建RDD、Transformation与Action、RDD的持久化_第1张图片

      11. cogroup(otherDataSet,[numPartitions]):

        def cogroupTest(sc: SparkContext): Unit = {
           val rdd_1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (1, "e")))
           val rdd_2: RDD[(Int, String)] = sc.makeRDD(Array((1, "d"), (2, "f")))
           val cogroupRDD: RDD[(Int, (Iterable[String], Iterable[String]))] = rdd_1.cogroup(rdd_2)
           cogroupRDD.foreach(println(_))
        
           /**
             * 打印结果为
             * (1,(CompactBuffer(a, e),CompactBuffer(d)))
             * (2,(CompactBuffer(b),CompactBuffer(f)))
             */
         }
      12. cartesian(otherDataSet):对两个RDD里的元素进行笛卡尔积操作

        def cartesianTest(sc: SparkContext): Unit = {
           val rdd_1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (1, "e")))
           val rdd_2: RDD[(Int, String)] = sc.makeRDD(Array((1, "d"), (2, "f")))
           rdd_1.cartesian(rdd_2).foreach(println(_))
        
           /**
             * 打印结果为
             * ((1,a),(1,d))
             * ((1,a),(2,f))
             * ((2,b),(1,d))
             * ((2,b),(2,f))
             * ((1,e),(1,d))
             * ((1,e),(2,f))
             */
         }
      13. coalesce(numPartitions,shuffle):对RDD进行重新分区。可以不触发shuffle操作

        1. numPartitions:重新分区的个数。
        2. shuffle:分区的时候是否shuffle,默认值为false,不能增加分区数,可以减少分区数。如果为true,可以增加分区数或者减少分区数。
        def coalesceTest(sc:SparkContext): Unit ={
           val rdd_1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (1, "e")),4)
           //打印结果为 2,说明重新分区成功了
           println(rdd_1.coalesce(2).partitions.size)
         }
      14. repartition(numPartitions):重新分区,而且必须shuffle操作

        def repartitionTest(sc:SparkContext): Unit ={
           val rdd_1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (1, "e")),4)
           //打印结果为5,,说明你成功分区了
           println(rdd_1.repartition(5).partitions.size)
         }
      15. repartitionAndSortWithinPartitions(partitioner:Partitioner):对RDD从新分区,并在分区内按照Key进行排序,这个在分区的算子中性能是比较高的。官方推荐使用。

        1. partitioner:它是一个分区器,决定了按照什么分区策略进行分区。这个分区器也可以按照业务规则自己定义分区策略。后续会讲到
        def repartitionAndSortWithinPartitionsTest(sc: SparkContext): Unit = {
           val rdd_1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (1, "e")), 4)
           rdd_1.repartitionAndSortWithinPartitions(new HashPartitioner(2)).foreach(println(_))
        
           /**
             * 打印结果为
             * (2,b)
             * (1,a)
             * (1,e)
             *
             */
         }
  3. Action(算子)

    1. 定义:Action是一种操作算子,它的操作结果是得到一个值或者是一个结果,当程序遇到操作算子的API的时候,就会真正的触发该操作算子之前的所有的TransformationAction
    2. 方法:

      方法名 方法解释
      reduce(func) 通过func函数先对每个分区上的数据集进行聚合,然后再聚合分区之间的数据集,接受两个参数,第一个参数是上一次计算得出的结果,直到计算到最后一个元素,然后将结果返回
      collect() 以数据的方式返回数据集中每个元素给Driver程序,为防止Driver程序内存溢出,要控制这个数据的大小
      count() 返回数据集中元素的个数
      first() 返回数据集中的第一个元素,类似于take(1)
      take(n) 以数组的形式返回数据集前n个元素
      takeSample(withReplacement, num, [seed]) RDD中随机抽取元素以数组的方式返回,num为返回的元素个数,withReplacementBoolean类型,代表采用哪种算法,seed为可选参数,代表生成器种子,在算法中充当随机参数
      takeOrdered(n, [ordering]) 返回数据集的前n个元素,返回的形式为自然顺序,或者自己定义排序规则
      saveAsTextFile(path) 将数据集保存到本地文件系统、hdfs、或者任何Hadoop支持的文件系统中,spark将在每个元素上调用toString方法,将其转换为一行文本文件进行保存
      saveAsSequenceFile(path) 将数据集的每个元素写到给定的目录的hadoop本地文件系统,hdfs或者hadoop支持的各种文件系统。这中K,V形式的RDD需要实现HadoopWritable 接口,在scala中也可以利用隐式转换来与正常数据类型进行转换
      saveAsObjectFile(path) RDD中元素序列成对象后存储到文件系统中,对于HDFS,默认采用SequenceFile保存。
      foreach(func) 在数据集的每个元素上运行函数func
    3. Action算子例子

      1. reduce(func):它是一个高阶函数,可以传入一个函数作为参数。该方法的是对RDD里的数据记性业务逻辑的计算。func针对RDD元素进行逻辑计算的函数

        def reduceTest(sc: SparkContext): Unit = {
           val rdd_1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "d"), (4, "e")))
           /**
             * reduce是一个高阶函数,需要传入一个函数作为参数,下边的书写方式就是传入了一个匿名函数
             * 高阶函数可以理解它比普通方法更加强大,普通方法不不能接受一个函数作为参数的,但是高阶函数是可以的
             */
           val result1: (Int, String) = rdd_1.reduce((x, y) => (x._1 + y._1, x._2 + y._2))
        
           /**
             * reduce是一个高阶函数,需要传入一个函数作为参数,下边的书写方式为传入一个普通的scala函数,
             * 其实与上边是等价的
             * 注意:如果这么写的话,该高阶函数传入函数一定要在算子的代码之前定义完成,否则会报
             * forward reference extends over definition of value tuple异常!!!!
             */
           def reduceFunc(x: (Int, String), y: (Int, String)): (Int, String) = {
             (x._1 + y._1, x._2 + y._2)
           }
           val result2: (Int, String) = rdd_1.reduce(reduceFunc)
        
        
           println(result1)
           println(result2)
        
           /**
             * 打印结果都为:(10,abcde)
             */
         }
      2. collect():返回数据集的所有元素给Driver,防止Driver内存溢出,在数据量大的时候要控制返回数据量的大小

         //以数据格式返回数据给Driver,如果数据比较大的话尽量不要使用,反之Driver内存不够
         def collectTest(sc: SparkContext): Unit = {
           val rdd_1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "d"), (4, "e")))
           println(rdd_1.collect().toList)
         }
      3. count():返回数据集中的元素的个数。代码就不在阐述了

        def countTest(sc: SparkContext): Unit = {
           val rdd_1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "d"), (4, "e")))
           println("rdd_1中的元素有"+rdd_1.count()+"个") //打印结果为 rdd_1中的元素又4个
         }
      4. first():返回数据集中的第一个元素

        def firstTest(sc: SparkContext): Unit = {
          val rdd_1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "d"), (4, "e")))
          println("rdd_1中的第一个元素为"+rdd_1.first()) //打印结果为 rdd_1中的第一个元素为(1, "a")
        }
      5. take(n:Int):获取数据集的前n个元素

        //获取数据集里的前n个元素
        def takeTest(sc: SparkContext): Unit = {
          val rdd_1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "d"), (4, "e")))
           //打印结果为:rdd_1中前2个元素为(1, "a"), (2, "b")
          println("rdd_1中前2个元素为" + rdd_1.take(2))
        }
      6. takeSample(withReplaceMent:boolean,num:Int,[seed]):从RDD中随机抽取元素以数组的方式返回。

        1. num为返回的元素个数。
        2. withReplacementBoolean类型,代表采用哪种算法。
        3. seed为可选参数,代表生成器种子,在算法中充当随机参数
        def takeSampleTest(sc: SparkContext): Unit = {
          val rdd_1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "d"), (4, "e")))
          val takeSampleArray: Array[(Int, String)] = rdd_1.takeSample(true, 2, 10)
        }
      7. takeOrdered(n:Int):抽取数据集中的n个元素,并按照自然顺序进行排序。

        //从数据集中抽取n个数据,并按照自然顺序排序
        def takeOrderedTest(sc: SparkContext): Unit = {
          val rdd_1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "d"), (4, "e")))
          val tuples: Array[(Int, String)] = rdd_1.takeOrdered(2)
        }
      8. saveAsTextFile(path:String):存储RDD数据到本地文件系统,hdfs文件系统,以及其他支持hdfs文件系统

         //保存数据集到本地文件系统,hdfs文件系统,以及支持hadoop文件系统,
         // spark会调用toString方法将数据一行一行的写入文件中
         def saveAsTestFileTest(sc: SparkContext): Unit = {
           val rdd_1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "d"), (4, "e")))
           rdd_1.saveAsTextFile("D://spark.txt")
         }
        
  4. RDD的持久化

    1. 定义:sparkRDD持久化是非常重要的,当我们将RDD持久化以后,那么各个节点就会将它自己操作的RDDpartition数据缓存到自己的内存中,当对RDD进行下一次操作的时候,该节点会就使用它自己节点上缓存的Partition数据,这样大大的提高了计算效率。
    2. 使用方式:调用persist()cache()方法。这两种方法的区别就是cache()方法是persist()方法的简化方式,cache()方法底层就是调用了persist()的空参方法,也就是persist(MEMORY_ONLY)方法。
    3. 清除缓存:调用unpersist()方法

    4. 持久化级别

      持久化级别 解释
      MEMORY_ONLY 将没有序列化的java对象持久化到内存中,spark的默认持久化级别,如果有的分区内存不够就不会在该分区上持久化
      MEMORY_AND_DISK 将没有序列化的java对象持久化到内存中,当内存中不够用的时候,将一部分数据持久化到磁盘中
      MEMORY_ONLY_SER 将RDD存储为序列化的Java对象(每个分区一个字节数组)。与反序列化对象相比,这通常更节省空间,特别是在使用快速序列化器时,但是读起来更需要cpu。
      MEMORY_AND_DISK_SER MEMORY_ONLY_SER类似,但超出内存的数据溢出到磁盘中
      DISK_ONLY 只将RDD分区存储在磁盘上。
      MEMORY_ONLY_2, MEMORY_AND_DISK_2, etc. 以副本的方式持久化数据
    5. cachecheckpoint的区别:

      1. cache是将RDD缓存在节点的内存中,RDD之间的依赖关系依然存在。checkpoint是以多副本的方式存储在节点的磁盘上,RDD之间的依赖关系就不存在了。
      2. cache缓存不用指定节点地址,但是checkpoint需要指定节点的地址。
  5. RDD分区

    1. HashPartition:根据Key的哈希值来分去,可能造成数据倾斜
    2. RangePartition:水塘抽样算法实现数据的分区,数据能够均匀的分区,但是不能保证数据的顺序。
    3. 自定义分区:根据业务自己定义key的分区策略,首先要实现Partitioner类,然后s实现里边的方法,方法内定义分区策略

你可能感兴趣的:(spark,大数据专栏(一)Spark)