Spark笔记
Spark概述
Spark是一个基于内存计算的大数据并行计算框架,是对MapReduce计算模型的扩展。
特点
- Spark可以基于内存也可以基于磁盘做迭代计算。
- 数据可以来自任何一种存储介质。如关系型数据库、本地文件系统、分布式存储等。
- 装载需要处理的数据至内存,并将这些数据集抽象为RDD(弹性分布式数据集)对象,然后采用一系列RDD操作处理RDD,并将处理好的结果以RDD的形式输出到内存,以数据流的方式持久化写入其他存储介质中。
- 使用Scala作为编程语言。它是一种面向对象、函数式编程语言,能够像操作本地集合对象一样轻松地操作分布式数据集。
优点
- 运行速度快
- 易用性好
- 通用性强
- 兼容性
Spark生态系统
应用层:Spark Streaming
数据处理引擎:Spark Core
资源管理层:YARN
数据存储层:HDFS
Spark Core是Spark生态系统的核心组件,是一个分布式大数据处理框架。Spark Core提供了多种资源调度管理
Spark应用执行的基本流程
- 当一个Spark应用程序被提交时,首先需要为这个应用程序构建运行环境,即由驱动程序创建一个SparkContext对象,SparkContext对象向集群资源管理器注册,之后SparkContext对象负责和集群资源管理器进行通信以及进行资源申请、任务的分配和运行监控等,此外还包括申请运行执行器进程的资源。
- 集群资源管理器根据预先设定的算法,在资源池里为执行器进程分配合适的运行资源,并启动执行器进程。再运行过程中,执行器运行情况将随着心跳信息发送到资源管理器上。
- SparkContext对象根据RDD之间的依赖关系构建DAG图,然后提交给有向无环图调度器进行解析,将DAG图分解成多个阶段(每个阶段就是一个任务集),并计算出各个Stage之间的依赖关系,然后把各个任务集提交给任务调度器进行处理。执行器进程向SparkContext对象申请任务,任务调度器将任务发放给执行器进程执行,同时SparkContext对象将应用程序代码发放给执行器进程,即将计算移到数据所在的节点上进行,移动计算比移动数据的网络开销要小得多。
- Task在执行器进程上运行,把执行结果反馈给Task Scheduler,然后再反馈给有向无环图调度器。运行完毕后写入数据,SparkContext对象向集群资源管理器注销并释放所有资源。
Scala编程
cd /usr/local/spark
./bin/spark-shell
Scala中使用Unit表示无返回值。
数组
定长数组长度不变,不能增删,只能修改某个位置的元素值,需要拥有相同的元素类型。下标从0开始。
var a:Array[String] = new Array[String](3)//所有元素初始化为null,int类型的数组初始化为0
var b = new Array[String](3)
var c = Array[String]("hello","scala")
c(1)
res1:String = scala//访问数组用(index),下标从0开始。
变长数组长度可变,可以增删
import scala.collection.mutable.ArrayBuffer
val arr1 = ArrayBuffer[Int]()//长度为0的变长数组
arr1 += 1
arr1 += (2,3,4,5)//变长数组添加元素
toBuffer和toArray方法可以转换数组为ArrayBuffer或Array。
遍历数组
val a = Array(1,2,3,4)
for(i <- 0 util (a.length,2))//从下标0开始隔一个遍历
for(i <- (0 util a.length).reverse)//尾部开始遍历
for(变量 <- 数组名)//不使用下标直接遍历
for(elem <- a if elem % 2 == 0) yield 2*elem//满足条件后创建新数组
a.filter(_%2==0)map{2 * _}//与上式效果一致
a.head//第一个元素
a.tail//除第一个以外的所有元素
a.sortBy(x => x)//升序
a.sortBy(x => -x)//降序
列表
不可变列表元素不可变,所有元素都有相同的数据类型。下标从0开始。
val L:List[Int]=(1,2,3,4)
val newList = 1::(3,5)
val 1::3::5::Nil
可变列表可以增删改元素
import scala.collection.mutable.ListBuffer
val LB1 = ListBuffer(1,2,3,4,5,6)
LB1 -= 6
LB1.remove(index)//删除index处的元素并返回删除的元素
LB1.remove(2,3)//从下标2开始删除3个元素
LB1 += 7
LB1.insert(0,6)//在0位置插入元素6
LB1 ++= Array('a','b')//和数组一样++=操作符可以追加任何集合
集合
集合是没有重复的元素合集,所有的元素都是唯一的。默认情况下,集合不可变,以哈希实现,即元素是根据hashCode进行组织的。
val a = Set("Scala","Python","Java")
val b = Set("C")
val c = a.++b//.++连接两个集合,或者使用 a.++(b)
val set = Set(1,2,3)
set.forall(e => e>100)//判断集合中的每个元素是否满足条件,返回Boolean
set.foreach(e => e+2)//遍历做处理
set.+(4)//添加新元素并创建新集合
映射(Hash tables)
val s1 = Map("LiHua"->99,"XiaoMing"->98)
val s2 = Map(("XiaoHong",99),("XiaoFang",98))
s1("XiaoMing")//获取值
s1.for((k,v) <- s) //遍历
s1 + ("Xiaoli"->1,"XiaoWang"->2)//添加一个或多个
s1 -"Xiaoli"-"XiaoWang"//删除一个或多个
var s3 = s1 ++ s2//合并映射,会去除重复的键值对
元组
元组不可变,元素类型可不一致,下标从1开始
val person=(1,"XiaoMing","男",23)
persion.productIterator.foreach{i => print("元组元素:"+i)}//元组元素:1元组元素:XiaoMing元组元素:男元组元素:23
函数
标准函数体:
def 函数名(形参:形参类型,形参:形参类型):返回值类型={
return
}
//有返回值时可以省略返回值类型和return
如 addInt(a:Int,b:Int)={
a+b
}
//自动返回函数体中的最后一个表达式的值,但是赋值语句返回的是空值,所以赋值语句不能在最后。
addInt(a:Int,b:Int){
a+b
}
//没有=时默认函数无返回值,等同于使用Unit
匿名函数
var x = (a:Int, b:Int)=>{a+b}(2,3)//匿名函数表达式的值就是函数的返回值,该处声明了一个匿名函数,并且调用然后赋值给一个变量
高阶函数
def f3(a:Int,b:Int,(a:Int,b:Int)=>Int)={f(a,b)}
f3(2,3, (a:Int,b:Int)=>{a+b} )//返回值为5
模式匹配
//变量 match{case 值 =>代码}
val value = 1
value match{
case 1 => print("1")
case 2 => print("2")
case_ => print("其他的数")
}
Scala类
默认是class类型,可以传参(称为类参数),类参数整个类中都可以访问
Scala实现水仙花数:
for(a<-100 until 1000){
val b = a/100%10
val s = a/10%10
val g =a%10
var sum=b*b*b + s*s*s + g*g*g
if(sum==a){
println("当前的⽔仙花数是:"+a)
}
三维向量的加减向量和乘除标量
class Vector(xc:Int,yc:Int,zc:Int){
var x:Int = xc
var y:Int = yc
var z:Int = zc
def add(n:Vecter){
x = x + n.x
y = y + n.y
z = z + n.z
}
def sub(n:Vecter){
x = x - n.x
y = y - n.y
z = z - n.z
}
def mul(elem:Int){
x = x * elem
y = y * elem
z = z * elem
}
def div(elem:Int){
x = x / elem
y = y / elem
z = z / elem
}
}
vector2=Vector(4,4,6)
new Vector(1,2,7).add(vector2)
new Vector(1,2,7).sub(vector2)
new Vector(1,2,7).mul(3)
new Vector(1,2,7).div(2)
//给定一组键值对(“spark”,2),(“hadoop”,6),(“hadoop”,4),(“spark”,6),键值对的key表示图书名称,value表示某天图书销量,请计算每个键对应的平均值,也就是计算每种图书的每天平均销量。
scala> val rdd = sc.parallelize(Array(("spark",2),("hadoop",6),("hadoop",4),("spark",6)))
scala> rdd.mapValues(x => (x,1)).reduceByKey((x,y) => (x._1+y._1,x._2 + y._2)).mapValues(x => (x._1 / x._2)).collect()
res22: Array[(String, Int)] = Array((spark,4), (hadoop,5))
Spark编程
RDD弹性分布式数据集,是一个不可变的分布式对象集合,是一个只读的分区记录集合
val arr = Array(1,2,3,4,5,6)
val rdd1 = sc.parallelize(arr)//默认分区为系统分区,我的是8核所以分区为8
val rdd2 = sc.makeRDD(arr)//系统为对象创建最佳分区,此处为3
RDD持久化
RDD的持久化是缓存在内存中的,之后的反复计算都是直接调用内存缓存的partition。
Spark的持久化机制是自动容错的,如果持久化的RDD的任何partition丢失了,那么Spark会自动通过其源RDD,使用转换操作重新计算该partition,而不需要计算所有分区。
sbt打包命令:
cd ~/sparkapp
/usr/local/sbt/sbt package
DataFrame
DataFrame是一个分布式的Row对象的数据集合。
创建
val dfUsers = sqlContext.read.load("/usr/local...")//parquest格式
val dfPerson = sqlContext.read.format("json").load()//json格式
val df = sc.parallelize().toDF("name:","age")
操作
df.show()//默认展示前20条数据,里面参数为int时展示前int条,参数为false时不进行缩略
RDD和DataFrame的联系与区别
区别:
- RDD是分布式的java对象的集合,但是对象内部结构对于RDD而言却是不可知的。
DataFrame是一种以RDD为基础的分布式数据集,提供了详细的结构信息,相当于关系数据库中的一张表
联系:
- 都是spark平台下的分布式弹性数据集,为处理超大型数据提供便利
- 都有惰性机制,在进行创建、转换,如map方法时,不会立即执行,只有在遇到Action才会运算
- 都会根据spark的内存情况自动缓存运算,这样即使数据量很大,也不用担心会内存溢出
- 三者都有partition的概念
- 三者有许多共同的函数,如filter,排序等
DataFrame的操作
df.count()//df的行数
df.distinct()//去重
df.dropDuplicates(seq("Java"))//根据指定字段(Java)去重
df.drop("Java")//去除指定字段,保留其余字段
df.sort()//和orderBy一样,默认升序
df.describe("Scala","Spark")//返回所传入字段的count、max、min、mean、stddev等值
Spark Streaming
Spark Streaming时Spark提供的用于处理流式数据的分布式大数据实时计算框架,具有可伸缩、高吞吐量、容错能力强等特点。
流数据时一组顺序、大量、快速、连续到达的数据序列,可被视为一个随时间延续二无限增长的动态数据集合。
特点:
- 数据实施到达
- 到达次序独立,不受系统控制
- 规模宏大且不被预知其最大值
- 不能再次取出处理
批处理和流处理的区别(静态和动态)
批处理的特点是有界、持久、⼤量,⾮常适合需要访问全套记录才能完成的计算⼯作,⼀般⽤于离线统计。
流处理的特点是⽆界、实时,⽆需针对整个数据集执⾏操作,⽽是对通过系统传输的每个数据项执⾏操作,⼀般⽤于实时统计。
操作
Dstream无状态转化操作
指每次对新的批次数据进行处理时,只会记录当前批次数据的状态,不会记录历史数据状态信息。
有状态转化操作
是跨时间区间跟踪数据的操作,包括滑动窗口转化操作和updateStateByKey()操作。
属性图
Spark GraphX是一个分布式图处理框架,它是基于Spark平台提供图计算和图挖掘的一个简洁易用的接口。GraphX的核心抽象(数据处理模型)是弹性分布式属性图。属性图是带有属性信息的顶点和边构成的图。
图存储模式
原则:
- 提高子图内部的连通性,降低子图之间的连通性。
- 尽量保持各子图的数据规模均衡
分类:
边分割存储指保持各个顶点在计算节点均匀分布,每个顶点都存储一次。
优点:通过顶点复制策略减少跨节点的边数目。
缺点:但不可避免地增加了邻接顶点和边的存储开销。
点分割存储指保持各个边在计算节点均匀分布。
优点:能够减少跨节点之间的数据通信。
缺点:但会增加各个边的邻接顶点的存储开销,同时也会引发数据同步问题。
Spark在机器学习上的优势
- Spark非常适合迭代计算,刚好适应机器学习对迭代计算的需要。
- 通信效率极高。
- MLlib基于RDD,可以和Spark SQL、GraphX、Spark Streaming无缝集成,并以RDD为基础进行联合数据计算。