数据开发实习复习笔记
这是一份我在寻找2025年暑期数据开发实习时的复习笔记,主要包括数据开发的基础知识、常用工具和技术栈等内容。希望对你们有所帮助。
SQL
- SQL(Structured Query Language)是一种用于管理关系型数据库的标准语言。
- 常用的SQL语句包括:SELECT、INSERT、UPDATE、DELETE、CREATE、DROP、ALTER等。
- SQL的基本语法结构包括:SELECT FROM WHERE GROUP BY HAVING ORDER BY。
- SQL的连接操作包括:INNER JOIN、LEFT JOIN、RIGHT JOIN、FULL OUTER JOIN等。
- SQL的子查询和嵌套查询。
- SQL的聚合函数包括:COUNT、SUM、AVG、MIN、MAX等。
- SQL的常用函数还有date_sub、datediff、lag、lead、row_number等。
下面是一些常见的sql场景示例
1. 连续问题
给定一张蚂蚁森林中用户每日领取的“减碳排放量”表 test1(id, dt, lowcarbon)(同一天同用户可能多条,需先汇总),请找出那些连续 3 天及以上每天领取量都大于 100 的用户。
先计算每天领取量大于 100 的记录,然后根据 id 和 dt 进行分组,计算每个分组的 diff 值,最后根据 diff 值分组,统计每个分组的记录数,如果记录数大于 1,则说明该用户的连续 3 天及以上每天领取量都大于 100。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
-- 假设原始表名为 test1,字段 (id, dt, lowcarbon)
SELECT
id
FROM (
-- 步骤 2:给每条“符合条件的”日期打一个统一的 diff 分组标识
SELECT
id,
dt,
DATE_SUB(
dt,
INTERVAL ROW_NUMBER() OVER (
PARTITION BY id
ORDER BY dt
) DAY
) AS diff
FROM (
-- 步骤 1:按天汇总并只保留 lowcarbon > 100
SELECT
id,
dt,
SUM(lowcarbon) AS lowcarbon
FROM test1
GROUP BY id, dt
HAVING lowcarbon > 100
) AS t
) AS t2
GROUP BY
id, diff -- 同一 diff 代表连续的一段
HAVING
COUNT(*) >= 3; -- 至少连续 3 天
2. 分组问题
给定一张用户操作时间戳表 test2(id, ts)(ts 为秒级时间戳),要求将同一用户相邻两次操作之间时间差小于 60 秒的归为同一组,大于等于 60 秒的新操作则算作开启一个新组,并给出每条记录对应的组号。
先计算相邻操作时间戳的秒差,然后根据 diff>=60 标记新一组,最后对每个用户分组计算组号。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-- 假设原始表名为 test2(id, ts)
SELECT
id,
ts,
SUM(
IF(diff >= 60, 1, 0)
) OVER (
PARTITION BY id
ORDER BY ts
) AS groupid
FROM (
SELECT
id,
ts,
-- 计算与上一次操作之间的秒差
ts
- LAG(ts, 1, 0) OVER (PARTITION BY id ORDER BY ts) AS diff
FROM test2
) AS t;
3. 间隔连续问题
游戏公司记录了用户每日登录数据表 test3(id, dt),要求计算每个用户在允许“隔一天”不登录的情况下的最长连续登录天数。也就是说,如果用户在连续的日期上登录,中间可以最多跳过 1 天(即日期差 ≤2 的都算作同一个连续段)。
先计算相邻登录日期差,然后根据 diff>2 标记新一段登录,最后对每个用户分组计算最大连续登录天数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
-- 假设表名为 test3,字段 (id, dt)
SELECT
id,
MAX(DATEDIFF(MAX(dt), MIN(dt)) + 1) AS max_allowed_gap_streak
FROM (
SELECT
id,
dt,
-- 根据 diff>2 标记新一段登录
SUM(
CASE WHEN diff > 2 THEN 1 ELSE 0 END
) OVER (
PARTITION BY id
ORDER BY dt
) AS groupid
FROM (
SELECT
id,
dt,
-- 计算与上一次登录日期的差值(天)
DATEDIFF(
dt,
LAG(dt) OVER (PARTITION BY id ORDER BY dt)
) AS diff
FROM test3
) AS t1
) AS t2
GROUP BY
id;
4. 日期交叉问题
这个问题要求找出在某个时间段内,两个日期范围交叉的记录。
按品牌分组,按结束日期排序,用max()方法找到当前行之前所有行的最大结束日期,然后用if()方法判断当前行的开始日期是否大于最大结束日期,如果是,则说明当前行和之前的日期范围没有交叉,否则说明当前行和之前的日期范围交叉。调整后的开始日期为当前行的开始日期和最大结束日期的较大值。对每个调整后的日期范围计算天数差,然后求和即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
-- 假设原始表名为 test4
SELECT
brand,
SUM(IF(days >= 0, days + 1, 0)) AS total_days
FROM (
-- 计算每个调整后区间的天数差
SELECT
brand,
DATEDIFF(edt, stt_adj) AS days
FROM (
-- 调整当前行的开始日期 stt_adj
SELECT
brand,
IF(
max_prev_edt IS NULL,
stt,
IF(stt > max_prev_edt, stt, DATE_ADD(max_prev_edt, INTERVAL 1 DAY))
) AS stt_adj,
edt
FROM (
-- 利用窗口函数计算当前行之前的最大结束日期
SELECT
brand,
stt,
edt,
MAX(edt) OVER(
PARTITION BY brand
ORDER BY edt
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
) AS max_prev_edt
FROM test4
) AS t1
) AS t2
) AS t3
GROUP BY brand;
5. 同时在线问题
给定一张直播平台的主播开播及关播时间表(包含主播 id、stt 开播时间、edt 关播时间),要求根据这些时间点计算出平台上同时在线的主播的最大数量。
将每个主播的记录拆成两个数据,一个是开播事件,一个是关播事件。然后用前缀和的方式计算每个时间点的同时在线主播数量,最后取最大值即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- 假设原始表名为 test5
SELECT
MAX(cnt) AS max_concurrent_hosts
FROM (
SELECT
dt,
SUM(flag) OVER (ORDER BY dt) AS cnt
FROM (
-- 开播事件:+1
SELECT
id,
stt AS dt,
1 AS flag
FROM test5
UNION ALL
-- 关播事件:-1
SELECT
id,
edt AS dt,
-1 AS flag
FROM test5
) AS t
) AS t2;
6.最大连续登录的最大天数问题
有一张用户登录表 user_login(uid, dt),记录了每个用户的登录日期。要求计算每个用户的最长连续登录天数。
先对用户按日期升序,然后用date_sub将连续日期映射到同一个“组”上,再分组计算每个用户的最大连续登录天数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
SELECT
B.uid AS uid,
MAX(B.num) AS cnt_days
FROM (
SELECT
A.uid,
A.dt1,
COUNT(*) AS num
FROM (
-- 将每条登录记录映射到同一个“组”上
SELECT
uid,
DATE_SUB(
dt,
INTERVAL ROW_NUMBER() OVER (
PARTITION BY uid
ORDER BY dt
) DAY
) AS dt1
FROM user_login
) AS A
GROUP BY
A.uid,
A.dt1
) AS B
GROUP BY
B.uid;
7.留存问题
计算用户留存率。给定用户打开 App 的日志表 ods_app_open(uid, dt),需要统计某个基准日期(如 2021-11-18)的当日活跃用户总数,以及这些用户在次日(+1天)和第七天(+6天)的留存人数。 先筛选出基准日期下的所有去重用户,再从日志中用leftjoin找出基准用户7天内的数据,再按照条件进行聚合。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-- 假设日志表为 ods_app_open(uid, dt)
SELECT
t1.dt,
COUNT(t1.uid) AS active_users, -- 基准日活跃用户数
COUNT(CASE WHEN DATEDIFF(t2.dt, t1.dt) = 1 THEN t2.uid END) AS day2_active_users, -- 次日留存
COUNT(CASE WHEN DATEDIFF(t2.dt, t1.dt) = 6 THEN t2.uid END) AS day7_active_users -- 第七天留存
FROM
(
-- 基准日用户
SELECT uid, dt
FROM ods_app_open
WHERE dt = '20211118'
GROUP BY uid, dt
) AS t1
LEFT JOIN
(
-- 基准日后 1~6 天的用户记录
SELECT uid, dt
FROM ods_app_open
WHERE dt > '20211118'
AND dt <= '20211124'
GROUP BY uid, dt
) AS t2
ON t1.uid = t2.uid
GROUP BY
t1.dt;
数据库
数据库的基本概念
索引
- 索引是数据库中用于加速数据检索的一种数据结构。
- 常见的索引类型有:普通索引、唯一索引、主键索引、全文索引等。 使用索引有如下几个好处
- 提高查询速度:索引通过直接定位数据的存储位置,避免全表扫描,从而提高查询速度。
- 索引可以加速排序:在查询中使用ORDER BY时,索引可以避免使用临时表进行排序,从而提高性能。
- 减少随机IO:索引可以将随机IO变为顺序IO,从而提高查询性能。
使用索引有如下几个缺点
- 占用存储空间:索引需要额外的存储空间来存储索引数据。
- 更新性能下降:在插入、更新和删除数据时,索引需要进行维护,从而导致性能下降。
B+树和B树
他们都是一种自平衡的树数据结构,主要用于数据库和文件系统中。B+树是B树的一种变体,具有以下特点:
- B+树的所有数据都存储在叶子节点中,非叶子节点只存储索引信息。但B树的非叶子节点也存储数据。
- B+树的叶子节点通过指针相连,形成一个链表,方便范围查询。而B树的叶子节点没有这种结构,在范围查询时需要遍历整个树。
mysql的索引结构
- B+树索引:B+树索引是MySQL中最常用的索引类型,适用于范围查询和排序操作。
- 不用二叉树的原因是二叉树的高度是log2(n),而B+树的高度是logb(n),b一般为3-4,所以B+树的高度更低,查询效率更高。
- 不用红黑树的原因是红黑树的出度是2,而B+树的出度是b,b一般为3-4,所以B+树的出度更高,查询效率更高。
- 不用哈希表的原因是索引的值在哈希表中是无序的,而B+树的值是有序的,所以B+树更适合范围查询。此外,哈希表需要将索引全部加载到内存中,而B+树可以将索引分成多个块,按需加载,从而节省内存空间。
- 不用B树的原因是B树的非叶子节点也存储数据,而B+树的非叶子节点只存储索引信息,所以B+树的存储效率更高。
聚集索引和非聚集索引
他们都是B+树索引的变种,主要区别在于数据存储的方式。
- 聚集索引(Clustered Index):聚集索引是将数据存储在叶子节点中的索引,数据的物理顺序与索引的顺序相同。每个表只能有一个聚集索引。
- 非聚集索引(Non-Clustered Index):非聚集索引是将索引存储在叶子节点中的索引,数据的物理顺序与索引的顺序不同。每个表可以有多个非聚集索引。 INnodb和MyISAM的区别
- InnoDB使用聚集索引,默认是主键,如果没有主键,则使用第一个唯一非空索引。如果没有唯一非空索引,则隐式定义一个主键。主键索引下叶子节点存储的是数据行的完整信息,辅助索引下叶子节点存储的是主键值和行号。
- MyISAM使用非聚集索引,主键索引和辅助索引的叶子节点都保存一个指向数据行的地址,表数据和索引分开存储。
最左前缀原则
- 最左前缀原则是指在使用复合索引时,查询条件必须从最左边的列开始匹配,才能使用索引。
事务
- 事务是指一组操作,要么全部成功,要么全部失败。
- 事务的ACID特性:
- 原子性(Atomicity):事务是一个不可分割的操作单元,要么全部成功,要么全部失败。
- 一致性(Consistency):事务执行前后,数据库的状态是一致的。
- 隔离性(Isolation):多个事务并发执行时,互不干扰。
- 持久性(Durability):一旦事务提交,对数据库的修改是永久性的,即使系统崩溃也不会丢失。
事务并发的主要问题
事务并发会主要有四个问题 1. 脏读:一个事务读取了另一个事务未提交的数据。 2. 不可重复读:一个事务读取了另一个事务已提交的数据,但在同一事务中再次读取时,数据发生了变化。 3. 幻读:一个事务读取了另一个事务已提交的数据,但在同一事务中再次读取时,数据发生了变化,导致查询结果不一致。 4. 丢失更新:两个事务同时更新同一条记录,导致一个事务的更新被另一个事务覆盖。
事务隔离级别
- 读未提交(Read Uncommitted):允许脏读、不可重复读和幻读。
- 读已提交(Read Committed):允许不可重复读和幻读,但不允许脏读。
- 可重复读(Repeatable Read):允许幻读,但不允许脏读和不可重复读。
- 序列化(Serializable):不允许脏读、不可重复读和幻读,性能最低。
HDFS
HDFS的架构
HDFS主要包括三个部分,namenode、datanode和secondary namenode。
- namenode:负责管理文件系统的元数据,包括文件名、文件大小、文件块位置等信息。namenode是HDFS的主节点,负责协调数据的读写操作。
- datanode:负责存储实际的数据块,并向namenode报告其状态。datanode是HDFS的工作节点,负责数据的读写操作。
- secondary namenode:负责备份namenode的元数据,并在namenode发生故障时进行恢复。secondary namenode是HDFS的辅助节点,负责元数据的备份和恢复,定期进行合并Fsimage和editlog。
HDFS的读写流程
- HDFS的写流程:
- 客户端向namenode请求文件的元数据,包括文件名、文件大小、文件块位置等信息。namenode会检查文件是否存在,如果不存在,就会允许客户端创建文件。
- 客户端再次向namenode请求第一个block上传到哪几个datanode上,namenode会返回一个datanode列表。假设返回的datanode列表为datanode1、datanode2、datanode3。
- 客户端向datanode1发送请求,要求上传数据块。datanode1会调用datanode2,datanode2会调用datanode3,形成一个链式调用。在通信管道建立起来后,datanode3,datanode2和datanode1逐级应答客户端。
- 客户端向datanode1发送第一个block,以packet为单位进行传输。datanode1收到后会传给datanode2,datanode2收到后会传给datanode3。
- 完成第一个block的传输后,客户端会再次请求namenode,要求上传第二个block。
- HDFS的读流程:
- 客户端向namenode请求文件的元数据,包括文件名、文件大小、文件块位置等信息。namenode会返回文件的datanode地址。
- 这些返回的datanode地址会按照集群拓扑结构得出datanode与客户端的距离,然后进行排序
- 客户端向第一个datanode发送请求,要求读取数据块。客户端会以packet为单位进行传输。先在本地缓存缓存,然后写入目标文件中。
读的时候是并行的,写的时候是串行的。
小文件的危害
- 小文件会导致namenode的内存占用过高,影响namenode的性能。
- 在计算时,map任务的数量会增加,导致任务调度和资源分配的开销增加。
- 读取小文件时,会导致大量的seek操作,影响读取性能。
Secondary Namenode的工作机制
- Secondary Namenode的主要工作是定期备份namenode的元数据,并在namenode发生故障时进行恢复。 edit log是一个日志文件,记录了namenode的所有操作,包括文件的创建、删除、修改等操作。FsImage记录了最新的元数据快照,包括文件名、文件大小、文件块位置等信息。Secondary Namenode会定期将edit log和FsImage进行合并,生成一个新的FsImage,并将其保存到namenode的本地磁盘中。
- Secondary Namenode的工作流程:
- Secondary Namenode询问NameNode是否需要checkpoint。直接带回NameNode是否检查结果
- Secondary Namenode请求执行checkpoint操作。
- NameNode 滚动正在写的edit log,将滚动前的编辑日志和镜像文件拷贝到Secondary Namenode。
- Secondary Namenode将编辑日志和镜像文件加载到内存中,合并成一个新的FsImage。
- 生成新的镜像文件fsimage.chkpoint
- 拷贝fsimage.chkpoint到NameNode
- Namenode将fsimage.chkpoint重命名为fsimage
所以如果NameNode中的元数据丢失了,Secondary Namenode中的fsimage.chkpoint就可以用来恢复数据。但近期没有写入的edit log会丢失,所以数据会部分丢失。
在上传文件的时候,有一个Datanode挂掉了,怎么办?
当DataNode突然挂掉了,客户端不能接收到ack,客户端会重新请求namenode,namenode会将这个DataNode从集群中剔除,并将数据块复制到其他DataNode上。客户端会重新请求namenode,获取新的DataNode列表,然后继续上传数据块。
在读取文件的时候,有一个block突然损坏了怎么办?
客户端读取完DataNode上的块之后会进行checksum验证,也就是把客户端读取到本地的块和DataNode上的块进行对比,如果不一致,客户端会重新请求namenode,然后从下一个拥有该block副本的DataNode上读取数据块。
MapReduce
简述MapReduce的工作流程
- map阶段: 首先通过InputFormat将输入数据分成多个split,默认大小等于block大小。并且每个split会被分配给一个map任务。同时将切片中的数据解析成key-value对。key表示偏移量,value表示数据内容。紧接着调用Mapper类中的map方法进行处理,解析为key-value对。
- shuffle阶段: map端shuffle:将map后的<key,value>写入到环形缓冲区,一半写元数据信息(key的起始位置,value的起始位置,value的长度,partition号), 一般写<key,value>数据,等达到80%的时候,就要进行spill操作了。spill操作之前需要对key进行排序,排序的方式是将key进行hash分区,然后对每个分区进行排序。然后spill到文件中,并且进行归并排序。最后将文件写入到磁盘中。 reduce端shuffle:reduce会拉取copy同一分区的各个maptask的结果到内存中,如果放不下,就会spill到磁盘上。然后对内存和磁盘上的数据进行归并排序。
- reduce阶段: reduce会对map的输出进行处理,调用Reducer类中的reduce方法进行处理。相同key的数据会调用一次reduce方法,每次调用会产生一个<key,value>对。最后将结果输出到HDFS中。
Spark
Hadoop和Spark的区别
- MapReduce需要将计算的中间结果写入磁盘,然后还要读取磁盘上的数据,而Spark会将中间结果保存在内存中,避免了频繁的磁盘IO操作,这得益于Spark的RDD(弹性分布式数据集)数据结构和DAG(有向无环图)计算模型。
- MapReduce在shuffle阶段需要将数据进行排序和分区,而Spark在shuffle阶段时如果选择基于hash的计算引擎,是不需要排序的。
- MapReduce是多进程模型,每个task会运行在一个JVM中,而Spark是多线程模型,每个executor会运行在一个JVM中,每个task则是运行在executor中的一个线程中。
RDD是什么
RDD(Resilient Distributed Dataset)是弹性分布式数据集,是Spark的核心数据结构。RDD是一个不可变的分布式对象集合,它是一个抽象类。RDD是不保存数据的,仅仅封装了计算逻辑。
Spark的shuffle过程
1. HashShuffle
HashShuffle分为普通机制和合并机制,有write和read两个阶段。
- write阶段是根据key进行分区,开始先将数据写入对应的buffer中,当buffer满了之后就会spill到磁盘上,这个时候会产生mapper*reducer个文件,产生了大量磁盘IO。read阶段就是reducer去拉取各个maptask产生的同一个分区的数据。
- 合并机制是让多个mapper共享buffer,这时候落盘的数量为reducer*core数,减少了磁盘IO。合并机制的缺点是会增加内存的使用量,可能会导致OOM。
2. SortShuffle
- 普通机制:maptask计算的结果会写入到一个内存数据结构中,每写一条数据之后,就会判断一下,是否达到了阈值,如果达到了,会先尝试增加内存到当前内存的2倍,如果申请不到才会spill。spill的时候先按照key进行分区和排序,然后将数据spill到磁盘,最后将所有临时的磁盘文件合并为一个大的磁盘文件并生成一个索引文件,然后reducer去拉取数据时,先解析索引文件,然后再根据索引去拉取。
- bypass机制:将普通机制的排序过程去掉了,它的触发条件是当shuffle maptask小于配置参数并且算子不是聚合类的shuffle算子的时候,该机制不会进行排序,从而提高性能。
Spark的作业运行流程是怎样的
首先,客户端会提交spark作业给资源管理器(如yarn),然后RM会分配资源container,并且选择合适的NM启动ApplicationMaster,然后AM启动Driver,紧接着向RM申请资源启动executor。Executor进程启动后会向Driver注册,全部注册完成后Driver开始执行函数,当执行到行动算子,触发一个job,并根据宽依赖开始划分stage。每个stage生成对应的TaskSet,之后将task分发到各个Executor上执行。
Application、Job、Stage、Task的关系
- Application:Spark应用程序,是一个完整的Spark作业,包含多个Job。
- Job:Spark作业,是一个由多个Stage组成的任务,通常对应一个行动算子(如count、collect等)。
- Stage:阶段,是Job的一个子任务,通常对应一个窄依赖或宽依赖的转换操作。每个Stage由多个Task组成。Stage等于宽依赖的个数+1。
- 窄依赖:一个父RDD的分区只对应一个子RDD的分区,如map、filter等。
- 宽依赖:一个父RDD的分区对应多个子RDD的分区,如groupByKey、reduceByKey等。
- Task:任务,是Stage的一个子任务,通常对应一个分区的数据处理。每个Task在Executor上运行。在一个阶段中,最后一个RDD的分区数等于该阶段的Task数。
Spark常见的算子
算子分为转换算子和行动算子,转换算子主要是将旧的 RDD 包装成新的 RDD,行动算子就是触发任务的调度和作业的执行。
转换算子:
map:将数据逐条进行转换,可以是数据类型的转换,也可以是值的转换 flatMap:先进行 map 操作,再进行扁平化操作 filter:根据指定的规则进行筛选 coalesce:减少分区的个数,默认不进行 shuffle repartition:可以增加或者减少分区的个数,一定发生 shuffle union:两个 RDD 求并集 zip:将两个 RDD 中的元素,以键值对的形式进行合并 reduceByKey:按照 key 对 value 进行聚合 groupByKey:按照 key 对 value 进行分组 cogroup:按照 key 对 value 进行合并
行动算子用的比较多的有:
collect:将数据采集到 Driver 端,形成数组 take:返回 RDD 的前 n 个元素组成的数组 foreach:遍历 RDD 中的每一个元素【executor 端】
Spark sql
RDD,DataFrame,DataSet的区别
- RDD(Resilient Distributed Dataset):弹性分布式数据集,是Spark的核心数据结构,提供了低级别的API,支持函数式编程。RDD是不可变的,支持分布式计算,但不支持SQL查询。
- DataFrame:分布式数据集,是Spark SQL的核心数据结构,类似于关系型数据库中的表,提供了更高级别的API,支持SQL查询。DataFrame是不可变的,支持分布式计算,但不支持函数式编程。
- DataSet:分布式数据集,是Spark 1.6版本引入的,结合了RDD和DataFrame的优点,提供了类型安全的API,支持函数式编程和SQL查询。DataSet是不可变的,支持分布式计算。
四大区别
- spark1.0产生了RDD,spark1.3产生了DataFrame,spark1.6产生了DataSet。
- RDD不支持SQL查询,DataFrame和DataSet支持SQL查询。
- RDD一般会和 spark mllib结合使用,DataFrame和DataSet一般不会。
- DataFrame是DataSet的特例,DataFrame的每一行都是Row类型,而DataSet可以是任意类型。
spark sql的三种join实现
Spark SQL 包含三种 Join 实现方式:broadcast hash join、shuffle hash join、sort merge join ,其中前两种基于 hash join ,适用场景不同:
broadcast hash join:适合小表与大表 Join ,小表会广播到所有 Executor 。 shuffle hash join:适合 “较大小表” 与大表 Join ,需先对表按 Join 字段重分区 。 sort merge join:适合两张较大表 Join ,涉及重分区、排序、合并流程 。
Hash Join的基础流程
Hash Join 核心分三步, 确定表类型:由 Spark 确定 build table(通常是小表 )和 probe table(通常是大表 ) 构建哈希表:遍历 build table 数据,按 Join 字段哈希,存入哈希表 。 匹配关联数据:遍历 probe table 数据,用相同哈希函数找哈希表中匹配数据,匹配成功则关联 。
Broadcast Hash Join
分两个阶段:
Broadcast 阶段:把小表广播到所有 Executor ,让每个 Executor 都能获取小表完整数据 。 Hash Join 阶段:在各 Executor 上,小表构建为哈希表,大表作为 probe table ,执行 Hash Join 逻辑完成关联 。
Shuffle Hash Join
包含两个阶段:
Shuffle 阶段:对两张表,依据 Join 字段做重分区,让相同 Key 的数据进入同一分区 。 Hash Join 阶段:在每个分区内,执行 Hash Join ,利用分区内数据完成关联 。
Sort Merge Join
包含三个阶段: Shuffle 阶段:按 Join 字段重分区两张表,保证相同 Key 数据在同一分区 。 Sort 阶段:对每个分区内的数据,按 Join 字段排序 。 Merge 阶段:遍历两个分区表,Key 相同则输出关联结果;Key 不同时,继续遍历 Key 较小表的数据,直至完成全部分区遍历 。
Spark streaming
spark streaming是一种准实时,微批次的数据处理框架 和Spark 基于 RDD 的概念很相似,Spark Streaming 使用离散化流(discretized stream)作为抽象表示,叫做DStream,代表一个持续不断的数据流。在内部实现上,DStream 是一系列连续的 RDD 来表示。每个 RDD 含有一段时间间隔内的数据 然后我再说一下sparkstreaming的基本工作原理:首先接受实时输入数据流,然后将数据封装成 batch,比如设置一秒的延迟,那么就会每到一秒就会将这一秒内的数据封装成一个batch最后将每个 batch 交给 spark的计算引擎进行处理,输出一个结果数据流