一、上次课回顾
- https://blog.csdn.net/SparkOnYarn/article/details/106384630
- 讲了函数完整的定义,定义函数的入参,每一个参数的定义;如果有返回值,=号可以不用写
- 类是用class来定义的,类中主要有属性(用var、val修饰)和方法,类中需要new出来才能使用;定义属性的时候可以用_占位符来占坑,不过要写明属性的类型;
- 主构造器和附属构造器,附属构造器用def this定义
- 我们也自己定义了一个SparkConf,形成了一个链式编程;val conf = new SparkConf conf.serAppName("").setMaster("")
- 去查看SparkConf.scala的源码
二、原生代码编写ScalaJdbc
首先联想下MySQL JDBC编程:
1)、MySQL的驱动
2)、Connection重量级的过程,借助于POOL连接池
3)、Statement
4)、ResultSet -->SQL执行的结果
5)、close释放资源
IO编程:
1)、打开资源
2)、业务处理
3)、释放资源
添加mysql依赖:
<!--MySQL的驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.28</version>
</dependency>
Scala最原生的代码连接MySQL数据库:
object ScalaJDBCApp {
def main(args: Array[String]): Unit = {
val url="jdbc:mysql://hadoop001:3306/ruozedata_hive"
val user="root"
val password="960210"
val sql="select DB_LOCATION_URI,DB_ID,name from dbs"
class.forName(className="com.mysql.jdbc.Driver")
val connection = DriverManager.getConnection(url,user,password)
val stmt=connection.createStatement()
val rs = stmt.executeQuery(sql)
while (rs.next()){
val location = rs.getString(1)
val dbid=rs.getString(2)
val name=rs.getString(3)
println(dbid + "" + location + "" + name)
}
rs.close()
stmt.close()
connection.close()
}
}
//这段代码要运行在linux服务器上的话需要加上的是class.forName("com.mysql.jdbc.Driver")
2.1、父类和子类
-
面向对象中已经介绍了class,class中有field属性,method/function方法;如下这些代码都是在一个类中的;
Class(xx:Int) { field method/function def this(xx:Int, yy:String) { 附属构造器 this (xx) 调用主构造器 } }
父类和子类:两个类之间
继承的代码:extendsApp
package com.ruozedata.bigdata.scala03
import com.ruozedata.bigdata.scala02.ConstructorDemo.People
object ExtendsApp {
def main(args: Array[String]): Unit = {
val bt1 = new bigTree("bigtree","北京",1000f)
}
}
class bigTree(name:String,city:String,Money:Float) extends People(name, city) {
println("people 3")
println("people 4")
}
override重写:
object ExtendsApp {
def main(args: Array[String]): Unit = {
val bt1 = new bigTree("bigtree","北京",1000f)
println(bt1.toString())
}
}
class bigTree(name:String,city:String,Money:Float) extends People(name, city) {
println("people 3")
override def toString() = "test"
//为什么在子类中要使用override重写,因为在父类中默认就有一个toString方法;
println("people 4")
}
运行结果:
test
不在子类中重写toString这个方法,直接在main函数下打印println(bt1.toString)的输出结果为:
com.ruozedata.bigdata.scala03.bigTree@5c7fa833
–> 完整的包名+类名@跟上hash值
去到Object.java中查看toString方法:
public String toString() {
return getClass().getName() + “@” + Integer.toHexString(hashCode());
}
小结:
子类中有一个方法,父类中也有一个相同的方法;override一般是用来在子类中重写父类的方法或者属性,(两项到Java中最顶层的object中就有一个toString方法))
假设我们定义了一个Animal类,Dog\Cat\Pig,每一类东西有某个相同特征,对动物来说,定义一个eat方法;对于狗来说是eat方法,对于猫来说,重写狗的eat方法,就是猫自己的方法;
在框架中一般定义了接口和抽象类,这样的话框架就会很好的扩展;
1、主构造器ConstructorDemmo代码:
package com.ruozedata.bigdata.scala02
object ConstructorDemo {
def main(args: Array[String]): Unit = {
val people = new People("john","北京")
println(people.city + "" + people.name)
val people2 = new People("sail","苏州",30)
}
//跟在class后面的就是主构造器
class People(var name:String,var city:String){
println("people 1")
//附属构造器的第一行必须要调用主构造器或者其它附属构造器
var age:Int = _
val money:Int =100000
def this(name:String,city:String,age:Int){
this(name,city)
this.age=age
}
println("people 2")
}
}
//附属构造器中又对money进行定义:
2、继承类ExtendsApp代码:
package com.ruozedata.bigdata.scala03
import com.ruozedata.bigdata.scala02.ConstructorDemo.People
object ExtendsApp {
def main(args: Array[String]): Unit = {
val bt1 = new bigTree("bigtree","北京",1000)
println(bt1.toString())
println(bt1.money)
}
}
class bigTree(name:String,city:String,age:Int) extends People(name, city) {
println("people 3")
override val money= 1000
// override def toString() = "test"
println("people 4")
}
//override val money = 10000; 重写了主类中对money的属性
2.1.1、官方代码中的子类和父类
MemoryManager --> 按住ctrl+t,查看这个类下的子类方法:StaticMemoryManager
子类继承父类:父类中有的东西,子类中必然都是有的;Spark中的内存管理
2.2、抽象类
-
Class Function没有具体的实现
-
抽象的类不能直接new,不能被实例化;只能通过子类来new,子类不能还是抽象类
abstract class A { def speak //定义一个speak函数,没有具体的实现 val name:String //没有具体赋值的属性,抽象属性 }
-
等号前面的一些东西就是没有具体实现的方法和属性;
与正常类做对比: class A { def speak = { val name: String = "" } }
-
抽象的东西不能直接new,会报错:class A is abstract,can not be instantiated;而是通过子类来new,子类不能还是抽象的;
object AbstractApp { def main(args: Array[String]): Unit = { val a = new B() a.speak } abstract class A { def speak val name:String } class B extends A { override def speak: Unit = {} val name:String="" println("b speak") } }
2.2.1、源码剖析(memorymanager和staticmemorymanager)
- 抽象类在Spark中的体现:
1、抽象类:
private[spark] abstract class MemoryManager(
conf: SparkConf,
numCores: Int,
onHeapStorageMemory: Long,
onHeapExecutionMemory: Long) extends Logging {
2、抽象类的子类:
private[spark] class StaticMemoryManager(
conf: SparkConf,
maxOnHeapExecutionMemory: Long,
override val maxOnHeapStorageMemory: Long,
numCores: Int)
extends MemoryManager(
conf,
numCores,
maxOnHeapStorageMemory,
maxOnHeapExecutionMemory) {
def maxOffHeapStorageMemory: Long
override def maxOffHeapStorageMemory: Long = 0L
在staticmemorymanager中把这个方法初始化了,也就是在抽象类子类中实现了方法:
具体在Spark中用的地方,查看SparkEnv.scala源码:
2.3、Trait接口
对于继承而言是不能够多继承的,所以只能够使用trait接口;
class后面跟的不仅仅可以是类还可以跟着接口,class A extends C(类) with B(接口)
三、Scala中的高阶函数
高阶函数:
val l = List(1,2,3,4,5,6,7,8)
–> List就是一个框,框里装的是1-8这8个数字
map映射:y=f(x) 为每个x作用上一个相同的函数
println(l.map(x => x*2))
输出结果如下:
List(2, 4, 6, 8, 10, 12, 14, 16)
更精简的写法:
println(l.map(_*2)) -->输出结果也是一样的,此处的_表示的是l中的每个元素,这种表示方法是最精简的;
有一份纯单词的log文件,为每个单词赋上一个1,写法:(_,1)–>集合中的每一个元素;
需求1:
单词*2过后取出大于10的数值:
println(l.map(_*2).filter(_>10))
需求2:
-
在1的基础上取出前2个数值:
println(l.map(_*2).filter(_>10).take(2))
需求3:
-
把原始数据list进行两两相加:
println(l.reduce(_+_)) println(l.reduce((x:Int,y:Int)=>x+y))
需求4:
-
两两相减
println(l.reduce(_-_)) println(l.reduce((x:Int,y:Int)=>x-y))
reduceLeft和reduceRight的使用:
在IDEA中参照如下进行测试:
l.reduceLeft((x:Int,y:Int) => {
println(x + "" + y)
x-y
})
fold函数:
概念:初始值
多重list
val a = List(List(1,2),List(3,4),List(5,6))
println(a.flatten)
输出如下:List(1, 2, 3, 4, 5, 6)
flatten的作用是把输出拉平。
FlatMap
val a =List(List(1,2),List(3,4),List(5,6),List(7,8))
val b = a.flatten
println(b.map(_*2))
-->
println(a.flatMap(_.map(_*2)))
在linux编程环境下词频统计是怎么做的
-
第一步操作:lines.flatMap(_.split("\t"))
得到的结果: hello world hello hello world welcome hello
-
为每个单词赋上一个1
words.map(x => (x,1)) 为每个元素赋上1个1 -
求和两两相加
reduceByKey(+)
输出结果:(hello,3)(world,2) (welcome,1)