引言Scala不仅是完全面向函数编程,还是完全面向对象语言。格式类的定义class类名{//类主体//定义类属性//Scala类属性是需要初始化的,初始化只需要_(下划线)就可以了varname:String=_varage:Int=_//类方法defshow(){函数逻辑}}类的使用//创建类对象val对象名:类属性=new类名称//获取类属性对象名.属性名//设置类属性对象名.属性名=值//执行类方法对象名.方法名()如果使用val声明属性,属性将不能被修改,底层会有final修饰私有属性属性被private修饰,将不能在类外边直接访问。小案例定义User类classUser{varname:String=_varage:Int=_defshow():Unit={println(s"name:$name;age:$age")}}类使用objectdemoextendsApp{//创建类对象valuser:User=newUser()//设置类属性user.name="Bob"user.age=16//获取类属性println(user.name)//执行类方法user.show()}----------------------------------Bobname:Bob;age:16
引言会涉及_(下划线)的其中一个用法Scala的宗旨:至简。所以把匿名函数作为函数的参数,可以进行很大程度的简化有一个参数的简化定义一个函数deffun(f:Int=>Unit):Unit={f(12)}执行函数传入匿名函数fun((a:Int)=>{println(a)})匿名函数的参数类型,可以被自动推断出来,可以简化fun((a)=>{println(a)})参数只有一个,代码在一行,代码块括号可以简化fun(a=>println(a))下面是println()函数的特殊简化,println()本身也是一个函数参数后面只用一次,可以用_(下划线)代替fun(println(_))fun(println)---------------12有多个参数的简化定义一个函数(两个参数)deffn(f:(Int,Int)=>Int):Unit={println(f(12,23))}执行函数传入匿名函数fn((a:Int,b:Int)=>{a+b})匿名函数的参数类型,可以被自动推断出来,可以简化fn((a,b)=>{a+b})代码在一行,代码块括号可以进一步简化fn((a,b)=>a+b)如果参数只用了一次可以使用_fn(_+_)-------35
引言Scala不仅是完全面向对象语言,而且还是完全面向函数编程语言,所以Scala叫做多范式编程语言,Scala的函数非常强大函数可以作为函数的返回值函数可以作为函数的参数函数可以赋值给变量函数作为返回值函数作为返回值,需要注意_(下换线)的用法把返回值函数写在外边//定义一个函数,作为返回值deffun(name:String):Unit={println(s"fun_name=$name")}//定义执行函数deffun1(name:String)={//加个_(下划线)表名该函数是返回值println(s"fun1_name=$name")fun_}//执行函数,返回值函数不会被执行fun1("Bob")-------------------------fun1_name=Bob//执行返回值函数fun1("Bob")("bigdataboy")-------------------------fun1_name=Bobfun_name=bigdataboy把返回值函数写在内部函数执行结果与上面一样,只是这样写跟容易理解deffun1(name:String)={//返回值函数deffun(name:String):Unit={println(s"fun_name=$name")}println(s"fun1_name=$name")fun_}函数柯里化就是把上面的格式进行简化,通过函数调用就可以看出来所以Scala里就会看到()()()()()()这样的调用deffun(name:String)(name1:String):Unit={println(s"name=$name")println(s"name1=$name1")}fun("Bob")("Bbigdataboy")----------------------------------------------fun1_name=Bobfun_name=bigdataboy函数作为参数把函数作为参数,不同点在于规定参数类型时的写法不一样deffun(f:String=>Unit):Unit={f()}//定义参数类型解析f:String=>Unit参数名称:传入函数的参数类型=>传入函数的返回值类型小例子自定义传入一段逻辑(函数)给函数deffun(f:Int=>Int,num:Int):Unit={//执行传入的函数(有参数也需要传参数)println(f(num))}参数函数//把传入的参数不做任何处理直接返回deffn(n:Int):Int={n}执行函数fun(fn,5)---------5传入匿名函数(作为参数)这也是Spark用的最多的,匿名函数可以看看这个//定义一个函数deffun(f:()=>Unit):Unit={f()}执行函数(传入匿名函数)fun(()=>{println("Hellobigdataboy")})---------------------------------------Hellobigdataboy函数赋值给变量变量可以接受一个匿名函数valadd=(a:Int,b:Int)=>a+b//调用println(add(12,34))---------------------------------46
如果你有Python基础,那么Scala的函数基础使用,你能快速的上手格式def函数名(参数名:参数类型,参数名:参数类型):返回值类型={方法体}defmani(args:Array[String]):Unit={print("Helloworld")}函数的入参(参数)和出参(返回值)有参数有返回值deffun(a:String):String={returna+"bigdataboy.cn"}println(fun("https://"))有参数没有返回值deffun(a:String):Unit={println(a)}fun("bigdataboy.cn")没有参数有返回值deffun():String={"HelloScala"}println(fun())没有参数没有返回值deffun():Unit={println("HelloScala")}fun()可变参数与Python类似,用*号表示可变参数可以传参,也可以不传参可变参数一般放在参数列表的最后面deffun(name:String*):Unit={println(name)}fun()fun("Bob","Black")--------------------------------List()ArraySeq(Bob,Black)默认参数默认参数与Python类似deffun(name:String,age:Int=13)={println(name,"-",age)}fun("Bob")fun(name="Bob",age=16)---------------------------------------(Bob,-,13)(Bob,-,16)精简函数格式如果能通过最后一行,推测出返回值类型,就可以不写返回值类型deffun()={println("Scala")"Scala"}//调用println(fun())--------------------ScalaScala可以使用分号隔开逻辑写成一行deffun()={println("Scala");"Scala"}//调用println(fun())--------------------ScalaScala在一行就可以去掉大括号。去掉大括号,写在一行就只对最近的一个逻辑有效,所以后面打印的是()deffun()=println("Scala");"Scala"//调用println(fun())--------------------Scala()如果函数,没有参数,可以去掉参数括号,但是在调用的时候,也不用加括号deffun=println("Scala");"Scala"//调用println(fun)-----Scala()小技巧:当明确没有返回值时,函数的=可以省略,编译器也就不会把最后一行代码作为返回值。deffun4(){println("Scala");"Scala"}println(fun4())--------------------------------------Scala()匿名函数格式()->{代码块}例子()->{vara=1varb=2println(a+b)}//写成一行分号区分代码块()->{vara=1;varb=2;println(a+b)}-------------------------------------------3
格式for(i<-0to|until5){循环体}for(i<-1to5){println(s"i=$i")}i:i是接收for循环次数的变量,不用声明是因为Scala能自动推断to:是[0,5],是前后都包含的意思until:是[0,5),是前包含后不包含的意思详解to和until到Range()控制循环步长1.to(5)-简写->1to50.until(5)-简写->0until5until和to的源码里都调用了一个Rang()的方法,所以for循环还能这样写for(i<-Range(0,5)){println(s"第$i次")}----------------------第0次第1次第2次第3次第4次Range()控制循环步长for(i<-Range(0,5,2)){println(s"第$i次")}----------------------第0次第2次第4次小案例一层循环打印九层妖塔for(i<-Range(1,18,2)){println(""*((18-i)/2)+"*"*i+""*((18-i)/2))}守卫循环循环守卫:所谓循环守卫就是加一个判断,成立执行循环体,不成立跳过本次循环跟Java和Python中的continue一样for(i<-1to6ifi%2==0){println(s"i=$i")}-------------------------------i=2i=4i=6其实也可以等价于for(i<-1to6){if(i%2==0){println(s"i=$i")}引入变量格式//原本格式,分号隔开for(i<-1to5;f=i%2){println(s"i=$i:f=$f")}//写一行;隔开逻辑,注意大括号for{i<-1to5;f=i%2}{println(s"i=$i:f=$f")}//不要分号换行隔开逻辑for{i<-1to5f=i%2}{println(s"i=$i:f=$f")}所以小案例变换//要分号for{i<-Range(1,18,2);j=((18-i)/2)}{println(""*j+"*"*i+""*j)}//不要分号代码块for{i<-Range(1,18,2)j=((18-i)/2)}{println(""*j+"*"*i+""*j)}for的返回值一般情况for都没有返回值//for的返回值一般情况for的返回值都是Unitvalres:Unit=for(i<-1to5){"abc"}yeild特殊情况它会把结果返回成一个集合valvalue=for(i<-1to5)yieldiprintln(value)-------------------------------------Vector(1,2,3,4,5)for跳出循环Scala是完全面向对象的语言,所以没有break。Scala使用的产生一个特定的异常,然后进行类似异常处理来保证后面代码的正常运行//产生异常,结束循环for(i<-1to5){if(i==3){Breaks.break()}println(s"s=$i")}----------------------s=1s=2Exceptioninthread"main"scala.util.control.BreakControl对异常进行特定处理,保证后面正常运行Breaks.breakable(//这对小括号可以换成大括号(表示包裹代码块)for(i<-1to5){if(i==3){Breaks.break()}println(s"s=$i")})println("跳出循环")---------------------------s=1s=2跳出循环
单分支结构式varfalg=trueif(falg){println("true")}双分支结构式varfalg=trueif(!falg){println("true")}else{println("false")}多分支结构式varname="a"if(name.equals("a")){println("a")}elseif(name.equals("b")){println("b")}else{println("未知")}小技巧当判断的代码块不写{}时,只对最近的一行代码有效//两种结果写法一样varfalg=trueif(falg)println("true")if(falg){println("true")}var&=trueif(!&)println("true")elseprintln("false")条件判断的返回值在Scala中,任何的表达式都有返回值条件判断的返回值就是每个代码块的最后一行的返回值返回值类型Any,AnyVal返回类型最方便是不写Any是返回值类型是String和Unit等等AnyVal是返回值类型是Int和Unit等等varmsg=truevalreg:Any=if(msg){"abc"//Scala可以这样单独写个值,Java不行}println(reg)定义返回值类型需要能确定全部返回类型varmsg=truevalreg:String=if(msg){"true"}else{"false"}println(reg)Scala中的“三元运算符”Scala中没有标准的三元运算符,也没有必要有,就省略了//Java中的三元运算符Stringnum=if(13==12)?"0":"1"//Scala中模拟的三元运算符varnum=if(13==12)"0"else"1"
groupby分组通常会和聚合函数一起使用,按照某个字段的内容进行分组,然后每个分组执行聚合操作原本数据idnamemoney1Bob12002Black21003BigDataBoy56004Bob23005Bob32006Black5600需求:按照姓名(name)进行分组,求平均工资(money)查询语句:selectname,avg(money)fromhive_dbgroupbyname;查询结果hive>selectname,avg(money)fromhive_db>groupbyname;QueryID=root_20200127203058_a0984c91-9ca1-4735-b6a9-ffd5aa2d17a7...TotalMapReduceCPUTimeSpent:18seconds160msecOKBigDataBoy5600.0Black3850.0Bob2233.3333333333335Timetaken:48.392seconds,Fetched:3row(s)having语句having与where语句的异同where针对表中的列发挥作用,查询数据;having针对查询结果中的列发挥作用,筛选数据。where后面不能写分组函数,而having后面可以使用分组函数。having只用于groupby分组统计语句。需求:不同名字(name)的平均工资(money)大于3000的查询语句:selectname,avg(money)avg_moneyfromhive_dbgroupbynamehavingavg_money>3000;查询结果:hive>selectname,avg(money)avg_moneyfromhive_db>groupbyname>havingavg_money>3000;QueryID=root_20200127204801_68c6a01d-21a3-4355-b3a8-69900f16b857...TotalMapReduceCPUTimeSpent:16seconds10msecOKBigDataBoy5600.0Black3850.0Timetaken:46.82seconds,Fetched:2row(s)
Join语句Hive支持通常的SQLJOIN语句,但是只支持等值连接,不支持非等值连接。表1(hive_db)idnamemoney1Bob12002Black21003BigDataBoy56004Bob23005Bob32006Black5600表2(city)nameaddrBobBeijingBlackHuNanBigDataBoySiChuan查询案例需求:表1的姓名(name)与表2的addr合并idnameaddr查询语句selecth.id,h.name,c.addrfromhive_dbhjoin#连接的另一张表citycon#筛选条件不支持orh.name=c.name;查询结果hive>select>h.id,h.name,c.addr>from>hive_dbh>join>cityc>on>h.name=c.name;QueryID=root_20200127215351_3f0945cf-dfd3-4c00-ba9a-b177cecf018f...MapReduceJobsLaunched:Stage-Stage-3:Map:1CumulativeCPU:2.86secHDFSRead:6494HDFSWrite:91SUCCESSTotalMapReduceCPUTimeSpent:2seconds860msecOK1BobBeijing2BlackHuNan3BigDataBoySiChuan4BobBeijing5BobBeijing6BlackHuNanTimetaken:31.054seconds,Fetched:6row(s)内连接join只有进行连接的两个表中满足连接条件的数据才会被保留下来。selecth.id,h.name,c.addrfromhive_dbhjoincityconh.name=c.name;左外连接leftjionon或者where筛选条件的左边的表的查询字段的所有数据将会保留下来selecth.id,h.name,c.addrfromhive_dbhleftjoincityconh.name=c.name;右外连接rightjionon或者where筛选条件的右边的表的查询字段的所有数据将会保留下来selecth.id,h.name,c.addrfromhive_dbhrightjoincityconh.name=c.name;满外连接fulljionon或者where筛选条件的两边的表的查询字段的所有数据将会保留下来,任一表的指定字段没有符合条件的值用NULL代替selecth.id,h.name,c.addrfromhive_dbhfulljoincityconh.name=c.name;多表连接注意:连接n个表,至少需要n-1个连接条件。例如:连接三个表,至少需要两个连接条件。
什么是SparkSpark是一种基于内存的快速、通用、可扩展的大数据分析引擎发展历史2009年诞生,采用Scala编写2010年开源2013年6月成为Apache孵化项目2014年2月成为Apache顶级项目Spark特点快比MapReduce相比要快百倍以上,实现了DAG执行引擎,通过内存高效处理数据流易用Spark支持Java、Python、Scala、R等API,还支持超过80种高级算法,使用户可以快速构建不同的应用。还支持Python和Scala的交互式Shell。通用Spark提供了一套统一的解决方案。Spark可以用于批处理、交互式查询(SparkSQL)、实时处理(SpakrStreaming)、机器学习(SparkMLlib)、图计算(GraphX),这些不同类型的处理都可以无缝使用。兼容性Spark可以十分方便的与其他开源产品进行融合,比如:可以使用HAdoop的Yarn和Apache的Mesos作为资源管理和调度器,并且可处理所有支持Hadoop的数据,包括HDFS、HBase,这样可以使得已经使用过Hadoop集群的用户非常友好,不需要做任何的数据迁移就可以使用Spark强大的处理能力。Spark的内置模块SparkCore:实现了Spark的基本功能,包含任务调度、内存管理、错误恢复、与存储系统交互等模块。SparkCore中还包含了对弹性分布式数据集(ResilientDistributedDataSet,简称RDD)的API定义。SparkSQL:是Spark用来操作结构化数据的程序包。通过SparkSQL,我们可以使用SQL或者ApacheHive版本的SQL方言(HQL)来查询数据。SparkSQL支持多种数据源,比如Hive表、Parquet以及JSON等。SparkStreaming:是Spark提供的对实时数据进行流式计算的组件。提供了用来操作数据流的API,并且与SparkCore中的RDDAPI高度对应。SparkMLlib:提供常见的机器学习(ML)功能的程序库。包括分类、回归、聚类、协同过滤等,还提供了模型评估、数据导入等额外的支持功能。集群管理器:Spark设计为可以高效地在一个计算节点到数千个计算节点之间伸缩计算。为了实现这样的要求,同时获得最大灵活性,Spark支持在各种集群管理器(ClusterManager)上运行,包括HadoopYARN、ApacheMesos,以及Spark自带的一个简易调度器,叫作独立调度器。