Spark编程之基本的RDD算子coalesce, repartition, checkpoint等。
1) coalesce(合并的意思), repartition
这两个算子都是为了对数据进行重新分区的。将原来的数据合并为给定的分区数,repartition是coalesce的调用,其中的shuffle参数设置为true。
以下是基本的api。
def coalesce ( numPartitions : Int , shuffle : Boolean = false ): RDD [T]
def repartition ( numPartitions : Int ): RDD [T]
其中的numPartitions指的是需要重新分区的分区数。
val y = sc.parallelize(1 to 10, 10)
val z = y.coalesce(2, false)
z.partitions.length //partitions.length返回的是分区的数目。
res9: Int = 2
- 2) persist 和cache
在spark中,cache调用了persist的 persist(StorageLevel.MEMORY_ONLY)。表明只利用内存进行缓存。
而persist可以设置缓存级别,persist()默认的也是调用persist(StorageLevel.MEMORY_ONLY)来进行缓存。这两个都是transformation,也就意味着它们是延迟加载的,只要真正碰到action的时候才会开始触发。
object StorageLevel {
val NONE = new StorageLevel(false, false, false, false)
val DISK_ONLY = new StorageLevel(true, false, false, false)
val DISK_ONLY_2 = new StorageLevel(true, false, false, false, 2)
val MEMORY_ONLY = new StorageLevel(false, true, false, true)
val MEMORY_ONLY_2 = new StorageLevel(false, true, false, true, 2)
val MEMORY_ONLY_SER = new StorageLevel(false, true, false, false)
val MEMORY_ONLY_SER_2 = new StorageLevel(false, true, false, false, 2)
val MEMORY_AND_DISK = new StorageLevel(true, true, false, true)
val MEMORY_AND_DISK_2 = new StorageLevel(true, true, false, true, 2)
val MEMORY_AND_DISK_SER = new StorageLevel(true, true, false, false)
val MEMORY_AND_DISK_SER_2 = new StorageLevel(true, true, false, false, 2)
val OFF_HEAP = new StorageLevel(false, false, true, false)
}
def cache(): RDD[T]
def persist(): RDD[T]
def persist(newLevel: StorageLevel): RDD[T]
val c = sc.parallelize(List("Gnu", "Cat", "Rat", "Dog", "Gnu", "Rat"), 2)
c.getStorageLevel //通过c.getStorageLevel可以返回它的缓存的级别。
res0: org.apache.spark.storage.StorageLevel = StorageLevel(false, false, false, false, 1)
c.cache
c.getStorageLevel
res2: org.apache.spark.storage.StorageLevel = StorageLevel(false, true, false, true, 1)
- 3) checkpoint
这个将会创建一个checkpoint缓存,被缓存的RDD将会被序列化存储到之前checkPoint的路径。checkPoint也是延迟加载的,需要等到真正触发到action的时候才会开始执行。
注意的是:checkPoint的这个路径必须在所有的slave中存在,否则无法进行缓存。所以checkpoint的话最好使用的是hdfs来进行缓存。
还有就是,如果一个rdd需要checkpoint的话,最好将这个checkpoint放在cache()之后,这样子效率高。否则还得重新启动一个任务来进行checkpoint,这样子会很耗时。
当spark需要利用到缓存的时候,首先会去找在内存中的cache().如果找的到的话,就会直接利用,如果cache的数据丢失了,找不到的话,才去checkpoint的路径中进行查找。
需要注意的是,checkpoint和cache(), persist()的区别,他们虽然都是缓存,但是cache的话会记下RDD之间的Lineage,而checkpoint会删除掉之前的lineage。
sc.setCheckpointDir("my_directory_name") //注意首先需要设置CheckpointDir。否则会报错。
val a = sc.parallelize(1 to 4)
a.checkpoint
a.count
res23: Long = 4
- 4) getCheckpointFile.
这个算子会返回已经checkpoint的rdd,如果没有的话会返回null。
def getCheckpointFile: Option[String]
sc.setCheckpointDir("/home/Documents")
val a = sc.parallelize(1 to 500, 5)
val b = a++a++a++a++a
b.getCheckpointFile
res49: Option[String] = None
b.checkpoint
b.getCheckpointFile
res54: Option[String] = None
b.collect
b.getCheckpointFile
- 5)getStorageLevel
可以获得当前的RDD的存储级别。这个只能被使用在一个新的没有被cache的rdd上面,重新改变RDD的存储级别的话会报UnsupportedOperationException的错误。
def getStorageLevel
val a = sc.parallelize(1 to 100000, 2)
a.persist(org.apache.spark.storage.StorageLevel.DISK_ONLY)
a.getStorageLevel.description
String = Disk Serialized 1x Replicated
a.cache
java.lang.UnsupportedOperationException: Cannot change storage level of an RDD after it was already assigned a level