map:

函数签名

def map[U: ClassTag](f: T => U): RDD[U]

转换算子其实就是转换方法,比如一个案例简单的理解一下转换算子map

def mapFunction(num: Int): Int = {
	num * 2
}

//map传入的可以是一个方法名
val mapRDD: RDD[Int] = rdd.map(mapFunction)

//map传入的也可以是一个匿名函数
val mapRDD: RDD[Int] = rdd.map(
	(num: Int) => {
		num * 2
	}
)

//=====>匿名函数简化
val mapRDD: RDD[Int] = rdd.map(_ * 2)

对于多个分区的数据处理上,map又会涉及到并行计算的特点

如果对于一个分区数据,map的操作会一个个的执行逻辑,只有前面一个数据的全部逻辑执行完成后,后面的数据才会开始执行,分区内的数据执行是有序的,但是对于不同分区内的数据计算确是无序的

mapPartitions:

函数签名

def mapPartitions[U: ClassTag]( f: Iterator[T] => Iterator[U],

preservesPartitioning: Boolean = false): RDD[U]

对于map是并行处理的,需要等数据一个一个的执行,这样一来就会消耗很多的运行时间,而mapPartitions则是可以以分区为单位进行数据转换操作,但是会将整个分区的数据加载到内存中进行引用,就是处理完得数据不会被释放掉,存在着对象引用的现象,所以在内存较小,数据量较大的时候,容易出现内存溢出。

map和mapPartitons的区别:
数据处理的角度:

Map 算子是分区内一个数据一个数据的执行,类似于串行操作。而 mapPartitions 算子是以分区为单位进行批处理操作。

功能的角度:

Map 算子主要目的将数据源中的数据进行转换和改变。但是不会减少或增多数据。MapPartitions 算子需要传递一个迭代器, 返回一个迭代器, 没有要求的元素的个数保持不变,所以可以增加或减少数据

性能的角度:

Map 算子因为类似于串行操作,所以性能比较低,而是 mapPartitions 算子类似于批处理,所以性能较高。但是 mapPartitions 算子会长时间占用内存,那么这样会导致内存可能不够用,出现内存溢出的错误。所以在内存有限的情况下,不推荐使用。使用 map 操作。

mapPartitionsWithIndex:

函数签名

def mapPartitionsWithIndex[U: ClassTag]( f: (Int, Iterator[T]) => Iterator[U],

preservesPartitioning: Boolean = false): RDD[U]

如果只想要获得某个分区的数据,那么该怎么办?就可以使用mapPartitionsWithIndex转换算子