大数据实战第十课之-Scala03

第一章、上次课回顾

第二章、使用原生Scala代码链接MySQL

第三章、父类和子类

四、Scala中高阶函数(Most Important)

第五章、本次课程作业

一、上次课回顾

回顾: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
.....
  1. Dog类是从animal中继承过来的,对于猫狗来说他们的爱好是不同的,只需要用override把eat方法重写即可,override出来的走的就是自己的方法。

  2. 在框架中定义一些接口或者抽象类,具体实现是由子类来实现的.

  3. 记住一句话:override可以重写父类的方法,属性指的是 class People(val name:String, val wife:String)

  4. 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进行词频统计:

  1. data目录下有一个文件内容如下:hello world hello hello world welcome hello
    我们需要为每一个单词赋上一个1,如下操作:<_,1>
    在MapReduce中:map<word,1>

    var lines = ......
    hello	world	hello
    hello	world	welcome
    hello
    
  2. 进行第一步操作:
    lines.flatMap(_.split("\t"))

    得到的结果:
    hello
    world
    hello
    hello
    world
    welcome
    hello
    
  3. 第二步操作:
    words.map(x => (x,1)) //为买个元素赋上一个1

  4. 第三步:求和(就是两两相加)
    reduceByKey(+)
    结果:(hello,3)(world,2) (welcome,1)

第五章、本次课程作业

  • 使用ScalikeJDBC操作MySQL数据库:

  • https://blog.csdn.net/zhikanjiani/article/details/94866872

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值