RDD
触发Action就会生成spark job
RDD的全称为Resilient Distributed Dataset,是一个弹性、可复原的分布式数据集是Spark中最基本的抽象,是一个不可变的、有多个分区的、可以并行计算的集合。
RDD中并不装真正要计算的数据,而装的是描述信息,描述以后从哪里读取数据,调用了用什么方法,传入了什么函数,以及依赖关系等。
RDD特点
有一些列连续的分区:分区编号从0开始,分区的数量决定了对应阶段Task的并行度
有一个函数作用在每个输入切片上: 每一个分区都会生成一个Task,对该分区的数据进行计算,整函数就是具体的计算逻辑
RDD和RDD之间存在一些列依赖关系:RDD调用Transformation后会生成一个新的RDD,子RDD会记录父RDD的依赖关系,包括宽依赖(有shuffle)和窄依赖(没有shuffle)
(可选的)K-V的RDD在Shuffle会有分区器,默认使用HashPartitioner
(可选的)如果从HDFS中读取数据,会有一个最优位置:spark在调度任务之前会读取NameNode的元数据信息,获取数据的位置,移动计算而不是移动数据,这样可以提高计算效率。
RDD算子的分类
Transformation:即转换算子,调用转换算子会生成一个新的RDD,Transformation是Lazy的,不会触发job执行。
Action:行动算子,调用行动算子会触发job执行,本质上是调用了sc.runJob方法,该方法从最后一个RDD,根据其依赖关系,从后往前,划分Stage,生成TaskSet。
RDD的分区
lines.partitions.length 分区个数,查看RDD分区数量
sc.textFile(“hdfs://linux201:9000/data”, 6 ) 可以指定分区数6
val arr = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
val rdd = sc.parallelize(arr)
把普通的 scala集合 转成 分布式的集合,在集群运行
分区数为设置的默认的分区数
rdd.sum
val rdd = sc.parallelize(arr, 2) 可设置分区数2
通过并行化方式,将Driver端的集合转成RDD
val rdd1: RDD[Int] = sc.parallelize(Array(1,2,3,4,5,6,7,8))
从HDFS指定的目录据创建RDD
val lines: RDD[String] = sc.textFile(“hdfs://node-1.51doit.cn:9000/log”)
使用上面两种方式创建RDD都可以指定分区的数量
Transformation算子map
map算子,功能所做映射
val rdd1: RDD[Int] = sc.parallelize(List(5,6,4,7,3,8,2,9,1,10)).map(_*2)
flatMap算子,先map在压平,spark中没有flatten方法
val rdd2 = sc.parallelize(Array(“a b c”, “d e f”, “h i j”))
rdd2.flatMap(.split(’ ')).collect
val rdd3 = sc.parallelize(List(List(“a b c”, “a b b”),List(“e f g”, “a f g”)))
rdd3.flatMap(.flatMap(_.split(" "))).collect
mapPartitions,将数据以分区为的形式返回进行map操作,一个分区对应一个迭代器,该方法和map方法类似,只不过该方法的参数由RDD中的每一个元素变成了RDD中每一个分区的迭代器,如果在映射的过程中需要频繁创建额外的对象,使用mapPartitions要比map高效的过。
val rdd1 = sc.parallelize(List(1, 2, 3, 4, 5), 2)
var r1: RDD[Int] = rdd1.mapPartitions(it => it.map(x => x * 10))
mapPartitionsWithIndex,类似于mapPartitions, 不过函数要输入两个参数,第一个参数为分区的索引,第二个是对应分区的迭代器。函数的返回的是一个经过该函数转换的迭代器。
val rdd1 = sc.parallelize(List(1,2,3,4,5,6,7,8,9), 2)
rdd1.mapPartitionsWithIndex(func).collect
index分区号,it方法
numbers.mapPartitionsWithIndex((index, it)) => {
it.map(e => s"partition: $index, val: $e")
}
sortByKey
groupByKey
sortBy算子,排序 是transformation但是会触发action(触发目的:进行采样操作方便排序)
sc.parallelize(List(5,11,22,13,2,1,10)).sortBy(x=>x,true)
sc.parallelize(List(5,11,22,13,2,1,10)).sortBy(x=>x+"",true)
sc.parallelize(List(5,11,22,13,2,1,10)).sortBy(x=>x.toString,true)
sortByKey算子,排序
val rdd1 = sc.parallelize(List((“hello”, 9), (“tom”, 8), (“kitty”, 7), (“tom”, 2)))
val rdd2 = rdd1.sortByKey()
groupBy算子,安装key分组
val rdd1 = sc.parallelize(List((“hello”, 9), (“tom”, 8), (“kitty”, 7), (“tom”, 2)))
val rdd2 = rdd1.groupBy(_._1)
groupByKey 按照key进行分组
val rdd2 = sc.parallelize(List((“jerry”, 9), (“tom”, 8), (“shuke”, 7), (“tom”, 2)))
val rdd2: RDD[(String, Iterable[Int])] = rdd1.groupByKey()
reduceByKey
val rdd2 = sc.parallelize(List((“jerry”, 9), (“tom”, 8), (“shuke”, 7), (“tom”, 2)))
val rdd3 = rdd1.reduceByKey(+)
distinct算子,去重
sc.parallelize(List(5,5,6,6,7,8,8,8)).distinct.collect
val rdd6 = sc.parallelize(List(5,6,4,7))
val rdd7 = sc.parallelize(List(1,2,3,4))
val rdd8 = rdd6.union(rdd7)
intersection算子,交集
val rdd6 = sc.parallelize(List(5,6,4,7))
val rdd7 = sc.parallelize(List(1,2,3,4))
val rdd9 = rdd6.intersection(rdd7)
subtract算子,差集
val rdd6 = sc.parallelize(List(5,6,4,7))
val rdd7 = sc.parallelize(List(1,2,3,4))
val rdd9 = rdd6.subtract(rdd7)
RDD简介
读取HDFS数据
读取本地数据
本地结合的转换
RDD调用转换算子获取RDD
RDD中分区和任务的划分
算子 转换算子RDD -RDD
map
filter
flatMap
mapPartitions
mapPartitionWithIndex
行动算子
foreach
collect()
take()
takeSample
takeOrdered
object CreateRDDFromDisk {
def main(args: Array[String]): Unit = {
val sc: SparkContext = SparkUtils.getSparkContext
//本地的list集合
val ls = List("a", "b", "c", "d", "e", "f")
val ls2: List[(String, Int)] = ls.map((_, 1))
//将存储对偶元组的list转换成Map集合
val mp: Map[String, Int] = ls2.toMap
mp.toArray
mp.toList
mp.toSet
mp.toSeq
val rdd1: RDD[(String, Int)] = sc.parallelize(mp.toList)
sc.stop()
}
private def lsToRDD(sc: SparkContext) = {
val bs: BufferedSource = Source.fromFile("d://word.txt")
val ls2 = bs.getLines().toList
sc.parallelize(ls2)
val ls = List("a", "b", "c", "d", "e", "f")
val rdd1: RDD[String] = sc.parallelize(ls)
val rdd2: RDD[String] = sc.parallelize(ls, 3)
println(rdd1.partitions.size)
println(rdd2.partitions.size)
}
/**
* 数组转成RDD
*
* @param sc
*/
private def arrToRDD(sc: SparkContext) = {
//创建一个本地数组
val arr = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
//将本地结合转成RDD
val rdd1 = sc.makeRDD(arr)
//参数1 本地集合 参数2 指定分区个数
//val rdd2 = sc.makeRDD(arr, 3)
//参数1 集合 参数2 分区数据
sc.parallelize(arr, 4)
/**
* 在本地运行模式中sc对象默认使用的是local[*]所有的核数据
* 机器8核 同时能8线程 最大限度的并行运行 8个任务 8个分区
*/
println(rdd1.partitions.size)
}
}
object CreateRDDFromHdfsFile {
def main(args: Array[String]): Unit = {
//设置控制台打印日志的级别
Logger.getLogger("org").setLevel(Level.ERROR)
//hdfs的本地用户名
System.setProperty("HADOOP_USER_NAME", "root")
//获取spark对象
val conf: SparkConf = new SparkConf()
//设置本地测试运行模式 设置app名称
conf.setMaster("local[*]").setAppName(this.getClass.getSimpleName)
val sc = new SparkContext(conf)
//读取HDFS数据
val rdd1: RDD[String] = sc.textFile("hdfs://linux201:9000/word.txt")
//获取当前RDD的分区数
val psize: Int = rdd1.partitions.size
//打印
println(psize)
sc.stop()
}
}
object FilterFunction {
def main(args: Array[String]): Unit = {
val sc: SparkContext = SparkUtils.getSparkContext
val arr: Array[Int] = Array(1, 3, 45, 6, 7, 7, 8, 9)
val rdd: RDD[Int] = sc.parallelize(arr, 3)
val rdd1: RDD[Int] = rdd.map(_ * 10)
//val rdd2: RDD[Int] = rdd1.filter(_ > 30)
//val rdd2: RDD[Int] = rdd1.filter(_ > 2).filter(_ % 2 == 0)
val rdd2 = rdd1.filter(e => e > 2 && e % 3 == 0)
rdd2.foreach(println)
}
}
object FlatMapFunction {
def main(args: Array[String]): Unit = {
val sc = SparkUtils.getSparkContext
val rdd: RDD[String] = sc.textFile("d://word.txt")
//对每行数据进行切割压平
val rdd2: RDD[String] = rdd.flatMap(_.split(" "))
//(单词, 1) (单词, 1)
val rdd3: RDD[(String, Int)] = rdd2.map((_, 1))
//将相同的单词聚合
val rdd4: RDD[(String, Int)] = rdd3.reduceByKey(_ + _)
//行动算子
rdd4.foreach(println)
}
}
object MapFunctionDemo {
def main(args: Array[String]): Unit = {
val arr = Array(1, 2, 4, 5, 6, 7)
val sc: SparkContext = SparkUtils.getSparkContext
val rdd1: RDD[Int] = sc.parallelize(arr, 3)
//rdd1调用map方法.方法中的函数作用在每一个元素上执行 arr.size
//由 rdd1调用map算子返回一个处理之后的新rdd2,map是一个转换算子
val rdd2 = rdd1.map(e => e * 10)
//rdd2 调用filter函数 ,返回一个处理后的新rdd filter转换算子
val rdd3: RDD[Int] = rdd2.filter(_ > 20)
}
}
object MapPartitionsDemo {
def main(args: Array[String]): Unit = {
val sc: SparkContext = SparkUtils.getSparkContext
val ls: List[String] = List("tom", "hello", "cat", "jack", "jerry")
val rdd1= sc.parallelize(ls, 3)
//val rdd2 = rdd1.map(_.toUpperCase)
val rdd2: RDD[String] = rdd1.mapPartitions(iters => {
println(Thread.currentThread() + "**")
for (elem <- iters) yield elem.toUpperCase + "aaa"
})
rdd2.foreach(println)
}
}
object MapPartitionWithIndexFunctionDemo {
def main(args: Array[String]): Unit = {
val sc: SparkContext = SparkUtils.getSparkContext
val arr: Array[String] = Array("a", "o", "b", "c", "u")
val rdd1: RDD[String] = sc.parallelize(arr, 3)
val rdd2 = rdd1.mapPartitionsWithIndex((index, iters) => {
for (elem <- iters) yield index + "---" + elem
})
//执行行动算子,将RDD的结果收集到本地 行动算子
/**
* collect行动算子 调用行动算子 触发job 开始处理运算数据
*/
val res: Array[String] = rdd2.collect() //收集成本地集合
res.foreach(println)
}
}
object TakeFunction {
def main(args: Array[String]): Unit = {
val sc: SparkContext = SparkUtils.getSparkContext
val arr = Array(7, 6, 2, 5, 11, 14, 8, 19)
val rdd: RDD[Int] = sc.parallelize(arr, 3)
//take行动算子 从0号区开始取值,顺序取
val res: Array[Int] = rdd.take(3)
for (elem <- res) {
println(elem)
}
sc.stop()
}
}