SparkCore

RDD详解

为什么需要RDD

分布式计算需要:

  • 分区控制
  • shuffle控制(不同分区进行数据传输)
  • 数据存储、序列化、发送
  • 数据计算API
  • 其他一系列功能

这些功能不能简单地通过python内置的本地集合对象(list、dict等)来实现,在分布式框架中,需要有一个统一的数据抽象对象,来实现上述分布式计算所需功能。
上述抽象对象:RDD

什么是RDD

Resilient Distributed Dataset,弹性分布式数据集,spark中最基本的数据抽象,代表一个不可变、可分区、里面元素可并行计算的集合
Resilient:数据可存放在内存或磁盘中
Distributed:数据是分布式存储的,可用于分布式计算(数据跨机器存储、跨进程存储;本地集合:数据全部在一个进程内部)
Dataset:数据集合,用来存放数据
image.png

RDD 5大特性

RDD数据结构内部有5大特性,前3个特性每个RDD都具备,后2个特性可选
image.png

  1. RDD有分区
  2. 计算方法作用到每一个分区(分片)之上
  3. RDD之间相互依赖
  4. KV型RDD可以有分区器
  5. RDD分区数据的读取尽量靠近数据所在地(数据不动,数据在哪,就在哪个机器上计算)

RDD有分区

分区是RDD数据存储的最小单位
一份RDD数据,本质上是分隔成了多个分区
image.png
image.png

RDD方法会作用在所有分区上

image.png
map方法体现在了每一个分区上
glom方法,将一个分区的数据转换为相同类别的内存数组进行处理,分区不变

RDD之间有依赖关系

image.png
image.png
image.png

KV型RDD可以有分区器

KV型RDD:RDD内存储的数据是二元元组,如(“hadoop”,3)
默认分区器:Hash分区规则,可以通过rdd.partitionBy方法手动设置一个分区器
这个特性只是可能的,因为并不是所有RDD都是KV型

RDD分区尽量靠近数据所在服务器

初始RDD(读取数据的时候)规划的时候,分区尽量规划到存储数据所在的服务器上
因此,尽量走本地读取,避免网络读取
本地读取:Executor所在服务器,也是一个DataNode,同时这个DataNode上有它要读的数据,因此可以直接读取硬盘,而不需要走网络
网络读取:读取数据时,需要经历网络传输才能读取到

因此,spark会在确保并行计算能力的前提下,尽量本地读取(非100%)

wordCount中RDD

image.png
1708676054434.png

总结

如何正确理解RDD

弹性分布式数据集,分布式计算的实现载体(数据抽象)

RDD 5大特性

  1. 可分区
  2. 方法应用到每一个分区
  3. RDD相互依赖
  4. KV型RDD可以有分区器
  5. RDD构建尽量靠近数据

RDD编程入门

程序执行入口–SparkContext对象

Spark RDD编程的程序入口对象是SparkContext对象(不论何种语言)
只有构建出SparkContext,基于sc才能执行后续的API调用和计算
本质上sc对编程来说,主要功能就是创建出第一个RDD出来
image.png

RDD创建

RDD创建的两种方式:

  1. 通过并行化集合创建(本地对象 转 分布式RDD)
  2. 读取外部数据源(读取文件)

并行化创建

image.png

读取文件创建

通过textFile API 读取本地数据或hdfs数据
sc.textFile(para1, para2)
para1必填,文件路径
para2可选,最小分区数(spark有自己的判断,允许范围内,para2有效,允许范围外,para2无效)
image.png
wholeTextFile
读取文件的API,适用于读取一堆小文件
image.png

RDD算子

算子

分布式集合对象上的API,称为算子

本地对象的API叫方法、函数

算子分类

  • Transformation:转换算子
  • Action:动作(行动)算子
transformation转换算子

定义:返回值仍然是一个RDD,称为转换算子
特性:lazy懒加载,如果没有action算子,则transformation算子不工作

action动作算子

定义:返回值不是RDD的就是action算子

区分

image.png
transformation转换算子相当于构建执行计划,action动作算子相当于执行计划

常用transformation转换算子

map算子

将RDD的数据一条一条处理(处理逻辑:基于map算子中接受的处理函数),返回新的RDD

rdd.map((func)
# func: f(T)->U

image.png

flatMap算子

对RDD执行map操作,然后进行解除嵌套操作

# 嵌套list
lst = [[1,2,3],[4,5,6],[7,8,9]]

# 解除嵌套
lst = [1,2,3,4,5,6,7,8,9]

flatMap传入参数和map一致,就是给map逻辑用的,在map逻辑上解除嵌套

reduceByKey算子

针对KV型RDD,自动按照key分组,根据提供的聚合逻辑,完成组内数据(value)的聚合操作

rdd.reducebyKey(func)
# func: (V,V)->V
# 接受两个类型一致的传入参数,返回值类型也和传入一致

key相同的分为一组,再根据value聚合

mapValues算子

针对二元元组RDD,对其元组内部的value执行map操作

rdd.mapValues(func)
# func: (V)->V
# 只针对value进行处理

groupBy算子

对RDD数据进行分组

rdd.groupBy(func)
# func: (T)->K
# 拿到返回值后,将相同返回值放入一个组中
# 分组完成后,每个组是一个二元元组,key是返回值,同组的数据放入迭代器中作为value

image.png
[('b',[('b',1), ('b', 1), ('b',1)])('a',[('a',1),('a',1)])]
key是返回值,value是同组的数据

filter算子

过滤想要的数据,进行保留

rdd.filter(func)
# func: (T)->bool 
# 传入的参数任意类型,返回值必须是布尔型(真True、假False)

image.png

distinct算子

对RDD进行去重,返回新RDD
rdd.distinct(参数) # 参数为去重分区数量,按几个分区进行去重,一般不传
image.png

union算子

将2个RDD合并为1个RDD并返回
rdd.union(other_rdd)
只合并(不同类型的RDD也可以合并),不去重
image.png

join算子

对2个RDD进行join(可实现SQL的内、外连接)
join算子只能用于二元元组,按key进行关联

rdd.join(other_rdd) # 内连接
rdd.leftOuterJoin(other_rdd) # 左外连接
rdd.rightOuterJoin(other_rdd) # 右外连接

image.png

intersection算子

求2个RDD的交集,返回新RDD
rdd.intersection(other_rdd)
image.png

glom算子

将RDD数据加上嵌套,嵌套按分区进行
rdd.glom()
image.png
[[1,2,3,4],[5,6,7,8,9]]

groupByKey算子

针对KV型RDD,自动按照key分组
rdd.groupByKey()
分组后只保留同组的value

sortBy算子

对RDD数据进行排序,基于指定的排序依据

rdd.sortBy(func, ascending = False, numPartitions=1)
# func: (T)->U:按RDD中哪个数据进行排序,如lambda x:x[1]表示按照RDD中第二列元素进行排序
# ascending = True 按升序排序,False 按降序排序
# numPartitions 用多少分区排序

image.png
image.png

sortByKey算子

针对KV型RDD,按key进行排序
sortByKey(ascending=True,numPartitions=None,keyfunc=<function RDD.<lambda>>)

常用算子案例

将案例提交到YARN集群中运行

pycharm中直接执行

import os
os.environ["HADOOP_CONF_DIR"]="/export/server/hadoop/etc/hadoop"

rdd = sc.textFile("hdfs://node1:8020/input/order.text") # 集群中文件须使用hdfs文件

# 如果运行的文件依赖其他py文件,可以通过设置属性来指定依赖代码
conf.set("spark.submit.pyFiles","defs.py") # conf.set(key,value)

通过服务器上spark-submit提交到集群运行

–py-files可以指定以来的其他py代码,支持单py文件或zip压缩包
/export/server/spark/bin/spark-submit --master yarn --py-Files ./defs.py ./main.py

常用action算子

countByKey算子

统计key出现的次数,一般适用于KV型RDD
image.png

collect算子

将RDD各个分区内的数据统一到driver中,形成一个list对象
rdd.collect()

  1. 将RDD各个分区的数据都拉取到driver
  2. 拉取前应该了解到数据集不大
  3. 太大的数据集会撑爆内存

reduce算子

对RDD数据集按照传入逻辑进行聚合

rdd.reduce(func)
# func : (T,T)->T

rdd.parallelize(range(1,10))
print(rdd.reduce(lambda a,b:a+b))

fold算子[很少用]

和reduce一样,接受传入逻辑进行聚合;聚合带有初始值

  • 分区内聚合
  • 分区间聚合

[[1,2,3], [4,5,6], [7,8,9]]
初始值为10
分区1聚合后得到10+1+2+3 = 16
分区2聚合后得到10+4+5+6 = 25
分区3聚合后得到10+7+8+9 = 34

rdd = sc.parallelize(range(1,10),3)
print(rdd.fold(10,lambda a,b:a+b))

最终聚合结果为10 + 16 +25 +34 =85

first算子

取出RDD的第一个元素
rdd.parallelize([3,2,1]).first()
3

take算子

取RDD的前N个元素,组成list返回
rdd.parallelize([1,2,3,4,5,6,7,8,9]).take(5)
[1,2,3,4,5]

top算子

对RDD数据集进行降序排序,取前N个
rdd.parallelize([1,2,3,4,5,6,7,8,9]).top(5)
[9,8,7,6,5]

count算子

计算RDD有多少条数据,返回值是一个数字
rdd.parallelize([1,2,3,4,5,6]).count()
6

takeSample算子

随机抽样RDD的数据
takeSample(bool,takeSampleNum,seed)

  • bool为真:允许取同一个数据;bool为假,不允许取同一个数据
  • 采样(抽样)数量
  • 随机种子(一般不给,spark会自动给随即种子)
rdd = sc.parallelize([1,1,1,1,1,1,1,1],1)
print(rdd.takeSample(True,8))

takeOrdered算子

对RDD排序取前N个

rdd.takeOrdered(para1, para2)
# para1 取N个数据
# para2 对排序数据进行更改(不更改数据本身,只修改到临时排序的数值)
# 默认升序,需要到倒序可以使用para2重排序

image.png

foreach算子

对RDD的每一个元素,执行提供的逻辑操作(同map),不过没有返回值
rdd.foreach(func)
image.png

saveAsTextFile算子

将RDD数据接入到文本文件中
支持本地写出hdfs等文件系统
image.png

小注意

action算子中:

  • foreach
  • saveAsTextFile

这两个算子是分区(Executor)直接执行,跳过Driver
其余action算子都会将结果发送给Driver

mapPartitions算子

map算子每次处理一个元素
mapPartitions算子一次处理一个分区的数据,作为一个迭代器(一次性list)对象传入过来(一次处理一个迭代器)
image.png
image.png

foreachPartition算子

类似foreach,一次处理一整个分区
foreachPartition就是个没有返回值的mapPartitions
image.png

partitionBy算子

对RDD进行自定义分区操作(默认hash分区)

rdd.partitionBy(para1, para2)
para1 重新分区后的分区数
para2 自定义分区规则,返回值为int,分区编号[0,分区数-1]

image.png

repartition算子

对RDD的分区执行重新分区(仅数量上)
rdd.repartition(N)
image.png
分区须谨慎:一般情况下spark代码中除了全局排序设置为1个分区外,通常所有api中的分区相关代码都不太理会
分区影响:

  1. 影响并行计算(内存迭代的并行管道数量)
  2. 分区的增加极可能导致shuffle

repartition api最好不用,用也是减少分区(方便全局排序)
image.png

groupByKey算子和reduceByKey算子区别

如果对数据执行 分组+聚合 ,reduceByKey性能>>>groupByKey+聚合逻辑
image.png
groupByKey只可以分组;reduceByKey除了可以分组,还可以聚合
使用groupByKey就是先分组,后聚合;reduceByKey先预聚合,再分区,再聚合,减少IO
image.png

总结

RDD创建的几种方式

  1. 并行化集合的方式(本地集合转分布式集合)
  2. 读取数据的方式(TextFile、WholeTextFile)

RDD查看分区数

调用getNumPartitions api查看分区数(返回int)

transformation和action算子的区别

transformation转换算子的返回值还是RDD,action算子的返回值不是RDD
transformation转换算子懒加载,碰到action算子才会执行

哪两个action算子不经过Driver直接执行输出

foreach和saveAsTextFile,直接由executor执行输出

groupByKey和reduceByKey区别

groupByKey算子只有分组功能,没有聚合逻辑,需自行补充聚合逻辑
reduceByKey算子支持分组聚合,先预聚合、再分组、再聚合,效率更高,传输IO小

mapPartitions和foreachPartition的区别

mapPartitions是一个转换算子,有返回值
foreachPartition是一个action算子,没有返回值
两个算子都是一次处理一整个分区的数据

分区操作的注意项

尽量不要增加分区(分区划分好后),可能破坏内存迭代的计算管道

RDD持久化

RDD过程数据

RDD之间进行相互迭代的计算(Transformation转换),执行开始后,新RDD产生,旧RDD消失
RDD的数据是过程数据,处理过程中存在,处理完成则清除
最大化利用资源,没用的RDD就会从内存中被清除,给后续的计算腾出空间
image.png
RDD3有两次使用,但第一次使用后,RDD3就被清除了;第二次用的时候的RDD3从RDD1重新执行构建出来

RDD缓存

针对某个或某些需要重复使用的RDD进行持久化优化,缓解整条链的重建
RDD缓存技术:spark提供缓存api,通过调用api,将指定的RDD数据保留再内存或硬盘上
image.png
image.png
image.png

  • 缓存技术可以将过程RDD数据持久化到内存或者硬盘上
  • 这个保存在设定上认为不安全

设计上认为有丢失的风险
缓存的特点:保留RDD之间的血缘(依赖)关系
缓存丢失:

  • 缓存不安全,断电、计算任务不足等情况下,清理缓存给计算让路
  • 硬盘有可能损坏

RDD checkpoint

checkpoint技术也是将RDD数据保存起来,但是仅支持硬盘存储

  • 设计上认为是安全的(设计上认为不会丢失)
  • 不保留血缘关系

image.png
RDD数据被checkpoint保存到HDFS中
缓存与checkpoint对比:

  1. checkpoint不管分区数量多少,风险一样;缓存分区越多,风险越高
  2. checkpoint支持写入hdfs,缓存不行,hdfs是高可靠存储,checkpoint认为更安全
  3. checkpoint不支持写入内存,缓存可以,缓存如果写入内存中,性能更好
  4. checkpoint因为设计上认为安全,所以不保留血缘关系;缓存设计上认为不安全,所以保留血缘关系

image.png
缓存:轻量级的、临时的、即使重新计算也不太费事的
checkoint:体量大的、计算费事的

总结

cache和checkpoint的区别

cache轻量化保存RDD数据,可存储在内存和一泡尿,是分散存储,设计上认为不安全,因此保留血缘
checkpoint重量级保存RDD数据,集中存储,只能存储硬盘上(hdfs),设计上认为是安全的,因此不保留血缘

cache和checkpoint性能对比

cache分散存储,各个executor并行执行,效率高,可以保存到内存中,更快,性能更好
checkpoint集中存储,涉及到网络IO,比较慢,但是存储到HDFS上更加安全

spark案例联系

搜索引擎日志分析

数据提供:搜狗实验室
网址:http://www.sogou.com/labs/resource/q.php
数据格式:搜索时间 用户ID 搜索内容 URL返回排名 用户点击顺序 用户点击的URL
image.png
image.png
image.png
image.png
image.png

提交到集群运行

image.png
image.png

总结

分词库

jieba

为什么所有服务器都要装jieba

yarn以集群运行,executor可以在所有服务器上运行,因此每台服务器都要有jieba库支撑

尽量提高任务计算资源

计算CPU核心和内存量
通过–executor-memory指定executor内存;
通过–executor-cores指定executor核心数
通过–num-executors指定总executor数量

共享变量

广播变量

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青铜念诗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值