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算子包含两步,即分组和收集

相关推荐
Elastic 中国社区官方博客4 小时前
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
大数据·开发语言·javascript·elasticsearch·搜索引擎·全文检索·apache
苏格拉没有底_coder5 小时前
引入 Kafka 消息队列解耦热点操作
分布式·kafka
lifallen6 小时前
Flink task、Operator 和 UDF 之间的关系
java·大数据·flink
顧棟7 小时前
Zookeeper 3.8.4 安装部署帮助手册
分布式·zookeeper
源码宝7 小时前
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
java·大数据·源码·智慧工地·智能监测·智能施工
XiaoQiong.Zhang8 小时前
简历模板3——数据挖掘工程师5年经验
大数据·人工智能·机器学习·数据挖掘
Faith_xzc9 小时前
Apache Doris FE 问题排查与故障分析全景指南
大数据·数据仓库·apache·doris
猕员桃10 小时前
《Elasticsearch 分布式搜索在聊天记录检索中的深度优化》
分布式·elasticsearch·wpf
沛沛老爹10 小时前
深入剖析 Celery:分布式异步任务处理的利器
分布式·python·微服务·celery·架构设计·worker节点
潘小磊10 小时前
高频面试之6Hive
大数据·hive·面试·职场和发展