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. ElasticSearch 实现分词全文检索 - 概述

    需求 做一个类似百度的全文搜索功能 所用的技术如下: ElasticSearch Kibana 管理界面 IK Analysis 分词器 SpringBoot ElasticSearch 简介 ES ...

  2. java学习日记20230226-java环境搭建及运行机制

    JDK安装 配置环境变量: 当执行的程序在当前目录不存在时,windows去系统path环境变量里面进行查找,如果没有找到报错不存在该命令. 我的电脑-属性-高级系统设置--环境变量 增加JAVA_H ...

  3. 图论专题 - LibreOJ

    第三部分 图论 第 1 章 最小生成树 #10064 「一本通 3.1 例 1」黑暗城堡#10065 「一本通 3.1 例 2」北极通讯网络 #10066 「一本通 3.1 练习 1」新的开始#100 ...

  4. 【剑指Offer】【树】二叉搜索树的后序遍历序列

    题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. A:在二叉树的后序遍历中,数组最后一个元素为根节点,左 ...

  5. Ubuntu docker安装、验证、卸载

    卸载Docker CE 卸载Docker CE软件包: sudo apt-get purge docker-ce 主机上的图像,容器,卷或自定义配置文件不会自动删除.要删除所有图像,容器和卷: sud ...

  6. vue常用插件集合(常用,但一般UI库又不太能满足)

    # v-base-plugins   ``` bash # install  npm i v-base-plugins --save  npm start #引入 import myPlugin fr ...

  7. C++ 中的匿名函数(lambda表达式)

    问题引入 使用std::sort函数对自定义类型排序时,我们需要传入一个比较函数作为参数.该比较函数只需要使用一次,但占有一个全局命名域中的名字,而且非常短,短到不需要名字就知道它的作用.这很浪费命名 ...

  8. 【面试题】 webpack面试篇

    1.与webpack类似的工具还有哪些?谈谈你为什么选择webpack? grunt 优点:出现的比较早,第一代打包工具 缺点:配置项太多,只有一个配置文件,而且不同的插件可能有自己的配置字段,学习成 ...

  9. 查询redis路径,清除redis缓存

    查询redis路径 1.执行ps -ef | grep redis 命令,结果如下(记住PID) 2.执行ps -u 系统用户名,进一步确定进程id, 我这里的系统用户名是root,执行ps -u r ...

  10. 压力&负载理论

    一.定义: 1.压力测试     是给软件不断加压,强制其在极限的情况下运行,观察它可以运行到何种程度,从而发现性能缺陷,是通过搭建与实际环境相似的测试环境,通过测试程序在同一时间内或某一段时间内,向 ...