RDD编程基础

RDD编程基础

1 RDD创建

1.1 从文件系统中加载数据创建RDD

Spark采用textFile()方法来从文件系统中加载数据创建RDD,该方法把文件的URI作为参数,这个URI可以是:本地文件系统的地址、分布式文件系统HDFS的地址,或者是Amazon S3的地址等等

1.1.1 从本地文件系统中加载数据创建RDD

假设存在以下目录和文件word.txt。请切换到pyspark窗口执行以下语句。

>>> lines = sc.textFile("file:///usr/local/spark/mycode/rdd/word.txt")`
>>> lines.foreach(print)
Hadoop is good
Spark is fast
Spark is better

在这里插入图片描述

1.1.2 从分布式文件系统HDFS中加载数据

下面看一下如何从HDFS文件系统中加载数据,把刚才在本地文件系统中的“/usr/local/spark/mycode/rdd/word.txt”上传到HDFS文件系统的hadoop用户目录下。然后,在pyspark窗口中,就可以使用下面任意一条命令完成从HDFS文件系统中加载数据:

>>> lines = sc.textFile("hdfs://localhost:9000/user/hadoop/word.txt")
>>> lines = sc.textFile("/user/hadoop/word.txt")
>>> lines = sc.textFile("word.txt")
1.1.3 通过并行集合(列表)创建RDD

可以调用SparkContext的parallelize方法,在Driver中一个已经存在的集合
(列表)上创建。

>>> array = [1,2,3,4,5]
>>> rdd = sc.parallelize(array)
>>> rdd.foreach(print)
1
2
3
4
5

在这里插入图片描述

2 RDD操作

2.1 转换操作

对于RDD而言,每一次转换操作都会产生不同的RDD,供给下一个“转换”使用,转换得到的RDD是惰性求值的,也就是说,整个转换过程只是记录了转换的轨迹,并不会发生真正的计算,只有遇到行动操作时,才会发生真正的计算,开始从血缘关系源头开始,进行物理的转换操作。
转换操作过程
常用的转换操作

1.2.2.行动操作

行动操作是真正触发计算的地方。Spark程序执行到行动操作时,才会执行真正的计算,从文件中加载数据,完成一次又一次转换操作,最终,完成行动操作得到结果。
在这里插入图片描述

1.2.3.惰性机制

所谓的“惰性机制”是指,整个转换过程只是记录了转换的轨迹,并不会发生真正的计算,只有遇到行动操作时,才会触发“从头到尾”的真正的计算。这里给出一段简单的语句来解释Spark的惰性机制。

>>> lines = sc.textFile("data.txt")
>>> lineLengths = lines.map(lambda s : len(s))
>>> totalLength = lineLengths.reduce( lambda a, b : a + b)

第一行从外部文件data.txt中构建得到一个RDD,名称为lines,但是,由于textFile()方法只是一个转换操作,因此,这行代码执行后,不会立即把data.txt文件加载到内存中,这时的lines只是一个指向这个文件的指针。
第二行代码用来计算每行的长度,同样,由于map()方法只是一个转换操作,这行代码执行后,不会立即计算每行的长度。
第三行代码的reduce()方法是一个“动作”类型的操作,这时,就会触发真正的计算。这时,Spark会把计算分解成多个任务在不同的机器上执行,每台机器运行位于属于它自己的map和reduce,最后把结果返回给Driver Program。

3 持久化

在Spark中,RDD采用惰性求值的机制,每次遇到行动操作,都会从头开始执行计算。每次调用行动操作,都会触发一次从头开始的计算。这对于迭代计算而言,代价是很大的,迭代计算经常需要多次重复使用同一组数据。

>>> list = ["Hadoop","Spark","Hive"]
>>> rdd = sc.parallelize(list)
>>> print(rdd.count()) # 行动操作,触发一次真正从头到尾的计算
3
>>> print(','.join(rdd.collect())) # 行动操作,触发一次真正从头到尾的计算
Hadoop,Spark,Hive

上面代码执行过程中,前后共触发了两次从头到尾的计算。可以通过持久化(缓存)机制避免这种重复计算的开销。
使用persist()方法对一个RDD标记为持久化,之所以说“标记为持久化”,是因为出现persist()语句的地方,并不会马上计算生成RDD并把它持久化,而是要等到遇到第一个行动操作触发真正计算以后,才会把计算结果进行持久化,持久化后的RDD将会被保留在计算节点的内存中被后面的行动操作重复使用。一般而言,使用cache()方法时,会调用persist(MEMORY_ONLY)。
最后,可以使用unpersist()方法手动地把持久化的RDD从缓存中移除。
针对上面的实例,增加持久化语句以后的执行过程如下

>>> list = ["Hadoop","Spark","Hive"]
>>> rdd = sc.parallelize(list)
>>> rdd.cache()  # 会调用persist(MEMORY_ONLY),但是,语句执行到这里,并不会缓存rdd,这是rdd还没有被计算生成
>>> print(rdd.count()) # 第一次行动操作,触发一次真正从头到尾的计算,这时才会执行上面的rdd.cache(),把这个rdd放到缓存中
3
>>> print(','.join(rdd.collect())) # 第二次行动操作,不需要触发从头到尾的计算,只需要重复使用上面缓存中的rdd
Hadoop,Spark,Hive

4 分区

RDD是弹性分布式数据集,通常RDD很大,会被分成很多个分区,分别保存在不同的节点上。

4.1 分区的作用

(1)增加并行度
(2)减少通信开销

4.2 RDD分区原则

原则:使分区的个数尽量等于集群中的CPU核心(core)数目。

对于不同的Spark部署模式而言(本地模式、Standalone模式、YARN模式、Mesos模式),都可以通过设置spark.default.parallelism这个参数的值,来配置默认的分区数目,一般而言:
*本地模式:默认为本地机器的CPU数目,若设置了local[N],则默认为N;
*Apache Mesos:默认的分区数为8;
*Standalone或YARN:在“集群中所有CPU核心数目总和”和“2”二者中取较大值作为默认值;

4.3 设置分区的个数

4.3.1创建RDD时手动指定分区个数

在调用textFile()和parallelize()方法的时候手动指定分区个数即可,语法格式如下:

sc.textFile(path, partitionNum)

其中,path参数用于指定要加载的文件的地址,partitionNum参数用于指定分区个数。

4.3.2 使用reparititon方法重新设置分区个数

通过转换操作得到新RDD时,直接调用repartition方法即可。

>>> data = sc.parallelize([1,2,3,4,5],2)
>>> len(data.glom().collect()) #显示data这个RDD的分区数量
2
>>> rdd = data.repartition(1)#对data这个RDD进行重新分区
>>> len(rdd.glom().collect())#显示rdd这个RDD的分区数量
1

4.4 自定义分区方法

Spark提供了自带的HashPartitioner(哈希分区)与RangePartitioner(区域分区),能够满足大多数应用场景的需求。与此同时,Spark也支持自定义分区方式,即通过提供一个自定义的分区函数来控制RDD的分区方式,从而利用领域知识进一步减少通信开销。

小结:以上是对RDD编程基础相关知识的一个汇总,以上图片和部分文字均来源于厦门大学林子雨教授所讲授的《spark编程基础(Python版)》所附课件和教案,是博主本人进行的一个总结和复习,仅用作学习用途!
Spark2.1.0+入门:RDD编程(Python版)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值