随着大数据的发展,spark逐渐成为主流技术之一,而且支撑的scala语言也成为做大数据热门的编程语言之一,在家无聊,就将scala中一些常用的的scala的高端函数以及set、map等代码进行整理,在最后有一个完整的wordcount大数据入门源码
偏应用函数
偏应用函数是一种表达式,不需要提供函数需要的所有参数,只需要提供部分,或不提供所需参数。/**
* 偏应用函数
*/
deflog(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,以上变化的是第二个参数,可以用偏应用函数处理
vallogWithDate = log(date,_:String)
logWithDate("log11")
logWithDate("log22")
logWithDate("log33")
高阶函数
函数的参数是函数,或者函数的返回类型是函数,或者函数的参数和函数的返回类型是函数的函数。
l 函数的参数是函数
l 函数的返回是函数
l 函数的参数和函数的返回是函数
/*** 高阶函数
* 函数的参数是函数 或者函数的返回是函数 或者函数的参数和返回都是函数
*/
//函数的参数是函数
def hightFun(f : (Int,Int) =>Int, a:Int ) : Int = {
f(a,100)
}
deff(v1 :Int,v2: Int):Int = {
v1+v2
}
println(hightFun(f, 1))
//函数的返回是函数
//1,2,3,4相加
defhightFun2(a : Int,b:Int) : (Int,Int)=>Int = {
deff2 (v1: Int,v2:Int) :Int = {
v1+v2+a+b
}
f2
}
println(hightFun2(1,2)(3,4))
//函数的参数是函数,函数的返回是函数
defhightFun3(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))
柯里化函数
l 可以理解为高阶函数的简化/**
* 柯里化函数
*/
def fun7(a :Int,b:Int)(c:Int,d:Int) = {
a+b+c+d
}
println(fun7(1,2)(3,4))
Scala字符串
1. String
2. StringBuilder 可变
3. string操作方法举例
Ø 比较:equalsØ 比较忽略大小写:equalsIgnoreCase
Ø indexOf:如果字符串中有传入的assci码对应的值,返回下标
/**
* String && StringBuilder
*/
valstr = "abcd"
valstr1 = "ABCD"
println(str.indexOf(97))
println(str.indexOf("b"))
println(str==str1)
/**
* compareToIgnoreCase
*
* 如果参数字符串等于此字符串,则返回值 0;
* 如果此字符串小于字符串参数,则返回一个小于 0 的值;
* 如果此字符串大于字符串参数,则返回一个大于 0 的值。
*
*/
println(str.compareToIgnoreCase(str1))
valstrBuilder =newStringBuilder
strBuilder.append("abc")
// strBuilder.+('d')
strBuilder+ 'd'
// strBuilder.++=("efg")
strBuilder++= "efg"
// strBuilder.+=('h')
strBuilder+= 'h'
strBuilder.append(1.0)
strBuilder.append(18f)
println(strBuilder)
集合
数组
1. 创建数组
Ø new Array[Int](10)
赋值:arr(0) = xxx
Ø Array[String](“s1”,”s2”,”s3”)
2. 数组遍历
Ø for
Ø foreach
3. 创建一维数组和二维数组
4. 数组中方法举例
Ø Array.concate:合并数组
Ø Array.fill(5)(“bjsxt”):创建初始值的定长数组
创建两种方式:
/**
* 创建数组两种方式:
* 1.new Array[String](3)
* 2.直接Array
*/
//创建类型为Int 长度为3的数组
valarr1 =newArray[Int](3)
//创建String 类型的数组,直接赋值
valarr2 = Array[String]("s100","s200","s300")
//赋值
arr1(0) = 100
arr1(1) = 200
arr1(2) = 300
遍历两种方式:
/**
* 遍历两种方式
*/
for(i <-arr1){
println(i)
}
arr1.foreach(i => {
println(i)
})
for(s <-arr2){
println(s)
}
arr2.foreach {
x => println(x)
}
创建二维数组
/*** 创建二维数组和遍历
*/
val arr3 = new Array[Array[String]](3)
arr3(0)=Array("1","2","3")
arr3(1)=Array("4","5","6")
arr3(2)=Array("7","8","9")
for(i <-0until arr3.length){
for(j <-0until arr3(i).length){
print(arr3(i)(j)+" ")
}
println()
}
var count = 0
for(arr <-arr3;i <-arr){
if(count%3 == 0){
println()
}
print(i+" ")
count +=1
}
arr3.foreach { arr => {
arr.foreach { println }
}}
val arr4 = Array[Array[Int]](Array(1,2,3),Array(4,5,6))
arr4.foreach { arr => {
arr.foreach(i => {
println(i)
})
}}
println("-------")
for(arr <-arr4;i <-arr){
println(i)
}
数组中的方法
list
1. 创建list
val list = List(1,2,3,4)Ø Nil长度为0的list
2. list遍历
foreach ,for3. list方法举例
Ø filter:过滤元素
Ø count:计算符合条件的元素个数
Ø map:对元素操作
Ø flatmap :压扁扁平,先map再flat
//创建
vallist = List(1,2,3,4,5)
//遍历
list.foreach{ x => println(x)}
// list.foreach { println}
//filter
vallist1 = list.filter { x => x>3 }
list1.foreach { println}
//count
valvalue = list1.count { x => x>3 }
println(value)
//map
valnameList = List(
"hello bjsxt",
"hello xasxt",
"hello shsxt"
)
valmapResult:List[Array[String]] = nameList.map{ x => x.split(" ") }
mapResult.foreach{println}
//flatmap
valflatMapResult : List[String] = nameList.flatMap{ x =>x.split(" ")}
flatMapResult.foreach { println }
4. list方法总结
set
1. 创建set
注意:set集合会自动去重
2. set遍历
foreach,for
3. set方法举例
Ø 交集:intersect ,&Ø 差集: diff ,&~
Ø 子集:subsetOf
Ø 最大:max
Ø 最小:min
Ø 转成数组,toList
Ø 转成字符串:mkString(“~”)
4. set方法总结
//创建valset1 = Set(1,2,3,4,4)
valset2 = Set(1,2,5)
//遍历
//注意:set会自动去重
set1.foreach { println}
for(s <- set1){
println(s)
}
println("*******")
/**
* 方法举例
*/
//交集
valset3 = set1.intersect(set2)
set3.foreach{println}
valset4 = set1.&(set2)
set4.foreach{println}
println("*******")
//差集
set1.diff(set2).foreach { println }
set1.&~(set2).foreach { println }
//子集
set1.subsetOf(set2)
//最大值
println(set1.max)
//最小值
println(set1.min)
println("****")
//转成数组,list
set1.toArray.foreach{println}
println("****")
set1.toList.foreach{println}
//mkString
println(set1.mkString)
println(set1.mkString("\t"))
set方法总结
map
1. map创建Ø Map(1 –>”bjsxt’)
Ø Map((1,”bjsxt”))
注意:创建map时,相同的key被后面的相同的key顶替掉,只保留一个
valmap = Map(
"1"-> "bjsxt",
2-> "shsxt",
(3,"xasxt")
)
2. 获取map的值
Ø map.get(“1”).get
Ø map.get(100).getOrElse(“no value”):如果map中没有对应项,赋值为getOrElse传的值。
//获取值
println(map.get("1").get)
valresult = map.get(8).getOrElse("no value")
println(result)
3. 遍历map
Ø for,foreach
//map遍历
for(x <- map){
println("====key:"+x._1+",value:"+x._2)
}
map.foreach(f => {
println("key:"+ f._1+" ,value:"+f._2)
})
4. 遍历key
Ø map.keys
//遍历key
valkeyIterable = map.keys
keyIterable.foreach { key => {
println("key:"+key+", value:"+map.get(key).get)
} }
println("---------")
5. 遍历value
Ø map.values
//遍历value
valvalueIterable = map.values
valueIterable.foreach { value => {
println("value: "+ value)
} }
6. 合并map
Ø ++ 例:map1.++(map2) --map1中加入map2Ø ++: 例:map1.++:(map2) –map2中加入map1
注意:合并map会将map中的相同key的value替换
//合并map
valmap1 = Map(
(1,"a"),
(2,"b"),
(3,"c")
)
valmap2 = Map(
(1,"aa"),
(2,"bb"),
(2,90),
(4,22),
(4,"dd")
)
map1.++:(map2).foreach(println)
7. map中的方法举例
Ø filter:过滤,留下符合条件的记录Ø count:统计符合条件的记录数
Ø contains:map中是否包含某个key
Ø exist:符合条件的记录存在不存在
/**
* map方法
*/
//count
valcountResult = map.count(p => {
p._2.equals("shsxt")
})
println(countResult)
//filter
map.filter(_._2.equals("shsxt")).foreach(println)
//contains
println(map.contains(2))
//exist
println(map.exists(f =>{
f._2.equals("xasxt")
}))
元组
1. 元组定义
与列表一样,与列表不同的是元组可以包含不同类型的元素。元组的值是通过将单个的值包含在圆括号中构成的。
2. 创建元组与取值
Ø val tuple = new Tuple(1) 可以使用newØ val tuple2 = Tuple(1,2) 可以不使用new,也可以直接写成val tuple3 =(1,2,3)
Ø 取值用”._XX” 可以获取元组中的值
注意:tuple最多支持22个参数
//创建,最多支持22个
valtuple =newTuple1(1)
valtuple2 =Tuple2("zhangsan",2)
valtuple3 =Tuple3(1,2,3)
valtuple4 = (1,2,3,4)
valtuple18 =Tuple18(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18)
valtuple22 =newTuple22(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)
//使用
println(tuple2._1 + "\t"+tuple2._2)
valt =Tuple2((1,2),("zhangsan","lisi"))
println(t._1._2)
3. 元组的遍历
tuple.productIterator得到迭代器,进而遍历
//遍历
valtupleIterator = tuple22.productIterator
while(tupleIterator.hasNext){
println(tupleIterator.next())
}
4. swap,toString方法
注意:swap元素翻转,只针对二元组/**
* 方法
*/
//翻转,只针对二元组
println(tuple2.swap)
//toString
println(tuple3.toString())
trait 特性
1. 概念理解
Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大。
与接口不同的是,它还可以定义属性和方法的实现。
一般情况下Scala的类可以继承多个Trait,从结果来看就是实现了多重继承。Trait(特征) 定义的方式与类类似,但它使用的关键字是 trait。
2. 举例:trait中带属性带方法实现
注意:
Ø 继承的多个trait中如果有同名的方法和属性,必须要在类中使用“override”重新定义。
Ø trait中不可以传参数
traitRead {valreadType = "Read"
valgender = "m"
defread(name:String){
println(name+" is reading")
}
}
traitListen {
vallistenType = "Listen"
valgender = "m"
deflisten(name:String){
println(name + " is listenning")
}
}
classPerson()extendsReadwithListen{
overridevalgender = "f"
}
objecttest {
defmain(args: Array[String]):Unit= {
valperson =newPerson()
person.read("zhangsan")
person.listen("lisi")
println(person.listenType)
println(person.readType)
println(person.gender)
}
}
3. 举例:trait中带方法不实现
objectLesson_Trait2 {defmain(args: Array[String]): Unit = {
valp1 =newPoint(1,2)
valp2 =newPoint(1,3)
println(p1.isEqule(p2))
println(p1.isNotEqule(p2))
}
}
traitEqule{
defisEqule(x:Any) :Boolean
defisNotEqule(x : Any) = {
!isEqule(x)
}
}
classPoint(x:Int, y:Int)extendsEqule {
valxx = x
valyy = y
defisEqule(p:Any) = {
p.isInstanceOf[Point] && p.asInstanceOf[Point].xx==xx
}
}
模式匹配match
1. 概念理解:
Scala 提供了强大的模式匹配机制,应用也非常广泛。
一个模式匹配包含了一系列备选项,每个都开始于关键字 case。
每个备选项都包含了一个模式及一到多个表达式。箭头符号 => 隔开了模式和表达式。
2. 代码及注意点
Ø 模式匹配不仅可以匹配值还可以匹配类型Ø 从上到下顺序匹配,如果匹配到则不再往下匹配
Ø 都匹配不上时,会匹配到case _ ,相当于default
Ø match 的最外面的”{ }”可以去掉看成一个语句
objectLesson_Match {
defmain(args: Array[String]): Unit = {
valtuple =Tuple6(1,2,3f,4,"abc",55d)
valtupleIterator = tuple.productIterator
while(tupleIterator.hasNext){
matchTest(tupleIterator.next())
}
}
/**
* 注意点:
* 1.模式匹配不仅可以匹配值,还可以匹配类型
* 2.模式匹配中,如果匹配到对应的类型或值,就不再继续往下匹配
* 3.模式匹配中,都匹配不上时,会匹配到 case _ ,相当于default
*/
defmatchTest(x:Any) ={
xmatch{
casex:Int=> println("type is Int")
case1 => println("result is 1")
case2 => println("result is 2")
case3=> println("result is 3")
case4 => println("result is 4")
casex:String => println("type is String")
// case x :Double => println("type is Double")
case_ => println("no match")
}
}
}
样例类(case classes)
1. 概念理解
使用了case关键字的类定义就是样例类(case classes),样例类是种特殊的类。实现了类构造参数的getter方法(构造参数默认被声明为val),当构造参数是声明为var类型的,它将帮你实现setter和getter方法。
Ø 样例类默认帮你实现了toString,equals,copy和hashCode等方法。
Ø 样例类可以new, 也可以不用new
2. 例子:结合模式匹配的代码
caseclassPerson1(name:String,age:Int)objectLesson_CaseClass {
defmain(args: Array[String]): Unit = {
valp1 =newPerson1("zhangsan",10)
valp2 =Person1("lisi",20)
valp3 =Person1("wangwu",30)
vallist = List(p1,p2,p3)
list.foreach { x => {
xmatch{
casePerson1("zhangsan",10) => println("zhangsan")
casePerson1("lisi",20) => println("lisi")
case_ => println("no match")
}
} }
}
}
Actor Model
1. 概念理解
Actor Model是用来编写并行计算或分布式系统的高层次抽象(类似java中的Thread)让程序员不必为多线程模式下共享锁而烦恼,被用在Erlang 语言上, 高可用性99.9999999 % 一年只有31ms 宕机Actors将状态和行为封装在一个轻量的进程/线程中,但是不和其他Actors分享状态,每个Actors有自己的世界观,当需要和其他Actors交互时,通过发送事件和消息,发送是异步的,非堵塞的(fire-andforget),发送消息后不必等另外Actors回复,也不必暂停,每个Actors有自己的消息队列,进来的消息按先来后到排列,这就有很好的并发策略和可伸缩性,可以建立性能很好的事件驱动系统。
Actor的特征:
Ø ActorModel是消息传递模型,基本特征就是消息传递
Ø 消息发送是异步的,非阻塞的
Ø 消息一旦发送成功,不能修改
Ø Actor之间传递时,自己决定决定去检查消息,而不是一直等待,是异步非阻塞的
什么是Akka
Akka 是一个用 Scala 编写的库,用于简化编写容错的、高可伸缩性的 Java 和Scala 的 Actor 模型应用,底层实现就是Actor,Akka是一个开发库和运行环境,可以用于构建高并发、分布式、可容错、事件驱动的基于JVM的应用。使构建高并发的分布式应用更加容易。
spark1.6版本之前,spark分布式节点之间的消息传递使用的就是Akka,底层也就是actor实现的。1.6之后使用的netty传输。
2. 例:Actor简单例子发送接收消息
importscala.actors.ActorclassmyActorextendsActor{
defact(){
while(true){
receive {
casex:String => println("save String ="+ x)
casex:Int => println("save Int")
case_ => println("save default")
}
}
}
}
objectLesson_Actor {
defmain(args: Array[String]): Unit = {
//创建actor的消息接收和传递
valactor =newmyActor()
//启动
actor.start()
//发送消息写法
actor ! "i love you !"
}
}
3. 例:Actor与Actor之间通信
caseclassMessage(actor:Actor,msg:Any)classActor1extendsActor{
defact(){
while(true){
receive{
casemsg :Message=> {
println("i sava msg! = "+ msg.msg)
msg.actor!"i love you too !"
}
casemsg :String => println(msg)
case_ => println("default msg!")
}
}
}
}
classActor2(actor :Actor)extendsActor{
actor !Message(this,"i love you !")
defact(){
while(true){
receive{
casemsg :String => {
if(msg.equals("i love you too !")){
println(msg)
actor! "could we have a date !"
}
}
case_ => println("default msg!")
}
}
}
}
objectLesson_Actor2 {
defmain(args: Array[String]): Unit = {
valactor1 =newActor1()
actor1.start()
valactor2 =newActor2(actor1)
actor2.start()
}
}
附赠Wordcount源码
importorg.apache.spark.SparkConfimportorg.apache.spark.SparkContext
importorg.apache.spark.rdd.RDD
importorg.apache.spark.rdd.RDD.rddToPairRDDFunctions
objectWordCount {
defmain(args: Array[String]): Unit = {
valconf =newSparkConf()
conf.setMaster("local").setAppName("WC")
valsc =newSparkContext(conf)
vallines :RDD[String] = sc.textFile("./words.txt")
valword :RDD[String] = lines.flatMap{lines => {
lines.split(" ")
}}
valpairs : RDD[(String,Int)] = word.map{ x => (x,1) }
valresult =pairs.reduceByKey{(a,b)=> {a+b}}
result.sortBy(_._2,false).foreach(println)
//简化写法
lines.flatMap { _.split(" ")}.map { (_,1)}.reduceByKey(_+_).foreach(println)
}
}