场景设定
假设有一个包含句子的 RDD:
scala
val rdd = sc.parallelize(List("Hello World", "Hi Spark"))
目标是:将每个句子拆分成单词。
1. 用 map
的效果
代码示例
scala
val resultMap = rdd.map(sentence => sentence.split(" "))
resultMap.collect()
输出结果
scala
Array[Array[String]] = Array(Array("Hello", "World"), Array("Hi", "Spark"))
发生了什么?
-
map
一对一转换:-
输入一个句子
"Hello World"
→ 输出一个单词数组Array("Hello", "World")
-
输入一个句子
"Hi Spark"
→ 输出一个单词数组Array("Hi", "Spark")
-
-
结果结构:嵌套的数组(每个元素还是数组)。
2. 用 flatMap
的效果
代码示例
scala
val resultFlatMap = rdd.flatMap(sentence => sentence.split(" "))
resultFlatMap.collect()
输出结果
scala
Array[String] = Array("Hello", "World", "Hi", "Spark")
发生了什么?
-
flatMap
一对多转换:-
输入一个句子
"Hello World"
→ 拆分成两个单词"Hello"
和"World"
-
输入一个句子
"Hi Spark"
→ 拆分成两个单词"Hi"
和"Spark"
-
-
结果结构:扁平化的数组(所有单词在一个数组中)。
核心区别总结
操作 | 输入 → 输出关系 | 结果结构 | 适用场景 |
---|---|---|---|
map | 1个输入 → 1个输出(类型可变) | 保持嵌套结构 | 简单转换(如类型转换、数值计算) |
flatMap | 1个输入 → 多个输出(自动展平) | 扁平化单层结构 | 拆分数据(如分词、展开嵌套结构) |
图解对比
原始数据: List("Hello World", "Hi Spark") ↓ ↓
map 处理: Array("Hello", "World") Array("Hi", "Spark") → 结果:嵌套数组 | | | |
flatMap 处理: "Hello" "World" "Hi" "Spark" → 结果:扁平数组
什么时候用 map
?
-
保留结构:比如将字符串转大写、对数字做运算。
scala
val numbers = sc.parallelize(List(1, 2, 3)) val doubled = numbers.map(_ * 2) // 输出:List(2, 4, 6)
什么时候用 flatMap
?
-
拆分或展开数据:比如将句子拆成单词、展开嵌套集合。
scala
val nestedList = sc.parallelize(List(List(1, 2), List(3, 4))) val flattened = nestedList.flatMap(identity) // 输出:List(1, 2, 3, 4)
高级用法
链式调用示例
scala
// 同时使用 map 和 flatMap
val sentences = sc.parallelize(List("Hello World", "Hi Spark"))// 步骤分解:
// 1. 用 map 将句子转大写
// 2. 用 flatMap 拆分单词
val result = sentences.map(_.toUpperCase).flatMap(_.split(" "))result.collect() // 输出:Array("HELLO", "WORLD", "HI", "SPARK")
一句总结
map
是变形,flatMap
是拆开压平!
需要保持结构用 map
,需要展开数据用 flatMap
!