SparkCore(一)

1.什么是RDD

RDD分布式数据集,是Spark中最基础的数据抽象,代码中谁一个抽象类,它代表一不可变、可分区、元素可并行计算的集合。

1.2RDD的特点

分区、只读、依赖、缓存、CheckPoint

分区:逻辑上分区,每个分区的数据都是抽象的存在,计算的时候云通过一个compute函数得到每个分区的数据。如果RDD是通过已有的文件系统构建,则compute函数是读取指定文件系统中的数据,如果RDD是通过其他RDD转换而来,则compute函数是执行转换逻辑将其他RDD的数据进行转换。
只读:RDD是只读的,要想改变RDD中的数据,只能在现有的RDD基础上创建新的RDD。
依赖:RDD通过算子进行转换, 转换得到新的RDD包含了从其他RDD衍生所必需的信息,RDD之间维护着这种血缘关系,也称之为依赖。
缓存:在应用程序中多次使用同一个RDD,但是只需要第一次使用的时候会根据血缘关系得到分区的数据。在其使用的时候会直接缓存,从缓存处读取而不是再根据血缘关系计算,这样就加速了后期的重用。
CheackPoint:RDD的血缘关系天然地可以实现容错,当RDD的某个分区的数据失败或丢失,可以通过血缘关系重建。但是对于长时间的迭代来说,随着迭代的进行,RDD之间的血缘关系会越来越长,一旦在后续迭代过程重出错,则需要通过非常长的血缘关系去重建,势必会影响性能。 因此 RDD支持Checkpoint将数据保存持久化到存储中,这样就可以切断之前的血缘关系,可以直接从Checkpoint拿到数据。

2.RDD编程

在Spark中创建RDD有3种创建方式: 1.从集合中创建RDD。 2.从外部存储创建RDD。3从其他RDD创建。

2.1从集合中创建

从集合中创建RDD,Spark主要提供了2中函数 :parallelize 和 makeRDD(从底层源码可以看到makeRDD调用了 parallelize)

object Spar01_RDD {
  def main(args: Array[String]): Unit = {
    val wordCount: SparkConf = new SparkConf().setMaster("local[*]").setAppName("SiyuanChen")
    val sc: SparkContext = new SparkContext(wordCount)

    /**
      * 创建RDD
      * 1从内存中创建 makeRDD 底层实现就是parallelize
      * 
      */
    val listRDD: RDD[Int] = sc.makeRDD(List(1,2,3,4))
    val listRDD1: RDD[Int] = sc.parallelize(List(1,2,3,4))
    
  }
}
package com.chensy.spark

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spar01_RDD {
  def main(args: Array[String]): Unit = {
    val wordCount: SparkConf = new SparkConf().setMaster("local[*]").setAppName("SiyuanChen")
    val sc: SparkContext = new SparkContext(wordCount)

    /**
      * 创建RDD
      * 1从内存中创建 makeRDD 底层实现就是parallelize
      *
      */
    //val listRDD: RDD[Int] = sc.makeRDD(List(1,2,3,4))
    //val listRDD1: RDD[Int] = sc.parallelize(List(1,2,3,4))

    //使用自定义分区
    //内存中创建
    //val listRDD: RDD[Int] = sc.makeRDD(List(1,2,3,4),2)
    //val value: RDD[String] = sc.makeRDD(Array("1","2","3"))

    /**
      * 从外部存储中创建
      * 默认情况下可以读取项目路径,也可以读取其他路径:HDFS
      * 默认从文件中读取的数据都是字符串类型
      * 读取文件时,传递分区参数为最小分区,但是不一定是这个分区数,取决Hadoop读取文件的规则
      *
      *
      */
    val fileRDD: RDD[String] = sc.textFile("in",2)

    fileRDD.saveAsObjectFile("output")

  }
}

2.2 RDD的转换

RDD整体上分为Value 类型和Key-Value类型
2.2.1 map(func)案例
1.作用:返回一个新的RDD,该RDD由每一个输入元素经过func函数转换过后组成
2需求:创建一个1-10的数组的RDD,将所有的元素*2形成新的RDD

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark02_Oper1 {
  def main(args: Array[String]): Unit = {
    val config: SparkConf = new SparkConf().setMaster("local[*]").setAppName("SiyuanChen")

    // 创建Spark上下文对象
    val sc = new SparkContext(config)

    /**
      * map 算子
      *
      */
    val listRDD: RDD[Int] = sc.makeRDD(1 to 10)
    val mapRDD: RDD[Int] = listRDD.map(_*2)
    println(mapRDD.collect().mkString(",")) //2,4,6,8,10,12,14,16,18,20
  }
}

2.2.2 mapPartitions(func)案例
作用:类似于map,但独立地在RDD的每个分片上运行,因此在类型为T的RDD上运行时,func的函数类型必须是Iterator[T]=>Iterator[U]。假设有N个元素,有M个分区,那么map的函数的将被调用N次,而mapPartitions被调用M次,一个函数一次处理的所有分区。
需求:创建一个RDD,使每个元素*2组成新的RDD

object Spark03_Oper2 {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("SiyuanChen")
    val sc: SparkContext = new SparkContext(conf)
    val listRDD: RDD[Int] = sc.makeRDD(1 to 10)

    /**
      *mapPartitions可以对一个RDD中的所有分区进行遍历
      * mapPartitons效率高于map算子,减少了发送到执行器执行交互的次数
      * mapPartitons可能会出现 内存溢出(oom)
      *
      */
    println(listRDD.mapPartitions(x => {
      x.map(_ * 2)
    }).collect().mkString(","))
  }
}

2.2.3mapPartitionsWithIndex(func)案例
作用:类似于mapPartitions,但func带有一个整数参数表示分片的索引值,因此在类型t的RDD上运行,func的函数类型必须是(Int,Interator[T]=>Interator[U]);
需求:创建一个RDD,使每个元素跟所在分区形成一个元祖组成一个新的RDD

object Spark04_Oper3 {
  def main(args: Array[String]): Unit = {

    val config: SparkConf = new SparkConf().setMaster("local[*]").setAppName("SiyuanChen")

    // 创建Spark上下文对象
    val sc = new SparkContext(config)
    //mapPartitionsWithIndex
    val listRDD: RDD[Int] = sc.makeRDD(1 to 10,2)
    println(listRDD.mapPartitionsWithIndex {
      case (index, datas) => {
        datas.map((_, "分区号" + index))
      }
    }.collect().mkString(","))//(1,分区号0),(2,分区号0),(3,分区号0),(4,分区号0),(5,分区号0),(6,分区号1),(7,分区号1),(8,分区号1),(9,分区号1),(10,分区号1)

  }
}

2.3.4flatMap(func)案例
作用:类似于map,但是每一个输入元素可以被映射为0或者多个输出元素(所以func应该返回)
需求:创建一个元素为1-5的RDD,运行flatMap创建一个新的RDD,新的RDD为1,1,2,1,2,3,1,2,3,4,1,2,3,4,5

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark05_Oper4 {
  def main(args: Array[String]): Unit = {

    val config: SparkConf = new SparkConf().setMaster("local[*]").setAppName("SiyuanChen")

    // 创建Spark上下文对象
    val sc = new SparkContext(config)
   //flatMap
    //1,2,3,4
    val listRDD = sc.makeRDD(1 to 5)
    println(listRDD.flatMap(1 to _).collect().mkString(","))
  }//1,1,2,1,2,3,1,2,3,4,1,2,3,4,5
}

2.2.6 glom案例
作用:将每一个分区形成一个数组,形容新的RDD类型时RDD[Array[T]]
需求:创建一个4个分区的RDD, 丙将每个分区的数据放到一个数组

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object Spark06_Oper5 {
  def main(args: Array[String]): Unit = {
    val config: SparkConf = new SparkConf().setMaster("local[*]").setAppName("SiyuanChen")

    // 创建Spark上下文对象
    val sc = new SparkContext(config)

    val listRDD: RDD[Int] = sc.makeRDD(List(1,2,8,4,3,5,6,7),3)
    //将一个分区的数据放在一个数组中
    val glomRDD: RDD[Array[Int]] = listRDD.glom()
    //glomRDD.collect().foreach(array=>{println(array.mkString(","))})
    glomRDD.collect().foreach(array=>{
      println(array.mkString(","))})

  }
}

2.2.7groupBy(func)案例
作用:分组,按照传入函数的返回值进行分组。将相同的key对应的值放入一个迭代器。
需求:创建一个RDD,按照元素%2的值进行分组

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object Spark07_Oper6 {
  def main(args: Array[String]): Unit = {
    val config: SparkConf = new SparkConf().setMaster("local[*]").setAppName("SiyuanChen")

    // 创建Spark上下文对象
    val sc = new SparkContext(config)
    //生成数据,按照指定的规则进行分组
    //分组后的数据形成了对偶元组(k-v),k表示分组的key v表示分组的数据集
    val listRDD: RDD[Int] = sc.makeRDD(List(1,2,3,4))
    println(listRDD.groupBy(i => i % 2).collect().mkString(","))
  }
}
//(0,CompactBuffer(2, 4)),(1,CompactBuffer(1, 3))

2.2.8filter(func)案例
作用:过滤。返回一个新的RDD。该RDD由经过func函数计算后返回true的输入元素组成
需求:创建一个RDD(12345),过滤出一个新的RDD(i%2==0)

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark08_Oper7 {

  def main(args: Array[String]): Unit = {

    val config: SparkConf = new SparkConf().setMaster("local[*]").setAppName("SiyuanChen")

    // 创建Spark上下文对象
    val sc = new SparkContext(config)
    val listRDD: RDD[Int] = sc.makeRDD(List(1,2,3,4))
    println(listRDD.filter(x => x % 2 == 0).collect().mkString(","))
//2,4
  }
}

2.2.9sample(withReplacement, fraction, seed) 案例
作用:以指定的随机种子随机抽象出书记fraction的数据,withReplacement 表示是抽搐的数据是否放回,true为有放回的抽象,false为无放回的抽样,seed用于指定随机数生成种子
需求:创建 一个1-10 RDD 从中选择放回和不放回抽样

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object Spark09_Oper8 {
  def main(args: Array[String]): Unit = {
    val config: SparkConf = new SparkConf().setMaster("local[*]").setAppName("WordCount")

    // 创建Spark上下文对象
    val sc = new SparkContext(config)
    val listRDD: RDD[Int] = sc.makeRDD(1 to 10)
    val sampleRDD:  RDD[Int] = listRDD.sample(false,0.4,2)
    println(sampleRDD.collect().mkString(","))


  }

}

2.2.10coalesce(numPartitions) 案例
作用:缩减分区数,用于大数据集过滤后,提高小数据集的执行效率
需求:创建一个4个分区的RDD,对其缩减分区

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object Spark10_Oper9 {
  def main(args: Array[String]): Unit = {
    val config: SparkConf = new SparkConf().setMaster("local[*]").setAppName("SiyuanChen")

    // 创建Spark上下文对象
    val sc = new SparkContext(config)
    val listRDD: RDD[Int] = sc.makeRDD(1 to 16,4)
    println("缩减分区前 = " + listRDD.partitions.size)
    val coalesceRDD: RDD[Int] = listRDD.coalesce(3)
    println("缩减分区后 = " + coalesceRDD.partitions.size)
    coalesceRDD.saveAsTextFile("outpou")
  }

}

2.2.11distinct([numTasks])) 案例
作用:对源RDD进行去重后返回一个新的RDD。默认情况下,只有8个并行任务来操作,但是可以传入一个可选的numtask参数去改变它
需求:创建一个RDD 使用distinct对其去重

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object Spark11_Oper10 {
  def main(args: Array[String]): Unit = {
    val config: SparkConf = new SparkConf().setMaster("local[*]").setAppName("SiyuanChen")

    // 创建Spark上下文对象
    val sc = new SparkContext(config)
    val listRDD: RDD[Int] = sc.makeRDD(List(1,2,1,5,2,9,6,1))
    val distinctRDD: RDD[Int] = listRDD.distinct()
    distinctRDD.saveAsTextFile("output")
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值