第一阶段:Spark streaming、spark sql、kafka、spark内核原 理(必须有一个大型项目经验);
第二阶段:spark运行的各种环境,各种故障的解决,性能 优化(精通spark内核、运行原理);
第三阶段:流处理、机器学习为鳌头,需要首先掌握前两个 阶段的内容;
跟随王家林老师的零基础讲解,注重动手实战,成为spark高手,笑傲大数据之林!
第一部分:学习笔记
本期内容:
1 Scala模式匹配彻底详解
2 Scala类型系统彻底详解
3 Spark源码阅读及作业
一、模式匹配和类型
(1)模式匹配可以匹配类型、值等
1、值的匹配
def bigData(data:String){
data match{
case "Spark" =>ptintln("Wow!")
case "Hadoop" =>println("OK")
case _O =>println(" The others!") //匹配其他形式的字符串
}
}
bigData("Hadoop") //传进Hadoop后,开始遍历匹配,匹配到后,会停止执行
bigData("Flink") //匹配其他的形式字符串
模式匹配的时候进行判断
def bigData(data:String){
data match{
case "Spark" =>ptintln("Wow!")
case "Hadoop" =>println("OK")
case _ if data =="Flink" =>println("Cool")
case _ =>println("Something else")
}
}
bigData("Spark")
bigData("Flin") //条件判断,进行分层过滤
用变量名接受了模式匹配输入的内容
def bigData(data:String){
data match{
case "Spark" =>ptintln("Wow!")
case "Hadoop" =>println("OK")
case data if data_ =="Flink" =>println("Cool" + data_)
case _ =>println("Something else")
} //将传进的data赋给变量data_
}
2、类型的匹配
import java.io._
def exception(e:Exception)
e catch{
case fileException:FileNotFoundException =>println("File not found:" +fileException)
case _:Exception =>ptintln(s"Exception getting thread from excutor SexecutedID",e)
}
//调用,匹配首先打印Exception,匹配类型
exception(new FileNotFoundException("Hello!"))
3、对集合进行匹配
def data(array:Array[String]){
array match{
case Array("Scala") =>("Scala") //匹配指定数组中的元素
case Array(Spark,hadoop,flink) =>println(spark +":" +hadoop+":" +flink)
case Array("Spark", _*) =>println("Spark ...")//匹配以某元素开头的元素
case _ =>println("Unknown") //匹配其他的数组元素
}
}
data(Array("Spark")
data(Array("Scala","Spark"),"Kafka") //匹配将值传给匹配的变量并打印
4、case class
case class person(name:String) //适合并发编程的消息传递
自动生成当前消息的case class的伴生对象case object
(1)case class 相当于Java中bin
(2)自己的实例化,调用伴生对象的apply方法,返回一个实例
//case class Worker(id:String,salary:Double) extends Person(name)
case class Person //直接定义Person
case class Worker(name:String,salary:Double) extends Person
case class Student(name:String,score:Double) extends Person
//定义函数sayHi
def sayHi(person:Person){
person match{
case Student(name,score) =>println("I am a student:" +name + score)
case Worker(name,salary) =>println("I am a Worker:" +name + salary)
case _ =>println("Unknown!")
}
}
sayHi(Worker("Spark",32)) //传进参数,匹配变量并接收
sayHi(Student("Spark",31))
二、类型参数
1、泛型类、函数
class Person[T](val content:T)
class Person[T](val content:T){
def getContent(id:T) = id + "_" +content
}
val p = new Person[String]("Spark") //实例化对象的时候指定泛型类型String
p.getContent("Scala") //类型控制,这里必须传入String类型
2、类型边界(对类型本身指定边界)
如:大数据Spark工程师,调用spark类型工作,也可以调用其子类型进行工作大数据Spark工程师[ _ <:Spark技能] //这边的上边界就是[Spark技能]。
1.class Pair[T <: Comparable[T]](val first : T,val second : T){
2. def bigger = if(first.compareTo(second) > 0)first else second
3.}
4.class Pair_Lower_Bound[T](val first:T,val second:T){
5. def replaceFirst[R >: T](newFirst:R)= new Pair_Lower_Bound[R](newFirst,second)
6.}
7.object Typy_Variables_Bounds {
8. def main(args: Array[String]){
9. val pair = new Pair("Spark", "Hadoop")
10. println(pair.bigger)
11. }
12.}
上述代码中给泛型类Pair中的类型T一个限定,即类型为T的成员有一个方法为CompareTo,如注释掉的代码会报错,因为不知道first和second的具体类型,无法判定first和second是否有CompareTo,那么就需要对T有一个限定(对变量类型本身的限定)。具体限定为[T<:Comparable[T]],即T类型为Comparable的子类型(如:compareTo),比较的实现为函数bigger。Class replaceFirst[R:>T]说明R类型为T的父类,Pair[T:<ComparableTo[T]]说明T类型为ComparableTo[T]的下界。
3、View Bounds视图界定(没有上下边界的类型)&隐式转换
支持对类型本身就行隐式转换(如:工作时可能出错,将其隐式转换为可以运行的状态,运行结束后再重新恢复原来的状态)将指定的类型进行隐式转换,转换的类型可以作为类型上界、下界。
View Bounds语法:<%
1.class Pair_NotPerfect[T <% Comparable[T]](val first : T,val second : T){
2. def bigger = if(first.compareTo(second) > 0)first else second
3.}
1.val pair = new Pair_NotPerfect("Spark", "Hadoop")
2.println(pair.bigger)
3.
4.val pairInt = new Pair_NotPerfect(3, 5) //Int -> RichInt
5.println(pairInt.bigger)
试图界定:是指我们可以把具体的传入的T类型的实例转换成Comparable[T]类型,如果comparable[T]类型不是T类型的父类,使用<%的方式可以进行隐式转换。
视图界定与隐式转换的过程:在应用类型T无法满足上界Comparable[T]的时候,使用<%做视图界定,将类型T隐式转换成Comparable[T]的子类型,例如整数类型Int会先变成RichInt类型,RichInt是以Comparable为类型上界的,所以用ComparaTo方法,即RichInt中有ComparaTo方法。
~[K:<% Writable] //K必须为Writeble类型或者隐式转换为其类型,在上下文中注入隐式值,而且注入的过程是自动的。
class Compare[T :Ordering](val n1:T,val n2:T){ //比较数字大小
def bigger(implicit ordered: Ordering[T]) if(ordered.Compare(n1,n2)>0)n1 else n2 }//一定存在一个Ordering 的T类型
new Compare[Int](8,3),bigger
new Compare[String]("Spark","Hadoop").bigger
}
[T:Ordering]其中的Ordering为隐式的,也就是Ordering[T];函数bigger中隐式传进一个参数ordered,他是一种上下文界定的方式。
注:String有一个Ordering[String]
Int 有一个Ordered[Int]
[T:Manifest] //实例化数组Array[T]
4、逆变和协变
C[+T]:如果A是B的子类,那么C[A]是C[B]的子类。逆变范围小;
C[-T]:如果A是B的子类,那么C[B]是C[A]的子类。协变范围大;
C[T]:无论A和B是什么关系,C[A]和C[B]没有从属关系。
class Person[+T] //强制定义为协变类型
[Dependence[_]] :表示可以为任何类型 相当于[Dependence[T]]
Manifest:类型分类,上下文界定,有一个Manifest的隐式值,想得到运行时的具体信息,使用Manifest来存储具体的类型,后来演化为ClassTag。
abstract class RDD[T: ClassTag](
@transient private var _sc: SparkContext,
@transient private var deps: Seq[Dependency[_]]
)
T:ClassTag :运行的时候会有更完善的类型进行匹配
import scala.reflect
{{{
* scala> def mkArray[T : ClassTag](elems: T*) = Array[T](elems: _*) //elems:可变参数
* mkArray: [T](elems: T*)(implicit evidence$1: scala.reflect.ClassTag[T])Array[T]
* 根据运行时的类型进行完善匹配,只有运行的时候知道其类型,定义 的时候不知道
* scala> mkArray(42, 13)
* res0: Array[Int] = Array(42, 13)
*
* scala> mkArray("Japan","Brazil","Germany")
* res1: Array[String] = Array(Japan, Brazil, Germany)
* }}}
*
5、多重界定
(1)T>:A<:B (T同时拥有上界B和下界A,A是B的子类型)
(2)T<:A with B(T为A或者B的子类,with为接口)
(3)T<%A<%B(视图界定,T即可隐式转换为A并且也可转换为B的类型)
(4)T:A:B(上下文界定)
第二部分:
作业:阅读Spark源码 RDD、HadoopRDD、SparkContext、Master、Worker的源码,并分析里面使用的所有的模式匹配和类型参数的内容
/*
* 类型参数的泛型
* 定义了newAPIHadoopFile方法,它有三个类型K,V,F
* 类型K,V,F使用限定,是这三个类型都是NewInputFormat[K, V]的子类型;
* K,V,F的类型上界是NewInputFormat[K, V];
* Hadoop读取文件的时候,限定输入文件的类型为NewInputFormat的子类;
* ClassTag[K],ClassTag[V],ClassTag[F]是具有丰富的上下文信息,运行时推断具体的类型。
* implicit隐式转化
* 类型的上界约束
*/
def newAPIHadoopFile[K, V, F <: NewInputFormat[K, V]]
(path: String)
(implicit km: ClassTag[K], vm: ClassTag[V], fm: ClassTag[F]): RDD[(K, V)] = withScope {
newAPIHadoopFile(
path,
fm.runtimeClass.asInstanceOf[Class[F]],
km.runtimeClass.asInstanceOf[Class[K]],
vm.runtimeClass.asInstanceOf[Class[V]])
}
/*
* 类型参数的泛型:视图界定(View Bounds)
* 定义了rddToSequenceFileRDDFunctions方法,它有两个类型K,V,它们是Writable类型或者被隐式转换为Writable类型
* 带一个参数rdd,它是带有(K, V)类型的RDD
* 方法返回一个带有类型(K, V)的SequenceFileRDDFunctions
* ClassTag是具有丰富的上下文信息,运行时推断具体的类型。
* implicit隐式转化
*/
def rddToSequenceFileRDDFunctions[K <% Writable: ClassTag, V <% Writable: ClassTag](
rdd: RDD[(K, V)]): SequenceFileRDDFunctions[K, V] = {
val kf = implicitly[K => Writable]
val vf = implicitly[V => Writable]
// Set the Writable class to null and `SequenceFileRDDFunctions` will use Reflection to get it
implicit val keyWritableFactory = new WritableFactory[K](_ => null, kf)
implicit val valueWritableFactory = new WritableFactory[V](_ => null, vf)
RDD.rddToSequenceFileRDDFunctions(rdd)
}
/*
* 类型参数的泛型:上下文界定
* 定义了rddToSequenceFileRDDFunctions方法,它有两个类型K,V,它们是Writable类型或者被隐式转换为Writable类型
* K : Ordering : ClassTag 表示存在一个隐式值Ordering[K],上下文界定
* 方法返回一个带有类型[K, V, (K, V)] 的OrderedRDDFunctions
* ClassTag是具有丰富的上下文信息,运行时推断具体的类型。
*/
@deprecated("Replaced by implicit functions in the RDD companion object. This is " +
"kept here only for backward compatibility.", "1.3.0")
def rddToOrderedRDDFunctions[K : Ordering : ClassTag, V: ClassTag](
rdd: RDD[(K, V)]): OrderedRDDFunctions[K, V, (K, V)] =
RDD.rddToOrderedRDDFunctions(rdd)