1.map 和 mapPartitions 的区别
数据处理角度
Map 算子是分区内一个数据一个数据的执行,类似于串行操作。而 mapPartitions 算子 是以分区为单位进行批处理操作
功能的角度
Map 算子主要目的将数据源中的数据进行转换和改变。但是不会减少或增多数据。 MapPartitions 算子需要传递一个迭代器,返回一个迭代器,没有要求的元素的个数保持不变, 所以可以增加或减少数据
性能的角度
Map 算子因为类似于串行操作,所以性能比较低,而是 mapPartitions 算子类似于批处 理,所以性能较高。但是 mapPartitions 算子会长时间占用内存,那么这样会导致内存可能 不够用,出现内存溢出的错误。所以在内存有限的情况下,不推荐使用。
2.coalesce和repartition区别
它们两个都是RDD的分区进行重新划分,repartition只是coalesce接口中shuffle为true的简易实现
1)如果现有分区数小于重新分区数:一般情况下现有的分区有数据分布不均匀的状况,利用HashPartitioner函数将数据重新分区,这时需要将shuffle设置为true。
2)如果现有分区数大于重新分区数,并且现有分区数和重新分区数相差不多,那么就可以将现有分区中的若干个分区合并成一个新的分区,最终合并为要求的重新分区的数量,这时可以将shuff设置为false,在shuffl为false的情况下,如果现有分区数小于重新分区数时,coalesce为无效的,不进行shuffle过程,父RDD和子RDD之间是窄依赖关系。
3)如果现有分区数大于重新分区数并且两者相差悬殊,这时如果将shuffle设置为false,父子RDD是窄依赖关系,他们同处在一个Stage中,就可能造成Spark程序的并行度不够,从而影响性能,如果在重新分区数为1的时候,为了使coalesce之前的操作有更好的并行度,可以讲shuffle设置为true。
总之:如果shuff为false时,如果传入的参数大于现有的分区数目,RDD的分区数不变,也就是说不经过shuffle,是无法将RDD的分区数变多的
3.reduceByKey 和 groupByKey 的区别
shuffle 的角度
reduceByKey 和 groupByKey 都存在 shuffle 的操作,但是 reduceByKey可以在 shuffle 前对分区内相同 key 的数据进行预聚合(combine)功能,这样会减少落盘的数据量,而 groupByKey 只是进行分组,不存在数据量减少的问题,reduceByKey 性能比较高
功能的角度
reduceByKey 其实包含分组和聚合的功能。GroupByKey 只能分组,不能聚合,所以在分组聚合的场合下,推荐使用 reduceByKey,如果仅仅是分组而不需要聚合。那么还是只能使用 groupByKey
4.aggregate和aggregateByKey的区别
aggregate:初始值会参与分区计算,并且参与分区间的计算
aggregateByKey:初始值只会参与分区内计算
5.reduceByKey、foldByKey、aggregateByKey、combineByKey 的区别
reduceByKey: 相同 key 的第一个数据不进行任何计算,分区内和分区间计算规则相同
FoldByKey: 相同 key 的第一个数据和初始值进行分区内计算,分区内和分区间计算规则相同
AggregateByKey:相同 key 的第一个数据和初始值进行分区内计算,分区内和分区间计算规则可以不相同
CombineByKey:当计算时,发现数据结构不满足要求时,可以让第一个数据转换结构。分区内和分区间计算规则不相同。
def main(args: Array[String]): Unit = {
val sparkConf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
val sc = new SparkContext(sparkConf)
//key---value类型
/**
* reduceByKey
* foldByKey
* aggregateByKey
* combineByKey
*/
val rdd: RDD[(String, Int)] = sc.makeRDD(List(
("a", 1), ("a", 2),("b", 3),
("b", 4), ("b",5),("a",6)
),2)
//获取相同key的平均值 =>(a,3)(b,4)
/**
* reduceByKey
* combineByKeyWithClassTag[V](
* (v: V) => v,//第一个值不会参与计算
* func,//分区内的计算规则
* func,//分区间的计算规则
* )
*/
rdd.reduceByKey(_+_)
/**
* aggregateByKey
* combineByKeyWithClassTag[U](
* (v: V) => cleanedSeqOp(createZero(), v),//初始值和第一个key的value值进行分区内的数据操作
* cleanedSeqOp,//分区内计算规则
* combOp,//分区间计算规则
* )
*/
rdd.aggregateByKey(0)(_+_,_+_)
/**
* foldByKey
* combineByKeyWithClassTag[V](
* (v: V) => cleanedFunc(createZero(), v),//初始值和第一个key的value值进行分区内的数据操作
* cleanedFunc,//分区内计算规则
* cleanedFunc,//分区间计算规则
* )
*/
rdd.foldByKey(0)(_+_)
/**
* combineByKey
* combineByKeyWithClassTag(
* createCombiner, //相同key的第一条数据进行处理
* mergeValue,//表示分区内数据的处理函数
* mergeCombiners,//表示分区间数据的处理集合
* )
*/
rdd.combineByKey(v=>v,(x:Int,y)=>x+y,(x:Int,y:Int)=>x+y)
//关闭
sc.stop()
}