spark rdd实战—分区器(Partitioner)的理解和使用

概述

在《spark2原理分析-RDD的Partitioner原理分析》一文中,我们了解了分区器的基本概念,本文通过实际的例子来进一步理解分区器的概念,并学习如何使用分区器。

分区器的使用场景

分区器在类型为(k,v)的RDD时使用。但不要频繁的修改分区器,频繁使用分区器可能会导致更多的shuffle操作。

HashPartitioner分区器的使用

  • 准备类型为(k,v)的RDD
    我们通过parallelize生成(k,v)对的RDD数据,在spark-shell中代码如下:
scala> import org.apache.spark.HashPartitioner
scala> val rdd2 = sc.parallelize(1 to 10000).map(x=>(x,x))
rdd2: org.apache.spark.rdd.RDD[(Int, Int)] = MapPartitionsRDD[1] at map at :24

scala> rdd2.partitions.length
res2: Int = 8

scala> rdd2.partitioner
res0: Option[org.apache.spark.Partitioner] = None

由于我是以local[*]模式启动的,而我的机器有8个核,所以默认的分区数是8。但从以上代码可以看出,分区器为None。
下面我们使用新的分区器:HashPartitioner来对数据进行重新分区:

  • 使用HashPartitioner分区器重新分区
scala> val rdd3 = rdd2.partitionBy(new HashPartitioner(10))
rdd3: org.apache.spark.rdd.RDD[(Int, Int)] = ShuffledRDD[3] at partitionBy at :26

scala> rdd3.partitioner
res9: Option[org.apache.spark.Partitioner] = Some(org.apache.spark.HashPartitioner@a)

scala> rdd3.partitions.length
res10: Int = 10

从以上例子中看出,我们使用自带的HashPartitioner(10)分区器来重新分区数据,重新定义分区器后,分区数已经发生了变化。分区数变成了按HashPartitioner分区的分区数。

RangePartitioner分区器的使用

  • 使用RangePartitioner分区器重新分区
scala> import org.apache.spark.RangePartitioner
import org.apache.spark.RangePartitioner

scala> val rdd3 = rdd2.partitionBy(new RangePartitioner(20, rdd2))
rdd3: org.apache.spark.rdd.RDD[(Int, Int)] = ShuffledRDD[4] at partitionBy at :26

scala> rdd3.partitioner
res3: Option[org.apache.spark.Partitioner] = Some(org.apache.spark.RangePartitioner@49057ee6)

scala> rdd3.partitions.length
res4: Int = 20

从以上的代码例子中可以看出,设置RangePartitioner分区器后,分区数变成了20个。

打印每个分区的数据

val parts = rdd3.partitions
for (p <- parts) {
    val idx = p.index
    val partRdd = rdd3.mapPartitionsWithIndex { 
       case(index:Int,value:Iterator[(String,Int)]) => 
         if (index == idx) value else Iterator()
    }
    val dataPartitioned = partRdd.collect()
    println("partition id:"+ idx, "elements: " + dataPartitioned.foreach(print))
}

通过这段代码可以打印出每个分区的数据。
通过打印RangePartitioner重新分区后的数据可以看出,RangePartitioner分区后的数据基本上是按照数据范围来划分的。

小结

本文说明了分区器的使用。并通过修改分区器来验证了分区器的作用。

你可能感兴趣的:(spark)