Apache Spark是一个分布式计算框架,旨在简化运行于计算机集群上的并行程序的编写。
Spark的前辈:MPI、MapReduce
特性:迭代式计算、交互式探索、内存缓存计算
每个Spark应用都由一个驱动器程序来发起集群上的各种并行操作,驱动器程序通过一个SparkContext对象来访问Spark。Spark集群是由两类程序构成:一个驱动程序和多个执行程序。本地模式时对所有的处理都运行在同一个JVM中,而在集群模式时包括一个运行Spark单机主程序和驱动程序的主节点和各自运行一个执行程序进程的多个工作节点。
在Spark Shell中,实际的驱动器程序就是Spark Shell本身,shell启动时就创建了一个SparkContext对象,sc变量。
Spark也可以在Java、Scala或Python的独立程序中使用,与shell中使用的主要区别在于需要自动初始化SparkContext。
例如:(Python中)
from pyspark import SparkConf, SparkContext
conf = SparkConf().setMaster("local").setAppName("My App")
sc = SparkContext(conf = conf)
在Spark中,通过对分布式数据集的操作来表达意图,这些计算会自动地在集群上并行进行。RDD是Spark对分布式数据和计算的基本抽象。
两种创建RDD的方法:
val collection = List("a", "b", "c", "d", "e")
val rddFromCollection = sc.parallelize(collection)
val rddFromTextFile = sc.textFile("LICENSE")
RDD操作:
map
、filter
、filterNot
。Spark中的转换操作时延后的!在RDD上调用一个转换操作并不会立即触发相应的计算,这些转换操作会链接起来,在执行操作被调用时才被高效的计算。val intFromStringRDD = rddFromTextFile.map(line => line.size)
函数名(1个RDD) | 目的 |
---|---|
map() | 将函数应用于RDD的每个元素,将返回值构成新的RDD |
flatMap() | 将函数应用于RDD的每个元素,将返回的迭代器的所有内容构成新的RDD |
filter() | 返回一个由通过传给filter()的函数的元素组成的RDD |
distinct() | 去重 |
sample(withReplacement, fraction, [seed]) | 对RDD采样,以及是否替换 |
函数名(2个RDD) | 目的 |
union() | 生成一个包含两个RDD中所有元素的RDD |
intersection() | 求两个RDD共同的元素的RDD |
subtract() | 移除一个RDD中的内容 |
cartesian() | 与另一个RDD的笛卡儿积 |
first
、take
、collect
。函数名 | 目的 |
---|---|
collect() | 返回RDD中的所有元素 |
count() | RDD中的元素个数 |
countByValue() | 各个元素在RDD中出现的次数 |
take(num) | 从RDD中返回num个元素 |
top(num) | 从RDD中返回最前面的num个元素 |
takeOrdered(num)(ordering) | 从RDD中按照提供的顺寻返回最前面的num个元素 |
takeSample(w | ithReplacement, num, [seed]) |
reduce(func) | 并行整合RDD中所有数据,如sum |
fold(zero)(func) | 和reduce()一样,但是需要提供初始值 |
aggregate(zeroValue)(seqOp, combOp) | 和reduce()相似,通常返回不同类型的函数 |
foreach(func) | 对RDD中的每个元素使用给定的函数 |
注: 通常只在需要将结果返回到驱动程序所在节点以供本地处理时,才调用collect
函数。如果在一个非常大的数据集上调用该函数,可能耗尽驱动程序的可用内存,导致程序崩溃。
pair RDD
函数名(1个RDD) | 目的 |
---|---|
reduceByKey(func) | 合并具有相同键的值 |
groupByKey() | 对具有相同键的值进行分组 |
combineByKey(createCombiner, mergeValue, mergeCombiners, partitioner) | 使用不同的返回类型合并具有相同键的值 |
mapValues(func) | 对pair RDD中的每个值应用一个函数而不改变键 |
flatMapValues(func) | 对pair RDD中每个值应用一个返回迭代器函数,然后对返回的每个元素都生成一个对应原键的键值对记录 |
keys() | 返回一个仅包含键的RDD |
values() | 返回一个仅包含值的RDD |
sortByKey() | 返回一个根据键排序的RDD |
函数名(2个RDD) | 目的 |
subtractByKey() | 删掉RDD中键与other RDD中键相同的元素 |
join() | 对两个RDD进行内连接 |
rightOuterJoin() | 对两个RDD进行连接操作,确保第一个RDD的键必须存在(右外连接) |
leftOuterJoin() | 对两个RDD进行连接操作,确保第二个RDD的键必须存在(左外连接) |
cogroup() | 将两个RDD中拥有相同键的数据分组到一起 |
RDD缓存策略\持久化:
Spark最强大的功能之一就是能够把数据缓存在集群的内存中。通过rddFromTextFile.cache
函数实现。
Spark为持久化RDD定义了几种不同的机制,用不同的StoreageLevel表示。rdd.cache()
是rdd.persist(StorageLevel.MEMORY)
的简写,将RDD存储为未序列化的java对象。存储级别:(MEMORY、MEMORY_SER、MEMORY_AND_DISK、MEMORY_AND_DISK_SER)。什么时候需要缓存数据需要对空间和时间进行权衡,还需要考虑垃圾回收的开销。调用unpersist()
方法可以手动把持久化的RDD从缓存中移除。
广播变量为只读变量,由运行SparkContext的驱动程序创建后发送给参与计算的节点。
val broadcastAList = sc.broadcast(List("a", "b", "c", "d", "e"))
累加器也是一种被广播到工作节点的变量,不同于广播变量,累加器可以累加,能保证在全局范围内累加起来的值能被正确的并行计算以及返回驱动程序。
聚合:对集群数据进行聚合时,一定要时刻记住我们分析的数据是存放在多台机器上的,并且聚合需要连接机器的网络来移动数据(需要考虑数据传输的效率)。
val grouped = mds.groupBy(md => md.matched)
创建直方图:(类别变量)
val matchCounts = parsed.map(md => md.matched).countByValue()
val matchContsSeq = matchCounts.toSeq
matchContsSeq.sortby(_._1).foreach(println)
连续变量的统计
import java.long.Double.isNaN
parsed.map(md => md.scores(0)).filter(!isNaN(_)).stats()
val stats = (0 until 9).map(md => md.scores(i)).filter(!isNaN(_)).stats()
Spark编程的核心概念:通过一个驱动器程序创建一个SparkContext和一系列RDD,然后进行并行操作。
filter()
这样的转化操作对RDD进行转化,以定义新的RDDpersist()
操作count()
或first()
)来触发一次并行计算,Spark会对计算进行优化后再执行。见Blog:
Spark学习笔记(二)——Spark机器学习
《Spark快速大数据分析》(《Learning Spark: Lightning-fast Data Analysis》)
《Spark高级数据分析》(《Advanced Analytics with Spark》)
《Spark 机器学习》(《Machine Learning with Spark》)
http://spark.apache.org