1. Spark核心概念简介

1.1 spark应用

每个spark应用都有一个驱动器程序(driver manager) 发起集群上的各种并行操作。

驱动程序的作用:

  1. 包含Main函数
  2. 定义集群上的分布式数据集
  3. 对数据集进行相关操作
  4. 管理多个执行器(executor集群模式
1.2 spark链接(SparkContext : sc)

定义: 驱动器程序通过SparkContext的对象访问Spark。该对象是对计算集群的一个链接。
作用: 可以用来创建RDD。
用法案例:

  1. 创建一个代表文件中各行文本的RDD: sc.textFile(“filePath”);

关于sparkSession,SparkContext,hiveContext,SQLContext的区别详见:

2. RDD编程

弹性分布式数据集。(Resilient Distributed Dataset)
不可变的分布式的元素集合。

为什么说是弹性?
当保存RDD数据的一台机器失败时,Spark可以使用这种特性重算丢掉的分区,这一过程对用户完全透明。

Spark中,所有的操作与RDD相关:
   a) 创建RDD
   b) 转化已有的RDD
   c) 调用RDD操作进行求值。
Spark 会自动将RDD中的数据分发到集群上,并将操作并行执行。

RDD概念:
   a) 不可变的分布式对象集合
   b) 每个RDD分为多个分区,不同的分区运行在集群中的不同节点上
   c) RDD可以包含任意类型的对象,包括用户自定义的对象

创建RDD的两种方式:
   a) 读取外部数据集
   b) 在驱动器程序里分发驱动器程序中的对象集合(比如list和set)
      把程序中已有的聚合传给SparkContext 的parallelize()

举例:val lines = sc.parallelize(List(“a”,“b”))
适用场景:学习Spark/开发原型/测试 时比较好用,可以很方便创建出自己的RDD
需要把整个数据集先放到一台机器的内存中

RDD支持的操作类型:
   a) 转化操作(transformation):由一个RDD生成一个新的RDD。常见的如过滤filter(),map()。
   b) 行动操作 (action):对RDD计算出一个结果保存到驱动器程序中,或者把结果保存到外部存储系统(如HDFS),如取第一个元素 first(),count()
转化操作返回RDD,行动操作返回的是其他数据类型

Spark可以处理比规定内存大的数据量的原因
Spark惰性计算RDD。
只有第一次在一个行动操作中用到时,才会真正计算。
一旦Spark了解了完整的转化操作链之后,就可以只计算求结果时真正的需要的数据。
例如:在行动操作 first() 中,Spark只需要扫描文件直到找到第一个匹配的行为为止,不会读取整个文件。

RDD计算特点:
RDD 默认情况下,每次进行行动操作时重新计算。
多个行动操作重用一个RDD,可以使用RDD.persist() 让Spark 把这个RDD缓存下来。
RDD缓存即持久化:
   a) 磁盘
   b) 内存
第一次持久化的RDD计算之后,Spark会把RDD内容保存在内存/磁盘(以分区方式存储到集群中的各机器上)
之后的行动操作 就可以重用这些数据了。
默认不持久化的原因: 对于大规模数据集,如果不重用该RDD,没必要浪费存储空间,Spark可以直接遍历一遍数据然后计算出结果。
persist 把数据的一部分读取到内存中,并反复查询这部分数据

Spark程序工作方式
   a) 从外部数据创建出输入RDD
   b) 使用诸如filter() 这样的转化操作对RDD进行转化,定义新的RDD。
   c) 告诉Spark 对需要被重用的中间结果RDD执行persist() 操作
   d) 使用行动操作(例如count()和first()等)来触发一次并行计算,Spark会对计算进行优化后再执行。

cache() 与使用默认存储级别调用persist() 是一样的

3. RDD操作

3.1 转化操作

许多转化操作都是针对各个元素,也就是这些转化操作每次只会操作RDD中的一个元素。
union()与filter() 的不同点在于它操作两个RDD而不是一个。
转化操作可以操作任意数量的输入RDD。

举例:
val inputRDD = sc.textFile(“log.text”)
val errorRDD = inputRDD.filter(line => line.contains(“error”))
val warnRDD = inputRDD.filter(line => line.contains(“warn”))
val badLinesRDD = errorRDD.union(warnRDD)
更好的方法是直接筛选出要么包含error要么包含warning的行,这样只对 inputRDD 进行一次筛选即可

Spark会使用 谱系图(lineage graph) 记录不用RDD之间的依赖关系

谱系图作用:
   a) Spark 根据这些信息来按需计算每个RDD
   b) 依靠谱系图在持久化的RDD丢失部分数据时恢复所丢失的数据

3.2 行动操作

概念:把最终求得的结果返回给驱动器程序,或者写入外部存储系统中。
由于行动操作需要生成实际的输出,它们会强制执行求值必须用到的RDD的转化操作。
每当调用一个新的行动操作时,整个RDD都会从头开始计算。

常用函数
count() 返回计数结果
take() 收集RDD中的一些元素
collect()获取这个RDD中的数据,会将数据收集到驱动器进程中。
整个数据集能在单台机器的内存中放得下时,才能使用collect()函数。

3.3 惰性求值

对RDD调用转化操作(如map())时,操作不会立即执行。Spark会在内部记录下所要执行的操作的相关信息。
通过惰性求值,可以把一些操作合并到一起来减少计算数据的步骤。
读取操作也是惰性的,调用sc.textFile() 时,数据并没有读取进来,而是必要时才会读取。读取操作也有可能执行多次。

RDD从两个方面理解:
1. 存放着特殊数据的数据集。
2. 通过转化操作构建出来的,记录如何计算数据的指令列表。

4. 向Spark传递函数

Spark 大部分转化操作和一部分行动操作,都需要依赖用户传递的函数来计算。

Scala传递函数:
1. 内联函数
2. 方法的引用
3. 静态方法

需要考虑的细节:
1.所传递的函数及其引用的数据需要是可序列化的
2.传递一个对象的方法或者字段时,会包含对整个对象的引用

class SearchFunctions(val query: String) {
	def isMatch(s: String): Boolean = {
   		s.contains(query)
    }
    def getMatchesFuntionReference(rdd: RDD[String]): RDD[String] = {
    	//问题:"isMatch" 表示 "this.isMatch" ,因此我们要传递整个"this"
    	rdd.map(isMatch)
   	}	   
   	def getMatchesFieldReference(rdd: RDD[String]): RDD[String] = {
   		//问题:"query" 表示 "this.query",因此我们要传递整个 "this"
   		rdd.map(x => x.split(query))
   	}
   	def getMatchesNoReference(rdd: RDD[String]): RDD[String] = {
   		//安全:只把我们需要的字段拿出来放到局部变量里
   		val query_ = this.query
   		rdd.map(x => x.split(query_))
   	}
}

5. 常见的转化操作和行动操作

5.1 基本RDD

1.针对各个元素的转化操作

函数

描述

map()

接收一个函数,把这个函数应用于RDD中的每个元素,

将函数的返回结果作为结果RDD中对应的元素

filter()

接收一个函数,将RDD中满足该函数的元素放入到新的RDD中返回

flatMap()

将函数分别应用到输入RDD的每个元素

返回的不是一个元素,而是一个返回值序列的迭代器。

输出的RDD不是由迭代器组成的,是包含各个迭代器可访问的所有元素

简单用途:把输入的字符串切分为单词

//代码示例:
val input = sc.parallelize(List(1,2,3,4))
val mapResult = input.map(x => x*x)//求平方
val filterResult = input.filter(x => x!=1) //过滤等于1的情况
//flatMap举例
val lines = sc.parallelize(Arrays.asList("hello world","hi"))
//words 的内容是 "hello","world","hi"
val words = lines.flatMap(line => line.split(" "))
words.first()//返回hello

RDD的flatMap()和map()的区别:

spark的overwrite什么意思 spark driver的作用是什么?_数据

2.针对各个元素的转化操作
要求:操作的RDD是相同数据类型的