获取RDD的分区方式

在Java中,你可以使用RDD的partitioner()方法来获取RDD的分区方式。它会返回一个Optional<Partitioner>对象,这是用来存放可能存在的对象的容器类。你可以对这个Optional对象调用isPresent()方法来检查其中是否有值,调用get()来获取其中的值。如果存在值的话,这个值会是一个Partitioner对象。这本质上是一个告诉我们RDD中各个键分别属于哪个分区的函数。

在Spark shell中使用partitioner()方法不仅是检验各种Spark操作如何影响分区方式的一种好办法,还可以从来在你的程序中检查想要使用的操作是否会生成正确的结果。

/**
 * @author Chenxiaorui
 * @date 2019/6/5 0005
 */
public class SortByKeyTest {

    public static void main(String[] args) {
        SparkConf conf = new SparkConf().setMaster("local").setAppName("sortByKey");
        JavaSparkContext sc = new JavaSparkContext(conf);

        JavaPairRDD<UserID, UserInfo> userData = sc.sequenceFile("hdfs://...", UserID.class, UserInfo.class)
                .partitionBy(new HashPartitioner(100))
                .persist(StorageLevels.MEMORY_AND_DISK);


        Optional<Partitioner> partitionOptional = userData.partitioner();
        Partitioner userdataPartition = partitionOptional.get();
        
        userdataPartition.numPartitions();

        if (partitionOptional.isPresent()) {
            partitionOptional.toString();
        }
    }

}

代码中,对userData进行了哈希分区并持久化到了内存和磁盘中,下面的调用可以查看userData数据的分区情况,并打印出分区结果。

从分区中获益的操作

Spark的许多操作都引入了将数据根据键跨节点进行混洗的过程。所有这些操作都会从数据分区中获益。就Spark1.0而言,能够从数据分区中获益的操作有cogroup()、groupWith()、join()、leftOuterJoin()、rightOuterJoin()、groupByKey()、reduceByKey()、combineByKey()以及lookup()。

对于像reduceByKey()这样只作用于单个RDD的操作,运行在未分区的RDD上的时候会导致每个键的所有对应值都在每台机器上进行本地计算,只需要把本地最终归约出的结果值从各工作节点传回主节点,所以原本的网络开销就不算大。而对于诸如cogroup()和join()这样的二元操作,预先进行数据分区会导致其中至少一个RDD不发生数据混洗。如果两个RDD使用同样的分区方式,并且他们还缓存在同样的机器上(比如一个RDD是通过mapValues()从另一个RDD中创建出来的,这两个RDD就会拥有相同的键和分区方式),或者其中一个RDD还没被计算出来,那么跨加点的数据混洗就不会发生了。