Scala中的部分函数和RDD中的部分算子名字一样,功能一样,用起来也差不多。但是为什么一个叫函数,一个却要叫算子,函数和算子的区别在哪,这让我有些好奇。于是查看了源码,对函数和算子进行了比较。下面以map
为例。
Scala中的map函数
Scala中的map通常定义在集合类中,例如Map
、List
、Seq
、Set
。作用是对该可迭代集合的所有元素应用一个函数,从而建立一个新的可迭代集合。
Builds a new iterable collection by applying a function to all elements of this iterable collection.
注意:List
属于scala.collection.immutable
的子类,而Map、Seq、Set
属于scala.collection
的子类
map
函数最底层的源码应该是scala.collection
里的如下代码
具体实现以
List
中的map
举例
源码为
|
|
List
中的map
重写了其父类collection.IterableOnce
的map
函数,定义了一个匿名函数(f:A=>B)
,对List中的每个元素A处理后输出B类型的List
。比如List[String]
经过map
处理后可以变成List[Interger]
其他collection的代码可以自行查看,也可以查看Scala的官方文档
Spark中的map算子
Spark中的算子分为转换算子(Transformations (return a new RDD))和行动算子(Actions (launch a job to return a value to the user program)), 转换算子根据数据处理方式的不同将算子整体上分为 Value 类型、双 Value 类型和 Key-Value 类型 。具体不再细讲,可以自行查询。
RDD中的map
代码如下:
|
|
可以看出,这里的map
首先创建了一个MapPartitionsRDD
并生成可迭代对象iter
,然后调用了Scala的map
函数处理iter
。
结论
Scala里的map
函数首先定义在scala.collection
里,然后子类(List
、Set
)重写父类的函数。因为Scala里的类型是隐式的,并且查看源代码在一个子类里也只发现了一个map
函数,所以Scala里的map
并没有重载,而是通过定义父类,子类重写父类函数的方法实现对不同数据结构的操作。
Spark里的map
是对RDD进行操作的算子,实际使用了可迭代对象来调用Scala中的map
函数。算子本身的定义就是对RDD操作的函数,所以算子应该也可以被称为是函数,但是为了区分Scala中的函数,所以使用了不同的名字。
补充
Spark中的算子并非全都有同名函数,原因可以从RDD的原理上分析。
行动算子需要进行shuffle
操作,在shuffle
时需要按键分区,对每个分区进行操作后输出。Scala中并没有Shuffle
操作,所以行动算子没有同名函数。
而转换算子是生成RDD或者将RDD转换成另外的RDD,Scala本身也有将collection
转换为collection
的函数,并且转换算子本身就调用了Scala的函数,所以有同名的也正常。