- 4.1 高阶函数-List集合
- 4.2 输出集合中大于10的数
- 4.3 take的使用
- 4.4 reduce的使用-求和
- 4.5 reduceleft的使用
- 4.6 fold参数
- 4.7 多重List
- 4.8 FlatMap使用
- 4.9 结合业务场景进行词频统计
一、上次课回顾
回顾:IDEA直接生成默认返回值是unit,导致没有返回值:
def main(args: Array[String]) :unit = {
}
类:Class一定要new出来后才能使用.
val属性 = _ _表示占位符,占个坑,占坑的时候要明确显示属性
例如 var name = _ ,出现如下报错
未指定name的类型:unbound placeholder parameter
进行如下修改:var name:String = _
Most Important:
链式编程:
val conf = new SparkConf //它其实调用了附属构造器def this() = this (true)
conf.setAppName("").setMaster("")..........
能力强的可以自行翻阅SparkConf.scala源码:
Ctrl+F12:查看方法
/** Set a configuration variable. */
def set(key: String, value: String): SparkConf = {
set(key, value, false)
}
/** Get a parameter; throws a NoSuchElementException if it's not set */
def get(key: String): String = {
getOption(key).getOrElse(throw new NoSuchElementException(key))
}
二、原生代码使用Scala链接MySQL
1)、MySQL的驱动
2)、获取Connection 重量级的获取过程,借助于POOL连接池
3)、Statement 借助于sql查询
4)、ResultSet 得到的是结果集
5)、Close 释放资源
POOL连接池先创建一批,初始化的时候初始化进去,用的时候直接在里面拿,比如有1000个请求,直接在池子里用,性能比1000个请求高
IO编程:打开资源、业务处理、释放资源
package com.ruozedata.bigdata
import java.sql.DriverManager
object ScalaJDBCApp {
def main(args: Array[String]): Unit = {
val url = "jdbc:mysql://10.0.0.135:3306/ruoze_g6"
val user = "root"
val password = "960210"
val sql = "select DB_LOCATION_URI,DB_ID,NAME from dbs"
//Class.forName("com.mysql.jdbc,Driver") java中添加驱动
classOf[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()
}
}
//代码输出:
1 hdfs://localhost:9000/user/hive/warehouse default
6 hdfs://hadoop004:9000/user/hive/warehouse/ruozeg6.db ruozeg6
11 hdfs://hadoop004:9000/user/hive/warehouse/test.db test
这种方法太过于累赘,后期我们借助框架实现:
主构造器和附属构造器都是在一个类里面的:于是引出父类和子类的概念:
伪代码:
Class(xx:Int){
field
method/funcrion
def this(xx:Int,yy:String) //附属构造器
this(xx)
.....
}
第三章:父类和子类
scala02包中的父类方法如下:
package scala02
object ConstructorDemo {
def main(args: Array[String]): Unit = {
val person = new Person("john", "苏州")
println(person.name + "生活在" + person.city)
val person1 = new Person("sail", "苏州", 25)
println(person1.name + "生活在" + person1.city + "年龄是" + person1.age)
}
//主构造器,跟在class后面的
class Person(var name: String, var city: String) {
println("person here")
var age: Int = _
//附属构造器 第一行必须要调用主构造器或者其他附属构造器,使用this关键字
def this(name: String, city: String, age: Int) {
this(name, city)
this.age = age
}
println("person leave")
}
}
3.1、子类extends父类
- 首先写一个基础的extendsApp,继承自scala02中的Constructor.Person,如下是子类。
package scala03
import scala02.ConstructorDemo.Person
object extendsApp {
def main(args: Array[String]): Unit = {
//new子类会先触发new父类()
val bj1 = new bjperson("大叔","北京",100000.0f)
//打印一个toString方法
println(bj1.toString())
}
class bjperson(name: String,city:String,money:Float)
extends Person(name,city){
println("bigtree here")
//toString需要一个override修饰符
//用来在子类中重写父类的方法或者属性,我们在父类中没有找到toString方法
override def toString() = "BigTree here"
println("bigtree leave")
}
}
- 运行这个子类extendsApp方法,输出如下:
意思是new子类这个动作首先会触发父类构造器(会先打印父类中的方法):
person here
person leave
bigtree here
bigtree leave
BigTree here
override的使用:
-
使用场景:
-
父类中有一个方法,子类中也有一个相同的方法。
override用来在子类中重写父类的方法或者属性。我们在父类中并没有找到toString方法,其实这个toString方法是内置的。
//override def toString() = “bigtree to string” 这段话注释掉后输出的结果是:
- com.ruozedata.bigdata.BigTree@675d3402
定位到源码object.java:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
默认的toString方法返回的是:完整的报名@+此对象哈希码的无符号十六进制
println(bt1.toString) 默认走的是父类的方法,如果子类重写了,那么调用的就是子类的方法。
3.2、子类重写父类
假设定义了一个父类Animal:定义了一个吃的方法
Dog eat
Cat eat
pig eat
.....
-
Dog类是从animal中继承过来的,对于猫狗来说他们的爱好是不同的,只需要用override把eat方法重写即可,override出来的走的就是自己的方法。
-
在框架中定义一些接口或者抽象类,具体实现是由子类来实现的.
-
记住一句话:override可以重写父类的方法,属性指的是 class People(val name:String, val wife:String)
-
scala中有两种赋值:var 和val,var在生命周期中可以被多次赋值,val就不能再赋值了。
Override的使用规则:
**当一个类extends另外一个类的时候:override的基本规则如下:**
-
子类中的方法要覆盖父类中的方法,必须写override
-
子类中的属性val要覆盖父类中的属性时,要override
-
父类中的变量不可以覆盖
MenoryManager.scala 父类 StaticMemoryManager.scala 子类 spark中的内存管理
继承类 子类继承父类中的money:
1、新建ConstructorDemo.scala
package scala03
object ConstructorDemo {
def main(args: Array[String]): Unit = {
val person = new Person("john","苏州")
println(person.name + "生活在" + person.city)
val person1 = new Person("sail","扬州",25)
}
//主构造器
class Person(var name:String,var city:String){
println("person here...")
var age:Int = _
val money = 1000000
//附属构造器,第一行必须要调用主构造器或者其它附属构造器,使用this关键字
def this(name:String,city:String,age:Int){
this(name,city)
this.age = age;
}
println("person leave...")
}
}
2、新建ExtendsApp.scala:
package scala03
import scala03.ConstructorDemo.Person
object ExtendsApp {
def main(args:Array[String])={
//new子类会先触发new父类,new出来一个苏州人1(sz1)
val sz1 = new szperson("煤老板","苏州",10000)
//打印一个toString方法
println(sz1.toString() )
//打印子类中sz1这个人所拥有的钱
println(sz1.money)
}
//新建一个苏州人类(szperson)继承自Person类中的(name,city)
class szperson(name:String,city:String,salary:Int) extends Person(name,city){
println("bigtree here")
//toString需要一个override修饰符
//用来在子类中重写父类的方法或者属性,我们在父类中没有找到toString方法
override def toString() = "BigTree here"
//重写主构造器中的钱
override val money: Int = 100
println("bigtree leave")
}
}
输出信息如下:
person here…
person leave…
bigtree here
bigtree leave
BigTree here
100 //重写了父类中的money(属性)
MemeryManager
StaticMemoryManager extends MemeryManager
父类中方法:MemeryManager.scala ==> def maxOffHeapStorageMemory: Long
子类中使用override重写掉:StaticMemoryManager.scala ==> override def maxOffHeapStorageMemory: Long = 0L
3.3、抽象类
package scala03
//抽象类,类中的方法没有具体实现
object AbstractApp{
def main(args: Array[String]): Unit = {
val a = new B()
a.speak() // 调用B中的speak
}
}
abstract class A {
def speak() //函数的定义但没有具体的实现
val name:String //没有具体实现的方法,没有具体赋值的属性
}
class B extends A{
val name:String = "B"
override def speak(): Unit = {
println("john speak")
} //B继承A后需要重写这个方法
输出: john speak
小结:
1、 抽象类中没有具体实现的方法
2、 抽象类不能直接new,而是通过子类来new(且子类不能还是抽象类),一定是要通过底层的能具体实现的子类来new
- 上述代码的A和B也是一个父子关系。
抽象类应用:Sparkenv.scala源码中,搜索memoryManager.scala,还有staticMemoryManager,
1、memoryManager.scala中的体现
2、staticMemoryManager.scala中的体现
/**
* A [[MemoryManager]] that statically partitions the heap space into disjoint regions.
*
* The sizes of the execution and storage regions are determined through
* `spark.shuffle.memoryFraction` and `spark.storage.memoryFraction` respectively. The two
* regions are cleanly separated such that neither usage can borrow memory from the other.
*/
private[spark] class StaticMemoryManager(
conf: SparkConf,
maxOnHeapExecutionMemory: Long,
override val maxOnHeapStorageMemory: Long,
numCores: Int)
extends MemoryManager(
conf,
numCores,
maxOnHeapStorageMemory,
maxOnHeapExecutionMemory) {
3、在SparkEnv.scala中的使用
val useLegacyMemoryManager = conf.getBoolean("spark.memory.useLegacyMode", false) //去配置文件中去读取,是布尔类型
val useLegacyMemoryManager = true //假设它读取出来的是true
val memoryManager: MemoryManager =
if (useLegacyMemoryManager) {
new StaticMemoryManager(conf, numUsableCores) //new了一个静态内存管理,跟上主构造器或附属构造器
} else {
UnifiedMemoryManager(conf, numUsableCores)
}
3.4 Scala中的trait(接口):
在抽象类中能否多继承,class B extends A with C(无法做到) ==> 引出概念多继承、
基本上可以等同为java中的interface
package scala03
//抽象类,类中的方法没有具体实现
object AbstractApp{
def main(args: Array[String]): Unit = {
val c = new C ()
val a = new B()
a.speak() // 调用B中的speak
}
}
abstract class A {
val name:String //没有具体实现的方法,没有具体赋值的属性
def speak() //函数的定义但没有具体的实现
}
//trait可以等同于Java的implementation
trait C{
def c()
}
//第一个用extends
class D extends A with C {
override def c(): Unit = {
println("")
}
override def speak(): Unit = ???
val name: String = ""
}
class B extends A{
val name:String = "B"
override def speak(): Unit = {
println("B speak")
} //B继承A后需要重写这个方法
}
第四章:Scala高阶函数(Most Important)
https://blog.csdn.net/zhikanjiani/article/details/90241193
4.1 高阶函数-集合
理解:MapReduce中仅仅只提供了两个函数map、reduce,而spark中提供非常多的函数供调用,更加人性化,开发效率更高。
val l = List(1,2,3,4,5,6,7,8) //List就是一个框,框中装的是1-8这8个数字
println(l.map((x:Int) => x*2)) //l * 2 每个元素都做一个相同的操作
精简表示:println(l.map(_*2))
输出:List(2, 4, 6, 8, 10, 12, 14, 16, 18)
提示:unspecified value parameters:f:Int => NotInferedB
解释:map : 映射 y=f(x) x作用上一个函数f 变成y
l.map((x:Int) => x*2) map对list中的每一个元素,变成x*2
x:Int 是入参,x可以随意赋值,Int是List中的元素类型
l.map() 提示:f:Int => B Int指的是函数中的每一个类型
在IDEA中实现
package com.ruozedata.bigdata
object higherfunctions {
def main(args: Array[String]): Unit = {
//list就是一个框,框里装的是1-9这9个数字
val l = List(1,2,3,4,5,6,7,8,9)
// 1*2每个元素都做一个相同的操作
println(l.map((x:Int) => x * 2))
}
}
对输出代码做简写
println(l.map(x =>x*2))
//继续简化
println(l.map(_*2))
_指的是前面l里面的每个元素
4.2 输出集合中大于10的数:
println(l.map(*2).filter(>10))
结果:List(12, 14, 16, 18)
在2的基础上使用(take)取前2个数
4.3 输出集合中大于10的数:
println(l.map(*2).filter(>10).take(2))
结果:List(12, 14)
4.4求和:两两相邻的数字加起来
/*
1+2+3+4+5+6+7+8+9
1+2=3
3+3=6
6+4=10
10+5=15
15+6=21
21+7=28
…
*/
//两两相加
println(l.reduce((x:Int,y:Int) => x+y))
简写如下:
println(l.reduce(+)) //"+"
两两相减
println(l.reduce((x:Int,y:Int) => x-y))
println(l.reduce(-)) //"-"
4.5 reduceLeft、reduceRight的使用
测试方法:它的运行过程是怎么样的?
在IDEA中运行,reduceLeft(-)
l.reduceLeft((x:Int,y:Int) =>{
println(x + "," + y)
x - y
})
结果:
1,2
-1,3
-4,4
-8,5
-13,6
-19,7
-26,8
-34,9
输出:-34-9 ==> -43
测试reduceRight(_-)
l.reduceRight((x:Int,y:Int) => {
println(x + ":" + y)
x - y
})
打印过程:
8:9
7:-1
6:8
5:-2
4:7
3:-3
2:6
1:-4
输出结果:(1 - (-4)) ==> 5
4.6 fold参数
概念:就是一个初始值的意思
l.fold(0)(+)
简易代码:
l.fold(10)((x:Int,y:Int) =>{
println(x + “:” + y)
x + y
})
结果如下:
10:1
11:2
13:3
16:4
20:5
25:6
31:7
38:8
46:9
55:10
在scala下直接进行操作如下:
scala> var l = List(1,2,3,4,5,6,7,8,9)
l: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> l.max
res6: Int = 9
scala> l.min
res7: Int = 1
scala> l.sum
res8: Int = 45
scala> l.count(_>3)
res9: Int = 6
4.7 多重list
val a = List(List(1,2),List(3,4),List(5,6))
println(a.flatten)
输出如下:List(1, 2, 3, 4, 5, 6)
flatten的作用是把输出拉平。
flatten源码中的例子:
val xs = List(
Set(1,2,3),
Set(1,2,3)
).flatten
// xs == List(1,2,3,1,2,3)
4.8 flatMap的使用
概念:
flatMap == flatten + map
val a = List(List(1,2,3),List(3,4),List(4,5,6))
val b = a.flatten
println(b.map(_*2))
==>等价于如下这句话
println(a.flatMap(_.map(_*2)))
输出如下:List(2, 4, 6, 6, 8, 8, 10, 12)
4.9 结合业务场景Scala进行词频统计
scala进行词频统计:
-
data目录下有一个文件内容如下:hello world hello hello world welcome hello
我们需要为每一个单词赋上一个1,如下操作:<_,1>
在MapReduce中:map<word,1>var lines = ...... hello world hello hello world welcome hello
-
进行第一步操作:
lines.flatMap(_.split("\t"))得到的结果: hello world hello hello world welcome hello
-
第二步操作:
words.map(x => (x,1)) //为买个元素赋上一个1 -
第三步:求和(就是两两相加)
reduceByKey(+)
结果:(hello,3)(world,2) (welcome,1)
第五章、本次课程作业
-
使用ScalikeJDBC操作MySQL数据库:
-
https://blog.csdn.net/zhikanjiani/article/details/94866872