Spark之RDD

目录

概述

一、RDD创建

Parallelized Collections

External Datasets

二、RDD操作

Transformations

Actions

三、RDD持久化


概述

在较高级别上,每个Spark应用程序都包含一个驱动程序,该程序运行在用户main函数中并且在集群上执行各种并行操作。Spark提供最主要的抽象是弹性分布式数据集(RDD),它是跨集群节点分割元素的集合,能并行操作。通过Hadoop文件系统(或者任何其他的Hadoop支持的文件系统),或者在驱动程序中已经存在的Scala集合开始并转换创建RDDs。用户还可以要求Spark在内存中持久化RDD,以便允许在并行操作有效的重用。最后,RDDs还可以从节点故障中自动恢复。

在Spark第二个抽象是可以在并行操作中使用共享变量。默认情况下,当Spark作为一个任务的集合在不同的节点上并行运行一个函数时,它会将函数中使用的每个变量的副本发送到各个任务中。有时候,在任务之间或者任务和驱动程序之间共享一个变量。Spark支持两种类型的共享变量:广播变量(可用于所有节点的内存缓存值)和累加器(例如计数器和求和)。

一、RDD创建

Parallelized Collections

通过在驱动程序中现有的集合上调用SparkContext的Parallelize方法来创建。集合中的元素会被复制成可以并行操作的分布式数据集。例如,创建包含数字1~5的并行集合:

val data = Array(1, 2, 3, 4, 5)
val distData = sc.parallelize(data)

一旦被创建,这个分布式数据集就能够被并行操作。比如你可以调用 distData.reduce((a,b) => a+b) 来求和。我们将在后面来描述分布式数据集的操作。

并行集合一个重要的参数是数据集的分区数。Spark将会在集群上为每个分区运行一个任务。通常,在集群上的每个CPU需要2-4个分区。正常情况下,Spark会基于集群尝试着自动设置分区数。但是,你也可以通过将它作为 parallelize 方法的第二参数手动的设置它(例如:sc.parallelize(data, 10) )。注意:代码的某些地方使用术语"切片"(分区的同义词)来保持向后兼容。

External Datasets

Spark能从任何Hadoop支持的存储源创建分布式数据集,包括你本地的文件系统,HDFS,Cassandra,HBase, Amazon S3等等。Spark支持文本文件, SequenceFiles以及其他任何Hadoop InputFormat。

文本文件RDDs能够使用SparkContext的textFile方法创建。此方法获取文件的URI(机器的本地路径或者hdfs://,s3n://等URI),并作为行的集合读取。以下是个实例调用:

scala> val distFile = sc.textFile("data.txt")
distFile: org.apache.spark.rdd.RDD[String] = data.txt MapPartitionsRDD[10] at textFile at <console>:26

一旦被创建,distFile就能够通过数据集操作对其进行操作。例如,我们能够使用 mapreduce 操作把所有行的大小加起来,代码如下:dataFile.map(s => s.length).reduce((a,b) => a+b).

关于使用spark读取文件的一些注意事项:

· 工作节点的路径要和本地文件系统的路径要相同。要么复制文件到所有的worker节点,要么使用网络挂载的共享文件系统

· Spark所有基于文件输入的方法(包括 textFile)都支持在目录、压缩文件和通配符上面运行。比如,你可以使用 textFile("/my/directory")textFile("/my/directory/*.txt"), and textFile("/my/directory/*.gz")

· 为控制文件分区数,textFile 方法也支持可选的第二参数。默认情况下,Spark为文件的每个block创建一个分区(HDFS中block默认是128M),但是你也可以通过传更大的值来请求更大的分区数。注意:分区数不能小于block数

二、RDD操作

RDDs支持两种操作类型:transformations(从已有的数据集创建一个新的数据集)和actions(在数据集上执行一个计算后返回值给驱动程序)。比如,maptransformation操作,它让每个数据集元素通过一个函数并且返回一个代表结果新的RDD。另一方面,reduceaction操作,它使用某些函数聚合RDD的所有元素并且返回最终的结果给驱动程序(尽管也有并行的reduceByKey返回一个分布式数据集)

Spark中所有的transformation是惰性的,因为它们不会立即计算出结果。相反的,它们只记得某些基础数据集的转换(例如文件),transformation只有在action要求一个结果返回给驱动程序时才会被计算。这样的设计使得Spark可以更高效地运行。例如,我们可以认识到通过map创建的数据集将用到reduce并且仅仅返回reduce的结果给驱动程序,而不是返回较大的map数据集。

默认情况下,每次执行一个action操作时,都可能重新计算每个transformation过的RDD。但是,你也可以使用persist(或者cache)方法在内存中持久化RDD,在这种情况下,Spark将这些元素保留在集群中,以便下次查询时可以更快的进行访问。还支持将RDD持久化到磁盘中,或者在多个节点之间复制。

为了说明RDD的基础知识,思考下以下基础程序:

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

第一行定义了一个从外部文件生成的基础RDD。该数据集并没有加载到内存或者有其他作用,lines变量仅仅是指向文件的指针。第二行定义了lineLengths变量,作为map转换之后的结果。相同的,lineLengths由于惰性并没有立即计算。最后,我们执行reduce(action操作)。此时,Spark将计算分解为任务,以在不同的机器上运行,每台机器都运行map的一部分并进行局部归约,仅返回结果给驱动程序。

如果我们想在后面再一次用到lineLengths变量,可以添加到缓存:

lineLengths.persist()

reduce第一次执行之后,会使lineLengths变量保存到内存中。

Transformations

下面列表列出了Spark支持一些常见的Transformation操作。

操作含义
map(func)返回一个新的分布式数据集,该数据集是通过将源数据集的每个元素传递给函数func形成的
filter(func)返回一个新的数据集,该数据集是通过选择源数据集中func返回true的那些元素形成的
flatMap(func)与map相似,但是每个输入项都可以映射到0个或多个输出项(所以func返回的是Seq,而不是单项)
union(otherDataset)返回一个新的数据集,其中包含源数据集中的元素和otherDataset数据集的元素的并集
distinct([numTasks]))返回一个新的数据集,其中包含源数据集的不同元素(相同元素只保留一个)
groupByKey([numTasks])

在(K,V)键值对的数据集上调用时,返回(K,Iterable <V>)键值对的形式的数据集

注意:如果要分组以便对每个键执行聚合(例如求和或平均值),则使用reduceByKeyAggregateByKey将产生更好的表现

reduceByKey(func,[numTasks])

在键值对的数据集上调用,返回的是键值对的数据集

每个键的所有值都会使用func函数聚合,func函数必须是(v,v)=>v。和groupByKey一样,reduce任务的数量可以通过可选的第二个参数进行配置。

sortByKey([ascending], [numTasks])在(K,V)形式的键值对上调用时,其中的K实现了Ordered,会返回一个通过键升序或者降序的键值对数据集,降序或者升序由ascending参数决定,true是升序,false是降序

Actions

下面列表列出了Spark支持一些常见的action操作。

操作含义
reduce(func)使用func函数(它接受两个参数,返回一个结果)来聚合数据集中的元素。这个函数应该是可交换的和可结合的,以便它能够正确的并行计算
collect()在驱动程序把所有数据集的元素作为集合返回
count()返回数据集中元素的个数
first()返回数据集第一个元素
take(n)把数据集中前n个元素作为数组返回
saveAsTextFile(path)将数据集的元素以文本文件(或文本文件集)的形式写入本地文件系统,HDFS或其他任何Hadoop支持的文件系统。Spark将在每个元素上调用toString,以将其转换为文件中的一行文本
countByKey()仅在(K,V)形式的键值对的RDD可用,返回(K,int)每个键计数的hashmap
foreach(func)在数据集的每个元素上执行func函数

三、RDD持久化

Spark最重要的功能之一是跨操作的在内存中持久化(或者缓存)数据集。当你持久化RDD时,每个节点会将其计算的RDD分区存储在内存中,并在该数据集(或从该数据集派生的数据集)上的其他操作中重用它们。这样可以使以后的速度更快(通常是10倍以上)。缓存是迭代算法和快速交互使用的关键工具。

你可以使用RDD的persist()或者cache()方法来将RDD持久化。当第一次在action操作被计算,它将保存在节点的内存中。Spark的缓存是容错的——如果任意的RDD的分区丢失,它将使用最初创建它的转换自动重新计算。

此外,每个RDD能够使用不同的存储等级来存储。例如,允许你在磁盘和内存中持久化,但作为java对象的序列化(为节省空间)在节点之间复制。通过将StorageLevel对象传递给persist()来设置这些级别。 cache()方法是使用默认存储级别StorageLevel.MEMORY_ONLY,完整的存储级别如下:

级别含义
MEMORY_ONLY将RDD作为反序列化的java对象存储在JVM中。如果RDD不能容纳在内存中,那么一些分区不能被缓存,并且每次需要时都会即时重新计算。这是默认级别。
MEMORY_AND_DISK将RDD作为反序列化的java对象存储在JVM中。如果RDD不能容纳在内存中,不能容纳的分区将保持在磁盘上,需要的时候再读取。
MEMORY_ONLY_SER
(Java and Scala)
将RDD存储为序列化的Java对象(每个分区一个字节数组)。 通常,这比反序列化的对象更节省空间,尤其是在使用快速序列化程序时,但读取时会占用更多CPU资源。
MEMORY_AND_DISK_SER
(Java and Scala)
与MEMORY_ONLY_SER类似,但是将内存中不能容纳的分区保存到磁盘上,而不是在需要时即时对其进行重新计算。
DISK_ONLY只将RDD分区保存到磁盘上
MEMORY_ONLY_2, MEMORY_AND_DISK_2, etc.与上面的级别相同,但是在两个群集节点上复制每个分区。
OFF_HEAP (experimental)与MEMORY_ONLY_SER类似,但是将数据存储在堆外存储器中。 这需要启用堆外内存。

翻译水平有限,翻译不当之处还请读者指正!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值