RDD常用算子内部的数据转换
今天这一讲,我们先来学习同一个 RDD 内部的数据转换。掌握 RDD 常用算子是做好 Spark 应用开发的基础,而数据转换类算子则是基础中的基础,因此我们优先来学习这类 RDD 算子
创建 RDD
俗话说,巧妇难为无米之炊,要想玩转厨房里的厨具,我们得先准备好米、面、油这些食材。学习 RDD 算子也是一样,要想动手操作这些算子,咱们得先有 RDD 才行。
在 Spark 中,创建 RDD 的典型方式有两种:
- 通过 SparkContext.parallelize 在内部数据之上创建 RDD
- 通过 SparkContext.textFile 等 API 从外部数据创建 RDD。
这里的内部、外部是相对应用程序来说的。开发者在 Spark 应用中自定义的各类数据结构,如数组、列表、映射等,都属于“内部数据”;而“外部数据”指代的,是 Spark 系统之外的所有数据形式,如本地文件系统或是分布式文件系统中的数据,再比如来自其他大数据组件(Hive、Hbase、RDBMS 等)的数据。
第一种创建方式的用法非常简单,只需要用 parallelize 函数来封装内部数据即可,比如下面的例子:
import org.apache.spark.rdd.RDD
val words: Array[String] = Array("Spark", "is", "cool")
val rdd: RDD[String] = sc.parallelize(words)
你可以在 spark-shell 中敲入上述代码,来直观地感受 parallelize 创建 RDD 的过程。通常来说,在 Spark 应用内定义体量超大的数据集,其实都是不太合适的,因为数据集完全由 Driver 端创建,且创建完成后,还要在全网范围内跨节点、跨进程地分发到其他 Executors,所以往往会带来性能问题。因此,parallelize API 的典型用法,是在“小数据”之上创建 RDD。
要想在真正的“大数据”之上创建 RDD,我们还得依赖第二种创建方式,也就是通过 SparkContext.textFile 等 API 从外部数据创建 RDD。由于 textFile API 比较简单,而且它在日常的开发中出现频率比较高,因此我们使用 textFile API 来创建 RDD。在后续对各类 RDD 算子讲解的过程中,我们都会使用 textFile API 从文件系统创建 RDD。
import org.apache.spark.rdd.RDD
val rootPath: String = _
val file: String = s"${rootPath}/wikiOfSpark.txt"
// 读取文件内容
val lineRDD: RDD[String] = spark.sparkContext.textFile(file)
RDD 内的数据转换
首先,我们先来认识一下 map 算子。毫不夸张地说,在所有的 RDD 算子中,map“出场”的概率是最高的。因此,我们必须要掌握 map 的用法与注意事项。
map:以元素为粒度的数据转换
我们先来说说 map 算子的用法:给定映射函数 f,map(f) 以元素为粒度对 RDD 做数据转换。其中 f 可以是带有明确签名的带名函数,也可以是匿名函数,它的形参类型必须与 RDD 的元素类型保持一致,而输出类型则任由开发者自行决定。
们使用如下代码,把包含单词的 RDD 转换成元素为(Key,Value)对的 RDD,后者统称为 Paired RDD。
// 把普通R