键值对RDD是Spark中许多操作所需要的常见数据类型,被称为pairRDD,提供了并行操作各个键或者跨界点重新进行数据分组的操作接口。
创建PairRDD
1.使用map()函数将普通RDD转换为PairRDD。
lines=sc.parallelize(["pandas","i like pandas"])
pairs = line.map(lambda x:(x[0],x))
PairRDD转化操作
以键值对{(1,2),(3,4),(3,6)}为例
函数名 | 目的 | 示例 | 结果 |
---|---|---|---|
reduceByKey(func) | 合并具有相同键的值 | rdd.reduceByKey(lambda x,y: x+y) | {(1,2),(3,10)} |
groupByKey() | 按照键对RDD进行分组 | rdd.groupByKey() | {(1,[2]),(3,[4,6])} |
comBinByKey() | 使用不同的返回类型合并具有相同键的值 | 示例见下 | |
mapValues(func) | 对pair的每一个值应用一个函数而不改变键值 | rdd.mapValues(lambda x:x+1) | {(1,3),(3,5),(3,7)} |
flatMapValues(func) | 对pair的每一个值应用一个迭代器行数,然后对返回的每一个元素都生成对用原值键值对记录 | rdd.flatMapValues(lambda x: (3,5)) | {(1,3),(1,5),(3,3),(3,5),(3,3),(3,5)} |
keys() | 返回一个包含所有键的RDD | rdd.keys() | {1,3,3} |
values() | 返回一个包含所有值的RDD | rdd.values() | {2,4,6} |
sortByKey() | 返回一个根据键值排序的RDD | rdd.sortByKey() | {(1,2),(3,4),(3,6)} |
以键值对{(1,2),(3,4),(3,6)}和other={(3,9)}为例
函数名 | 目的 | 示例 | 结果 |
---|---|---|---|
subtractByKey | 删除pair中键与other rdd键相同的元素 | rdd.subtractByKey(other) | {(1,2)} |
join | 对两个rdd进行内连接 | rdd.join(other) | {(3,(4,9)),(3,(6,9))} |
rightOuterJoin | 右外连接 | rdd.rightOuterJoin(other) | {(3,(4,9)),(3,(6,9))} |
leftOuterJoin | 左外连接 | rdd.leftOuterJoin(other) | {(1,(2,none))(3,(4,9)),(3,(6,9))} |
cogroup | 将两个RDD中拥有相同键的数据分组到一起 | rdd.cogroup(other) | {(1,([2],[])),(3,([4,6],[9]))} |
同时pairrdd也支持普通RDD所支持的函数,传送门,例如
#对值进行筛选
result = pair.filter(lambda x:len(x)>20)
聚合操作
pair RDD提供的针对键的转化操作,类似以基础RDD的fold(),combine(),reduce()等行动操作。
reducceByKey()
#计算键对应的平均值
rdd.mapValues(lambda x :(x,1)),reduceByKey(lambda x,y:(x[0]+y[0],x[1]+y[1]))
foldByKey()
类似于上一个,但需要初始值
combineByKey()
combinByKey()会遍历所有分区中的元素,包含3个过程:
- 如果是一个新的元素,使用createCombiner()函数创建该键对应的累加器的初始值,这一过程在每一个分区都发生。
- 如果是已经遇到的键,使用mergeValue()方法将该键对应的累加器的当前值于新的值进行合并
- 因为每个分区都是独立进行处理的,同一个键可能有多个累加器,所以需要使用用户提供的mergeCombiner()方法将各个分区的结果进行合并。
sumCount = num.combineByKey((lambda x: (x,1),
(lambda x,y: (x[0]+y,x[1]+1)),
(lambda x,y: (x[0]+y[0],x[1]+y[1]))))
并行度调优
spark始终尝试根据集群大小来推断出一个有意义的默认值来确认分区数,但是有时需要我们主动调优。
data = [('a',3),('b',4),('a',1)]
sc.parallelize(data).reduceByKey(lambda x,y: x +y ) # 默认
sc.parallelize(data).reduceByKey(lambda x,y: x +y, 10) # 自定义并行度
数据分组
groupByKey() 对当个RDD进行分组结果为 [(k,[V])]
cogroup() 对多个rdd进行分组结果为[(K,([V1],[V2]))]
连接
见上表
数据排序
sortByKey() 使用参数ascending来选择正序还是倒序。
行动操作
以键值对{(1,2),(3,4),(3,6)}为例
函数名 | 目的 | 示例 | 结果 |
---|---|---|---|
countByKey() | 对键进行统计 | rdd.countByKey() | {(1,1),(3,2)} |
collectAsMap() | 将结果以映射表的形式返回,以便于查询 | rdd.collectAsMap() | map{(1,2),(3,6)} |
lookup(key) | 返回对应键的所有值 | rdd.lookup(1) | [2] |
数据分区
对数据集在节点间的分区进行控制,在分布式程序中节点之间的通信代价很大。