Spark之cache ,persist ,checkpoint ,广播变量及其案例 : 根据IP地址(浏览器访问日志获取) / 经度纬度定位地理位置案例(7)

一  cache 和 persist 和 unpersist

1  cache 和 persist 

1.1  cache 和 persist 的使用场景 (为什么使用 ?)

一个 application 多次触发 Action ,为了复用前面 RDD 计算好的数据 ,避免反复读取 HDFS (数据源) 中的数据和重复计算 .

1.2  persist ,可以将数据缓存到内存或持久化到磁盘[ executor 所在的内存或磁盘], 第一次触发Action 才放入到内存或磁盘 (第一次读取数据时速度会比较慢 ,边读取数据边将数据放到内存中--executor进程中), 以后再出发 Action 会读取缓存 , RDD 的数据再进行操作并且复用 persist 的数据(所以第二次读取时速度会比第一次快几倍 /十几倍或者是几十倍 ,因为是从内存中读取的)

只要( spark-shell 客户端) application 不停止 (sc.stop 或者 ctrl+C) ,cache 缓存到内存中的数据就一直在

1.3  cache 或 persist 的 RDD 或其子 RDD 多次触发 Action ,那么 cache 或 persist 才有意义

1.4  如果将数据缓存到内存 ,内存不够 ,以分区为单位 ,只缓存部分分区的数据

即当内存很小时 ,不能将 cache 的数据全部存在内存里面 ,只能存先前的一部分 ,后一部分就存不下了 ,当下次 Action 再读取RDD 的数据的时候 ,速度仍会比之前块 , 虽然有一部分数据要从头(HDFS)读取 ,都是另外一部分缓存到内存中了就可以从内存中读取 .

1.5  支持多种 StorageLevel ,可以将数据序列化 ,默认放入内存使用的是 java 对象的方式(Java Serialization)存储到内存中 ,但是很占用空间,存储的内容比原数据大3倍左右), 优点是速度快(因为不需要反序列化--Java Serialization) ,也可以使用其他的序列化方法 ,通常是指 Kryo Serialization---需要反序列化 (占用空间小 ,速度快---较优的数据压缩/序列化方法)

Kryo Serialization 比 Java Serialization 稍慢 ,因为 Kryo Serialization 需要反序列化

1.6  cache 底层调用的是 persist 方法 ,可以指定其他存储级别

存储级别有以下几种 : 

1)  MEMORY_ONLY : 默认只放在内存 ,不序列化 (当内存足够大 ,数据很小的情况下可以使用)

2)  MEMORY_ONLY_SER : 默认存放在内存 ,按指定方式序列化

3)  DISK_ONLY_2 : 存磁盘 ,且存 2 份(在不同机器的磁盘中--属于该 application 的Task 或 executor 所在机器的磁盘中 )

4)  MEMORY_AND_DISK_SER : 优先存放在内存 ,内存存不下再存放到磁盘 ,按指定方式序列化

1.7  cache 和 persist 方法 ,严格来说 ,不是 Transformation ,因为没有生成新的 RDD ,只是标记当前 RDD 要 cache 或 persist

1.8  最佳实践(最佳的方法)有以下两种方法 :

1)  原始的数据 ,结果整理过滤后或轻度聚合后再进行 cache 或 persist ,这样的效果最佳(大大减小了数据量 ,减少内存空间的使用) ;

2)  推荐使用的存储级别为 : MEMORY_AND_DISK_SER (优先将数据缓存到内存 ,如果内存放不下再序列化放到磁盘).

2 unpersist : 释放内存里面缓存的RDD数据

1)  unpersist(false) : 异步 ,内存中缓存的RDD数据一边释放 ,程序可以一边往下走进行其他的操作

2)  unpersist(true) : 同步 ,内存中缓存的RDD数据释放完才能进行下一步的操作

3  程序代码实操

3.1  spark-shell 客户端 (linux虚拟机上)

spark-shell 客户端 : 
---第一步 : 指定序列化器(指定序列化方式)
sc.getCof.set("spark.serializer" ,"org apache.spark.serializer.KryoSerializer")

---第二步 : 导包 (存储方式/级别的包)
import org.apache.spark.storage.StorageLevel

---第三步 : 创建原始的RDD
val rdd1 = sc.texeFile("hdfs://linux04:8020/wc")

---第四步 : 指定的存储方式将RDD数据缓存到内存和磁盘中的方法
rdd1.persist(StorageLevel.MEMORY_AND_DISK_SER)

---第五步 : 可以对RDD使用算子进行操作了 ,原始数据和操作后的数据会被缓存到指定的存储位置
rdd1.count   --触发action后 ,可以到spark web 界面查看缓存的效果(第二次操作的速度会明显比第一次快很多)

 3.2  java 客户端上(二)---颜值降序 ,年龄升序的规则排序

1) 获取 conf 对象 ,指定 spark 的序列化器 ,注册自定义的 bean 使用 Kryo 进行序列化

2) 创建 sc ,根据 sc 创建原始的 RDD ,获取到数据

3) 自定义一个 bean (case class)(如果自定义的bean是 case class 类型 ,也是自动进行序列化接口的 ,但是普通的class bean 是要自己实现序列化接口的 ,这样才能够传入数据)

4) 对数据进行切割处理 ,将需要的字段封装到自定义的 bean 对象 ,字段与bean里面的属性值要一一对应,得到一个指定Boy类型的新的RDD

5) 新的RDD调用sortBy方法 , 根据需求,应用 tuple3 的排序规则 ,ASCLL码表 ,自己可以指定bean对象中的字段(颜值,年龄)进行升序降序排序 ,一个字段或者多个字段都可以,得到最终结果 .

object CunstomSort02 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local[*]")
    --指定spark的序列化器 Kryo
    conf.set("spark.serializer","org.apache.spark.serializer.KryoSerializer")
    --注册自定义的bean使用kryo进行序列化
    conf.registerKryoClasses(Array(classOf[Boy1]))
    --创建 sparkcontext
    val sc = new SparkContext(conf)
    --使用 sc 创建原始的RDD
    val list = List("nin,16,99.99", "lin,18,99.99", "auu,15,99.88")
    val listRDD: RDD[String] = sc.parallelize(list)
    --对数据进行切割处理 ,然后将数据封装到自定义的 boybean 对象里面
    val mapRDD: RDD[Boy1] = listRDD.map(it => {
      val fields = it.split(",")
      val name = fields(0)
      val age = fields(1).toInt
      val faceValue = fields(2).toDouble
      new Boy1(name, age, faceValue)
    })
    println(mapRDD.collect().toBuff
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值