Spark RDD

概念

RDD是一种抽象,是Spark对于分布式数据集的抽象,它用于囊括所有内存中和磁盘中的分布式数据实体

RDD 与 数组对比

对比项 数组 RDD
概念类型 数据结构实体 数据模型抽象
数据跨度 单机进程内 跨进程、跨计算节点
数据构成 数组元素 数据分片(Partitions)
数据定位 数组下标、索引 数据分片索引

RDD 4大属性

partitions 数据分片: 数据属性

partitioner 分片切割规则: 定义了把原始数据集切割成数据分片的切割规则

dependencies RDD依赖: 每个RDD都会通过dependencies属性来记录它所依赖的前一个、或是多个RDD,简称"父RDD"

compute 转换函数: 与此同时,RDD使用compute属性,来记录从父RDD到当前RDD的转换操作

例子

不同的食材形态,如带泥土豆、土豆片、即食薯片等等,对应的就是RDD概念

同一种食材形态在不同流水线上的具体实物,就是 RDD 的 partitions 属性

食材按照什么规则被分配到哪条流水线,对应的就是 RDD 的 partitioner 属性

每一种食材形态都会依赖上一种形态,这种依赖关系对应的是 RDD 中的 dependencies 属性

不同环节的加工方法对应 RDD的 compute 属性

RDD 编程模型

在RDD的编程模型中,一共有两种算子,Transformations 类算子和Actions类算子

开发者需要使用Transformations 类算子,定义并描述数据形态的转换过程,然后调用Actions类算子,将计算结果收集起来、或是物化到磁盘

延迟计算

RDD编程模型下,Spark在运行时的计算被划分为两个环节

  • 基于不同数据形态之间的转换,构建计算流图(DAG,Directed Acyclic Graph)
  • 通过Actions类算子,以回溯的方式去触发执行这个计算流图

换句话说,开发者调用的各类Transformations算子,并不立即执行计算

当且仅当开发者调用Actions算子时,之前调用的转换算子才会付诸执行

常用算子

算子类型 适用范围 算子用途 算子集合
Transformations 任意RDD RDD内数据转换 map、mapPartitons、mapPartitonsWithIndex、flatMap、 filter
Paired RDD RDD内数据耦合 groupByKey、sortByKey、reduceByKey、aggregateByKey
任意RDD RDD间数据整合 union、intersection、join、cogroup、cartesian
任意RDD 数据整理 sample、distinct
Actions 任意RDD 数据收集 collect、first、take、takeSample、takeOrdered、count
任意RDD 数据持久化 saveAsTextFile、saveAsSequenceFile、saveAsObjectFile
任意RDD 数据遍历 foreach

map: 元素为粒度对RDD做数据转换

val rdd: RDD[Int] = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result: RDD[Int] = rdd.map(x => x + 1)
result.collect() // 返回 Array(2, 3, 4, 5, 6)

在这个例子中,我们使用 parallelize 方法创建一个包含整数的 RDD
接着,我们使用 map 算子将 RDD 中的每个整数都加上 1,生成一个新的 RDD
最后,我们使用 collect 方法将新的 RDD 中的元素取回到驱动程序中

mapPartitons: 以数据分区为粒度,使用映射函数f对RDD进行数据转换

val rdd = sc.parallelize(List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 3)
val result = rdd.mapPartitions(partition => {
  val sum = partition.sum
  Iterator(sum)
}).collect()

这个例子中,我们首先创建了一个包含10个元素的RDD,并将其分成3个分区
然后,我们使用mapPartitions算子,以数据分区为粒度进行转换
在这个例子中,我们使用partition.sum计算每个数据分区的和,并将其放入一个新的迭代器中
最后,我们使用collect算子将结果收集到本地
这个例子展示了如何使用mapPartitions算子以数据分区为单位进行操作,从而提高执行效率

flatMap:从元素到集合、再从集合到元素

val sentences: RDD[String] = sc.parallelize(List("Hello world", "How are you", "I am fine"))
val words: RDD[String] = sentences.flatMap(sentence => sentence.split(" "))

在上面的代码中,我们首先创建了一个包含多个句子的 RDD,然后使用 flatMap 方法,对每个句子进行拆分操作
具体地,对于 RDD 中的每个元素(即句子),我们都将其分割成单词,然后使用 yield 关键字将每个单词作为一个新的元素返回
最终,我们得到了一个包含所有单词的 RDD

filter:过滤RDD

val numbersRDD = sc.parallelize(Seq(-2, 0, 5, -10, 7, -3, 9))
val positiveNumbersRDD = numbersRDD.filter(x => x >= 0)
positiveNumbersRDD.foreach(println) // RDD[0, 5, 7, 9]

我们创建了一个包含数字的RDD,然后使用filter算子过滤掉其中的负数,最终返回一个新的RDD,只包含正数

mapPartitionsWithIndex: 每个元素映射为一个包含索引和单词的元组

val data = List("apple", "banana", "orange", "grape", "pear")
val rdd = sc.parallelize(data, 2)

val result = rdd.mapPartitionsWithIndex { (index, partition) =>
  partition.map(word => (index, word))
}

result.foreach(println)

这段代码创建了一个包含 5 个元素的列表,并将其转换为一个包含 2 个分区的 RDD
接着,使用 mapPartitionsWithIndex 函数将每个元素映射为一个包含索引和单词的元组,最后打印出结果

在这个例子中,mapPartitionsWithIndex 函数的输入函数接受两个参数:分区索引和分区中的元素迭代器
元素迭代器包含了分区中的所有元素,因此我们可以在其中使用 map 函数对所有元素进行操作
最终的输出结果是一个包含索引和单词的元组的 RDD

groupByKey:分组收集

groupByKey的字面意思是"按照Key做分组",但实际上,groupByKey算子包含两步,即分组和收集

相关推荐
zhixingheyi_tian2 小时前
Spark 之 Aggregate
大数据·分布式·spark
PersistJiao2 小时前
Spark 分布式计算中网络传输和序列化的关系(一)
大数据·网络·spark
求积分不加C3 小时前
-bash: ./kafka-topics.sh: No such file or directory--解决方案
分布式·kafka
nathan05293 小时前
javaer快速上手kafka
分布式·kafka
宅小海5 小时前
scala String
大数据·开发语言·scala
小白的白是白痴的白5 小时前
11.17 Scala练习:梦想清单管理
大数据
java1234_小锋5 小时前
Elasticsearch是如何实现Master选举的?
大数据·elasticsearch·搜索引擎
谭震鸿7 小时前
Zookeeper集群搭建Centos环境下
分布式·zookeeper·centos
Java 第一深情9 小时前
零基础入门Flink,掌握基本使用方法
大数据·flink·实时计算
MXsoft6189 小时前
华为服务器(iBMC)硬件监控指标解读
大数据·运维·数据库