Spark Core

以下是今天学习的知识点与代码测试:

Spark Core

Spark-Core编程(二)

RDD转换算子

RDD 根据数据处理方式的不同将算子整体上分为 Value 类型、双 Value 类型和 Key-Value 类型。

Value类型:
  1. map

➢ 函数签名

def mapU: ClassTag(f: T => U): RDDU

➢ 函数说明

将处理的数据逐条进行映射转换,这里的转换可以是类型的转换,也可以是值的转换。

val sparkConf = new SparkConf().setMaster("local\*" ).setAppName("RDD_function" )
val sparkContext = new SparkContext(sparkConf)

val dataRDD: RDDInt = sparkContext.makeRDD(List (1, 2, 3, 4))
val dataRDD1: RDDInt = dataRDD.map(
num => {
num * 2
}
)
val dataRDD2: RDDString = dataRDD1.map(
num => {
"" + num
}
)
sparkContext.stop()

代码测试:

  1. mapPartitions

➢ 函数签名

def mapPartitionsU: ClassTag(

f: IteratorT => IteratorU,

preservesPartitioning: Boolean = false): RDDU

➢ 函数说明

将待处理的数据以分区为单位发送到计算节点进行处理,这里的处理是指可以进行任意的处理,哪怕是过滤数据。

val dataRDD1: RDDInt = dataRDD.mapPartitions(
datas => {
datas.filter(_==2)
}
)

map 和 mapPartitions 的区别:

➢ 数据处理角度

Map 算子是分区内一个数据一个数据的执行,类似于串行操作。而 mapPartitions 算子是以分区为单位进行批处理操作。

➢ 功能的角度

Map 算子主要目的将数据源中的数据进行转换和改变。但是不会减少或增多数据。MapPartitions 算子需要传递一个迭代器,返回一个迭代器,没有要求的元素的个数保持不变,所以可以增加或减少数据

➢ 性能的角度

Map 算子因为类似于串行操作,所以性能比较低,而是 mapPartitions 算子类似于批处理,所以性能较高。但是 mapPartitions 算子会长时间占用内存,那么这样会导致内存可能不够用,出现内存溢出的错误。所以在内存有限的情况下,不推荐使用。使用 map 操作。

  1. mapPartitionsWithIndex

➢ 函数签名

def mapPartitionsWithIndexU: ClassTag(

f: (Int, IteratorT) => IteratorU,

preservesPartitioning: Boolean = false): RDDU

➢ 函数说明

将待处理的数据以分区为单位发送到计算节点进行处理,这里的处理是指可以进行任意的处理,哪怕是过滤数据,在处理时同时可以获取当前分区索引。

  1. flatMap

➢ 函数签名

def flatMapU: ClassTag(f: T => TraversableOnceU): RDDU

➢ 函数说明

将处理的数据进行扁平化后再进行映射处理,所以算子也称之为扁平映射。

val dataRDD = sparkContext.makeRDD(List (
List (1,2),List (3,4)
),1)
val dataRDD1 = dataRDD.flatMap(
list => list
)

map和flatMap的区别:

map会将每一条输入数据映射为一个新对象。

flatMap包含两个操作:会将每一个输入对象输入映射为一个新集合,然后把这些新集合连成一个大集合。

  1. glom

➢ 函数签名

def glom(): RDDArray\[T]

➢ 函数说明

将同一个分区的数据直接转换为相同类型的内存数组进行处理,分区不变

val dataRDD = sparkContext.makeRDD(List (
1,2,3,4
),1)
val dataRDD1:RDDArray\[Int] = dataRDD.glom()

  1. groupBy

➢ 函数签名

def groupByK(f: T => K)(implicit kt: ClassTagK): RDD(K, Iterable\[T)]

➢ 函数说明

将数据根据指定的规则进行分组, 分区默认不变,但是数据会被打乱重新组合,我们将这样的操作称之为 shuffle。极限情况下,数据可能被分在同一个分区中。

一个组的数据在一个分区中,但是并不是说一个分区中只有一个组val dataRDD = sparkContext.makeRDD(List (1,2,3,4),1)
val dataRDD1 = dataRDD.groupBy(
_%2
)

  1. filter

函数签名

def filter(f: T => Boolean): RDDT

函数说明

将数据根据指定的规则进行筛选过滤,符合规则的数据保留,不符合规则的数据丢弃。

当数据进行筛选过滤后,分区不变,但是分区内的数据可能不均衡,生产环境下,可能会出

现数据倾斜。

val dataRDD = sparkContext.makeRDD(List (
1,2,3,4
),1)
val dataRDD1 = dataRDD.filter(_%2 == 0)

val dataRDD2 = dataRDD.filter(_%2 == 1)

  1. sample

函数签名

def sample(

withReplacement: Boolean,

fraction: Double,

seed: Long = Utils.random.nextLong): RDDT

➢ 函数说明

根据指定的规则从数据集中抽取数据

val dataRDD = sparkContext.makeRDD(List (
1,2,3,4
),1)

// 抽取数据不放回(伯努利算法)
// 伯努利算法:又叫 0 1 分布。例如扔硬币,要么正面,要么反面。
// 具体实现:根据种子和随机算法算出一个数和第二个参数设置几率比较,小于第二个参数要,大于不要
// 第一个参数:抽取的数据是否放回, false :不放回
// 第二个参数:抽取的几率,范围在 0,1 之间 ,0 :全不取; 1 :全取;
// 第三个参数:随机数种子

val dataRDD1 = dataRDD.sample(false , 0.5)

// 抽取数据放回(泊松算法)
// 第一个参数:抽取的数据是否放回, true :放回; false :不放回
// 第二个参数:重复数据的几率,范围大于等于 0. 表示每一个元素被期望抽取到的次数
// 第三个参数:随机数种子

val dataRDD2 = dataRDD.sample(true , 2)

Spark Core

Spark-Core编程(三)

Value类型:
  1. distinct

➢ 函数签名

def distinct()(implicit ord: OrderingT = null): RDDT

def distinct(numPartitions: Int)(implicit ord: OrderingT = null): RDDT

➢ 函数说明

将数据集中重复的数据去重

val dataRDD = sparkContext.makeRDD(List (
1,2,3,4,1,2
))
val dataRDD1 = dataRDD.distinct()
val dataRDD2 = dataRDD.distinct(2)

  1. coalesce

➢ 函数签名

def coalesce(numPartitions: Int, shuffle: Boolean = false,

partitionCoalescer: OptionPartitionCoalescer = Option.empty)

(implicit ord: OrderingT = null)

: RDDT

➢ 函数说明

根据数据量缩减分区,用于大数据集过滤后,提高小数据集的执行效率

当 spark 程序中,存在过多的小任务的时候,可以通过 coalesce 方法,收缩合并分区,减少分区的个数,减小任务调度成本

val dataRDD = sparkContext.makeRDD(List (
1,2,3,4,1,2
),6)
val dataRDD1 = dataRDD.coalesce(2)

  1. repartition

➢ 函数签名

def repartition(numPartitions: Int)(implicit ord: OrderingT = null): RDDT

➢ 函数说明

该操作内部其实执行的是 coalesce 操作,参数 shuffle 的默认值为 true。无论是将分区数多的RDD 转换为分区数少的 RDD,还是将分区数少的 RDD 转换为分区数多的 RDD,repartition操作都可以完成,因为无论如何都会经 shuffle 过程。

val dataRDD = sparkContext.makeRDD(List (
1,2,3,4,1,2
),2)
val dataRDD1 = dataRDD.repartition(4)

  1. sortBy

➢ 函数签名

def sortByK(

f: (T) => K,

ascending: Boolean = true,

numPartitions: Int = this.partitions.length)

(implicit ord: OrderingK, ctag: ClassTagK): RDDT

➢ 函数说明

该操作用于排序数据。在排序之前,可以将数据通过 f 函数进行处理,之后按照 f 函数处理的结果进行排序,默认为升序排列。排序后新产生的 RDD 的分区数与原 RDD 的分区数一致。中间存在 shuffle 的过程。

val dataRDD = sparkContext.makeRDD(List (
1,2,3,4,1,2
),2)
val dataRDD1 = dataRDD.sortBy(num=>num, false , 4)
val dataRDD2 = dataRDD.sortBy(num=>num, true , 4)

双Value类型:
  1. intersection

➢ 函数签名

def intersection(other: RDDT): RDDT

➢ 函数说明

对源 RDD 和参数 RDD 求交集后返回一个新的 RDD

val dataRDD1 = sparkContext.makeRDD(List (1,2,3,4))
val dataRDD2 = sparkContext.makeRDD(List (3,4,5,6))
val dataRDD = dataRDD1.intersection(dataRDD2)

  1. union

➢ 函数签名

def union(other: RDDT): RDDT

➢ 函数说明

对源 RDD 和参数 RDD 求并集后返回一个新的 RDD(重复数据不会去重)

val dataRDD1 = sparkContext.makeRDD(List (1,2,3,4))
val dataRDD2 = sparkContext.makeRDD(List (3,4,5,6))
val dataRDD = dataRDD1.union(dataRDD2)

  1. subtract

➢ 函数签名

def subtract(other: RDDT): RDDT

➢ 函数说明

以源 RDD 元素为主,去除两个 RDD 中重复元素,将源RDD的其他元素保留下来。(求差集)

val dataRDD1 = sparkContext.makeRDD(List (1,2,3,4))
val dataRDD2 = sparkContext.makeRDD(List (3,4,5,6))
val dataRDD = dataRDD1.subtract(dataRDD2)

  1. zip

➢ 函数签名

def zipU: ClassTag(other: RDDU): RDD(T, U)

➢ 函数说明

将两个 RDD 中的元素,以键值对的形式进行合并。其中,键值对中的 Key 为第 1 个 RDD

中的元素,Value 为第 2 个 RDD 中的相同位置的元素。

val dataRDD1 = sparkContext.makeRDD(List ("a" ,"b" ,"c" ,"d" ))
val dataRDD2 = sparkContext.makeRDD(List (1,2,3,4))
val dataRDD = dataRDD1.zip(dataRDD2)

Spark Core

Spark-Core编程(四)

Key-Value类型:
  1. partitionBy

➢ 函数签名

def partitionBy(partitioner: Partitioner): RDD(K, V)

➢ 函数说明

将数据按照指定 Partitioner 重新进行分区。Spark 默认的分区器是 HashPartitioner

val rdd: RDD(Int, String) =
sc.makeRDD(Array ((1,"aaa" ),(2,"bbb" ),(3,"ccc" )),3)

val rdd2: RDD(Int, String) =
rdd.partitionBy(new HashPartitioner(2))

  1. groupByKey

➢ 函数签名

def groupByKey(): RDD(K, Iterable\[V)]

def groupByKey(numPartitions: Int): RDD(K, Iterable\[V)]

def groupByKey(partitioner: Partitioner): RDD(K, Iterable\[V)]

➢ 函数说明

将数据源的数据根据 key 对 value 进行分组

val dataRDD1 =
sc.makeRDD(List (("a" ,1),("b" ,2),("c" ,3),("a" ,4)))
val dataRDD2 = dataRDD1.groupByKey()
val dataRDD3 = dataRDD1.groupByKey(2)
val dataRDD4 = dataRDD1.groupByKey(new HashPartitioner(2))

  1. reduceByKey

➢ 函数签名

def reduceByKey(func: (V, V) => V): RDD(K, V)

def reduceByKey(func: (V, V) => V, numPartitions: Int): RDD(K, V)

➢ 函数说明

可以将数据按照相同的 Key 对 Value 进行聚合

val dataRDD1 = sc.makeRDD(List (("a" ,1),("b" ,2),("c" ,3),("a" ,4)))
val dataRDD2 = dataRDD1.reduceByKey(+)
val dataRDD3 = dataRDD1.reduceByKey(+, 2)

reduceByKey 和 groupByKey 的区别:

从 shuffle 的角度:reduceByKey 和 groupByKey 都存在 shuffle 的操作,但是 reduceByKey可以在 shuffle 前对分区内相同 key 的数据进行预聚合(combine)功能,这样会减少落盘的数据量,而 groupByKey 只是进行分组,不存在数据量减少的问题,reduceByKey 性能比较高。

从功能的角度:reduceByKey 其实包含分组和聚合的功能。GroupByKey 只能分组,不能聚

合,所以在分组聚合的场合下,推荐使用 reduceByKey,如果仅仅是分组而不需要聚合。那

么还是只能使用 groupByKey

  1. aggregateByKey

➢ 函数签名

def aggregateByKeyU: ClassTag(zeroValue: U)(seqOp: (U, V) => U,

combOp: (U, U) => U): RDD(K, U)

➢ 函数说明

将数据根据不同的规则进行分区内计算和分区间计算val dataRDD1 =
sc.makeRDD(List (("a" ,1),("b" ,2),("c" ,3),("a" ,4)))
val dataRDD2 =
dataRDD1.aggregateByKey(0)(+,+)

  1. foldByKey

➢ 函数签名

def foldByKey(zeroValue: V)(func: (V, V) => V): RDD(K, V)

➢ 函数说明

当分区内计算规则和分区间计算规则相同时,aggregateByKey 就可以简化为 foldByKey

val dataRDD1 =
sc.makeRDD(List (("a" ,1),("b" ,2),("c" ,3),("a" ,4)))
val dataRDD2 = dataRDD1.foldByKey(0)(+)

  1. combineByKey

➢ 函数签名

def combineByKeyC(

createCombiner: V => C,//将当前值作为参数进行附加操作并返回

mergeValue: (C, V) => C,// 在分区内部进行,将新元素V合并到第一步操作得到的C中

mergeCombiners: (C, C) => C): RDD(K, C)//将第二步操作得到的C进行分区间计算

➢ 函数说明

最通用的对 key-value 型 rdd 进行聚集操作的聚集函数(aggregation function)。类似于

aggregate(),combineByKey()允许用户返回值的类型与输入不一致。

示例:现有数据 List(("a", 88), ("b", 95), ("a", 91), ("b", 93), ("a", 95), ("b", 98)),求每个key的总值及每个key对应键值对的个数

val list: List(String, Int) = List (("a" , 88), ("b" , 95), ("a" , 91), ("b" , 93),("a" , 95), ("b" , 98))
val input: RDD(String, Int) = sc.makeRDD(list, 2)
val combineRDD: RDD(String, (Int, Int)) = input.combineByKey(
(_, 1),//a=>(a,1)
(acc: (Int, Int), v) => (acc._1 + v, acc._2 + 1),// acc _1 为数据源的value,acc _2 为key出现的次数,二者进行分区内部的计算
(acc1: (Int, Int), acc2: (Int, Int)) => (acc1._1 + acc2._1, acc1._2 + acc2._2)// 将分区内部计算的结果进行分区间的汇总计算,得到每个key的总值以及每个key出现的次数
)

reduceByKey、foldByKey、aggregateByKey、combineByKey 的区别:

reduceByKey: 相同 key 的第一个数据不进行任何计算,分区内和分区间计算规则相同

FoldByKey: 每一个key 对应的数据和初始值进行分区内计算,分区内和分区间计算规则相

AggregateByKey:每一个 key 对应的数据和初始值进行分区内计算,分区内和分区间计算规则可以不相同

CombineByKey:当计算时,发现数据结构不满足要求时,可以让第一个数据转换结构。分区

内和分区间计算规则不相同。

相关推荐
程序员龙叔3 小时前
编写高质量 Skill 系列 -- 如何设计需求分析与用例生成的 SKILL
自动化测试·软件测试·python·软件测试工程师·接口测试·性能测试·skill·ai测试
用户8356290780516 小时前
使用 Python 操作 Word 内容控件
后端·python
摇滚侠6 小时前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush46 小时前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5206 小时前
Linux 11 动态监控指令top
linux
qq_369224337 小时前
Windows全系通用!ntdll.dll文件丢失、报错、闪退问题的完整排查与修复教程
windows·dll·dll修复·dll丢失·dll错误
码云骑士7 小时前
32-慢查询排查全流程(下)-索引优化实战与最左前缀原则
python
不会C语言的男孩8 小时前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言
古城小栈8 小时前
Unix 与 Linux 异同小叙
linux·服务器·unix