pySpark RDD基本用法

RDD的全称是:Resilient Distributed Dataset (弹性分布式数据集),它有几个关键的特性:

RDD是只读的,表示它的不可变性。

可以并行的操作分区集合上的所有元素。

每个RDD的内部,有5个主要特性:

  • A list of partitions (一个分区列表,可以获取所有的数据分区)
  • A function for computing each split(对给定的分区内的数据进行计算的function)
  • A list of dependencies on other RDDs (一个RDD所依赖的父RDD列表)
  • Optionally, a Partitioner for key-value RDDs (可选:如何进行K-V的RDD分区)
  • Optionally, a list of preferred locations to compute each split on(可选:数据做运算时最优的地址,即数据本地性)

1.RDD的三种基本运算

  • Transformation(转换)

    概念:

    将一个RDD通过一系列操作变为另一个RDD的过程,这个操作可能是简单的加减操作,也可能是某个函数或某一系列函数。

注:所有Transformation函数都是Lazy(惰性的),不会立即执行,需要Action函数来触发

Transformation操作不会触发真正的计算,只会建立RDD的关系图

  • Action(动作)

    概念:

    Action操作代表依次计算的结束,返回值不是RDD,将结果返回到Driver程序或输出到外部(文件或文件夹)。

注:所有Action函数立即执行(Eager),比如reduce、saveAsTextFile、count等。

所以Transformation只是建立计算关系,Action才是实际的执行者。

每个Action操作都会形成一个DAG调用SparkCoutext的runJob方法向集群提交请求,所以每个Action操作都对应一个DAG/Job。

  • Persisitence(持久化)

    概念:

    Persisitence操作对于那些会重复使用的 RDD,可以将RDD"持久化"在内存中以供后续使用,以提高执行性能。

注:持久化算子有三种,cache,persist,checkpoint,以上算子都可以将RDD持久化,持久化的单位是partition。cache和persist都是懒执行的。必须有一个action类算子触发执行。checkpoint算子不仅能将RDD持久化到磁盘,还能切断RDD之间的依赖关系。

2 常用算子使用实例

python中将数据抽象成4大数据结构,分别是tuple,list,dict,set。再粗分下,又可以分成list和k-v两种数据结构。针对这两种数据机构,spark中都有相应的算子。

初始化pyspark代码:

  import time
import argparse from pyspark import SparkContext, SparkConf
from pyspark.sql.dataframe import DataFrame
from pyspark.sql.session import SparkSession
import json from pyspark.sql import HiveContext
from pyspark.sql import SQLContext sparkconf = SparkConf().setAppName("Python Spark2").set("spark.ui.showConsoleProgress", "false")\
.set("spark.serializer","org.apache.spark.serializer.KryoSerializer")\
.set("hive.exec.dynamici.partition",True)\
.set("hive.exec.dynamic.partition.mode","nonstrict") spark = SparkSession.builder.config(conf=sparkconf).enableHiveSupport().getOrCreate()
sc = spark.sparkContext

2.1基本RDD运算

2.1.1初始函数

使用parallelize函数初始化一个rdd:

  intRDD = sc.parallelize([1,2,3,4,5,6])
intRDD.collect()
:[1, 2, 3, 4, 5, 6]

parallelize,本意是平行化的意思,使数据生成于各个计算节点,用于并行计算的意思。还可以使用直接读txt文件的方式来:

  rdd = sc.textFile(file,3)

2.1.2 map函数

再使用map函数,对各个节点做相应的运算。map函数可以遍历所有的节点,生成另外一个RDD。

  intRDD.map(lambda x:x+1).collect()
:[2, 3, 4, 5, 6, 7]

2.1.3 filter函数

filter函数可以对RDD内的元素进行筛选,并产生新的RDD。

  intRDD.filter(lambda x:x>4).collect()
:[5, 6]

2.1.4 distinct函数

distinct函数对RDD内的元素进行去重复操作。并不产生新的RDD。

  intRDD = sc.parallelize([1,2,3,4,5,6,6])
intRDD.distinct().collect()
:[1, 2, 3, 4, 5, 6]

2.1.5 groupby运算

groupby运算可以通过匿名函数将数据分为多个List。

  intRDD = sc.parallelize([1,2,3,4,5,6,6])
gRDD = intRDD.groupBy(lambda x: "big" if(x>4) else "small").collect()
print(gRDD)
:[('big', <pyspark.resultiterable.ResultIterable object at 0x7f1970214640>), ('small', <pyspark.resultiterable.ResultIterable object at 0x7f1951f15ee0>)]
print(list(gRDD[0][1]))
:[5, 6, 6]

2.2 多个RDD"转换"运算

RDD支持求并集,交集,差集和笛卡尔积运算。

  intRDD1 = sc.parallelize([1,2])
intRDD2 = sc.parallelize([3,4,5])
intRDD3 = sc.parallelize([5,6,6])
intRDD4 = intRDD1.union(intRDD2).union(intRDD3).collect() #并集
print(intRDD4)
:[1, 2, 3, 4, 5, 5, 6, 6] intRDD5 = intRDD2.intersection(intRDD3).collect()#交集
print(intRDD5)
:[5] intRDD6 = intRDD2.subtract(intRDD3).collect()#差集
print(intRDD6)
:[3, 4] intRDD7 = intRDD1.cartesian(intRDD3).collect()#笛卡尔积
print(intRDD7)
:[(1, 5), (1, 6), (1, 6), (2, 5), (2, 6), (2, 6)]

2.3 基本的action运算

2.3.1 读取运算

  intRDD = sc.parallelize([1,2,3,4,5,6,6])
print(intRDD.take(1))
print(intRDD.first())
print(intRDD.takeOrdered(3))
print(intRDD.takeOrdered(3,lambda x:-x)) :[1]
:1
:[1, 2, 3]
:[6, 6, 5]

2.3.2 统计功能

  print(intRDD.stats())
:(count: 7, mean: 3.857142857142857, stdev: 1.8070158058105026, max: 6.0, min: 1.0)

2.4基本K-V RDD运算

Spark RDD 支持键值(K-V)运算,K-V运算也是Map/Reduce的基础。

2.4.1 同样的初始化方法

  intRDD = sc.parallelize([(1,2),(3,2),(4,5)])
intRDD.collect()
:[(1,2),(3,2),(4,5)]

2.4.2 filter函数

filter算子的入参是tuple,可以用x[0]和x[1]区分两个值。

  intRDD = sc.parallelize([(1,2),(3,2),(4,5)])
intRDD.filter(lambda x:x[0] > 3).collect()
:[(4, 5)]

2.4.3 mapValues函数

需要注意的是mapValues的入参是value,返回值也是value。

  intRDD = sc.parallelize([(1,2),(3,2),(4,5)])
intRDD.mapValues(lambda x:x+1).collect()
:[(1, 3), (3, 3), (4, 6)]

2.4.4 sortByKey函数

通过key值来做排序

  intRDD = sc.parallelize([(1,2),(3,2),(4,5)])
intRDD.sortByKey().collect()
intRDD.sortByKey(ascending = False).collect() :[(1, 3), (3, 3), (4, 6)]
:[(4, 5), (3, 2), (1, 2)]

2.4.5 reduceByKey函数

通过key来归纳数据

  intRDD = sc.parallelize([(1,2),(3,2),(4,5),(1,6)])
intRDD.reduceByKey(lambda x,y:x+y)
intRDD.collect()
:[(1,8),(3,2),(4,5)]

2.5 多个 K-V RDD运算

2.5.1 join运算

创建两个RDD通过join做运算拼接

  intRDD1 = sc.parallelize([(1,2),(3,2),(4,5),(1,6)])
intRDD2 = sc.parallelize([(1,2)])
intRDD1.join(intRDD2).collect()
:[(1, (2, 2)), (1, (6, 2))]

默认的join运算是通过intRDD1.key=intRDD2.key做运算的,生成一个新的RDD,key值不变,value值为tuple类型,做值得聚合。

2.5.2 leftOuterJoin运算

创建两个RDD通过leftOuterJoin做运算拼接

  intRDD1 = sc.parallelize([(1,2),(3,2),(4,5),(1,6)])
intRDD2 = sc.parallelize([(1,2)])
intRDD1.leftOuterJoin(intRDD2).collect()
:[(1, (2, 2)), (1, (6, 2)), (3, (2, None)), (4, (5, None))]

leftOuterJoin运算是通过intRDD1的key做left join运算的,生成一个新的RDD,key值为intRDD1的key,value值为tuple类型,做值的聚合。

2.5.3 rightOuterJoin运算

创建两个RDD通过rightOuterJoin做运算拼接

  intRDD1 = sc.parallelize([(1,2),(3,2),(4,5),(1,6)])
intRDD2 = sc.parallelize([(1,2)])
intRDD1.rightOuterJoin(intRDD2).collect()
[(1, (2, 2)), (1, (6, 2))]

rightOuterJoin运算是通过intRDD2的key做right join运算的,生成一个新的RDD,key值为intRDD2的key,value值为tuple类型,做值的聚合。

2.5.4 subtractByKey运算

subtractByKey会清理掉key相同的值:

  intRDD1 = sc.parallelize([(1,2),(3,2),(4,5),(1,6)])
intRDD2 = sc.parallelize([(1,9)])
intRDD1.subtractByKey(intRDD2).collect()
:[(3, 2), (4, 5)]

2.6 K-V 的 action 运算

K-V 的RDD同样支持first等运算,但是也支持一些只有K-V情况下的值。

2.6.1 collectAsMap 运算

可以将输出的值转换成map,但是需要注意的是会将key重复的值抹掉。

  intRDD1 = sc.parallelize([(1,2),(3,2),(4,5),(1,6)])
print(intRDD1.collectAsMap())
:{1: 6, 3: 2, 4: 5}

2.6.2 lookup 运算

通过key值查找对应的value值:

  intRDD1 = sc.parallelize([(1,2),(3,2),(4,5),(1,6)])
print(intRDD1.lookup(1))
:[2, 6]

2.7 RDD持久化

如果我们相对一个RDD进行复用操作的时候,基于RDD的特性,当以rdd通过transformation转化为另外一个rdd的时候,前面的rdd就会被自动释放,此时还想在原来的rdd身上进行其它操作,需要从源头进行数据计算,这样效率自然会降低。为了能够在rdd重用的时候,直接从内存中加载相关数据,所以我们需要缓存算子(persist/cache)将rdd数据持久化到内存等等其它地方。

  • MEMORY_ONLY RDD中所有的数据都会以未经序列化的java对象的格式优先存储在内存中,如果内存不够,剩下的数据不会进行持久化。很容易出OOM=OutOfMemoryException异常。java的gc频率和对象个数成正比。gc的时候会stop-the-world。

  • MEMORY_ONLY_SER 和MEMORY_ONLY的操作几乎一致,唯一的区别是在内存中存储的不在是未经序列化的java对象,是序列化之后的数据,rdd经过序列化之后,每一个partition就只有一个字节数组,也就是说一个partition就是一个java对象。

  • MEMORY_AND_DISK 和MEMORY_ONLY的唯一区别在于,MEMORY_ONLY不会持久化哪些在内存中持久化的数据,MEMORY_AND_DISK会将哪些在内存中保存不下的数据保存到磁盘中。

  • MEMORY_AND_DISK_SER 就比MEMORY_AND_DISK多了一点,存储的是序列化的java对象

  • DISK_ONLY 磁盘存储,效率太低,一般不用XXXXX_2(MEMORY_ONLY_2等等) 是在上述所有操作的基础之上进行了一个备份。从安全、高可用的角度上考虑,如果备份所消耗的时间,比数据丢失之后从源头重新计算一遍的代价小,我们才考虑使用Xxxx_2。

  • OFF_HEAP 非堆。上述所有的操作都会使用Spark自身的内存资源,所以为了给计算提供足够的资源,可以将持久化的数据保存到非executor中。常见的OFF_HEAP:Tachyon/Alluxio

    from pyspark import StorageLevel
    intRDD1.persist(storageLevel=StorageLevel.MEMORY_ONLY)
    intRDD1.unpersist()

pySpark RDD基本用法的更多相关文章

  1. Spark核心类:弹性分布式数据集RDD及其转换和操作pyspark.RDD

    http://blog.csdn.net/pipisorry/article/details/53257188 弹性分布式数据集RDD(Resilient Distributed Dataset) 术 ...

  2. [PySpark] RDD programming on a large file

    重难点 一.parallelize 方法 一般来说,Spark会尝试根据集群的状况,来自动设定slices的数目.然而,你也可以通过传递给parallelize的第二个参数来进行手动设置. data_ ...

  3. [Pyspark]RDD常用方法总结

    aggregate(zeroValue, seqOp, combOp) 入参: zeroValue表示一组初值 Tuple seqOp表示在各个分区partition中进行 什么样的聚合操作,支持不同 ...

  4. Cheat Sheet pyspark RDD(PySpark 速查表)

  5. PySpark Rdd Cheat Sheet Python

  6. pyspark学习笔记

    记录一些pyspark常用的用法,用到的就会加进来 pyspark指定分区个数 通过spark指定最终存储文件的个数,以解决例如小文件的问题,比hive方便,直观 有两种方法,repartition, ...

  7. PySpark 大数据处理

    本文主要介绍Spark的一些基本算子,PySpark及Spark SQL 的使用方法. 虽然我从2014年就开始接触Spark,但几年来一直没有真正地学以致用,时间一久便忘了如何使用,直到在工作中用到 ...

  8. [Spark][python]RDD的collect 作用是什么?

    [Spark][Python]sortByKey 例子的继续 RDD的collect() 作用是什么? “[Spark][Python]sortByKey 例子”的继续 In [20]: mydata ...

  9. [Dynamic Language] pyspark Python3.7环境设置 及py4j.protocol.Py4JJavaError: An error occurred while calling z:org.apache.spark.api.python.PythonRDD.collectAndServe解决!

    pyspark Python3.7环境设置 及py4j.protocol.Py4JJavaError: An error occurred while calling z:org.apache.spa ...

  10. Spark算子与RDD基本转换

    map 将一个RDD中的每个数据项,通过map中的函数映射变为一个新的元素. 输入分区与输出分区一对一,即:有多少个输入分区,就有多少个输出分区. flatMap 属于Transformation算子 ...

随机推荐

  1. pat乙级:模拟链表问题(汇总,包含所有pat中链表题目分析)

    更新:优化文章结构,增加了部分内容如(1110区块反转)和自己代码和他人代码分析.看完你就懂了 转载请注明出处和链接地址:(https://www.cnblogs.com/ahappyfool/p/1 ...

  2. 【转载】docker swarm集群中部署traefik和其他服务

    以下配置来自:https://blog.csdn.net/wave_sheep/article/details/104186192 感谢作者! traefik.yaml version: '3' se ...

  3. WPF里面触发器

    WPF中有种叫做触发器的东西(记住不是数据库的trigger哦).它的主要作用是根据trigger的不同条件来自动更改外观属性,或者执行动画等操作. WPFtrigger的主要类型有:Trigger. ...

  4. vue中vue2-google-maps使用谷歌地图的基础操作

    小哥我最近使用谷歌地图做了一个项目,于是乎各种坑就扑面而来,未免下次接着踩坑特留下自己的爬坑记录. 首先我是没用过谷歌地图也不知道靠谱不靠谱,于是乎傻傻的入坑了, 1.首先你要是没有vpn(或者fq工 ...

  5. LeetCode(Java版)

    两数之和 题目描述 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数. 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用. 示例: 给定 nums = [2, 7, 11, 15 ...

  6. iPhone添加节假日日历地址

    添加苹果节假日日历地址 手动订阅节假日: 打开"设置">"日历">"帐户">"添加帐户">&qu ...

  7. vue项目,本地启动时,请求地址会自动加上http://localhost:

    wepack设置时,使用代理 devServer: { hot: true, host: '0.0.0.0', port: "2023", // 项目启动端口, 默认8080 // ...

  8. mysql 获取当月所有日期列表

    select date from (SELECT DATE_FORMAT(DATE_SUB(last_day(curdate()), INTERVAL xc-1 day), '%Y-%m-%d') a ...

  9. Qt ui_xxx.h no file or directory

    今天是2023年1.19,22号就过年了,先祝大家新年快乐! 首先经过这几天的研究,出现这个问题,提示其实已经很明显了,就是没找到文件,那么为什么没找到文件呢?基本上就是编译的时候没有找到相应的文件, ...

  10. js判断数组的方法

    1.实例的__proto__ 属性 非标准ie浏览器不支持 let arr = [1,2,3]; console.log('__proto__',arr.__proto__ === Array.pro ...