Spark (Python版) 零基础学习笔记(三)—— Spark Actions总结及举例

Actions算子是Spark算子的一类,这一类算子会触发SparkContext提交job作业。下面介绍常用的Spark支持的actions。

1. reduce(func)
使用函数func(两个输入参数,返回一个值)对数据集中的元素做聚集操作。函数func必须是可交换的(我理解的就是两个参数互换位置对结果不影响),并且是相关联的,从而能够正确的进行并行计算。

>>> data = sc.parallelize(range(1,101))
>>> data.reduce(lambda x, y: x+y)
5050

2. collect()
在driver程序中以数组形式返回数据集中所有的元素。这以action通常在执行过filter或者其他操作后返回一个较小的子数据集时非常有用。

>>> data = sc.parallelize(range(1,101))
>>> data.filter(lambda x: x%10==0).collect()
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

3. count()
返回数据集中元素的个数。

>>> data.count()
100

4. first()
返回数据集中的第一个元素,相当于take(1)。

>>> data.first()
1

5. take()
以数组形式返回数据集中前n个元素。需要注意的是,这一action并不是在多个node上并行执行,而是在driver程序所在的机器上单机执行,会增大内存的压力,使用需谨慎。

>>> data.take(10)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

6. takeSample(withReplacement, num, [seed])
以数组形式返回从数据集中抽取的样本数量为num的随机样本,有替换或者无替换的进行采样。可选参数[seed]可以允许用户自己预定义随机数生成器的种子。

>>> data.takeSample(False, 20)
[60, 97, 91, 62, 48, 7, 49, 89, 40, 44, 15, 2, 33, 8, 30, 82, 87, 96, 32, 31]   
>>> data.takeSample(True, 20)
[96, 71, 20, 71, 80, 42, 70, 93, 77, 26, 14, 82, 50, 30, 30, 56, 93, 46, 70, 70]

7. takeOrdered(n, [ordering])
返回RDD的前n个元素,可以利用自然顺序或者由用户执行排序的comparator。

>>> score = [('Amy',98),('Bob',87),('David',95),('Cindy',76),('Alice',84),('Alice',33)]
>>> scoreRDD = sc.parallelize(score)
>>> scoreRDD.takeOrdered(3)
[('Alice', 33), ('Alice', 84), ('Amy', 98)]  #可以根据两个Alice的例子看到,当元祖中第一个元素相同时,会继续比较第二个元素,仍然按升序排列
>>> scoreRDD.takeOrdered(3, key=lambda x: x[1])  #按照分数升序排序
[('Alice', 33), ('Cindy', 76), ('Alice', 84)]
>>> scoreRDD.takeOrdered(3, key=lambda x: -x[1])  #按照分数降序排序
[('Amy', 98), ('David', 95), ('Bob', 87)]

注意,第2个参数这里是一个匿名函数,这个匿名函数并不会改变scoreRDD中的值,也就是第3个例子中,并不是将每个人的分数变为负数,而是提供一个排序的依据,说明此时为降序排序。如果是想要改变RDD中的值,可以进行如下操作:

>>> scoreRDD.map(lambda x: (x[0], -x[1])).takeOrdered(3, lambda x: x[1])
[('Amy', -98), ('David', -95), ('Bob', -87)]

这个例子并没有什么实际意义,只是提醒takeOrdered算子中第二个参数的作用。

8. saveAsTextFile(path)
将数据集中的元素以文本文件(或者文本文件的一个集合)的形式写入本地文件系统,或者HDFS,或者其他Hadoop支持的文件系统的指定路径path下。Spark会调用每个元素的toString方法,将其转换为文本文件中的一行。

9. saveAsSequenceFile(path)
将数据集中的元素以Hadoop SequenceFile的形式写入本地文件系统,或者HDFS,或者其他Hadoop支持的文件系统的指定路径path下。RDD的元素必须由实现了Hadoop的Writable接口的key-value键值对组成。在Scala中,也可以是隐式可以转换为Writable的键值对(Spark包括了基本类型的转换,例如Int,Double,String等等)

10. saveAsObjectFile(path)
利用Java序列化,将数据集中的元素以一种简单的形式进行写操作,并能够利用SparkContext.objectFile()加载数据。(适用于Java和Scala)

11. countByKey()
只能作用于键值对(K, V)形式的RDDs上。按照Key进行计数,返回键值对(K, int)的哈希表。

>>> score = [('Amy',98),('Bob',87),('David',95),('Cindy',76),('Alice',84),('Alice',33)]  #一组学生对应的成绩
>>> scoreRDD = sc.parallelize(score)
>>> scoreRDD.countByKey()
defaultdict(<class 'int'>, {'Cindy': 1, 'Alice': 2, 'Bob': 1, 'Amy': 1, 'David': 1})  
>>> result = scoreRDD.countByKey()
>>> type(result)  #查看返回值类型
<class 'collections.defaultdict'> 
>>> result['Alice']
2
>>> result['Sunny']
0
>>> testDict = {'Cindy': 1, 'Alice': 2, 'Bob': 1, 'Amy': 1, 'David': 1}
>>> testDict['Sunny']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'Sunny'

!!!特别注意,Pyspark中返回的是一个collections.defaultdict()类,collections是python的一个模块,是一个数据类型容器模块,需要注意defaultdict与dict还是有区别的。defaultdict是Python内建函数dict的一个子类,构建的是一个类似dictionary的对象,其中key的值是自行赋值,但是value的类型,是function_factory(工厂函数)的类实例,即使对于一个key,它的value值有缺失,也会有一个默认值。上述代码中最后的例子可以看书,虽然result和testDict中都没有key为‘Sunny’这个键值对,但是result会返回一个默认值0,而testDict就出现了KeyError的错误。关于defaultdict和dict的区别,这里就不做过多的解释,但是大家需要注意这里返回的类型并不是dict。

12. foreach(func)
在数据集的每个元素上调用函数func。这一操作通常是为了实现一些副作用,比如更新累加器或者与外部存储系统进行交互。注意:在foreach()之外修改除了累加器以外的变量可能造成一些未定义的行为。更多内容请参阅闭包进行理解。

猜你喜欢

转载自blog.csdn.net/zhangyang10d/article/details/53239404
今日推荐