1、MapPartition和Map的区别:
map和mapParttion都是spark的算子,他们在进行数据处理时有一定的区别:
- map是RDD中的每一个元素进行操作。
- mapPartition是对RDD的每一个分区的迭代器进行操作,返回的是迭代器。
mapPartiton的优势:
提高性能,比如我们对一个含有100条log数据的分区进行操作,使用map的话函数要执行100次计算。使用MapPartitions操作之后,一个task仅仅会执行一次function,function一次接收所有的partition数据。如果map执行的过程中还需要创建对象,比如创建redis连接,jdbc连接等。map需要为每个元素创建一个链接而mapPartition为每个partition创建一个链接。mapPartiton的缺点:
对于一个partition有很多数据的话,一次函数处理可能会导致OOM。普通的map一般不会导致OOM。
2、coalesce和repartition区别:
repartition(numPartitions:Int):RDD[T]
coalesce(numPartitions:Int,shuffle:Boolean=false):RDD[T]
它们两个都是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和reduce区别:
- reduce:是把RDD中的每一个元素拿出来处理并形成一个新的RDD元素 (数据是一个一个处理的,一个输入元素对应一个输出元素);
- reduceByKey:是把RDD中的key相同的一组数据拿出来处理,形成一个新的RDD里面放的是元组(数据是一组一组处理的,相同元素的key进行归并处理);
4、collect和foreach区别:
- collect 在驱动程序中,以数组的形式返回数据集的所有元素;
Spark内有collect方法,是Action操作里边的一个算子,这个方法可以将RDD类型的数据转化为数组, 同时会从远程集群是拉取数据到driver端。
劣势:
,
- collect是Action里边的,根据RDD的惰性机制,真正的计算发生在RDD的Action操作。因此,一次collect就会导致一次Shuffle,而一次Shuffle调度一次stage,一次stage包含多个已分解的任务碎片Task,会导致程序运行时间大大增加,属于比较耗时的操作,即使是在local模式下也同样耗时。
- 从环境上来讲,本机local模式下运行并无太大区别,若放在分布式环境下运行,一次collect操作会将分布式各个节点上的数据汇聚到一个driver节点上,后续所执行的运算和操作就会脱离这个分布式环境而相当于单机环境下运行,这与Spark的分布式理念不合。
- 将大量数据汇集到一个driver节点上,并且像这样val arr = data.collect(),将数据用数组存放,占用了jvm堆内存,会内存溢出。
- 单机环境下使用collect问题并不大,但分布式环境下尽量规避;
- collectPartitions也属于Action的一种操作,也会将数据汇集到Driver节点上,与collect区别并不是很大,唯一的区别是collectPartitions产生数据类型不同于collect,collect是将所有RDD汇集到一个数组里产生一维数组,collectPartitions是将各个分区内所有元素存储到一个数组里,再将这些数组汇集到driver端产生二维数组。
解决方案:
- 遍历RDD中元素,可以使用foreach语句;
- 打印RDD中元素,可用take语句,返回数据集前n个元素,data.take(999).foreach(println);
- 查看其中内容,可用saveAsTextFile方法。
@Test
def collectTest: Unit ={
sc.parallelize(Seq(("a",1),("b",2),("c",3)))
.mapValues(item => item*10)
.collect()
.foreach(println(_))
}
结果:
(a,10)
(b,20)
(c,30)
- foreach操作是直接调迭代rdd中每一条数据
class foreachTest {
val conf = new SparkConf().setMaster("local[6]").setAppName("sortBy")
val sc = new SparkContext(conf)
@Test
def foreachTest: Unit ={
val rdd = sc.parallelize(Seq(1,2,3,4,5,6))
rdd.foreach( item => println(item) )
}
}