RDD 概述
RDD(Resilient Distributed Dataset):弹性分布式数据集
RDD 特性
- 一组分区(Partition),即是数据集的基本组成单位
(1)在spark中,数据集是以分区为基本组成单位的,每个分区会被一个task处理,task的数量决定了并行计算的粒度
(2)每个分配的存储是由BlockManager 实现的, 每个分区都会被逻辑映射成 BlockManager 的一个 Block,,而这个 Block 会被一个 Task 负责计算
protected def getPartitions:Array[Partition]
- 一个计算每个分区的函数
在spark中,数据的计算是以分区为单位进行计算的
def compute (split:Partition,context:TaskContext): Interator[T]
- RDD之间的依赖关系
在spark中,RDD 的每一次转换都会生成一个新的 RDD, 其中的转换关系被记录了下来,称之为血缘依赖,血缘依赖最重要的作用是可以减少数据的容错成本,例如一个 RDD 由于内存不足,导致整个计算任务失败,那么就可以利用其中的依赖关系,找到失败RDD的父RDD后,从父RDD处开始进行计算,而不是从头开始进行计算
protected def getDependencies:Seq[Dependency[_]]=deps
- 一个Partitioner
在spark中,对于 key-value的 RDD,提供了分区器 Partitioner,可以去控制数据流向几个分区
val partitioner:scala.Option [org.apache.spark.Partitioner]
- 一个列表,列表中存储了每个Partition的优先位置(preferred location).
计算策略的抉择,即移动数据块到某个结点进行计算合适,还是移动计算逻辑到数据块的存储结点进行计算合适
protected def getPreferredLocations(split:Partition):scala.Seq[String]
案例演示
基础案例:WordCount
前提:
windows上已经配置了scala(我的:scala-2.11.8) 和 hadoop(我的:hadoop-3.1.0) 环境
- 创建一个maven工程(我的:maven-3.6.3),并添加相应依赖
- 添加scala 框架支持(idea中搜索插件并安装scala插件)
然后idea会提示让你设置library,选择上述装好的scala-2.11.8目录即可
- 创建一个scala文件夹,并把它修改为Source Root
- 导入依赖
<dependencies>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
<build>
<finalName>WordCount</finalName>
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.4.6</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
- 需求实现:统计文本文件中的单词,并输出到控制台
源文件:
控制台:
package com.xcu.bigdata.spark.core.pg01_wordcount
import org.apache.spark.{SparkConf, SparkContext}
object Spark01_WordCount {
def main(args: Array[String]): Unit = {
// TODO 1. 准备Spark环境
/*
setMaster: 设置Spark环境的运行位置,如 local 或者 hdfs
[k]表示运行核数为k个,* 表示电脑所有的核数
setAppName:设置当前应用程序的名字
*/
val sparkConf = new SparkConf().setMaster("local[*]").setAppName("WordCount")
// TODO 2. 和Spark进行连接
val sc: SparkContext = new SparkContext(sparkConf)
// TODO 3. 业务操作
// TODO 3.1 读取目录下的所有文件
val fileRDD = sc.textFile("./input/word.txt")
// TODO 3.2 将读取到的每行内容进行切割然后扁平化
val wordRDD: RDD[String] = flieRDD.flatMap((x: String) => {x.split(" ")})
// TODO 3.3 转换结构
val mapRDD = wordRDD.map((word: String) => (word, 1))
// TODO 3.4 聚合
val reduceRDD = mapRDD.reduceByKey((x: Int, y: Int) => (x + y))
// TODO 3.5 收集并打印
val res: Array[(String, Int)] = reduceRDD.collect()
res.foreach(println)
// TODO 4. 释放连接
sc.stop()
}
}
升级案例:WordCount
方法1:
(“Hello Scala”, 2):表示一行单词出现2次
package com.xcu.bigdata.spark.core.pg01_wordcount
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
/**
* @Desc : 较为复杂的wordCount
*/
object Spark03_WordCount {
def main(args: Array[String]): Unit = {
// 创建配置文件
val conf: SparkConf = new SparkConf().setAppName("Spark03_WordCount").setMaster("local[*]")
// 创建SparkContext,该对象是提交的入口
val sc = new SparkContext(conf)
// 创建RDD
val rdd: RDD[(String, Int)] = sc.makeRDD(List(("Hello Scala", 2), ("Hello Spark", 3), ("Hello World", 2)))
// 扁平化
val flatMapRDD: RDD[(String, Int)] = rdd.flatMap {
case (words, count) => {
words.split(" ").map(word => (word, count))
}
}
// 按key聚合
val resRDD: RDD[(String, Int)] = flatMapRDD.reduceByKey((x: Int, y: Int) => {
x + y
})
//打印输出
resRDD.foreach(println)
//释放资源
sc.stop()
}
}
输出:
(Spark,3)
(Hello,7)
(World,2)
(Scala,2)
方法2:
package com.xcu.bigdata.spark.core.pg01_wordcount
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
/**
* @Desc : 较为复杂的wordCount
*/
object Spark03_WordCount {
def main(args: Array[String]): Unit = {
// 创建配置文件
val conf: SparkConf = new SparkConf().setAppName("Spark03_WordCount").setMaster("local[*]")
// 创建SparkContext,该对象是提交的入口
val sc = new SparkContext(conf)
// 创建RDD
val rdd: RDD[(String, Int)] = sc.makeRDD(List(("Hello Scala", 2), ("Hello Spark", 3), ("Hello World", 2)))
// 结构转换
val rdd1: RDD[String] = rdd.map {
case (str, count) => {
(str + " ") * count
}
}
// 扁平化
val flatMapRDD: RDD[String] = rdd1.flatMap((s: String) => {
s.split(" ")
})
// 转换结构
val mapRDD: RDD[(String, Int)] = flatMapRDD.map((word: String) => {
(word, 1)
})
// 按key聚合
val resRDD: RDD[(String, Int)] = mapRDD.reduceByKey((x: Int, y: Int) => {
x + y
})
//打印输出
resRDD.foreach(println)
//释放资源
sc.stop()
}
}