【博学谷学习记录】超强总结,用心分享|狂野大数据课程【RDD算子相关的操作】的总结分析

RDD算子: 指的是RDD对象中提供了非常多的具有特殊功能的函数, 我们一般将这样的函数称为算子(大白话: 指的RDD的API)

相关的算子的详细官方文档: https://spark.apache.org/docs/3.1.2/api/python/reference/pyspark.html#rdd-apis

3.1 RDD算子的分类

整个RDD算子, 共分为二大类: Transformation(转换算子) 和 Action(动作算子)

转换算子: 
	1- 所有的转换算子在执行完成后, 都会返回一个新的RDD
	2- 所有的转换算子都是LAZY(惰性),并不会立即执行, 此时可以认为通过转换算子来定义RDD的计算规则
	3- 转换算子必须遇到Action算子才会触发执行

动作算子: 
	1- 动作算子在执行后, 不会返回一个RDD, 要不然没有返回值, 要不就返回其他的
	2- 动作算子都是立即执行, 一个动作算子就会产生一个Job执行任务,运行这个动作算子所依赖的所有的RDD

相关的转换算子:

在这里插入图片描述

相关的动作算子:

在这里插入图片描述

3.2 RDD的转换算子

值类型的算子:

  • map算子:
    • 格式: rdd.map(fn)
    • 说明: 根据传入的函数, 对数据进行一对一的转换操作, 传入一行, 返回一行
rdd = sc.parallelize([1,2,3,4,5,6,7,8,9,10])

需求: 请对每一个元素进行 +1 返回
rdd.map(lambda num: num + 1).collect()

结果:
	[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
  • groupBy算子:
    • 格式: groupBy(fn)
    • 说明: 根据传入的函数对数据进行分组操作
rdd = sc.parallelize([1,2,3,4,5,6,7,8,9,10])

需求: 请将数据分为奇数和偶数二部分

def jo(num):
    if num % 2 == 0:
        return 'o'
    else:
        return 'j'

rdd.groupBy(jo).collect()
结果:
	[
		('j', <pyspark.resultiterable.ResultIterable object at 0x7f1a1bc22490>),
        ('o', <pyspark.resultiterable.ResultIterable object at 0x7f1a1bc0a2b0>)
    ]
mapValues(list): 将 kv中value转换为list

rdd.groupBy(jo).mapValues(list).collect()
结果:
	[
		('j', [1, 3, 5, 7, 9]), 
		('o', [2, 4, 6, 8, 10])
	]



思考: 上述的函数, 是否有简单的写法呢? 或者说直接使用lambda如何写呢?
rdd.groupBy(lambda num: 'o' if num % 2 == 0 else 'j' ).mapValues(list).collect()
结果:
	[
		('j', [1, 3, 5, 7, 9]), 
		('o', [2, 4, 6, 8, 10])
	]
  • filter算子
    • 格式: filter(fn)
    • 说明: 过滤算子, 可以根据函数中指定的过滤条件, 对数据进行过滤操作, 条件返回True表示保留, 返回False表示过滤掉
rdd = sc.parallelize([1,2,3,4,5,6,7,8,9,10])

需求: 请将 <=3的数据过滤掉
rdd.filter(lambda num: num > 3).collect()
结果:
	[4, 5, 6, 7, 8, 9, 10]
  • flatMap算子:
    • 格式: flatMap(fn)
    • 说明: 在map算子的基础上, 在加入一个压扁的操作, 主要适用于一行中包含多个内容的操作, 实现一转多的操作
rdd = sc.parallelize(['张三 李四 王五 赵六','田七 周八 李九'])

需求: 将其转换为一个个的姓名
rdd.flatMap(lambda line: line.split(' ')).collect()
或者
rdd.flatMap(lambda line: line.split()).collect()
结果:
	['张三', '李四', '王五', '赵六', '田七', '周八', '李九']

双值类型算子:

  • union(并集) 和 intersection(交集)
    • 格式: rdd1.union|intersection(rdd2)
rdd1 = sc.parallelize([3,1,5,7,9])
rdd2 = sc.parallelize([5,8,2,4,0])

结果:
	并集:
		rdd1.union(rdd2).collect()
		结果:
		[3, 1, 5, 7, 9, 5, 8, 2, 4, 0]
		
		去重操作: 
		rdd1.union(rdd2).distinct().collect()
		结果:
		[8, 4, 0, 1, 5, 9, 2, 3, 7]
		
	交集:
		rdd1.intersection(rdd2).collect()
		结果:
		[5]

KV类型相关的算子:

  • groupByKey算子:
    • 格式: groupByKey()
    • 说明: 根据key进行分组操作
rdd = sc.parallelize([('c01','张三'),('c02','李四'),('c02','王五'),('c03','赵六'),('c02','田七'),('c02','周八'),('c03','李九')])

需求: 根据班级分组统计
rdd.groupByKey().collect()
结果:
[
	('c01', <pyspark.resultiterable.ResultIterable object at 0x7f1a1bc0af10>), 
	('c02', <pyspark.resultiterable.ResultIterable object at 0x7f1a1bc0af40>), 
	('c03', <pyspark.resultiterable.ResultIterable object at 0x7f1a1bc0afd0>)
]
rdd.groupByKey().mapValues(list).collect()
结果:
[
	('c01', ['张三']), 
	('c02', ['李四', '王五', '田七', '周八']), 
	('c03', ['赵六', '李九'])]

rdd.groupByKey().mapValues(list).map(lambda kv: (kv[0],len(kv[1]))).collect()

结果:
[('c01', 1), ('c02', 4), ('c03', 2)]
  • reduceByKey()
    • 格式: reduceByKey(fn)
    • 说明: 根据key进行分组, 将一个组内的value数据放置到一个列表中, 对这个列表基于 传入函数进行聚合计算操作
rdd = sc.parallelize([('c01','张三'),('c02','李四'),('c02','王五'),('c03','赵六'),('c02','田七'),('c02','周八'),('c03','李九')])

需求: 统计每个班级有多少个人
rdd.map(lambda kv:(kv[0],1)).reduceByKey(lambda agg,curr: agg + curr).collect()
结果:
[('c01', 1), ('c02', 4), ('c03', 2)]


如果不转为1:
rdd.reduceByKey(lambda agg,curr: agg + curr).collect()    
结果: 
[('c01', '张三'), ('c02', '李四王五田七周八'), ('c03', '赵六李九')]
  • sortByKey()算子
    • 格式: sortByKey(ascending = True|False)
    • 说明: 根据key进行排序操作, 默认按照key进行升序排序, 如果需要倒序, 设置 ascending 为False
rdd = sc.parallelize([('c03','张三'),('c05','李四'),('c01','王五'),('c09','赵六'),('c02','田七'),('c07','周八'),('c06','李九')])

根据班级序号排序
rdd.sortByKey().collect()
结果: 
[('c01', '王五'), ('c02', '田七'), ('c03', '张三'), ('c05', '李四'), ('c06', '李九'), ('c07', '周八'), ('c09', '赵六')]

rdd.sortByKey(ascending=False).collect()
结果:
[('c09', '赵六'), ('c07', '周八'), ('c06', '李九'), ('c05', '李四'), ('c03', '张三'), ('c02', '田七'), ('c01', '王五')]


思考:
rdd = sc.parallelize([('c03','张三'),('c05','李四'),('c011','王五'),('c09','赵六'),('c02','田七'),('c07','周八'),('c06','李九')])

rdd.sortByKey().collect()       
结果: 字典序 由于key是字符串
[('c011', '王五'), ('c02', '田七'), ('c03', '张三'), ('c05', '李四'), ('c06', '李九'), ('c07', '周八'), ('c09', '赵六')]
  • countByKey() 和 countByValue()
    • 严格意义上应该是属于action算子
    • 说明:
      • countByKey() 根据key进行分组 统计每个分组下有多少个元素
      • countByValue() 根据value进行分组, 统计相同value有多少个
rdd = sc.parallelize([('c01','张三'),('c02','李四'),('c02','王五'),('c03','赵六'),('c02','田七'),('c02','周八'),('c03','李九')])

rdd.countByKey()
defaultdict(<class 'int'>, {'c01': 1, 'c02': 4, 'c03': 2})

rdd.countByValue() 将列表找那个每一个元素, 作为一个整体来统计相同的value有多少个
defaultdict(<class 'int'>, {('c01', '张三'): 1, ('c02', '李四'): 1, ('c02', '王五'): 1, ('c03', '赵六'): 1, ('c02', '田七'): 1, ('c02', '周八'): 1, ('c03', '李九'): 1})

rdd = sc.parallelize([1,2,1,2,3,1,2,4])

rdd.countByValue()                     
defaultdict(<class 'int'>, {1: 3, 2: 3, 3: 1, 4: 1})

3.3 RDD的动作算子

  • collect() 算子

    • 格式: collect()
    • 作用: 收集各个分区的数据, 将数据汇总到一个大的列表返回
  • reduce() 算子

    • 格式: reduce(fn)
    • 作用: 根据传入的函数对数据进行聚合操作
rdd = sc.parallelize([1,2,3,4,5,6,7,8,9,10])

rdd.reduce(lambda agg,curr: agg + curr)
结果: 55
  • first()算子
    • 格式: first()
    • 说明: 获取第一个元素
rdd = sc.parallelize([1,2,3,4,5,6,7,8,9,10])
rdd.first()
1
  • take() 算子
    • 格式: take(N)
    • 说明: 获取前N个元素, 类似于limit操作
rdd = sc.parallelize([1,2,3,4,5,6,7,8,9,10])
rdd.take(5)
结果
[1, 2, 3, 4, 5]
  • top() 算子
    • 格式: top(N, [fn])
    • 说明: 对数据集进行倒序排序操作, 如果是kv类型, 默认是针对key进行排序, 获取前N个元素
    • fn: 可以自定义排序, 根据谁来排序
rdd = sc.parallelize([1,2,3,4,5,6,7,8,9,10])
rdd.top(3)
结果:
[10, 9, 8]


rdd = sc.parallelize([('c03','张三'),('c05','李四'),('c011','王五'),('c09','赵六'),('c02','田七'),('c07','周八'),('c06','李九')])

rdd.top(3)
结果:
[('c09', '赵六'), ('c07', '周八'), ('c06', '李九')]



rdd = sc.parallelize([('c03',5),('c05',9),('c011',2),('c09',6),('c02',80),('c07',12),('c06',10)])

rdd.top(3,lambda kv: kv[1])
结果:
[('c02', 80), ('c07', 12), ('c06', 10)]
  • count()算子
    • 格式: count()
    • 说明: 统计多少个
rdd = sc.parallelize([('c03',5),('c05',9),('c011',2),('c09',6),('c02',80),('c07',12),('c06',10)])

rdd.count()
7
  • foreach()算子
    • 格式: foreach(fn)
    • 说明: 对数据集进行遍历操作, 遍历后做什么, 取决于传入的函数
rdd = sc.parallelize([('c03',5),('c05',9),('c011',2),('c09',6),('c02',80),('c07',12),('c06',10)])

rdd.foreach(lambda kv: print(kv))
('c03', 5)
('c05', 9)
('c011', 2)
('c09', 6)
('c02', 80)
('c07', 12)
('c06', 10)
  • takeSample()算子

    • 格式: takeSample(True|False, N,seed(种子值))

      • 参数1: 是否允许重复采样
      • 参数2: 采样多少个, 如果允许重复采样, 采样个数不限制, 否则最多等于本身数量个数
      • 参数3: 设置种子值, 值可以随便写, 一旦写死了, 表示每次采样的内容也是固定的(可选的) 如果没有特殊需要, 一般不设置
    • 作用: 数据抽样

rdd = sc.parallelize([1,2,3,4,5,6,7,8,9,10])

rdd.takeSample(True,5)
[9, 9, 4, 8, 9]
rdd.takeSample(True,5)
[3, 8, 1, 3, 9]
rdd.takeSample(False,5)
[6, 1, 8, 7, 3]
rdd.takeSample(False,5)
[5, 7, 6, 3, 8]
rdd.takeSample(False,20)
[2, 10, 7, 5, 8, 9, 3, 4, 6, 1]
rdd.takeSample(False,5) 
[8, 3, 10, 7, 9]

rdd.takeSample(False,5,2)  
[6, 10, 4, 5, 7]
rdd.takeSample(False,5,2)
[6, 10, 4, 5, 7]
rdd.takeSample(False,5,2)
[6, 10, 4, 5, 7]
rdd.takeSample(False,3,2)
[6, 10, 4]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值