离线数据抽取
写在前面:
此笔记是本人在备战大数据赛项整理出来的,不涉及国赛涉密内容,如点赞收藏理想,我将会把所有模块的笔记开源分享出来,如有想询问国赛经验的可以关注私聊我,我会一一回复。
1. Scala
Scala简介
Scala 是一门满足现代软件工程师需求的语言;它是一门静态类型语言,支持混合范式;它也是一门运行在 JVM 之上的语言,语法简洁、优雅、灵活。Scala 拥有一套复杂的类型系统,Scala方言既能用于编写简短的解释脚本,也能用于构建大型复杂系统。
Scala基础
1. 数据类型
2. 变量和常量的声明
定义变量或者常量的时候,也可以写上返回的类型,一般省略,如:val a:Int = 10常量不可再赋值/*** 定义变量和常量* 变量 :用 var 定义 ,可修改 * 常量 :用 val 定义,不可修改*/var name = "zhangsan"println(name)name ="lisi"println(name)val gender = "m"// gender = "m"//错误,不能给常量再赋值注意:scala有个原则就是极简原则,不用写的东西一概不写。定义变量有两种形式一种是像上面那样用val修饰另一种是var进行修饰val 定义的变量不可变相当与java中的final用表达式进行赋值Val x=1Val y=if(1>0) 1 else -1混和表达式Val a =if (x>0) 1 else “jay”需要注意的是any是所有的父类,相当于java里的objectelse缺失的表达式val p=if (x>5) 1
3. 类和对象
创建类
class Person{val name = "zhangsan"val age = 18def sayName() = {"my name is "+ name}}
创建对象
object Lesson_Class {def main(args: Array[String]): Unit = {val person = new Person()println(person.age);println(person.sayName())}}
apply方法
/*** object 单例对象中不可以传参,* 如果在创建Object时传入参数,那么会自动根据参数的个数去Object中寻找相应的apply方法*/object Lesson_ObjectWithParam {def apply(s:String) = {println("name is "+s)}def apply(s:String,age:Int) = {println("name is "+s+",age = "+age)}def main(args: Array[String]): Unit = {Lesson_ObjectWithParam("zhangsang")Lesson_ObjectWithParam("lisi",18)}}
伴生类和伴生对象
class Person(xname :String , xage :Int){var name = Person.nameval age = xagevar gender = "m"def this(name:String,age:Int,g:String){this(name,age)gender = g}def sayName() = {"my name is "+ name}}object Person {val name = "zhangsanfeng"def main(args: Array[String]): Unit = {val person = new Person("wagnwu",10,"f")println(person.age);println(person.sayName())println(person.gender)}}
注意点:
建议类名首字母大写 ,方法首字母小写,类和方法命名建议符合驼峰命名法。scala 中的object是单例对象,相当于java中的工具类,可以看成是定义静态的方法的类。object不可以传参数。另:Trait不可以传参数scala中的class类默认可以传参数,默认的传参数就是默认的构造函数。
重写构造函数的时候,必须要调用默认的构造函数。
class 类属性自带getter ,setter方法。使用object时,不用new,使用class时要new ,并且new的时候,class中除了方法不执行(不包括构造),其他都执行。如果在同一个文件中,object对象和class类的名称相同,则这个对象就是这个类的伴生对象,这个类就是这个对象的伴生类。可以互相访问私有变量。
4. This
/qq_39521554/article/details/81045826?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
5. if else
/** * if else */valage =18if(age < 18 ){ println(“no allow”) }elseif(18<=age&&age<=20){ println(“allow with other”) }else{ println(“allow self”) }
6. for ,while,do…while
to和until 的用法(不带步长,带步长区别)
/*** to和until* 例:* 1 to 10 返回1到10的Range数组,包含10* 1 until 10 返回1到10 Range数组 ,不包含10*/println(1 to 10 )//打印 1, 2, 3, 4, 5, 6, 7, 8, 9, 10println(1.to(10))//与上面等价,打印 1, 2, 3, 4, 5, 6, 7, 8, 9, 10println(1 to (10 ,2))//步长为2,从1开始打印 ,1,3,5,7,9println(1.to(10, 2)) println(1 until 10 ) //不包含最后一个数,打印 1,2,3,4,5,6,7,8,9println(1.until(10))//与上面等价println(1 until (10 ,3 ))//步长为2,从1开始打印,打印1,4,7在scala中,Range代表的是一段整数的范围,官方有关range的api:http://www.scala-/api/current/index.html#scala.collection.immutable.Range这些底层其实都是Range,Range(1,10,2):1是初始值,10是条件,2是步长,步长也可以为负值,递减。until和Range是左闭右开,1是包含的,10是不包含。而to是左右都包含。
for循环
/*** for 循环* */for( i <- 1 to 10 ){println(i)}//for循环数组val arr=Array(“a”,”b”,”c”)for(i<-arr)println(i)
创建多层for循环(高级for循环)
//可以分号隔开,写入多个list赋值的变量,构成多层for循环//scala中 不能写count++ count-- 只能写count+var count = 0;for(i <- 1 to 10; j <- 1 until 10){println("i="+ i +", j="+j)count += 1}println(count);//例子: 打印小九九for(i <- 1 until 10 ;j <- 1 until 10){if(i>=j){print(i +" * " + j + " = "+ i*j+" ")}if(i==j ){println()}}
for循环中可以加条件判断,可以使用分号隔开,也可以不使用分号(使用空格)
//可以在for循环中加入条件判断for(i<- 1 to 10 ;if (i%2) == 0 ;if (i == 4) ){println(i)}
scala中不能使用count++,count—只能使用count = count+1 ,count += 1
for循环用yield 关键字返回一个集合(把满足条件的i组成一个集合)
val result = for(i <- 1 to 100 if(i>50) if(i%2==0)) yield i
println(result)
while循环,while(){},do {}while()
//将for中的符合条件的元素通过yield关键字返回成一个集合val list = for(i <- 1 to 10 ; if(i > 5 )) yield i for( w <- list ){println(w)}/*** while 循环*/var index = 0 while(index < 100 ){println("第"+index+"次while 循环")index += 1 }index = 0 do{index +=1 println("第"+index+"次do while 循环")}while(index <100 )
加深练习
需求说明:定义一个数组val a1=Array(1,2,3,4,5,6,7,8,9)把其中的偶数取出。
def main(args: Array[String]): Unit = {var a1=Array.range(1,10)for(i<-a1 if(i%2==0)) {println(i)}}}
7. 懒加载
Val lazyVal={println(“I am too lazy”);1}
lazy val lazyVal={println(“I am too lazy”);1}
8. Scala方法与函数
Scala方法的定义
有参方法
无参方法
def fun (a: Int , b: Int ) : Unit = {println(a+b)}fun(1,1)def fun1 (a : Int , b : Int)= a+bprintln(fun1(1,2))
注意点:
方法定义语法 用def来定义可以定义传入的参数,要指定传入参数的类型方法可以写返回值的类型也可以不写,会自动推断,有时候不能省略,必须写,比如在递归方法中或者方法的返回值是函数类型的时候。scala中方法有返回值时,可以写return,也可以不写return,会把方法中最后一行当做结果返回。当写return时,必须要写方法的返回值。如果返回值可以一行搞定,可以将{}省略不写传递给方法的参数可以在方法中使用,并且scala规定方法的传过来的参数为val的,不是var的。如果去掉方法体前面的等号,那么这个方法返回类型必定是Unit的。这种说法无论方法体里面什么逻辑都成立,scala可以把任意类型转换为Unit.假设,里面的逻辑最后返回了一个string,那么这个返回值会被转换成Unit,并且值会被丢弃。
方法与函数
定义一个方法:
def method(a:Int,b:Int) =a*b val a =2
method(3,5)
定义一个函数:
Val f1=(x:Int,y:Int)=>x+y
f1 (1,2)
匿名函数
(x:Int,y:Int)=>x+y
在函数式编程语言中,函数是“头等公民”,它可以像任何其他数据类型一样被传递和操作,函数可以在方法中传递。
递归方法
/*** 递归方法 * 5的阶乘*/def fun2(num :Int) :Int= {if(num ==1)numelse num * fun2(num-1)}print(fun2(5))
参数有默认值的方法
默认值的函数中,如果传入的参数个数与函数定义相同,则传入的数值会覆盖默认值。如果不想覆盖默认值,传入的参数个数小于定义的函数的参数,则需要指定参数名称。/*** 包含默认参数值的函数* 注意:* 1.默认值的函数中,如果传入的参数个数与函数定义相同,则传入的数值会覆盖默认值* 2.如果不想覆盖默认值,传入的参数个数小于定义的函数的参数,则需要指定参数名称*/def fun3(a :Int = 10,b:Int) = {println(a+b)}fun3(b=2)
可变参数的方法
多个参数用逗号分开/*** 可变参数个数的函数* 注意:多个参数逗号分开*/def fun4(elements :Int*)={var sum = 0;for(elem <- elements){sum += elem}sum}println(fun4(1,2,3,4))
匿名函数
有参匿名函数无参匿名函数有返回值的匿名函数 可以将匿名函数返回给val定义的值/*** 匿名函数* 1.有参数匿名函数* 2.无参数匿名函数* 3.有返回值的匿名函数* 注意:* 可以将匿名函数返回给定义的一个变量*///有参数匿名函数val value1: (Int)=>Unit = (a : Int) => {println(a)}value1(1)//无参数匿名函数val value2 = ()=>{println("我爱学习")}value2()//有返回值的匿名函数val value3 = (a:Int,b:Int) =>{a+b}println(value3(4,4))
嵌套方法
/*** 嵌套方法* 例如:嵌套方法求5的阶乘*/def fun5(num:Int)={def fun6(a:Int,b:Int):Int={if(a == 1){b}else{fun6(a-1,a*b)}}fun6(num,1)}println(fun5(5))
偏应用函数
偏应用函数是一种表达式,不需要提供函数需要的所有参数,只需要提供部分,或不提供所需参数。
/*** 偏应用函数*/def log(date :Date, s :String)= {println("date is "+ date +",log is "+ s)}val date = new Date()log(date ,"log1")log(date ,"log2")log(date ,"log3")//想要调用log,以上变化的是第二个参数,可以用偏应用函数处理val logWithDate = log(date,_:String)logWithDate("log11")logWithDate("log22")logWithDate("log33")
高阶函数
函数的参数是函数,或者函数的返回类型是函数,或者函数的参数和函数的返回类型是函数的函数。
函数的参数是函数函数的返回是函数函数的参数和函数的返回是函数
/*** 高阶函数* 函数的参数是函数或者函数的返回是函数 或者函数的参数和返回都是函数*///函数的参数是函数def hightFun(f : (Int,Int) =>Int, a:Int ) : Int = {f(a,100)}def f(v1 :Int,v2: Int):Int = {v1+v2}println(hightFun(f, 1))//函数的返回是函数//1,2,3,4相加def hightFun2(a : Int,b:Int) : (Int,Int)=>Int = {def f2 (v1: Int,v2:Int) :Int = {v1+v2+a+b}f2}println(hightFun2(1,2)(3,4))//函数的参数是函数,函数的返回是函数def hightFun3(f : (Int ,Int) => Int) : (Int,Int) => Int = {f} println(hightFun3(f)(100,200))println(hightFun3((a,b) =>{a+b})(200,200))//以上这句话还可以写成这样//如果函数的参数在方法体中只使用了一次 那么可以写成_表示println(hightFun3(_+_)(200,200))
柯里化函数
高阶函数的简化定义柯里化(Currying)指的是把原来接受多个参数的函数变换成接受一个参数的函数过程,并且返回接受余下的参数且返回结果为一个新函数的技术。scala柯里化风格的使用可以简化主函数的复杂度,提高主函数的自闭性,提高功能上的可扩张性、灵活性。可以编写出更加抽象,功能化和高效的函数式代码。//柯理化object KLH {def main(args: Array[String]): Unit = {def klh(x:Int)(y:Int) =x*yval res=klh(3)(_)println(res(4))}}/*** 柯里化函数*/def fun7(a :Int,b:Int)(c:Int,d:Int) = {a+b+c+d}println(fun7(1,2)(3,4))
2. Spark
spark简介
Spark 是一种基于内存的快速、通用、可扩展的大数据分析计算引擎。
在YARN上运行Spark
配置
大部分为
Spark on YARN
模式提供的配置与其它部署模式提供的配置相同。下面这些是为
Spark on YARN
模式提供的配置。
Spark属性
在YARN上启动Spark
确保
HADOOP_CONF_DIR
或
YARN_CONF_DIR
指向的目录包含Hadoop集群的(客户端)配置文件。这些配置用于写数据到dfs和连接到YARN ResourceManager。
有两种部署模式可以用来在YARN上启动Spark应用程序。在yarn-cluster模式下,Spark driver运行在application master进程中,这个进程被集群中的YARN所管理,客户端会在初始化应用程序之后关闭。在yarn-client模式下,driver运行在客户端进程中,application master仅仅用来向YARN请求资源。
和Spark单独模式以及Mesos模式不同,在这些模式中,master的地址由"master"参数指定,而在YARN模式下,ResourceManager的地址从Hadoop配置得到。因此master参数是简单的
yarn-client
和
yarn-cluster
在yarn-cluster模式下启动Spark应用程序。
./bin/spark-submit --class path.to.your.Class --master yarn-cluster [options] <app jar> [app options]
例子:
$ ./bin/spark-submit --class org.apache.spark.examples.SparkPi \--master yarn-cluster \--num-executors 3 \--driver-memory 4g \--executor-memory 2g \--executor-cores 1 \--queue thequeue \lib/spark-examples*.jar \10
以上启动了一个YARN客户端程序用来启动默认的 Application Master,然后SparkPi会作为Application Master的子线程运行。客户端会定期的轮询Application Master用于状态更新并将更新显示在控制台上。一旦你的应用程序运行完毕,客户端就会退出。
在yarn-client模式下启动Spark应用程序,运行下面的shell脚本
$ ./bin/spark-shell --master yarn-client
添加其它的jar
在yarn-cluster模式下,driver运行在不同的机器上,所以离开了保存在本地客户端的文件,
SparkContext.addJar
将不会工作。为了使
SparkContext.addJar
用到保存在客户端的文件,在启动命令中加上
--jars
选项。
$ ./bin/spark-submit --class my.main.Class \--master yarn-cluster \--jars my-other-jar.jar,my-other-other-jar.jarmy-main-jar.jarapp_arg1 app_arg2
注意事项
在Hadoop 2.2之前,YARN不支持容器核的资源请求。因此,当运行早期的版本时,通过命令行参数指定的核的数量无法传递给YARN。在调度决策中,核请求是否兑现取决于用哪个调度器以及如何配置调度器。
Spark executors使用的本地目录将会是YARN配置(yarn.nodemanager.local-dirs)的本地目录。如果用户指定了
spark.local.dir
,它将被忽略。
--files
和
--archives
选项支持指定带#号文件名。例如,你能够指定
--files localtest.txt#appSees.txt
,它上传你在本地命名为
localtest.txt
的文件到HDFS,但是将会链接为名称
appSees.txt
。当你的应用程序运行在YARN上时,你应该使用
appSees.txt
去引用该文件。
如果你在yarn-cluster模式下运行
SparkContext.addJar
,并且用到了本地文件,
--jars
选项允许
SparkContext.addJar
函数能够工作。如果你正在使用 HDFS, HTTP, HTTPS或FTP,你不需要用到该选项。