一.引言
使用spark很久第一次用到 distinct 算子,趁热打铁熟悉一下 distinct 的操作。
二.源码
distinct 算子会返回一个新的 RDD,这里的每一个元素都是唯一的不会有重复。
/**
* Return a new RDD containing the distinct elements in this RDD.
*/
def distinct(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T] = withScope {
map(x => (x, null)).reduceByKey((x, y) => x, numPartitions).map(_._1)
}
/**
* Return a new RDD containing the distinct elements in this RDD.
*/
def distinct(): RDD[T] = withScope {
distinct(partitions.length)
}
三.distinct 使用示例
随机生成20个(Int, Char)格式truple,并序列化为5个Partiton,使用 distinct去重。
// Spark 初始化
val sc = new SparkContext(conf)
val random = scala.util.Random
random.setSeed(100)
sc.setLogLevel("error")
val randomChar = ('a' to 'z').zipWithIndex.map(x => (x._2, x._1)).toMap
val randomSample = (0 until 20).map(x => {
val num = random.nextInt(100)
val char = randomChar(random.nextInt(26))
(num, char)
})
// Distinct 实现
val rdd = sc.parallelize(randomSample, 5)
println("Partition Number Count: " + rdd.getNumPartitions)
val distinctArr = rdd.distinct.collect()
println("Distinct Number Count: " + distinctArr.length)
println(distinctArr.sorted.mkString(" "))
四.DIY Distinct
distinct的源码也很简单,通过 reduceByKey 就能实现。
// 源码实现
println("Diy Demo: ")
val rdd2 = sc.parallelize(randomSample, 5)
val distinctArr2 = rdd2.map(x => (x, null)).reduceByKey((x, y) => x, 5).map(_._1).collect()
println(distinctArr2.sorted.mkString(" "))
Tips:
Distinct 是对 RDD 的整个内容去重,不管是 truple 还是 String 或者是其他类型,这里容易和 pairRdd 混淆,最开始认为 distinct 是对 PairRDD 的 key 进行去重,后来发现不是。