spark编程模型(四)之RDD创建操作(Creation Operation)

Spark 主要以一个 弹性分布式数据集(RDD)的概念为中心,它是一个容错且可以执行并行操作的元素的集合。有两种方法可以创建 RDD :

(1)在你的 driver program(驱动程序)中 parallelizing 一个已存在Scala的集合,

(2)在外部存储系统中引用一个数据集,例如,一个共享文件系统,HDFSHBase,或者提供 Hadoop InputFormat 的任何数据源。

并行化集合创建操作

并行化集合是通过调用SparkContextparallelize方法,在一个已经存在的Scala集合上创建的一个Seq对象。集合的对象就会被复制,创建出一个可以被并行操作的分布式数据集。

SparkContext类中实现了parallelizemakeRDD两个并行化集合创建操作

parallelize()

(a) def parallelize[T: ClassTag](seq: Seq[T],numSlices: Int = defaultParallelism): RDD[T]

  • seq参数为已经存在的scala集合

  • numSlices参数为RDD的分区数,默认根据您的群集情况来自动的设置的分区的数量

使用parallelize操作并行化1~5的数据集,未指定分区数,由于运行的Spark集群只有一个Worker节点,存在一个Executor,所以生成的RDD只有一个分区

scala> val data = Array(1, 2, 3, 4, 5)
data: Array[Int] = Array(1, 2, 3, 4, 5)

scala> val distData = sc.parallelize(data)
distData: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[6] at parallelize at <console>:26

scala> distData.collect
res7: Array[Int] = Array(1, 2, 3, 4, 5)

scala> distData.partitions.size
res8: Int = 1

显式地设置RDD的分区数为4个:

scala> val distData = sc.parallelize(data, 4)
distData: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[7] at parallelize at <console>:26

scala> distData.collect
res9: Array[Int] = Array(1, 2, 3, 4, 5)

scala> distData.partitions.size
res11: Int = 4
makeRDD()

(a) def makeRDD[T: ClassTag](seq: Seq[T],numSlices: Int = defaultParallelism): RDD[T]

该方法用法和parallelize一样

(b) def makeRDD[T: ClassTag](seq: Seq[(T, Seq[String])]): RDD[T]

用法和parallelize类似,不过该方法可以指定每一个分区的首选位置(preferredLocations)

scala> var collect = Seq((1 to 5,Seq("slave1","slave2")),
(6 to 10,Seq("slave3","slave4")))
collect: Seq[(scala.collection.immutable.Range.Inclusive, Seq[String])] = List((Range(1, 2, 3, 4, 5,),List(slave1, slave2)), (Range(6, 7, 8, 9, 10),List(slave3, slave4)))
 
scala> var rdd = sc.makeRDD(collect)
rdd: org.apache.spark.rdd.RDD[scala.collection.immutable.Range.Inclusive] = ParallelCollectionRDD[6] at makeRDD at :23
 
scala> rdd.partitions.size
res33: Int = 2
 
scala> rdd.preferredLocations(rdd.partitions(0))
res34: Seq[String] = List(slave1, slave2)
 
scala> rdd.preferredLocations(rdd.partitions(1))
res35: Seq[String] = List(slave3, slave4)

外部存储创建操作

Spark 可以从 Hadoop 所支持的任何存储源中创建 distributed dataset(分布式数据集),包括本地文件系统,HDFS,Cassandra,HBase,Amazon S3 等等。 Spark 支持文本文件SequenceFiles,以及任何其它的 Hadoop InputFormat

textFile()

def textFile(path: String, minPartitions: Int = defaultMinPartitions): RDD[String]

可以使用 SparkContexttextFile 方法来创建文本文件RDD。此方法需要一个文件的 URI(计算机上的本地路径 ,hdfs://,s3n:// 等等的 URI),并且读取它们作为一个 lines(行)的集合

val distFile = sc.textFile("data.txt")
distFile.map(s => s.length).reduce((a, b) => a + b)

注意:

(1)如果使用本地文件系统的路径,所工作节点的相同访问路径下该文件必须可以访问。复制文件到所有工作节点上,或着使用共享的网络挂载文件系统

(2)所有 Spark 基于文件的 input 方法, 包括 textFile, 支持在目录上运行, 压缩文件, 和通配符. 例如, 您可以使用 textFile("/my/directory"), textFile("/my/directory/*.txt"), and textFile("/my/directory/*.gz")

(3)textFile方法也可以通过第二个可选的参数来控制该文件的分区数量. 默认情况下, Spark 为文件的每一个 block(块)创建的一 个 partition 分区(HDFS 中块大小默认是 128MB),当然你也可以通过传递一个较大的值来要求一个较高的分区数量。请注意,分区的数量不能够小于块的数量


SparkContext.wholeTextFiles 可以读取包含多个小文本文件的目录, 并且将它们作为一个 (filename, content) pairs 来返回. 这与 textFile 相比, 它的每一个文件中的每一行将返回一个记录. 分区由数据量来确定, 某些情况下, 可能导致分区太少. 针对这些情况, wholeTextFiles 在第二个位置提供了一个可选的参数用户控制分区的最小数量

针对 SequenceFiles, 使用 SparkContextsequenceFile[K, V] 方法,其中 KV 指的是文件中 keyvalues 的类型. 这些应该是 Hadoop 的 Writable 接口的子类, 像 IntWritableText. 此外, Spark 可以让您为一些常见的 Writables 指定原生类型; 例如, sequenceFile[Int, String] 会自动读取 IntWritablesTexts

针对其它的 Hadoop InputFormats, 您可以使用 SparkContext.hadoopRDD 方法, 它接受一个任意的 JobConf input format class, key classvalue class. 通过相同的方法你可以设置你的 input source(输入源). 你还可以针对InputFormats使用基于 new MapReduce API (org.apache.hadoop.mapreduce) SparkContext.newAPIHadoopRDD

RDD.saveAsObjectFileSparkContext.objectFile 支持使用简单的序列化的 Java objects 来保存 RDD. 虽然这不像 Avro 这种专用的格式一样高效,但其提供了一种更简单的方式来保存任何的 RDD
posted @ 2018-08-11 01:19  oldsix666  阅读(482)  评论(0编辑  收藏  举报