13.1 大数据计算引擎 Spark(上)
1.Spark 特点(Spark 为什么更快)
DAG 切分的多阶段计算过程更快速
使用内存存储中间结果更高效
RDD 的编程模型更简单
2.Spark WordCount 编程示例
val textFile=sc.textFile("hdfs://...");
val counts=textFile.flatMap(line=>line.split(" "))
.map(word=>(word,1))
.reduceByKey(_+_);
counts.saveAsTextFile("hdfs://...");
第 1 行代码:根据 HDFS 路径生成一个输入数据 RDD
第 2 行代码:再输入数据 RDD 上执行 3 个操作,得到一个新的 RDD。
将输入数据的每一行文本用空格拆分成单词
将每个单词进行转换,word=>(word,1),生成的结构
相同的 key 进行统计,统计方式是对 Value 求和,(_+_)
第 3 行代码:将这个 RDD 保存到 HDFS。
Spark 优化了 MapReduce 计算过程。
3.作为编程模型的 RDD
RDD 是 Spark 的核心概念,是弹性分布式数据集(Resilient Distributed Datasets)的缩写。
RDD 即是 Spark 面向开发者的编程模型,又是 Spark 自身框架的核心元素。
大数据计算就是在大规模的数据集上进行一系列的计算处理。
MapReduce 针对输入数据,将计算过程分为两个阶段,Map 阶段+Reduce 阶段,可以理解为面向过程的大数据计算。
MapReduce 编程时,思考的是,如何将计算逻辑用 Map 和 Reduce 两个阶段实现,Map 和 Reduce 函数的输入和输出是什么,MapReduce 是面向过程的。
Spark 直接针对数据进行编程,将大规模数据集合抽象成一个 RDD 对象。
然后在这个 RDD 上进行各种计算处理,得到一个新的 RDD,继续计算处理,直到得到最后的结果数据。所以 Spark 可以理解为面向对象的大数据计算。
Spark 编程时,思考的是一个 RDD 对象需要经过什么样的操作,转换为另一个 RDD 对象,思考的重心和落脚点在 RDD 上。
WordCount 的代码示例,第二行代码实际上进行了 3 次 RDD 转换,每次转换都得到一个新的 RDD,
因为新的 RDD 可以继续调用 RDD 的转换函数,所以连续写成一行代码。事实上,可以分成 3 行。
val rdd1=textFile.flatMap(line=>line.split(" "));
val rdd2=rdd1.map(word=>(word,1));
val rdd3=rdd2.reduceByKey(_+_);
RDD 上定义函数分两种,一种是转换(transformation)函数,这种函数的返回值还是 RDD;另一种是执行(action)函数,这种函数不再返回 RDD。
RDD 定义了很多转换操作函数,比如有
计算 map(func),
过滤 filter(func),
合并数据集 union(otherDateset),
根据 Key 聚合 reduceByKey(func,[numPartitions]),
连接数据集 join(otherDateset,[numPartions]),
分组 groupByKey([numPartitions])
等十几个函数。
4.作为数据分片的 RDD
和 MapReduce 一样,Spark 也是对大数据进行分片计算,Spark 分布式计算的数据分片,任务调度都是以 RDD 为单位展开的,每个 RDD 分片都会分配到一个执行进程去处理。
RDD 上的转换操作又分成两种:
一种转换操作产生的 RDD 不会出现新的分片,比如 map,filter 等,也就是说一个 RDD 数据分片,经过 map 或者 filter 转换操作后,结果还是当前分片。
就像你用 map 函数对每个数据加 1,得到的还是这样一组数据,只是值不同。实际上,Spark 并不是按照代码写的操作顺序去生成 RDD,比如:
rdd2=rdd1.map(func);
这样的代码并不会在物理上生成一个新的 RDD。物理上,Spark 只有在产生新的 RDD 分片时候,才会在物理上真的生成一个 RDD,Spark 的这种特性也被称作惰性计算。
令一种转换操作产生的 RDD 则会产生新的分片,比如 reduceByKey,来自不同分片的相同 Key 必须聚合在一起操作,这样就会产生新的 RDD 分片。
然而,实际执行过程中,是否会产生新的 RDD 分片,并不是根据转换函数就能判断出来的。
评论