RDD
RDD简介
RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是 Spark 中最基本的数据抽象,它代表一个不可变、可分区、里面的元素可并行计算的集合。RDD 具有数据流模型的特点:自动容错、位置感知性调度和可伸缩性。RDD 允许用户在执行多个查询时显式地将工作集缓存在内存中,后续的查询能够重用工作集,这极大地提升了查询速度。
RDD属性
-
一组分片(Partition),即数据集的基本组成单位。对于 RDD 来说,每个分片都会被一个计算任务处理,并决定并行计算的粒度。用户可以在创建 RDD 时指定 RDD 的分片个数,如果没有指定,那么就会采用默认值。默认值就是程序所分配到的 CPU Core 的数目。
-
一个计算每个分区的函数。Spark 中 RDD 的计算是以分片为单位的,每个 RDD 都会实现 compute 函数以达到这个目的。compute 函数会对迭代器进行复合,不需要保存每次计算的结果。
-
RDD 之间的依赖关系。RDD 的每次转换都会生成一个新的 RDD,所以 RDD 之间就会形成类似于流水线一样的前后依赖关系。在部分分区数据丢失时,Spark可以通过这个依赖关系重新计算丢失的分区数据,而不是对 RDD 的所有分区进行重新计算。
-
一个 Partitioner,即 RDD 的分片函数。当前 Spark 中实现了两种类型的分片函数,一个是基于哈希的 HashPartitioner,另外一个是基于范围的RangePartitioner。只有对于于 key-value 的 RDD,才会有Partitioner,非 key-value 的 RDD 的 Parititioner 的值是 None。Partitioner 函数不但决定了RDD本身的分片数量,也决定了 parent RDD Shuffle 输出时的分片数量。
-
一个列表,存储存取每个 Partition 的优先位置(preferred location)。对于一个 HDFS 文件来说,这个列表保存的就是每个 Partition 所在的块的位置。按照“移动数据不如移动计算”的理念,Spark 在进行任务调度的时候,会尽可能地将计算任务分配到其所要处理数据块的存储位置。
RDD在Python的API
创建RDD
参考资料1:
from pyspark import SparkContext
sc = SparkContext("local", "Simple App")
加载数据
- 通过并行集合导入:
rdd = sc.parallelize([('a',7),('a',2),('b',2)])
rdd2 = sc.parallelize([('a',2),('d',1),('b',1)])
rdd3 = sc.parallelize(range(10))
rdd4 = sc.parallelize([('a',['x','y','z']),
('b',['p','r'])])
- 导入外部数据:
- 从本地或 HDFS 读取一个文本文件:textFile
- 读取一个文件的路径:wholeTextFiles
textFile = sc.textFile("my/directory/*.txt")
textFile2 = sc.wholeTextFiles("my/directory/")
获取RDD信息
基本信息
- 列出 RDD 分区数:
rdd.getNumPartitions()
返回值默认是 2,如果在导入并行集合数据时标明分区,例如:
rdd = sc.parallelize([('a',7),('a',2),('b',2)], 3)
则 getNumPartitions
函数返回的值即为设定值 3.
- 计算 RDD 样本个数:
rdd.count()
返回值为 3.
- 通过 key 计算 RDD 样本个数:
rdd.countByKey()
RDD 的元素若是一个 tuple 形式 (a,b) 存在,则 a 为 key,b 为 value.
上述代码返回值为一个 dictionary 格式:
defaultdict(<type 'int'>, {
'a': 2, 'b': 1})
通过 items()
可以得到 list 返回格式,list 中每个元素为 (key, count) 的 tuple 的形式:
rdd.countByKey().items()
上述代码返回值为:
[('a', 2), ('b', 1)]
- 通过 Value 计算 RDD 样本个数:
rdd.countByValue()
上述代码返回值为:
defaultdict(<type 'int'>, {
('b', 2): 1, ('a', 2): 1, ('a', 7): 1})
⚠️:这边按照 countByValue()
中的 value 不是指按照 tuple 中的 value 来计数,而是把整个 tuple 当作一个 value 来统计计数。
- 返回一个 key-values 数对给主机:
rdd.collectAsMap()
{
'a': 2, 'b': 2}
这边有点难以解释 'a': 2
,如果将 rdd 改成:
rdd = sc.parallelize([('a',2),('a',7),('b',2)])
rdd.collectAsMap()
上述代码返回值为:
{
'a': 7, 'b': 2}
从以上两个结果可以看出,collectAsMap()
返回的是 key 对应的 value 是 RDD 里最新的一个值(譬如说,rdd = sc.parallelize([('a',2),('a',7),('b',2)])
中的 ‘a’ 一开始指代的是 2,然后又被 7 覆盖,因此 ‘a’ 最终指的是 7)。
- RDD的元素求和:
rdd3.sum()
上述代码返回值为:
4950
- 判断RDD是否为空:
例如:
rdd.isEmpty()