1,列出至少5个会发生shuffle的算子
去重
def distinct()
def distinct(numPartitions:Int)
聚合
def reduceByKey(func: (V, V) => V, numPartitions: Int): RDD[(K, V)]
def reduceByKey(partitioner: Partitioner, func: (V, V) => V): RDD[(K, V)]
def groupBy[K](f: T => K, p: Partitioner):RDD[(K, Iterable[V])]
def groupByKey(partitioner: Partitioner):RDD[(K, Iterable[V])]
def aggregateByKey[U: ClassTag](zeroValue: U, partitioner: Partitioner): RDD[(K, U)]
def aggregateByKey[U: ClassTag](zeroValue: U, numPartitions: Int): RDD[(K, U)]
def combineByKey[C](createCombiner: V => C, mergeValue: (C, V) => C, mergeCombiners: (C, C) => C): RDD[(K, C)]
def combineByKey[C](createCombiner: V => C, mergeValue: (C, V) => C, mergeCombiners: (C, C) => C, numPartitions: Int): RDD[(K, C)]
def combineByKey[C](createCombiner: V => C, mergeValue: (C, V) => C, mergeCombiners: (C, C) => C, partitioner: Partitioner, mapSideCombine: Boolean = true, serializer: Serializer = null): RDD[(K, C)]
排序
def sortByKey(ascending: Boolean = true, numPartitions: Int = self.partitions.length): RDD[(K, V)]
def sortBy[K](f: (T) => K, ascending: Boolean = true, numPartitions: Int = this.partitions.length)(implicit ord: Ordering[K], ctag: ClassTag[K]): RDD[T]
重分区
def coalesce(numPartitions: Int, shuffle: Boolean = false, partitionCoalescer: Option[PartitionCoalescer] = Option.empty)
def repartition(numPartitions: Int)(implicit ord: Ordering[T] = null)
集合或者表操作
def intersection(other: RDD[T]): RDD[T]
def intersection(other: RDD[T], partitioner: Partitioner)(implicit ord: Ordering[T] = null): RDD[T]
def intersection(other: RDD[T], numPartitions: Int): RDD[T]
def subtract(other: RDD[T], numPartitions: Int): RDD[T]
def subtract(other: RDD[T], p: Partitioner)(implicit ord: Ordering[T] = null): RDD[T]
def subtractByKey[W: ClassTag](other: RDD[(K, W)]): RDD[(K, V)]
def subtractByKey[W: ClassTag](other: RDD[(K, W)], numPartitions: Int): RDD[(K, V)]
def subtractByKey[W: ClassTag](other: RDD[(K, W)], p: Partitioner): RDD[(K, V)]
def join[W](other: RDD[(K, W)], partitioner: Partitioner): RDD[(K, (V, W))]
def join[W](other: RDD[(K, W)]): RDD[(K, (V, W))]
def join[W](other: RDD[(K, W)], numPartitions: Int): RDD[(K, (V, W))]
def leftOuterJoin[W](other: RDD[(K, W)]): RDD[(K, (V, Option[W]))]
2.spark中map和foreach的区别
1.map是有返回值的,foreach没有返回值
2.map常用于将某个RDD作为元素的处理,而foreach常用作为结果的输出到其他的存储系统。
3.map是属于tranformation,foreach属于action
3.checkpoint的应用场景和使用步骤
在应用执行中,有时候有些RDD的数据需要在其他地方多次用到(包括其他job中用到),为了使整个依赖链条不至于很长导致运行缓慢,可以用checkpoint来缩短依赖链条。
最好是把数据checkpoint到hdfs上,保证数据的安全性,并在用数据的时候进行拉取。
在代码层面是这样执行的,如果再用到某个RDD的数据的时候,首先会检查是否做了缓存,如果做了缓存,会直接从缓存里面拿出数据,如果没有缓存,则判断是否做了checkpoint,如果做了checkpoint,则从checkpoint的指定的路径下获取数据,如果没有checkpoint,只能重新开始计算得到数据。

4.简述RDD的概念
这位老哥总结的挺全–By燃烧的岁月_点我
我这里写我的拙见:
Spark中的RDD(Resilient Distributed Dataset)就是弹性分布式数据集,是Spark中基本的数据抽象。每个RDD都被分为多个分区,这些分区运行在集群中的不同节点。创建RDD的两种方式:读取一个外部数据集,或者在驱动器里面分发驱动器程序中的对象集合。(在任何时候都能够进行重算是我们为什么把RDD描述为"弹性"的原因--来自Spark快速大数据分析 p22)
RDD支持两种类型的操作:转化操作(transformation)和行动操作(action),转化操作会返回一个新的RDD(惰性计算的,只有第一次在行动操作中用到时才会真正计算)
步入正题:RDD的五大特性(来自spark-core_2.11-2.20-sources.jar RDD.scala)
/**
- A list of partitions
- A function for computing each split
- A list of dependencies on other RDDs
- Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned)
- Optionally, a list of preferred locations to compute each split on (e.g. block locations for an HDFS file)
*/
翻译过来就是
1.一组分片(Partition),即数据集的基本组成单位。对于RDD来说,每个分片都会被一个计算任务处理,并决定并行计算的粒度。用户在创建RDD时指定RDD时指定RDD的分片个数,如果没有指定,那么就会采用默认制。默认值就是所分配的 CPU core的数目(也有讲到,分片数不能少于blocks数量)
2.一个计算每个分区的函数。Spark中的RDD的计算是以分片为单位的,每个RDD都会实现compute函数以达到这个目的。compute函数会对迭代器进行复合,不需要保存每次计算的结果。(RDD抽象类要求其所有子类都必须实现compute方法,该方法介绍的参数之一是一个Partition对象,目的是计算该分区中的数据)
3.RDD之间的依赖关系。RDD的每次转换都会生成一个新的RDD,所以RDD之间就会形成类似于流水线一样的前后依赖关系。在部分数据丢失时,Spark可以通过这个依赖关系重新计算丢失的分区数据,而不是对RDD的所有分区进行重新计算。(参照下面说的宽窄依赖)
4.一个Partitioner,即RDD的分片函数。当前Spark中实现类两种类型的分片函数,一个是基于哈希的HashPartitioner,另外一个是基于范围的RangePartitioner。(只有对于k-v类型的RDD才会有Partitioner,非k-v得RDD的Partitioner的值是None)。Partitioner函数不但决定了本身的分片数量,也决定了parent RDD Shuffle 输出时的分片数量。
5.一个列表,存储存取每个Partition的优先位置(preferred location)。对于一个HDFS文件来说,这个列表保存的就是每个Partition所在的块的位置。按照“移动数据不如移动计算”的理念,Spark在进行任务调度的时候,会尽可能地将计算任务分配到其所要处理数据块的存储位置。
5.Spark任务的提交流程
简单说就是:
1.Driver向Master进行注册 (发送任务描述消息)
2.Master收到任务描述,开始生成任务信息,并放到队列中
3.Master开始通知Worker启动Executor并发送任务消息
4.Worker开始启动Executor
5.Eexecutor向Driver注册
6.Driver把生成的task发送给相应的Executor
复杂点就是

6.数据仓库分几层,及其意义

ODS层(临时存储层)、PDW(数据仓库层)、DM(数据集市层)、APP(应用层)
ODS层:
为临时存储层,是接口数据的临时存储区域,为后一步的数据处理做准备。
一般来说ODS层的数据和源系统的数据是同构的,主要目的是简化后续数据加工处理的工作。
从数据粒度上来说ODS层的数据粒度是最细的.ODS层的表通常包括两类,一个用于存储当前需要加载的数据,一个用于存储处理完后的历史数据。
历史数据一般保存3-6个月后要清楚,以节省空间。但不同的项目要区别对待,如果源系统的数据量不大,可以保留更长的时间,甚至全量保存。
PDW层:
为数据仓库层,PDW层的数据应该是一致的、精确的、干净的数据,即对源系统数据进行了清洗(去除了杂质)后的数据。
这一层的数据是遵循数据库第三范式的,其数据粒度通常和ODS的粒度相同。在PDW层会保存BI系统中所有的历史数据,例如保存10年的数据。
DM层:
作为数据集市层,这层数据是面向主题来进行组织数据的,通常是星形或雪花模型的数据。从数据粒度来说,这层的数据是轻量级汇总的数据,已经不存在明细数据了,
从数据的时间跨度来说,通常是PDW层的一部分,主要目的是为了满足用户分析的需求,从而分析的角度来说,用户只需要分析近几年的即可。
从数据的广度来说,仍然覆盖了所有业务数据。
APP层:
为应用层,这层数据是完全为了满足具体的分析需求而构建的,也是星形或雪花结构的数据。从数据粒度俩说就是高度汇总的数据。
从数据的广度来说,则并不一定会覆盖所有的业务数据,而是DM层数据的一个真子集,从某种意义上来说是DW层数据的一个重复。
从极端情况来说,可以为每一张报表在APP层构建一个模型来支持,达到以空间换取时间的目的,
数据仓库的标准分层只是一个建议性质的标准,实际实施时根据实际情况来决定数据仓库的分层,不同类型的数据也可能采用不同的分层方法。
本文深入探讨Spark中的关键概念,如shuffle算子、RDD特性、任务提交流程及数据仓库分层等,助您掌握Spark核心机制。
315

被折叠的 条评论
为什么被折叠?



