1. collect算子作用
收集一个弹性分布式数据集(RDD)的所有元素到一个数组中,以便观察。collect是Action类型的一个算子,会从远程集群拉去数据到driver端,最后将大量数据汇集到一个driver节点上,将数据用数组存放,占用了jvm堆内存,非常容易造成内存溢出,只用作小型数据的观察
2. 弊端
首先,由于collect是从各节点将数据拉到driver端,需要重新分区,所以,一次collect就会导致一次Shuffle,而一次Shuffle调度一次stage,然而一次stage包含很多个已分解的任务碎片Task。这么一来,会导致程序运行时间大大增加,属于比较耗时的操作,即使是在local模式下也同样耗时。
其次,从环境上来讲,本机local模式下运行并无太大区别,可若放在分布式环境下运行,一次collect操作会将分布式各个节点上的数据汇聚到一个driver节点上,而这么一来,后续所执行的运算和操作就会脱离这个分布式环境而相当于单机环境下运行,这也与Spark的分布式理念不合。
最后,将大量数据汇集到一个driver节点上,并且像这样val arr = data.collect(),将数据用数组存放,占用了jvm堆内存,可想而知,是有多么轻松就会内存溢出。
3. 规避
若需要遍历RDD中元素,大可不必使用collect,可以使用foreach语句;
若需要打印RDD中元素,可用take语句,data.take(1000).foreach(println),这点官方文档里有说明;
若需要查看其中内容,可用saveAsTextFile方法。
总之,单机环境下使用collect问题并不大,但分布式环境下尽量规避,如有其他需要,手动编写代码实现相应功能就好。
4. 补充
collectPartitions:
同样属于Action的一种操作,同样也会将数据汇集到Driver节点上,与collect区别并不是很大,唯一的区别是:collectPartitions产生数据类型不同于collect,collect是将所有RDD汇集到一个数组里,而collectPartitions是将各个分区内所有元素存储到一个数组里,再将这些数组汇集到driver端产生一个数组;collect产生一维数组,而collectPartitions产生二维数组。