Spark--RDD持久化

引言

要实现同一个rdd的分组聚合操作和分组操作
通过以下代码会发现代码的重复率很高,性能很低
如果一个RDD需要重复使用,那么需要从头再次执行来获取数据
RDD对象可以重用,但是数据无法重用
这时候我们就可以思考如何能够使RDD的数据也能够重用呢?

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

    val rdd: RDD[String] = sc.makeRDD(List("hello spark","hello scala"))
    val flatRDD: RDD[String] = rdd.flatMap(_.split(" "))
    val mapRDD: RDD[(String, Int)] = flatRDD.map((_,1))
    val reduceRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_+_)
    reduceRDD.collect().foreach(println)
    println("----------------------")
    val rdd1: RDD[String] = sc.makeRDD(List("hello spark","hello scala"))
    val flatRDD1: RDD[String] = rdd1.flatMap(_.split(" "))
    val mapRDD1: RDD[(String, Int)] = flatRDD1.map((_,1))
    val groupRDD1: RDD[(String, Iterable[Int])] = mapRDD1.groupByKey()
    groupRDD1.collect().foreach(println)


    sc.stop()
  }
}
(spark,1)
(scala,1)
(hello,2)
----------------------
(spark,CompactBuffer(1))
(scala,CompactBuffer(1))
(hello,CompactBuffer(1, 1))

一. RDD Cache缓存

RDD 通过Cache 或者 Persist 方法将前面的计算结果缓存,默认情况下会把数据以缓存在 JVM 的堆内存中。但是并不是这两个方法被调用时立即缓存,而是触发后面的 action 算子时,该RDD 将会被缓存在计算节点的内存中,并供后面重用。 所以持久化操作必须在行动算子执行时完成的。
RDD对象的持久化操作不一定是为了重用,在数据执行较长,或数据比较重要的场合也可以采用持久化操作
在这里插入图片描述
cache默认持久化的操作,底层调用的是Persist的MEMORY_ONLY,只能将数据保存到内存中,如果想要保存到磁盘文件,需要更改存储的级别
未设置缓存

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

    val rdd: RDD[String] = sc.makeRDD(List("hello spark","hello scala"))
    val flatRDD: RDD[String] = rdd.flatMap(_.split(" "))
    val mapRDD: RDD[(String, Int)] = flatRDD.map(x=>{
      println("map执行一次")
      (x,1)
    })
    val reduceRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_+_)
    reduceRDD.collect().foreach(println)
    println("----------------------")
    val groupRDD1: RDD[(String, Iterable[Int])] = mapRDD.groupByKey()
    groupRDD1.collect().foreach(println)

    sc.stop()
  }
}
map执行一次
map执行一次
map执行一次
map执行一次
(spark,1)
(scala,1)
(hello,2)
----------------------
map执行一次
map执行一次
map执行一次
map执行一次
(spark,CompactBuffer(1))
(scala,CompactBuffer(1))
(hello,CompactBuffer(1, 1))

设置缓存

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

    val rdd: RDD[String] = sc.makeRDD(List("hello spark","hello scala"))
    val flatRDD: RDD[String] = rdd.flatMap(_.split(" "))
    val mapRDD: RDD[(String, Int)] = flatRDD.map(x=>{
      println("map执行一次")
      (x,1)
    })
    //设置了缓存
    //mapRDD.cache()
    mapRDD.persist(StorageLevel.DISK_ONLY)
    val reduceRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_+_)
    reduceRDD.collect().foreach(println)
    println("----------------------")
    val groupRDD1: RDD[(String, Iterable[Int])] = mapRDD.groupByKey()
    groupRDD1.collect().foreach(println)
    
    sc.stop()
  }
}
map执行一次
map执行一次
map执行一次
map执行一次
(spark,1)
(scala,1)
(hello,2)
----------------------
(spark,CompactBuffer(1))
(scala,CompactBuffer(1))
(hello,CompactBuffer(1, 1))

二. RDD CheckPoint检查点

所谓的检查点其实就是通过将RDD 中间结果写入磁盘 由于血缘依赖过长会造成容错成本过高,这样就不如在中间阶段做检查点容错,如果检查点之后有节点出现问题,可以从检查点开始重做血缘,减少了开销。
对 RDD 进行 checkpoint 操作并不会马上被执行,必须执行 Action 操作才能触发。

object Spark_rdd_01 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("RDD").setMaster("local[*]")
    val sc = new SparkContext(conf)
    sc.setCheckpointDir("datas\\checkpoint")

    val rdd: RDD[String] = sc.makeRDD(List("hello spark","hello scala"),1)
    val flatRDD: RDD[String] = rdd.flatMap(_.split(" "))
    val mapRDD: RDD[(String, Int)] = flatRDD.map(x=>{
      println("map执行一次")
      (x,1)
    })
    //checkpoint需要落盘,需要指定检查点保存路径
    //检查点路径保存的文件,当作业执行完毕后,不会被删除
    //一般保存路径都是在分布式存储系统:HDFS
    mapRDD.checkpoint()
    val reduceRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_+_)
    reduceRDD.collect().foreach(println)
    println("----------------------")
    val groupRDD1: RDD[(String, Iterable[Int])] = mapRDD.groupByKey()
    groupRDD1.collect().foreach(println)

    sc.stop()
  }
}
map执行一次
map执行一次
map执行一次
map执行一次
map执行一次
map执行一次
map执行一次
map执行一次
(scala,1)
(spark,1)
(hello,2)
----------------------
(scala,CompactBuffer(1))
(spark,CompactBuffer(1))
(hello,CompactBuffer(1, 1))

在这里插入图片描述

三. 缓存和检查点区别

  • cache和persist只是将数据保存起来,不切断血缘依赖,会在血缘关系中添加新的依赖,一旦出现问题,可以从头读取数据,而Checkpoint 检查点会切断血缘依赖,重新建立新的血缘关系,checkpoint等同于改变数据源
  • 缓存的数据通常存储在磁盘、内存等地方,可靠性低,如果作业执行完毕,临时保存的数据文件就会丢失,Checkpoint 的数据通常存储在HDFS等高容错、高可用的文件系统,涉及到磁盘IO,性能较低,但数据安全,可靠性高。
  • 建议对checkpoint()的RDD 使用Cache 缓存,和cache联合使用,这样 checkpoint 的 job 只需从 Cache缓存中读取数据即可,否则需要再从头计算一次RDD。
object Spark_rdd_01 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("RDD").setMaster("local[*]")
    val sc = new SparkContext(conf)
    sc.setCheckpointDir("datas\\checkpoint")

    val rdd: RDD[String] = sc.makeRDD(List("hello spark","hello scala"),1)
    val flatRDD: RDD[String] = rdd.flatMap(_.split(" "))
    val mapRDD: RDD[(String, Int)] = flatRDD.map(x=>{
      println("map执行一次")
      (x,1)
    })
    mapRDD.cache()
    mapRDD.checkpoint()
    val reduceRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_+_)
    reduceRDD.collect().foreach(println)
    println("----------------------")
    val groupRDD1: RDD[(String, Iterable[Int])] = mapRDD.groupByKey()
    groupRDD1.collect().foreach(println)

    sc.stop()
  }
}
map执行一次
map执行一次
map执行一次
map执行一次
(scala,1)
(spark,1)
(hello,2)
----------------------
(scala,CompactBuffer(1))
(spark,CompactBuffer(1))
(hello,CompactBuffer(1, 1))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spark中的RDD(Resilient Distributed Datasets)是一种分布式的数据结构,它可以被分割成多个分区,每个分区可以在不同的节点上进行计算。RDD提供了一系列的转换和操作函数,可以对RDD进行各种操作。 RDD转换函数包括map、filter、flatMap、union、distinct、groupByKey、reduceByKey、sortByKey等。这些函数可以对RDD进行转换操作,生成新的RDD。 RDD操作函数包括count、collect、reduce、take、foreach等。这些函数可以对RDD进行操作,返回结果或者将结果输出到外部系统。 在使用RDD时,需要注意一些问题,如RDD的惰性计算、RDD的持久、RDD的分区等。同时,还需要根据实际情况选择合适的RDD转换和操作函数,以达到最优的计算效果。 总之,Spark中的RDD转换和操作函数是非常重要的,掌握它们可以帮助我们更好地使用Spark进行分布式计算。 ### 回答2: Spark是一个基于内存计算的分布式计算框架,可以实现大规模数据集的快速处理。在Spark中,RDD(弹性分布式数据集)是数据处理的核心概念,它是一种可以分区、并行计算和容错的不可变数据结构。而Spark中的函数式编程模型则将RDD的转换与操作都看做是函数的调用,从而简洁明了,易于理解和操作。 在Spark中,解决一个具体问题通常涉及一系列RDD的转换和操作。RDD的转换包括对原有RDD进行过滤、映射、聚合等处理,得到新的RDD;操作则是对新的RDD进行输出、保存、统计、排序等操作。以下介绍几种常见的RDD转换和操作函数。 1. map函数 map函数是一种转换函数,它可以将一个RDD中每个元素通过一个用户定义的函数映射到另一个RDD中,并得到新的RDD。例如,将一个整型RDD中的每个元素都乘以2后得到一个新的整型RDD: ``` val rdd1 = sc.parallelize(Array(1, 2, 3, 4)) val rdd2 = rdd1.map(x => x*2) ``` 2. filter函数 filter函数也是一种转换函数,它可以根据用户定义的条件过滤一个RDD中的元素,并得到一个新的RDD。例如,将一个字符串RDD中长度大于5的元素过滤出来得到一个新的字符串RDD: ``` val rdd1 = sc.parallelize(Array("hello", "world", "spark", "rdd")) val rdd2 = rdd1.filter(x => x.length > 5) ``` 3. reduce函数 reduce函数是一种操作函数,它可以将一个RDD中的元素按照用户定义的函数进行聚合并得到一个结果。例如,将一个整型RDD中的所有元素相加得到一个整数结果: ``` val rdd1 = sc.parallelize(Array(1, 2, 3, 4)) val result = rdd1.reduce((x, y) => x + y) ``` 4. collect函数 collect函数也是一种操作函数,它可以将一个RDD中的所有元素收集起来并输出到Driver端。然而,使用collect函数需要注意RDD的大小,如果RDD很大,就可能会出现内存溢出的情况。例如,将一个整型RDD中的所有元素收集起来并输出到屏幕: ``` val rdd1 = sc.parallelize(Array(1, 2, 3, 4)) val result = rdd1.collect() result.foreach(println) ``` 5. saveAsTextFile函数 saveAsTextFile函数也是一种操作函数,它可以将一个RDD中的所有元素保存到指定的文本文件中。例如,将一个字符串RDD中的所有元素保存到hdfs的一个文本文件中: ``` val rdd1 = sc.parallelize(Array("hello", "world", "spark", "rdd")) rdd1.saveAsTextFile("hdfs://localhost:8020/user/abc/output") ``` 总之,Spark中的RDD转换和操作函数具有弹性、高效、简单等特点,能够满足各种大规模数据处理需求。需要特别注意的是,Spark中的函数式编程模型是基于JVM的,因此要充分利用内存和CPU资源,需要对集群配置和调优进行一定的优和测试。 ### 回答3: Spark中的RDD(Resilient Distributed Datasets)是分布式的弹性数据集,它可以在大规模集群上并行地计算,并且提供了一系列的转换和操作函数。其中,Spark提供的Spark函数简单易用,具有高效的数据处理能力,可以帮助开发者快速开发分布式应用程序。 RDD转换函数是将一个RDD转换成另一个RDD的函数,转换后的RDD通常包含了数据处理、筛选和过滤后的新数据集,可以用来接着进行后续的计算。 例如,map函数可以将RDD中的每个元素应用一个函数,然后返回一个新的转换过的RDD: ``` val originalData = sc.parallelize(List(1, 2, 3, 4, 5)) val mappedData = originalData.map(x => x * 2) ``` 这里,map函数将原始数据中的每个元素都乘上了2,返回了一个新的RDD。 除了map函数, 还有flatMap、filter、groupBy等常用的转换函数,都可以帮助我们对RDD做出各种各样的数据处理和转换。 RDD操作函数则是对RDD进行真正的计算操作,例如reduce、count、collect等函数,这些函数会触发Spark的分布式计算引擎执行真正的计算任务。 比如,reduce函数可以将RDD中的所有元素进行聚合,返回一个单一的结果: ``` val originalData = sc.parallelize(List(1, 2, 3, 4, 5)) val reducedData = originalData.reduce(_ + _) ``` 这里,reduce函数将原始数据中的所有元素进行相加操作,返回了一个整数类型的结果。 Spark提供的操作函数非常丰富,从基本的聚合、排序、统计操作,到高级的机器学习和图形处理等操作,开发者可以根据不同的业务需求灵活选择使用。 总之,Spark中的RDD转换和操作函数是分布式数据处理的核心之一,通过这些函数,开发者能够方便地对海量数据进行分布式的计算和处理。同时,Spark也提供了丰富的API和工具,便于开发者进行高效的Spark应用程序开发。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值