day03 PySpark课程笔记
今日内容:
- 1- 如何构建RDD
- 2- RDD算子相关的操作(记录)
- 3- 综合案例
1. 如何构建RDD
构建RDD对象的方式主要有二种:
通过 parallelize('''') API 来构建RDD对象
通过加载外部数据集的方式构建: textFile(....)
1.1 通过并行化的方式来构建RDD
代码演示:
# 演示如何创建RDD对象" 方式一
from pyspark import SparkContext, SparkConf
import os
# 锁定远端python版本:
os.environ['SPARK_HOME'] = '/export/server/spark'
os.environ['PYSPARK_PYTHON'] = '/root/anaconda3/bin/python3'
os.environ['PYSPARK_DRIVER_PYTHON'] = '/root/anaconda3/bin/python3'
if __name__ == '__main__':
print("演示:如何创建RDD")
# 1- 构建SparkContext对象
conf = SparkConf().setMaster("local[3]").setAppName('create_rdd')
sc = SparkContext(conf=conf)
# 2- 构建RDD对象
rdd_init = sc.parallelize(['张三','李四','王五','赵六','田七','周八','李九'],5)
# 需求:给每一个元素添加一个 10序号
rdd_map = rdd_init.map(lambda name: name + '10')
# 如何查看RDD中每个分区的数据,以及分区的数量
print(rdd_init.getNumPartitions())
print(rdd_init.glom().collect())
print(rdd_map.glom().collect())
说明:
验证RDD是存在分区的, 而且每一个计算函数作用在每个分区上进行处理
如何查看RDD有多少个分区: rdd.getNumPartitions()
如何查看RDD中每一个分区的数据: rdd.glom()
当采用本地模拟数据(并行方式)构建RDD的时候, RDD分区数量取决于:
1- 默认: setMaster("local[N]") 取决于 N的值, 当N为*的时候, 表示为当前节点的CPU核心数
2- 同时也可以通过parallelize算子来设置分区数量, 设置多少就为多少个分区
1.2 通过读取外部数据方式构建RDD
代码实现:
# 演示: 如何构建RDD 方式二 通过外部文件的方式构建
from pyspark import SparkContext, SparkConf
import os
# 锁定远端python版本:
os.environ['SPARK_HOME'] = '/export/server/spark'
os.environ['PYSPARK_PYTHON'] = '/root/anaconda3/bin/python3'
os.environ['PYSPARK_DRIVER_PYTHON'] = '/root/anaconda3/bin/python3'
if __name__ == '__main__':
print("演示构建RDD的方式二:")
# 1- 创建SparkContext对象:
conf = SparkConf().setMaster('local[*]').setAppName('create_rdd_2')
sc = SparkContext(conf=conf)
# 2- 读取外部的文件数据
# 路径写法: 协议 + 路径
# 本地路径: file:///
# HDFS: hdfs://node1:8020/
rdd_init = sc.textFile('file:///export/data/workspace/sz30_pyspark_parent/_02_pyspark_core/data/')
#rdd_init = sc.textFile('hdfs://node1:8020/pyspark_data/words.txt',15)
print(rdd_init.getNumPartitions())
print(rdd_init.glom().collect())
当读取后, 分区 过多, 在写入到HDFS的时候, 就会产生大量的小文件, 如果由于数据源文件比较多导致的, 可以采用在读取数据的时候, 尽量减少分区数:
# 演示: 如何构建RDD 方式二 小文件合并操作
from pyspark import SparkContext, SparkConf
import os
# 锁定远端python版本:
os.environ['SPARK_HOME'] = '/export/server/spark'
os.environ['PYSPARK_PYTHON'] = '/root/anaconda3/bin/python3'
os.environ['PYSPARK_DRIVER_PYTHON'] = '/root/anaconda3/bin/python3'
if __name__ == '__main__':
print("演示构建RDD的方式二:")
# 1- 创建SparkContext对象:
conf = SparkConf().setMaster('local[*]').setAppName('create_rdd_2')
sc = SparkContext(conf=conf)
# 2- 读取外部的文件数据
# 路径写法: 协议 + 路径
# 本地路径: file:///
# HDFS: hdfs://node1:8020/
# wholeTextFiles: 尽可能的减少分区数量, 从而减少最终输出到目的地文件数量
rdd_init = sc.wholeTextFiles('file:///export/data/workspace/sz30_pyspark_parent/_02_pyspark_core/data',1)
print(rdd_init.getNumPartitions())
print(rdd_init.glom().collect())
关于textFile在读取数据的时候, 分区数量确定:
确定分区数量取决于两个公式:
defaultMinPartitions = min(default.parallelism,2) | 设置minPartition的值
其中:
default.parallelism = setMaster('local[N]') = N值
设置minPartition的值 : textFile(path,minPartition)
如果设置minPartition的值, defaultMinPartitions 等于此值, 否则按照min(default.parallelism,2) 来计算
本地文件:
rdd分区数量 = max(文件分片数量,defaultMinPartitions)
HDFS文件:
rdd分区数量 = max(文件block块数量,defaultMinPartitions)
2. RDD算子相关的操作
在spark中, 将支持传递函数的或者说具有一些特殊功能的方法或者函数称为算子
2.1 RDD算子分类
在整个RDD算子中, 主要可以将算子分为两大类: transformation(转换算子) 和 action(动作算子)
转换算子:
1- 返回一个新的RDD
2- 所有的转换算子都是惰性的, 只有遇到action算子才会触发执行
3- RDD并不存储实际的数据, 只存储转换的规则, 当遇到action算子后, 根据规则对数据进行处理即可
动作算子:
1- 不会返回一个RDD, 要不然没有返回值, 要不返回其他的
2- 所有动作算子都是立即执行, 在代码中每一个action都会去触发一个JOB的任务
转换算子:
action算子:
整个Spark所有的RDD的算子文档: https://spark.apache.org/docs/3.1.2/api/python/reference/pyspark.html#rdd-apis
2.2 RDD的Transformation算子操作
值类型的算子: 主要是针对value进行处理相关的算子
- Map算子: 一对一的转换操作
- 作用: 根据用户传入的自定义转换规则(函数) 将数据一对一的转换称为一个新的RDD
- map算子是作用在每一个分区上每一个元素上,对每一个元素执行自定义的函数
# 案例演示:
rdd_init = sc.parallelize([1,2,3,4,5,