优化阅读格式

This commit is contained in:
heibaiying
2019-07-31 17:18:07 +08:00
parent ceb868fe13
commit ca7c99802b
91 changed files with 4059 additions and 4058 deletions

View File

@ -27,28 +27,28 @@
## 一、Transformation
spark常用的Transformation算子如下表
spark 常用的 Transformation 算子如下表:
| Transformation算子 | Meaning含义 |
| Transformation 算子 | Meaning含义 |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| **map**(*func*) | 对原RDD中每个元素运用 *func* 函数并生成新的RDD |
| **filter**(*func*) | 对原RDD中每个元素使用*func* 函数进行过滤并生成新的RDD |
| **map**(*func*) | 对原 RDD 中每个元素运用 *func* 函数,并生成新的 RDD |
| **filter**(*func*) | 对原 RDD 中每个元素使用*func* 函数进行过滤,并生成新的 RDD |
| **flatMap**(*func*) | 与 map 类似,但是每一个输入的 item 被映射成 0 个或多个输出的 items *func* 返回类型需要为 Seq )。 |
| **mapPartitions**(*func*) | 与 map 类似但函数单独在RDD的每个分区上运行 *func*函数的类型为 Iterator\<T> => Iterator\<U> ,其中T是RDD的类型即RDD[T] |
| **mapPartitions**(*func*) | 与 map 类似,但函数单独在 RDD 的每个分区上运行, *func*函数的类型为 Iterator\<T> => Iterator\<U> ,其中 T 是 RDD 的类型,即 RDD[T] |
| **mapPartitionsWithIndex**(*func*) | 与 mapPartitions 类似,但 *func* 类型为 (Int, Iterator\<T>) => Iterator\<U> ,其中第一个参数为分区索引 |
| **sample**(*withReplacement*, *fraction*, *seed*) | 数据采样有三个可选参数设置是否放回withReplacement、采样的百分比*fraction*、随机数生成器的种子seed |
| **union**(*otherDataset*) | 合并两个RDD |
| **intersection**(*otherDataset*) | 求两个RDD的交集 |
| **union**(*otherDataset*) | 合并两个 RDD |
| **intersection**(*otherDataset*) | 求两个 RDD 的交集 |
| **distinct**([*numTasks*])) | 去重 |
| **groupByKey**([*numTasks*]) | 按照key值进行分区即在一个 (K, V) 对的 dataset 上调用时,返回一个 (K, Iterable\<V>) <br/>**Note:** 如果分组是为了在每一个 key 上执行聚合操作例如sum 或 average),此时使用 `reduceByKey``aggregateByKey` 性能会更好<br>**Note:** 默认情况下,并行度取决于父 RDD 的分区数。可以传入 `numTasks` 参数进行修改。 |
| **reduceByKey**(*func*, [*numTasks*]) | 按照key值进行分组并对分组后的数据执行归约操作。 |
| **aggregateByKey**(*zeroValue*,*numPartitions*)(*seqOp*, *combOp*, [*numTasks*]) | 当调用KV对的数据集时返回KU对的数据集其中使用给定的组合函数和zeroValue聚合每个键的值。与groupByKey类似reduce任务的数量可通过第二个参数进行配置。 |
| **sortByKey**([*ascending*], [*numTasks*]) | 按照key进行排序其中的key需要实现Ordered特质即可比较 |
| **join**(*otherDataset*, [*numTasks*]) | 在一个 (K, V) 和 (K, W) 类型的 dataset 上调用时,返回一个 (K, (V, W)) pairs 的 dataset等价于内连接操作。如果想要执行外连接可以使用`leftOuterJoin`, `rightOuterJoin``fullOuterJoin` 等算子。 |
| **groupByKey**([*numTasks*]) | 按照 key 值进行分区,即在一个 (K, V) 对的 dataset 上调用时,返回一个 (K, Iterable\<V>) <br/>**Note:** 如果分组是为了在每一个 key 上执行聚合操作例如sum 或 average),此时使用 `reduceByKey``aggregateByKey` 性能会更好<br>**Note:** 默认情况下,并行度取决于父 RDD 的分区数。可以传入 `numTasks` 参数进行修改。 |
| **reduceByKey**(*func*, [*numTasks*]) | 按照 key 值进行分组,并对分组后的数据执行归约操作。 |
| **aggregateByKey**(*zeroValue*,*numPartitions*)(*seqOp*, *combOp*, [*numTasks*]) | 当调用KV对的数据集时返回KU对的数据集其中使用给定的组合函数和 zeroValue 聚合每个键的值。与 groupByKey 类似reduce 任务的数量可通过第二个参数进行配置。 |
| **sortByKey**([*ascending*], [*numTasks*]) | 按照 key 进行排序,其中的 key 需要实现 Ordered 特质,即可比较 |
| **join**(*otherDataset*, [*numTasks*]) | 在一个 (K, V) 和 (K, W) 类型的 dataset 上调用时,返回一个 (K, (V, W)) pairs 的 dataset等价于内连接操作。如果想要执行外连接可以使用 `leftOuterJoin`, `rightOuterJoin``fullOuterJoin` 等算子。 |
| **cogroup**(*otherDataset*, [*numTasks*]) | 在一个 (K, V) 对的 dataset 上调用时,返回一个 (K, (Iterable\<V>, Iterable\<W>)) tuples 的 dataset。 |
| **cartesian**(*otherDataset*) | 在一个 T 和 U 类型的 dataset 上调用时,返回一个 (T, U) 类型的 dataset即笛卡尔积。 |
| **coalesce**(*numPartitions*) | 将RDD中的分区数减少为numPartitions。 |
| **repartition**(*numPartitions*) | 随机重新调整RDD中的数据以创建更多或更少的分区并在它们之间进行平衡。 |
| **coalesce**(*numPartitions*) | 将 RDD 中的分区数减少为 numPartitions。 |
| **repartition**(*numPartitions*) | 随机重新调整 RDD 中的数据以创建更多或更少的分区,并在它们之间进行平衡。 |
| **repartitionAndSortWithinPartitions**(*partitioner*) | 根据给定的 partitioner分区器对 RDD 进行重新分区,并对分区中的数据按照 key 值进行排序。这比调用 `repartition` 然后再 sorting排序效率更高因为它可以将排序过程推送到 shuffle 操作所在的机器。 |
下面分别给出这些算子的基本使用示例:
@ -73,7 +73,7 @@ sc.parallelize(list).filter(_ >= 10).foreach(println)
### 1.3 flatMap
`flatMap(func)``map`类似但每一个输入的item会被映射成 0 个或多个输出的items *func* 返回类型需要为`Seq`)。
`flatMap(func)``map` 类似,但每一个输入的 item 会被映射成 0 个或多个输出的 items *func* 返回类型需要为 `Seq`)。
```scala
val list = List(List(1, 2), List(3), List(), List(4, 5))
@ -82,7 +82,7 @@ sc.parallelize(list).flatMap(_.toList).map(_ * 10).foreach(println)
// 输出结果 10 20 30 40 50
```
flatMap 这个算子在日志分析中使用概率非常高这里进行一下演示拆分输入的每行数据为单个单词并赋值为1代表出现一次之后按照单词分组并统计其出现总次数代码如下
flatMap 这个算子在日志分析中使用概率非常高,这里进行一下演示:拆分输入的每行数据为单个单词,并赋值为 1代表出现一次之后按照单词分组并统计其出现总次数代码如下
```scala
val lines = List("spark flume spark",
@ -99,7 +99,7 @@ map(word=>(word,1)).reduceByKey(_+_).foreach(println)
### 1.4 mapPartitions
与 map 类似但函数单独在RDD的每个分区上运行 *func*函数的类型为`Iterator<T> => Iterator<U>` (其中T是RDD的类型),即输入和输出都必须是可迭代类型。
与 map 类似,但函数单独在 RDD 的每个分区上运行, *func*函数的类型为 `Iterator<T> => Iterator<U>` (其中 T 是 RDD 的类型),即输入和输出都必须是可迭代类型。
```scala
val list = List(1, 2, 3, 4, 5, 6)
@ -116,7 +116,7 @@ sc.parallelize(list, 3).mapPartitions(iterator => {
### 1.5 mapPartitionsWithIndex
与 mapPartitions 类似,但 *func* 类型为`(Int, Iterator<T>) => Iterator<U>` ,其中第一个参数为分区索引。
与 mapPartitions 类似,但 *func* 类型为 `(Int, Iterator<T>) => Iterator<U>` ,其中第一个参数为分区索引。
```scala
val list = List(1, 2, 3, 4, 5, 6)
@ -128,17 +128,17 @@ sc.parallelize(list, 3).mapPartitionsWithIndex((index, iterator) => {
buffer.toIterator
}).foreach(println)
//输出
0分区:100
0分区:200
1分区:300
1分区:400
2分区:500
2分区:600
0 分区:100
0 分区:200
1 分区:300
1 分区:400
2 分区:500
2 分区:600
```
### 1.6 sample
数据采样。有三个可选参数:设置是否放回(withReplacement)、采样的百分比(fraction)、随机数生成器的种子(seed)
数据采样。有三个可选参数:设置是否放回 (withReplacement)、采样的百分比 (fraction)、随机数生成器的种子 (seed)
```scala
val list = List(1, 2, 3, 4, 5, 6)
@ -147,7 +147,7 @@ sc.parallelize(list).sample(withReplacement = false, fraction = 0.5).foreach(pri
### 1.7 union
合并两个RDD
合并两个 RDD
```scala
val list1 = List(1, 2, 3)
@ -158,7 +158,7 @@ sc.parallelize(list1).union(sc.parallelize(list2)).foreach(println)
### 1.8 intersection
求两个RDD的交集
求两个 RDD 的交集:
```scala
val list1 = List(1, 2, 3, 4, 5)
@ -231,7 +231,7 @@ sc.parallelize(list02).sortBy(x=>x._2,ascending=false).foreach(println)
### 1.13 join
在一个 (K, V) 和 (K, W) 类型的 Dataset 上调用时,返回一个 (K, (V, W)) 的 Dataset等价于内连接操作。如果想要执行外连接可以使用`leftOuterJoin`, `rightOuterJoin``fullOuterJoin` 等算子。
在一个 (K, V) 和 (K, W) 类型的 Dataset 上调用时,返回一个 (K, (V, W)) 的 Dataset等价于内连接操作。如果想要执行外连接可以使用 `leftOuterJoin`, `rightOuterJoin``fullOuterJoin` 等算子。
```scala
val list01 = List((1, "student01"), (2, "student02"), (3, "student03"))
@ -246,7 +246,7 @@ sc.parallelize(list01).join(sc.parallelize(list02)).foreach(println)
### 1.14 cogroup
在一个 (K, V) 对的 Dataset 上调用时,返回多个类型为 (K, (Iterable\<V>, Iterable\<W>)) 的元组所组成的Dataset。
在一个 (K, V) 对的 Dataset 上调用时,返回多个类型为 (K, (Iterable\<V>, Iterable\<W>)) 的元组所组成的 Dataset。
```scala
val list01 = List((1, "a"),(1, "a"), (2, "b"), (3, "e"))
@ -254,7 +254,7 @@ val list02 = List((1, "A"), (2, "B"), (3, "E"))
val list03 = List((1, "[ab]"), (2, "[bB]"), (3, "eE"),(3, "eE"))
sc.parallelize(list01).cogroup(sc.parallelize(list02),sc.parallelize(list03)).foreach(println)
// 输出: 同一个RDD中的元素先按照key进行分组然后再对不同RDD中的元素按照key进行分组
// 输出: 同一个 RDD 中的元素先按照 key 进行分组,然后再对不同 RDD 中的元素按照 key 进行分组
(1,(CompactBuffer(a, a),CompactBuffer(A),CompactBuffer([ab])))
(3,(CompactBuffer(e),CompactBuffer(E),CompactBuffer(eE, eE)))
(2,(CompactBuffer(b),CompactBuffer(B),CompactBuffer([bB])))
@ -284,7 +284,7 @@ sc.parallelize(list1).cartesian(sc.parallelize(list2)).foreach(println)
### 1.16 aggregateByKey
当调用KV对的数据集时返回KU对的数据集其中使用给定的组合函数和zeroValue聚合每个键的值。与`groupByKey`类似reduce任务的数量可通过第二个参数`numPartitions`进行配置。示例如下:
当调用KV对的数据集时返回KU对的数据集其中使用给定的组合函数和 zeroValue 聚合每个键的值。与 `groupByKey` 类似reduce 任务的数量可通过第二个参数 `numPartitions` 进行配置。示例如下:
```scala
// 为了清晰,以下所有参数均使用具名传参
@ -299,11 +299,11 @@ sc.parallelize(list,numSlices = 2).aggregateByKey(zeroValue = 0,numPartitions =
(spark,7)
```
这里使用了`numSlices = 2`指定aggregateByKey父操作parallelize的分区数量为2其执行流程如下
这里使用了 `numSlices = 2` 指定 aggregateByKey 父操作 parallelize 的分区数量为 2其执行流程如下
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-aggregateByKey.png"/> </div>
基于同样的执行流程,如果`numSlices = 1`则意味着只有输入一个分区则其最后一步combOp相当于是无效的执行结果为
基于同样的执行流程,如果 `numSlices = 1`,则意味着只有输入一个分区,则其最后一步 combOp 相当于是无效的,执行结果为:
```properties
(hadoop,3)
@ -311,7 +311,7 @@ sc.parallelize(list,numSlices = 2).aggregateByKey(zeroValue = 0,numPartitions =
(spark,4)
```
同样的,如果每个单词对一个分区,即`numSlices = 6`,此时相当于求和操作,执行结果为:
同样的,如果每个单词对一个分区,即 `numSlices = 6`,此时相当于求和操作,执行结果为:
```properties
(hadoop,5)
@ -319,7 +319,7 @@ sc.parallelize(list,numSlices = 2).aggregateByKey(zeroValue = 0,numPartitions =
(spark,7)
```
`aggregateByKey(zeroValue = 0,numPartitions = 3)`的第二个参数`numPartitions`决定的是输出RDD的分区数量想要验证这个问题可以对上面代码进行改写使用`getNumPartitions`方法获取分区数量:
`aggregateByKey(zeroValue = 0,numPartitions = 3)` 的第二个参数 `numPartitions` 决定的是输出 RDD 的分区数量,想要验证这个问题,可以对上面代码进行改写,使用 `getNumPartitions` 方法获取分区数量:
```scala
sc.parallelize(list,numSlices = 6).aggregateByKey(zeroValue = 0,numPartitions = 3)(
@ -332,7 +332,7 @@ sc.parallelize(list,numSlices = 6).aggregateByKey(zeroValue = 0,numPartitions =
## 二、Action
Spark常用的Action算子如下
Spark 常用的 Action 算子如下:
| Action动作 | Meaning含义 |
| -------------------------------------------------- | ------------------------------------------------------------ |
@ -344,10 +344,10 @@ Spark常用的Action算子如下
| **takeSample**(*withReplacement*, *num*, [*seed*]) | 对一个 dataset 进行随机抽样 |
| **takeOrdered**(*n*, *[ordering]*) | 按自然顺序natural order或自定义比较器custom comparator排序后返回前 *n* 个元素。只适用于小结果集,因为所有数据都会被加载到驱动程序的内存中进行排序。 |
| **saveAsTextFile**(*path*) | 将 dataset 中的元素以文本文件的形式写入本地文件系统、HDFS 或其它 Hadoop 支持的文件系统中。Spark 将对每个元素调用 toString 方法,将元素转换为文本文件中的一行记录。 |
| **saveAsSequenceFile**(*path*) | 将 dataset 中的元素以Hadoop SequenceFile 的形式写入到本地文件系统、HDFS 或其它 Hadoop 支持的文件系统中。该操作要求RDD中的元素需要实现 Hadoop 的 Writable 接口。对于Scala语言而言它可以将Spark中的基本数据类型自动隐式转换为对应Writable类型。(目前仅支持Java and Scala) |
| **saveAsObjectFile**(*path*) | 使用 Java 序列化后存储,可以使用 `SparkContext.objectFile()` 进行加载。(目前仅支持Java and Scala) |
| **saveAsSequenceFile**(*path*) | 将 dataset 中的元素以 Hadoop SequenceFile 的形式写入到本地文件系统、HDFS 或其它 Hadoop 支持的文件系统中。该操作要求 RDD 中的元素需要实现 Hadoop 的 Writable 接口。对于 Scala 语言而言,它可以将 Spark 中的基本数据类型自动隐式转换为对应 Writable 类型。(目前仅支持 Java and Scala) |
| **saveAsObjectFile**(*path*) | 使用 Java 序列化后存储,可以使用 `SparkContext.objectFile()` 进行加载。(目前仅支持 Java and Scala) |
| **countByKey**() | 计算每个键出现的次数。 |
| **foreach**(*func*) | 遍历RDD中每个元素并对其执行*fun*函数 |
| **foreach**(*func*) | 遍历 RDD 中每个元素,并对其执行*fun*函数 |
### 2.1 reduce
@ -363,7 +363,7 @@ sc.parallelize(list).reduce(_ + _)
### 2.2 takeOrdered
按自然顺序natural order或自定义比较器custom comparator排序后返回前 *n* 个元素。需要注意的是`takeOrdered`使用隐式参数进行隐式转换,以下为其源码。所以在使用自定义排序时,需要继承`Ordering[T]`实现自定义比较器,然后将其作为隐式参数引入。
按自然顺序natural order或自定义比较器custom comparator排序后返回前 *n* 个元素。需要注意的是 `takeOrdered` 使用隐式参数进行隐式转换,以下为其源码。所以在使用自定义排序时,需要继承 `Ordering[T]` 实现自定义比较器,然后将其作为隐式参数引入。
```scala
def takeOrdered(num: Int)(implicit ord: Ordering[T]): Array[T] = withScope {
@ -374,7 +374,7 @@ def takeOrdered(num: Int)(implicit ord: Ordering[T]): Array[T] = withScope {
自定义规则排序:
```scala
// 继承Ordering[T],实现自定义比较器按照value值的长度进行排序
// 继承 Ordering[T],实现自定义比较器,按照 value 值的长度进行排序
class CustomOrdering extends Ordering[(Int, String)] {
override def compare(x: (Int, String), y: (Int, String)): Int
= if (x._2.length > y._2.length) 1 else -1