RDD的三类算子
Transformation
- 通过已有的RDD生成新的RDD
- 惰性计算:Transformation 只会记录RDD的转化关系,不会触发计算(类似于py 里面的惰性序列,如 zip)
- 举例:map,filter,groupBy,reduceBy
- 优点:可以中间插入优化过程
Action
- 通过RDD计算得到一个或者一组值
- Action是立即执行的
- 举例:cout,reduce,saveAsTextFile
- 缺点:不能插入优化过程
Persistence
- cache:缓存到内存
- Persist:更灵活的缓存策略
- cache() 方法调用的也是 persist方法,缓存策略均为MEMORY_ONLY
- 可以通过persist方法手工设定StorageLevel来满足工程需要的存储级别
- cache或者persist并不是action
常用函数
- map:通过函数 func 对源的每一个元素进行处理,返回新的RDD
- filter:选择通过 func 函数返回 True 的元素
- flatmap:与 map 类似,但是返回是一个序列,而不是单个项,操作的序列里面的每一个元素必须是一个可迭代对象
- groupBy:当调用 (k, v) 对的数据集时,返回一个数据集 (k, iter) 对。注意:如果分组时为了对每个键执行聚合,则使用 reduceByKey 或 gateByKey 性能会更好。注意,默认情况下,输出的并行级别取决于父 RDD 分区的数量。通常通过可选的 Nuffice 参数设置不同数量的任务
- reduceByKey:在对 (k, v) 对的数据集进行调用时,返回(k, v) 对的数据集,其中每个键的值都使用给定的reduce参数func进行聚合,该函数必须是类型 (v, v) => v。于 groupByKey 中一样,reduce 任务的数量可以通过可选的第二个参数进行配置
- union:取并集
- distinct:去重
- join:当调用 (k, v) 和 (k, w) 的 RDD时,返回 (k, (v, w)) 对的 RDD,包含每个键的所有元素对,外部连接通过 leftOuterJoin、rightOuterJoin 和 fullOuterJoin 进行
- foreach:遍历数据集应用 func
- collect:将 数据集的所有元素作为数组返回
- count:返回元素数量
- first:返回第一个元素
map 和 flatMap 的区别
map 返回对每个元素操作的单个项,flatMap 返回对整个序列操作之后的序列,flatMap要处理的每个元素必须是可迭代对象
>>> rdd1 = sc.parallelize(["a,b,c", "d,e,f", "h,i,j"])
>>> rdd2 = rdd1.flatMap(lambda x:x.split(','))
>>> rdd2.collect()
['a', 'b', 'c', 'd', 'e', 'f', 'h', 'i', 'j']
>>> rdd3 = rdd1.map(lambda x:x.split(','))
>>> rdd3.collect()
[['a', 'b', 'c'], ['d', 'e', 'f'], ['h', 'i', 'j']]
>>>
union, intersection
>>> rdd1 = sc.parallelize([('a', 1), ('b', 2)])
>>> rdd2 = sc.parallelize([('c', 1), ('b', 2)])
>>> rdd3 = rdd1.union(rdd2)
>>> rdd3.collect()
[('a', 1), ('b', 2), ('c', 1), ('b', 2)]
>>> rdd4 = rdd1.intersection(rdd2)
>>> rdd4.collect()
[('b', 2)]
>>> rdd1 = sc.parallelize([1,2,3])
>>> rdd2 = sc.parallelize([2,4])
>>> rdd3 = rdd1.union(rdd2)
>>> rdd3.collect()
[1, 2, 3, 2, 4]
>>> rdd4 = rdd1.intersection(rdd2)
>>> rdd4.collect()
[2]
>>>
groupBy
>>> rdd1 = sc.parallelize([('a', 1), ('b', 2)])
>>> rdd2 = sc.parallelize([('c', 1), ('b', 3)])
>>> rdd3 = rdd1.union(rdd2)
>>> rdd3.collect()
[('a', 1), ('b', 2), ('c', 1), ('b', 3)]
>>> rdd4 = rdd3.groupByKey()
>>> rdd4.collect() # 得到的分组对象也是惰性序列
[('b', <pyspark.resultiterable.ResultIterable object at 0x7f2b9b701a58>), ('c', <pyspark.resultiterable.ResultIterable object at 0x7f2b9b701898>), ('a', <pyspark.resultiterable.ResultIterable object at 0x7f2b9b701c18>)]
>>> for i in rdd4.collect():
... print(i)
...
('b', <pyspark.resultiterable.ResultIterable object at 0x7f2b9b709e80>)
('c', <pyspark.resultiterable.ResultIterable object at 0x7f2b9b7091d0>)
('a', <pyspark.resultiterable.ResultIterable object at 0x7f2b9b7094e0>)
>>> for i in rdd4.collect():
... _iter = i[1]
... for j in _iter:
... print(j)
...
2
3
1
1
>>>
reduceByKey, sortByKey
>>> rdd1 = sc.parallelize([('a', 1), ('b', 2)])
>>> rdd2 = sc.parallelize([('c', 1), ('b', 3)])
>>> rdd3 = rdd1.union(rdd2)
>>> rdd3.collect()
[('a', 1), ('b', 2), ('c', 1), ('b', 3)]
>>> rdd4 = rdd3.reduceByKey(lambda a, b: a+b)
>>> rdd4.collect()
[('b', 5), ('c', 1), ('a', 1)]
>>> rdd5 = rdd4.sortByKey(ascending=False)
>>> rdd5.collect()
[('c', 1), ('b', 5), ('a', 1)]
>>> # 先调换 k,v 的位置,根据 key 排序,然后再调换 k,v 的位置
>>> rdd6 = rdd4.map(lambda x:(x[1],x[0])).sortByKey(ascending=False).map(lambda x:(x[1],x[0]))
>>> rdd6.collect()
[('b', 5), ('c', 1), ('a', 1)]
>>>
广播变量的使用
使用广播变量,可以让集群中的节点共享这个广播变量