Spark快速入门(2) 核心概念和抽象:Transformations(1)

前一篇我们介绍了RDD的概念,知道了RDD是一组只读并且支持分区的数据集。创建RDD的第一种方式是读取文件,本节我们介绍第二种方式,从一个已有的RDD创建出新的RDD。

Transformations

Transformations(转换)使得我们可以从一个已有的RDD,创建出新的RDD。我们需要指定如何从一个已有的数据,获取新的数据。Transformations通常又被称为Spark的一类算子:变换/转换算子。下面我们介绍几种常见的Transformations的方式:

Filter

def filter(p: T -> Boolean): RDD[T] -> RDD[T]

filter算子通过定义一个predicate,返回已有RDD中满足此条件的RDD,转换为新的RDD。例如下面是一个filter算子,过滤出所有的偶数。

Spark快速入门(2) 核心概念和抽象:Transformations(1)_第1张图片
filter算子
Filter RDD实现

上文中介绍过RDD必须要实现三个方法,Filter RDD的这三个方法是如何实现的呢,假设Y=X.filter(p):

  • Y.partitions() -> Array[Partition]:
    返回和X相同的分区,filter算子并不改变RDD分区方式。

  • Y.iterator(p: Parent, parents -> Array[Iterator[T]]) -> Iterator[T] :
    获取X对应的iterator,遍历X的所有数据,过滤掉不满足predicate的数据,返回Y的iterator。

  • Y.dependencies() -> Array[Dependency]:
    Y的第k个分区,依赖X的第k个分区。

Map

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

map算子通过定义一个函数,将已有RDD的所有数据,经过函数计算后的结果,生成一个新的RDD。例如下面的map算子,将所有的数据乘以2。

Spark快速入门(2) 核心概念和抽象:Transformations(1)_第2张图片
map算子

flatMap

def flatMap(f: T -> Array[U]): RDD[T] -> RDD[U]

flatMap算子是filter和map算子的泛化形式,已有RDD的每个数据,在经过flatMap算子后变为一个数组,如果想过滤一些数据,只需让这些数据在转换后的结果为空数组。

flatMap RDD的举例

举个例子更好的理解flatMap,假如我们想实现word count的功能,每一行可能会出现多个单词,因此需要对每行的字符串进行分词,得到这一行所有单词的数组,在处理所有行之后,得到的是一个二维数组。我们进行word count的时候,希望所有单词在一个一维数组中,因此需要flat的结果,这里就需要用到flatMap,java和scala的示例代码如下:

JavaRDD wordsFromFile = inputFile
        .flatMap(content -> Arrays.asList(content.split(" ")).iterator());
val words = lines.flatMap(_.split(" "))

Transformations的特点

Lazy执行

Transformations并不是创建后立马执行的,而是会被下一节介绍的actions算子触发才会执行的。因为我们在通过Transformations创建RDD时,并不知道从哪里开始执行,以及数据要写在哪里,通过Lazy执行,我们可以使真正需要输出的数据才会被计算。

Predicate闭包

Predicate闭包被发送到每个执行filter计算的executor上,而且我们无法控制predicate的代码何时何地被执行。因此要保证predicate只处理RDD中的数据,而不会访问本地文件,或者闭包中的本地索引等。

计算依赖图

Transformations会把整个计算过程组织成一个依赖图,框架会按照依赖图依次执行每个过程,这里我们画出的是partition级别的filter算子的依赖图:

Spark快速入门(2) 核心概念和抽象:Transformations(1)_第3张图片
filter算子的依赖图

你可能感兴趣的:(Spark快速入门(2) 核心概念和抽象:Transformations(1))