spark键值对操作(一)

来源:互联网 发布:代备案域名30元 编辑:程序博客网 时间:2024/05/29 10:10

键值对RDD也叫做Pair RDD

1. 创建Pair RDD

把一个普通 RDD转换为pair RDD的时候使用map()函数来实现

#使用第一个单词作为一个键,创建一个pair RDDpairs=lines.map(lambda x:(x.split(" ")[0],x))

2.Pair RDD转化操作

2.1针对单个pairRDD的转换操作

reduceByKey(func)
合并具有相同键的值

rdd.reduceByKey((x, y) => x + y)

groupByKey()
对具有相同键的值进行分组

rdd.groupByKey()

生成的数据示例如下
{
(1,[2]),
(5,[1,5,8]),
(7,[6,7,8])
}

combineByKey(createCombiner,mergeValue,mergeCombiners,partitioner)

使用不同的返回类型合并具有相同键的值

mapValues(func)
对pair RDD 中的每个值应用一个函数而不改变键

rdd.mapValues(x => x+1)

flatMapValues(func)
对pair RDD 中的每个值应用一个返回迭代器的函数,然后对返回的每个元素都生成一个对应原键的键值对记录。通常用于符号化

val a = sc.parallelize(List(("fruit", "apple,banana,pear"), ("animal", "pig,cat,dog,tiger")))a.flatMapValues(_.split(",")).collect()Array[(String, String)] = Array((fruit,apple), (fruit,banana), (fruit,pear),     (animal,pig), (animal,cat), (animal,dog), (animal,tiger))

keys()
返回一个仅包含键的RDD

values()
返回一个仅包含值的RDD

sortByKey()
返回一个根据键排序的RDD
函数接受一个ascending参数,表示是否按升序排序,默认是true
也可以自定义排序顺序

#比如虽然rdd是整数,但是利用字符串排序rdd.sortByKey(ascending=True, numPartitions=None, keyfunc = lambda x: str(x))

2.2针对两个pairRDD转换操作

操作的两个键
(rdd = {(1, 2), (3, 4), (3, 6)}other = {(3, 9)})

subtractByKey
删掉RDD 中键与other RDD 中的键相同的元素

rdd.subtractByKey(other)

结果 {(1, 2)}

join
对两个RDD 进行内联结
普通的join操作符表示内连接,只有在两个pair RDD都存在键时才输出。当一个输入对应的键有多个值时,生成的pair RDD会包括来自两个输入RDD的每一组相对应的记录

rdd.join(other)

结果
{(3, (4, 9)), (3,(6, 9))}

rightOuterJoin
对两个RDD 进行连接操作,确保第二个RDD 的键必须存在(右外连接)

leftOuterJoin
对两个RDD 进行连接操作,确保第一个RDD 的键必须存在(左外连接)

var rdd1 = sc.makeRDD(Array(("A","1"),("B","2"),("C","3")),2)var rdd2 = sc.makeRDD(Array(("A","a"),("C","c"),("D","d")),2)rdd1.rightOuterJoin(rdd2).collect

结果
Array[(String, (Option[String], String))] = Array((D,(None,d)), (A,(Some(1),a)), (C,(Some(3),c)))

cogroup
将两个RDD 中拥有相同键的数据分组到一起

rdd.cogroup(other)

结果
{(1,([2],[])), (3,([4, 6],[9]))}

2.1.聚合操作

reduceByKey()
reduceByKey()与reduce()类似,reduceByKey() 会为数据集中的每个键进行并行的归约操作,每个归约操作会将键相同的值合并起来

foldByKey()
与fold() 一样,foldByKey() 操作所使用的合并函数对零值与另一个元素进行合并,结果仍为该元素。

rdd.mapValues(lambda x: (x, 1)).reduceByKey(lambda x, y: (x[0] + y[0], x[1] + y[1]))
#利用reduceByKey实现单词计数sc = SparkContext("local","test")rdd=sc.textFile("file:///G:/Reference/source/spark/text.txt")words=rdd.flatMap(lambda x:x.split(" "))print(words.map(lambda x:(x,1)).take(5))result=words.map(lambda x:(x,1)).reduceByKey(lambda x,y:x+y)#也可以利用words.countByValue()直接进行单词计数

combineByKey()

#完整的函数定义def combineByKey(self, createCombiner, mergeValue, mergeCombiners,                     numPartitions=None, partitionFunc=portable_hash):

combineByKey() 会遍历分区中的所有元素,每个元素的键要么还没有遇到过,要么就和之前的某个元素的键相同。遇到新元素时,combineByKey() 会使用一个叫作createCombiner() 的函数来创建那个键对应的累加器的初始值,如果这是一个在处理当前分区之前已经遇到的键,它会使用mergeValue() 方法将该键的累加器对应的当前值与这个新的值进行合并,如果有多个分区,需要使用mergeCombiners()将各个分区结果合并

#利用combineByKey()求平均值#第一个匿名函数用于生产累加器,第二个匿名函数则处理已有累加器key的value,第三个则用于处理跨分区sumCount = nums.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])))sumCount.map(lambda key, xy: (key, xy[0]/xy[1])).collectAsMap()

这里写图片描述

spark中很多函数都是都是在combineByKey()基础上实现的

也可以为RDD指定分区数进行调优

data = [("a", 3), ("b", 4), ("a", 1)]sc.parallelize(data).reduceByKey(lambda x, y: x + y, 10)

也可以使用repartition()或者coalesce()在除分组操作和聚合操作之外也能改变分区,coalesce()是repartition()优化版

2.2数据分组

groupByKey()
使用RDD 中的键来对数据进行
分组。对于一个由类型K 的键和类型V 的值组成的RDD,所得到的结果RDD 类型会是[K, Iterable[V]]。

groupBy()
用于未成对数据上,可以根据除键以外的条件分组,它可以接收一个函数,对源RDD中的每个元素使用该函数将返回结果作为键再进行分组

cogroup()
对多个共享同一个键的RDD 进行分组,如果键值不是同一种类型则生成如下的的RDD

[(K, (Iterable[V], Iterable[W]))]

3.Pair RDD行动操作

countByKey()
对每个键对应的元素分别计数

collectAsMap()
将结果以映射表的形式返回,以便查询

lookup(key)
返回给定键对应的所有值