2.SparkCore-RDD编程

、 RDD编程

1、编程模型

在Spark中,RDD被表示为对象,通过对象上的方法调用来对RDD进行转换。经过一系列的transformations定义RDD之后,就可以调用actions触发RDD的计算,action可以是向应用程序返回结果(count, collect等),或者是向存储系统保存数据(saveAsTextFile等)。在Spark中,只有遇到action,才会执行RDD的计算(即延迟计算),这样在运行时可以通过管道的方式传输多个转换。

要使用Spark,开发者需要编写一个Driver程序,它被提交到集群(Application)以调度运行Worker,如下图所示。Driver中定义了一个或多个RDD,并调用RDD上的action,Worker则执行RDD分区计算任务。

术语

描述

 Application       

Spark的应用程序,包含一个Driver program和若干Executor

 SparkContext   

Spark应用程序的入口,负责调度各个运算资源,协调各个Worker Node上的Executor

 Driver Program

运行Application的main()函数并且创建SparkContext

 Executor

是为Application运行在Worker node上的一个进程,该进程负责运行Task,并且负责将数据存在内存或者磁盘上。

每个Application都会申请各自的Executor来处理任务

 ClusterManager

在集群上获取资源的外部服务(例如:Standalone、Mesos、Yarn)

 Worker Node

集群中任何可以运行Application代码的节点,运行一个或多个Executor进程,个节点可以起一个或多个Executor

 Task

运行在Executor上的工作单元,每个Executor由若干core组成,每个Executor的每个core一次只能执行一个Task,每个Task执行的结果就是生成了目标RDD的一个partiton

 Job

SparkContext提交的具体Action操作,常和Action对应

 Stage

每个Job会被拆分很多组task,每组任务被称为Stage,也称TaskSet

 RDD

是Resilient distributed datasets的简称,中文为弹性分布式数据集;是Spark最核心的模块和类

 DAGScheduler

根据Job构建基于Stage的DAG,并提交Stage给TaskScheduler

 TaskScheduler

将Taskset提交给Worker node集群运行并返回结果

 Transformations

是Spark API的一种类型,Transformation返回值还是一个RDD, 所有的Transformation采用的都是懒策略,

如果只是将Transformation提交是不会执行计算的

 Action

是Spark API的一种类型,Action返回值不是一个RDD,而是一个scala集合;计算只有在Action被提交的时候计算才 被触发。

2、RDD创建

在Spark中创建RDD的创建方式大概可以分为三种:从集合中创建RDD从外部存储创建RDD;从其他RDD创建。

1)由一个已经存在的Scala集合创建,集合并行化。

val rdd1 = sc.parallelize(Array(1,2,3,4,5,6,7,8))

而从集合中创建RDD,Spark主要提供了两种函数:parallelize和makeRDD。我们可以先看看这两个函数的声明:

def parallelize[T: ClassTag](

      seq: Seq[T],

      numSlices: Int = defaultParallelism): RDD[T]

def makeRDD[T: ClassTag](

      seq: Seq[T],

      numSlices: Int = defaultParallelism): RDD[T]

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

  我们可以从上面看出makeRDD有两种实现,而且第一个makeRDD函数接收的参数和parallelize完全一致。其实第一种makeRDD函数实现是依赖了parallelize函数的实现,来看看Spark中是怎么实现这个makeRDD函数的:

def makeRDD[T: ClassTag](

    seq: Seq[T],

    numSlices: Int = defaultParallelism): RDD[T] = withScope {

  parallelize(seq, numSlices)

}

  我们可以看出,这个makeRDD函数完全和parallelize函数一致。但是我们得看看第二种makeRDD函数函数实现了,它接收的参数类型是Seq[(T, Seq[String])],Spark文档的说明是:

   Distribute a local Scala collection to form an RDD, with one or more location preferences (hostnames of Spark nodes) for each object. Create a new partition for each collection item.

   原来,这个函数还为数据提供了位置信息,来看看我们怎么使用:

scala> val bigdata1= sc.parallelize(List(1,2,3))

bigdata1: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[10] at parallelize at <console>:21

scala> val bigdata2 = sc.makeRDD(List(1,2,3))

bigdata2: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[11] at makeRDD at <console>:21

scala> val seq = List((1, List("slave01")),(2, List("slave02")))

seq: List[(Int, List[String])] = List((1,List(slave01)),

 (2,List(slave02)))

scala> val bigdata3 = sc.makeRDD(seq)

bigdata3: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[12] at makeRDD at <console>:23

scala> bigdata3.preferredLocations(bigdata3.partitions(1))

res26: Seq[String] = List(slave02)

scala> bigdata3.preferredLocations(bigdata3.partitions(0))

res27: Seq[String] = List(slave01)

scala> bigdata1.preferredLocations(bigdata1.partitions(0))

res28: Seq[String] = List()

我们可以看到,makeRDD函数有两种实现,第一种实现其实完全和parallelize一致;而第二种实现可以为数据提供位置信息,而除此之外的实现和parallelize函数也是一致的,如下:

def parallelize[T: ClassTag](

    seq: Seq[T],

    numSlices: Int = defaultParallelism): RDD[T] = withScope {

  assertNotStopped()

  new ParallelCollectionRDD[T](this, seq, numSlices, Map[Int, Seq[String]]())

}

def makeRDD[T: ClassTag](seq: Seq[(T, Seq[String])]): RDD[T] = withScope {

  assertNotStopped()

  val indexToPrefs = seq.zipWithIndex.map(t => (t._2, t._1._2)).toMap

  new ParallelCollectionRDD[T](this, seq.map(_._1), seq.size, indexToPrefs)

}

都是返回ParallelCollectionRDD,而且这个makeRDD的实现不可以自己指定分区的数量,而是固定为seq参数的size大小。

由外部存储系统的数据集创建,包括本地的文件系统,还有所有Hadoop支持的数据集,比如HDFS、Cassandra、HBase等

scala> val bigdata = sc.textFile("hdfs://node01:8020/RELEASE")

bigdata: org.apache.spark.rdd.RDD[String] = hdfs:// hadoop102:9000/RELEASE MapPartitionsRDD[4] at textFile at <console>:24

(2)读取文件生成

可以从Hadoop支持的任何存储源创建分布式数据集,包括本地文件系统,HDFS,Cassandra,HBase等

scala> val file = sc.textFile("/spark/hello.txt")

(3)其他方式

读取数据库等等其他的操作。也可以生成RDD。

RDD可以通过其他的RDD转换而来的。

3TransFormation

RDD编程APISpark支持两个类型(算子)操作:Transformation和Action

Transformation主要做的是就是将一个已有的RDD生成另外一个RDD。Transformation具有lazy特性(延迟加载)。Transformation算子的代码不会真正被执行。只有当我们的程序里面遇到一个action算子的时候,代码才会真正的被执行。这种设计让Spark更加有效率地运行。

转换

含义

map(func)

返回一个新的RDD,该RDD由每一个输入元素经过func函数转换后组成

filter(func)

返回一个新的RDD,该RDD由经过func函数计算后返回值为true的输入元素组成

flatMap(func)

类似于map,但是每一个输入元素可以被映射为0或多个输出元素(所以func应该返回一个序列,而不是单一元素)

mapPartitions(func)

类似于map,但独立地在RDD的每一个分片上运行,因此在类型为T的RDD上运行时,func的函数类型必须是Iterator[T] => Iterator[U]

mapPartitionsWithIndex(func)

类似于mapPartitions,但func带有一个整数参数表示分片的索引值,因此在类型为T的RDD上运行时,func的函数类型必须是

(Int, Interator[T]) => Iterator[U]

union(otherDataset)

对源RDD和参数RDD求并集后返回一个新的RDD

intersection(otherDataset)

对源RDD和参数RDD求交集后返回一个新的RDD(交集)

distinct([numTasks]))

对源RDD进行去重后返回一个新的RDD

groupByKey([numTasks])

在一个(K,V)的RDD上调用,返回一个(K, Iterator[V])的RDD

reduceByKey(func, [numTasks])

在一个(K,V)的RDD上调用,返回一个(K,V)的RDD,使用指定的reduce函数,将相同key的值聚合到一起,与groupByKey类似,reduce任务的个数可以通过第二个可选的参数来设置

aggregateByKey(zeroValue)(seqOp, combOp, [numTasks])

先按分区聚合 再总的聚合   每次要跟初始值交流 例如:aggregateByKey(0)(_+_,_+_) 对k/y的RDD进行操作

sortByKey([ascending], [numTasks])

在一个(K,V)的RDD上调用,K必须实现Ordered接口,返回一个按照key进行排序的(K,V)的RDD

sortBy(func,[ascending], [numTasks])

与sortByKey类似,但是更灵活 第一个参数是根据什么排序  第二个是怎么排序 false倒序   第三个排序后分区数  默认与原RDD一样

join(otherDataset, [numTasks])

在类型为(K,V)和(K,W)的RDD上调用,返回一个相同key对应的所有元素对在一起的(K,(V,W))的RDD  相当于内连接(求交集)

cogroup(otherDataset, [numTasks])

在类型为(K,V)和(K,W)的RDD上调用,返回一个(K,(Iterable<V>,Iterable<W>))类型的RDD

cartesian(otherDataset)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值