RDD弹性分布式数据集

一、什么是RDD

什么是RDD?RDD是只读的,分区记录的集合。RDD只能基于稳定物理存储中的数据集合以及其他已有的RDD上执行确定性操作来创建。这些确定性操作被称为转换(transformation),例如map、filter、groupBy、join。因此RDD并不需要物化。并且也因为这个机制使得RDD含有如何从其他RDD衍生出本RDD的相关信息(即Lineage:血统),因此在RDD部分数据分区丢失的时候可以从物理存储的数据计算出相应的RDD分区--------摘自《spark技术内幕》

       上面这段话摘自《spark技术内幕》,我认为描述的的非常简洁和准确。对此,我们有两个基本问题需要解决,RDD怎么创建?转换是什么意思?

二、RDD的创建

《spark技术内幕》中在说明创建时没有具体的样例代码,均是文字性描述,为了便于理解,这里选录了《hadoop权威指南》中有关创建RDD的部分,原文描述如下:

RDD的创建方式有三种

  1. 来自内存中的一个对象集合(也称并行化一个集合)
  2. 使用外部存储器(例如hdfs)中的数据集
  3. 对现有的RDD进行转换

第一种方法适用于对少量的输入数据进行并行的CPU密集型计算,例如下面这段代码对数字1到10运行独立运算

var params=sc.parallelize(1 to 10)
val result=params.map(performExpensiveComputation)

 performExpensiveComputation函数对输入的值并行运算,其并行度由spark.default.parallelism属性决定,默认值取决于spark作业的地点,本地运行时默认值就是内核数(core),而在集群上运行时,它是集群中executor节点的内核的总数。

可以为某个特定运算设置并行性级别,指定parallelize()方法的第二个参数即可:

sc.parallelize(1 to 10, 10)

创建RDD的第二种方式,是创建一个指向外部数据集的引用。例如以一个文本文件创建String对象的RDD:

val text:RDD[String] = sc.textFile(inputPath)

路径inputPath可以是任意的Hadoop文件系统路径,比如本地文件系统或HDFS上的一个文件。由于Spark使用了旧的MapReduce API中的TextInputFormat来读取这个文件。这就意味着文件切分行为与Hadoop是一样的,因此在HDFS的情况下,一个Spark分区对应一个HDFS块(block)。这个默认行为可以改变,传入第二个参数来请求一个特殊的切分数量:

sc.textFile(inputPath, 10)

另外一个方法允许把多个文本文件作为一个整体来处理,返回的RDD中,是成对的string,第一个string是文件的路径,第二个string是文件的内容。因为每个文件都会加载进内存,所以这种方式仅仅适合于小文件:

val files:RDD[(String, String)] = sc.wholeTextFiles(inputPath)

Spark能够处理文本文件以外的其他文件格式,比如,序列文件可以这样读入:

sc.sequenceFile[IntWritable, Text](inputPath)

注意这里指定序列文件的键和值的Writable类型的方式。对于常用的Writable类型,Spark能够映射到Java中对应的基本类型,因此我们可以使用等价的方式:

sc.sequenceFile[Int, String](inputPath)

从任意的Hadoop InputFormat来创建RDD,有两种方式:基于文件的格式,使用hadoopFile(),接收一个路径;其他格式,比如HBase的TableInputFormat,使用hadoopRDD()。这些方法使用的是旧的MapReduce API。如果要用新的MapReduce API,使用newAPIHadoopFile()和newAPIHadoopRDD()。下面是读取Avro数据文件的示例,使用特定的API和一个WeatherRecord类:

val job = new Job()
AvroJob.setInputKeySchema(job, WeatherRecord.getClassSchema)
val data = sc.newAPIHadoopFile(inputPath,
    classOf[AvroKeyInputFormat[WeatherRecord]],
    classOf[AvroKey[WeatherRecord]], classOf[NullWritable],
    job.getConfiguration)

除了路径之外,newAPIHadoopFile()方法还需要InputFormat的类型、键的类型、值的类型,再加上Hadoop配置,该配置中带有Avro的模式 schema,在第二行我们使用AvroJob帮助类做了设置。

创建RDD的第三种方式,是转换已存在的RDD。

三、RDD的转换

RDD中的所有转换都是惰性的,也就是说,他们并不会直接计算结果,相反的,他们只记住这些应用到基础数据集是哪个的转换动作。只有发生一个要求返回结果给Driver的动作时,这些转换才会真正运行。这个设计的巧妙之处在于我们不必要每个操作都在数据集上计算(往往数据集都很大),而是将某些操作延迟,在必要的时候(即发生动作时)再执行。这极大提高了spark的效率,也从侧面反映了RDD是一个逻辑集中的实体,也可以理解为是一种分布式的内存抽象。

RDD支持的转换如下所示

                          转换                                                                      含义
map(func)返回一个新的数据集,该数据集由每一个输入元素经过func函数转换而成
filter(func)返回一个新的数据集,该数据集由经过func函数计算后返回值为true的输入元素组成
flatMap(func)类似于map,但每一个输入元素可以被映射成为一个或多个输出元素
mapPartitions(func)类似于map,但独立的在RDD的每一个分片上运行,因此在类型为T的RDD上运行时,func的函数必须是Iterator[T]=>Iterator[U]

mapPartitionsWithSplit(func)

类似于mapPartitions,但func带有一个整数参数表示分片的索引值,因此在类型为T的RDD上运行时,func的函数类型必须是( Int, Iterator[T] )=>Iterator[U]
sample(withReplacement,seed)根据fraction指定的比例对数据进行采样,可以选择是否用随机种子进行替换,seed用于指定随机种子
union(otherDataset)返回一个数据集,新数据集由原数据集和参数数据集联合而成
distinct([num Tasks])返回一个原数据集中所有不重复元素的新数据集
groupByKey([num Tasks])

在一个(K,V)对的数据集上调用,返回一个(K,Seq[V])对的数据集

注意默认情况下,只有8个并行任务来做操作,但是可以传入一个可选的numTasks参数来改变它

reduceByKey([num Tasks])在一个(K,V)对的数据集上调用,返回一个(K,V)对的数据集。使用指定的reduce函数,将相同的key值聚合在一起,与groupByKey类似。reduce的任务可以传入一个可选的numTasks参数来改变它
sortByKey([ascending],[num Tasks])在一个(K,V)对的数据集上调用,K必须实现Ordered接口,返回一个按照Key进行排序的(K,V)对数据集,升序或者降序由ascending决定
join(otherDataset,[num Tasks])在类型为(K,V)和(K,W)类型的数据集上调用,返回一个相同key对应的所有元素对在一起的(K,(V,W))数据集
cogroup(otherDataset,[num Tasks])在类型为(K,V)和(K,W)类型的数据集上调用,返回一个(K,Seq(V),Seq(W))元组的数据集,这个操作也被成为groupwith
cartesian(otherDataset)

笛卡尔积,在类型为T和U的数据集上调用,返回一个(T,U)对数据集(两两的元素对)

四、RDD的动作

RDD支持的动作如下表所示

                               动作                                                                        含义
reduce(func)通过函数func(接受两个参数,返回一个参数)聚集数据集中所有元素,这个功能必须是可交换的且可关联的,从而可以正确并行执行
collect()在驱动程序中,以数组形式返回数据集所有元素,通常在使用filter或者其他操作返回一个足够小的数据子集时使用比较有用
count()返回数据集的元素个数
first()返回数据集的第一个元素(类似于take(1))
take()

返回一个由数据集前n个元素组成的数组

注意,这个操作目前并非并行执行,而是由驱动程序计算所有的元素

takeSample(withReplacement,

num,seed)

返回一个数组,该数组由从数据集中随机采样的n个元素组成,可以选择是否用随机数替换不足的部分,seed指定随机种子
saveAsTextFile(path)将数据集的元素以TextFile的形式保存到本地文件系统----HDFS或者其他任何Hadoop支持的文件系统,对于每个元素,spark会调用toString方法,将它替换为文件中的文本行
saveAsSequenceFile(path)将数据集的元素以Hadoop sequencefile的格式保存到指定的目录下,可以是本地文件系统或者其他任何Hadoop支持的文件系统,这个仅限于由(K,V)对组成,并实现了Hadoop的Writable接口,或者可以隐式的转换为Writable的RDD(spark包含了基本类型的转换,例如Int,Double,String等)
countByKey()对(K,V)类型的RDD有效,返回一个(K,Int)对的map,表示每一个key对应的元素个数
foreach(func)在数据集的每一个元素上,运行函数func进行更新,通常用于边缘效果,例如更新一个累加器,或者和外部存储系统进行交互,例如Habse
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值