zoukankan      html  css  js  c++  java
  • 5.RDD的Action操作和持久化persist()

    1.1 Action操作

    前边提到的first() 、collect() 都是Action操作。常用的有:

    collect():把数据返回驱动器程序中最简单、最常见的操作, 通常在单元测试中使用,数据量不能太大,因为放在内存中,数据量大会内存溢出。

    reduce():类似sum() ,如:val sum = rdd.reduce((x, y) => x + y) ,结果同sum

    fold():和reduce() 类似,多一个“初始值”,当初始值为零时效果同reduce().    fold(0) = reduce()

    take(n) :返回RDD 中的n 个元素,并且尝试只访问尽量少的分区。

    top(n) :从RDD 中获取前几个元素

    count() :用来返回元素的个数

    countByValue() :返回一个从各值到值对应的计数的映射表

    sum():返回汇总

    启动spark-shell

    scala> val rdd=sc.parallelize(1 to 5)
    rdd: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[0] at parallelize at <console>:24
    
    scala> rdd.count()
    res0: Long = 5
    
    scala> rdd.first()
    res1: Int = 1
    
    scala> rdd.take(2)
    res2: Array[Int] = Array(1, 2)
    
    scala> rdd.top(3)
    res3: Array[Int] = Array(5, 4, 3)
    
    scala> rdd.sum()
    res4: Double = 15.0
    
    scala> rdd.fold(0)((x,y)=>x+y)
    res6: Int = 15
    
    scala> rdd.fold(1)((x,y)=>x+y)
    res7: Int = 17

    fold(n) 的执行原理:

    每个分区里进行这样的计算:初始值+sum(元素)

    最后进行:初始值+sum(分区sum值)

    初始值累加次数为分区数+1次

    scala> val rdd = sc.parallelize(1 to 5,2)
    
    scala> rdd.fold(1)((x,y)=>x+y)
    
    res8: Int = 18
    
    scala> rdd.fold(2)((x,y)=>x+y)
    
    res9: Int = 21

    1.2 持久化函数persist()

    RDD 是惰性(Lazy)求值的,当我们希望能多次使用同一个RDD时,RDD 调用行动操作,Spark 每次都会重算RDD 以及它的所有依赖, 这在迭代算法中消耗格外大。

    如:

    val rdd1 = rdd.map(x => x+1)

    println(rdd1.first())

    println(rdd1.count())

    println(rdd1.sum())

    println(rdd1.collect().mkString(","))

     

    如果不做处理的话,每个Action函数执行时都会执行一遍rdd.map(x => x+1) ,消耗很大。

     

    Spark提供rdd的persist()函数来解决这个重复计算的问题,persist()把需要重复使用的rdd存起来,这样仅第一个Action操作才会计算,其他Action操作不需要再计算。

     

    当我们执行rdd的persist()时,计算出RDD 的节点会分别保存它们所求出的分区数据。如果一个有持久化数据的节点发生故障,Spark 会在需要用到缓存的数据时重算丢失的数据分区。

    rdd的persist()有5种持久化级别,分别是:

    来自org.apache.spark.storage.StorageLevel 的定义。

    默认情况下persist() 会把数据以序列化的形式缓存在JVM 的堆空间中。

     

    这样上方案例可以优化为:

    val rdd1 = rdd.map(x => x+1)

    rdd1.persist(StorageLevel.DISK_ONLY)

    println(rdd1.first())

    println(rdd1.count())

    println(rdd1.sum())

    println(rdd1.collect().mkString(","))

    rdd1.unpersist()    //释放缓存,必须手工释放

     

     

    如果觉得数据过于重要,怕存一份有风险,则可以存2份:

    rdd1.persist(StorageLevel.MEMORY_ONLY_2)

    值得注意:

    如果要缓存的数据太多,内存中放不下,Spark 会自动利用最近最少使用(LRU)的缓存

    策略把最老的分区从内存中移除。但是对于仅把数据存放在内存中的缓存级别,下一次要用到

    已经被移除的分区时,这些分区就需要重新计算。

    不必担心你的作业因为缓存了太多数据而被打断。

     

  • 相关阅读:
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    cookie相关内容:用法,特点,常用功能以及与session的异同
    JSP (一)
    Node.js npm 环境配置
    新老版本vue-cli的安装及创建项目等方式的比较
    npm 代理设置及更换为国内下载源
    for...of的使用
    打印机使用方法
    给OC项目添加icon
  • 原文地址:https://www.cnblogs.com/braveym/p/12202068.html
Copyright © 2011-2022 走看看