说明
本章主要是对spark最核心的数据结构RDD的介绍和应用。属于Spark分析计算引擎的敲门砖,需重点掌握。
概念
1.本质是弹性分布式集合,是spark中最基本最核心的数据结构。
2.将spark需要处理的数据和中间计算结果以RDD形式存储在内存中。
3.spark中除了RDD数据类型之外,还有DataFrame和DataSet
4.在python中一切皆对象,RDD数据类型就是RDD对象,提供了一些处理RDD对象的算子(方法)
5.RDD是存储数据的集合,类似于python中的列表
特点
分区:弹性,将RDD中数据拆分成多份进行处理,一个分区数据对应一个task线程执行
只读:RDD只能读取,不能进行修改,类似于python的不可变类型
依赖:新RDD是由旧RDD计算产生的
缓存:将计算结果进行缓存,保证spark程序的容错性。如果spark计算失败,会从缓存出获取rdd
重新计算。将缓存RDD优先保存在内存中,spark程序运行结束后缓存的RDD就会被销毁。
CheckPoint:类缓存操作,将Spark的中间计算结果RDD永久存储在HDFS中,Spark程序运行结
束后不会删除checkpoint
RDD的创建
python数据转换为RDD
注这里展示示例代码,可以自己敲一遍然后运行验证
# 将Python转化为rdd数据
from pyspark import SparkContext
# 生成SparkContext类对象
sc = SparkContext()
# 使用sc对象的下的parallelize方法将python数据转化为rdd
# int_data = 123 不能转化
str_data = 'abc'
list_data = [1,2,3]
dict_data = {'a':1,'b':2}
tuple_data = (1,2,3)
set_data = {1,2,3}
# 一般使用列表类型转化为rdd
rdd = sc.parallelize(python对象)
# 使用rdd方法计算
# 查看转化后的rdd数据
res = rdd.collect()
print(res)
文件数据转化为RDD
from pyspark import SparkContext
sc = SparkContext()
# 读取hdfs上文件数据转为rdd
rdd1 =sc.textfile('hdfs://node1:8080/data')
rdd2 =sc.textfile('/data/words.txt')
rdd3 = sc.textFile('file:///root/data')
rdd4 = sc.textFile('file:///root/data/employees.json')
#查看数据
print(rdd1)
print(rdd2)
print(rdd3)
print(rdd4)
RDD的分区
python数据转化时分区数制定
# rdd的分区数指定
from pyspark import SparkContext
# 生成SparkContext类对象
sc = SparkContext()
# python转化时指定分区数
data = [1,2,3,4,5,6]
# numSlices指定分区数
rdd = sc.parallelize(data, numSlices=8)
# glom()按照分区查看数据
res = rdd.glom().collect()
print(res)
读取文件数据时进行分区数指定
from pyspark import SparkContext
# 生成SparkContext类对象
sc = SparkContext()
# 文件数据指定分区数
rdd = sc.textFile('/data', minPartitions=4)
# glom()按照分区查看数据
res = rdd.glom().collect()
print(res)
使用glom前后对比
小文件数据转换为RDD
在一个目录下,有多个文件,如果文件的大小不够一个块的大小,一个文件就对应一个分区,文件超过一个块,那就一个block(128M)块对应一个分区。目录下都是小文件,那么读取目录下的文件数据,会对应很多个分区。一个分区对应一个task线程,当小文件过多时,会占用大量的线程,造成资源浪费,使用wholeTextFiles
方法可以解决。该方法会现将读取到的数据合并在一起,然后重新进行分区。
# rdd的分区数指定
from pyspark import SparkContext
# 生成SparkContext类对象
sc = SparkContext()
# 文件数据指定分区数 ,读取目录下的多个小文件
rdd = sc.textFile('/data')
# glom()按照分区查看数据
res = rdd.glom().collect()
# 将小文件合并 一个分区数据 1000条数据在一个分区,对应一个task线程
print(res)
print(len(res))
# wholeTextFiles读取目录中的多个小文件数据
rdd2= sc.wholeTextFiles('/data')
res = rdd2.glom().collect()
print(res)
print(len(res))
常用的RDD算子
主要分两类,即转换算子transformation以及执行算子action。
transformation:转化算子,对rdd数据进行转化计算并得到新的rdd,定义了一个线程任务
action:执行算子,触发计算任务,让计算任务进行执行并得到结果。触发线程执行。
常用的transformation算子
map
对旧rdd数据进行转化操作,得到新的rdd,此方法不会改变rdd的数据结构
写法:rdd.map(对于x的操作)
注:x代表rdd列表中的每一个元素
flatMap
转化算子, 对旧rdd数据进行转化操作, 得到新的rdd,将新rdd扁平化
写法:rdd.flatMap(对于x的操作)
filter
可以过滤rdd中的一部分元素,达到数据清洗的效果
写法:rdd.filter(lambda 参数:参数条件过滤)
distinct
对rdd中重复数据进行去重操作, 返回一个去重后的新rdd
写法: rdd.distinct()
groupBy
groupBy算子接收一个函数,这个函数的返回值作为key,然后通过这个key来对里面的元素进行分组。
写法:rdd.groupBy(lambda 参数:根据参数编写分组条件)
mapValues
写法:rdd.mapValues(lambda 参数:根据参数的V值进行map操作)
k-v算子
groupByKey
直接将k-v类型的数据中的key作为group的key值
写法:rdd.groupByKey()
reduceByKey()
将相同key值的数据放在一起,然后对每个key中对应的value值进行相关计算
写法:rdd.reduceByKey(lambda 参数1,参数2:对两个参数计算)
sortByKey()
根据key值对数据进行排序, 默认升序(ascending=True), 降序(ascending=False)
写法:rdd.sortByKey()
join
join():内连接,保留两个rdd共有的key值的数据
leftOuterJoin():左外连接,保留左边rdd的所有数据,右边关联不上的用None值填充
rightOuterJoin():右外连接,保留右边rdd的所有数据,左边关联不上的用None值填充
fullOuterJoin():满外连接,保留左右rdd的所有数据,关联不上的用None值填充
常见的action算子
collect
取出所有值,大量数据慎用collect(), 容易造成内存溢出
写法:rdd.collect()
collectAsMap
将rdd的k-v格式数据转换成字典格式 例如:[('男',45), ('女',7)] -> {'男':45, '女':7}
写法:rdd.collectAsMap
reduce
非k-v类型数据的相关计算
写法:rdd.reduce(lambda 参数1,参数2:两个参数计算)
count
统计rdd元素个数
写法:rdd.count()
take
取出指定数量值
写法:rdd.take(数量)
saveAsTextFile()
将结果rdd保存到hdfs的目录中, 保存的目录是不存在的, 会自动创建
写法:rdd.saveAsTextFile(path)