知识点:
如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。
换句话来说就是,用transient关键字标记的成员变量不参与序列化过程。
这对于需要被临时保存的缓存数据而言是合理的。
例如:
@transient val sparkContext: SparkContext,
stripMargin
方法https://www.jianshu.com/p/08986dbab540
如:
var sql =
s"""
| select
| case when app_id is null then 0 else app_id end as app_id,
| case when app_package is null then '-' else app_package end as app_package,
| case when first_type is null then 0 else first_type end as first_type,
| case when second_type is null then 0 else second_type end as second_type
| from cpd_reco.dm_cpd_recommend_app_info where day='${yesterday}'
""".stripMargin
https://blog.csdn.net/zalan01408980/article/details/79653386
1、时间字符类型转Date类型
import java.text.SimpleDateFormat
val time = "2017-12-18 00:01:56"
val newtime :Date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(time)
println(newtime)
//output:Mon Dec 18 00:01:56 CST 2017
2、Long类型转字符类型
val time:Long= 1513839667//秒
val newtime :String = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(time*1000)
println(newtime)
//output:2017-12-21 15:01:07
3、时间字符类型转Long类型
val time = "2017-12-18 00:01:56"
val newtime :Long= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(time).getTime
println(newtime) //output:1513526516000
Scala 提供了三种创新的字符串插值方法:s,f 和 raw.
s 字符串插值器
在任何字符串前加上s,就可以直接在串中使用变量了。
val name="James"
println(s"Hello,$name")//Hello,James 此例中,$name嵌套在一个将被s字符串插值器处理的字符串中。插值器知道在这个字符串的这个地方应该插入这个name变量的值,以使输出字符串为Hello,James。使用s插值器,在这个字符串中可以使用任何在处理范围内的名字。
字符串插值器也可以处理任意的表达式。例如:
println(s"1+1=${1+1}") 将会输出字符串1+1=2。任何表达式都可以嵌入到${}中。
f 插值器
在任何字符串字面前加上 f,就可以生成简单的格式化串,功能相似于其他语言中的 printf 函数。当使用 f 插值器的时候,所有的变量引用都应当后跟一个printf-style格式的字符串,如%d。
val height=1.9d
val name="James"
println(f"$name%s is $height%2.2f meters tall")//James is 1.90 meters tall f 插值器是类型安全的。如果试图向只支持 int 的格式化串传入一个double 值,编译器则会报错。例如:
val height:Double=1.9d
scala>f"$height%4d"
found : Double
required: Int
f"$height%4d"
^ f 插值器利用了java中的字符串数据格式。这种以%开头的格式在 [Formatter javadoc] 中有相关概述。如果在具体变量后没有%,则格式化程序默认使用 %s(串型)格式。
raw 插值器
除了对字面值中的字符不做编码外,raw 插值器与 s 插值器在功能上是相同的。如下是个被处理过的字符串:
scala>s"a\nb"
res0:String=
a
b 这里,s 插值器用回车代替了\n。而raw插值器却不会如此处理。
scala>raw"a\nb"
res1:String=a\nb 当不想输入\n被转换为回车的时候,raw 插值器是非常实用的。
除了以上三种字符串插值器外,使用者可以自定义插值器。
SQLContext和HiveContext区别与联系为:
SQLContext现在只支持SQL语法解析器(SQL-92语法)
HiveContext现在支持SQL语法解析器和HiveSQL语法解析器,默认为HiveSQL语法解析器,用户可以通过配置切换成SQL语法解析器,来运行HiveSQL不支持的语法。
使用HiveContext可以使用Hive的UDF,读写Hive表数据等Hive操作。SQLContext不可以对Hive进行操作。
Spark SQL未来的版本会不断丰富SQLContext的功能,做到SQLContext和HiveContext的功能容和,最终可能两者会统一成一个Context
HiveContext包装了Hive的依赖包,把HiveContext单独拿出来,可以在部署基本的Spark的时候就不需要Hive的依赖包,需要使用HiveContext时再把Hive的各种依赖包加进来。
SQL的解析器可以通过配置spark.sql.dialect参数进行配置。在SQLContext中只能使用Spark SQL提供的”sql“解析器。在HiveContext中默认解析器为”hiveql“,也支持”sql“解析器。
Spark Application可以使用SQLContext的sql()方法执行SQL查询操作,sql()方法返回的查询结果为DataFrame格式。代码如下:
Scala:
val sqlContext = ... // An existing SQLContext
val df = sqlContext.sql("SELECT * FROM table")
collect、toArray:将RDD转换为Scala的数组。
collectAsMap:与collect、toArray相似。collectAsMap将key-value型的RDD转换为Scala的map。
注意:map中如果有相同的key,其value只保存最后一个值。
原文链接:https://blog.csdn.net/T1DMzks/java/article/details/70189509
parallelize
调用SparkContext 的 parallelize(),将一个存在的集合,变成一个RDD,这种方式试用于学习spark和做一些spark的测试
scala版本
def parallelize[T](seq: Seq[T], numSlices: Int = defaultParallelism)(implicit arg0: ClassTag[T]): RDD[T]
- 第一个参数一是一个 Seq集合
- 第二个参数是分区数
- 返回的是RDD[T]
scala> sc.parallelize(List("shenzhen", "is a beautiful city"))
res1: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[1] at parallelize at
java版本
def parallelize[T](list : java.util.List[T], numSlices : scala.Int) : org.apache.spark.api.java.JavaRDD[T] = { /* compiled code */ }
- 第一个参数是一个List集合
- 第二个参数是一个分区,可以默认
- 返回的是一个JavaRDD[T]
java版本只能接收List的集合
JavaRDD
makeRDD
只有scala版本的才有makeRDD
def makeRDD[T](seq : scala.Seq[T], numSlices : scala.Int = { /* compiled code */ })
跟parallelize类似
sc.makeRDD(List("shenzhen", "is a beautiful city"))
textFile
调用SparkContext.textFile()方法,从外部存储中读取数据来创建 RDD
例如在我本地F:\dataexample\wordcount\input下有个sample.txt文件,文件随便写了点内容,我需要将里面的内容读取出来创建RDD
scala版本
var lines = sc.textFile("F:\\dataexample\\wordcount\\input")
java版本
JavaRDD
注: textFile支持分区,支持模式匹配,例如把F:\dataexample\wordcount\目录下inp开头的给转换成RDD
var lines = sc.textFile("F:\\dataexample\\wordcount\\inp*")
多个路径可以使用逗号分隔,例如
var lines = sc.textFile("dir1,dir2",3)
https://www.cnblogs.com/chorm590/p/spark_201904201159.html
https://www.cnblogs.com/Gxiaobai/p/10056482.html
https://blog.csdn.net/huangyinzhao/article/details/80341763
通过阅读上面的讲解,发现其实在combineByKey这个函数中传入的处理数据的函数,都是只是对key-value键值对数据中的value进行处理,定义的那些函数都并不处理key。所以像第一个链接中的 v: (String, Int)) => (v: (String, Int) 这个createCombiner函数,都是除去了key之后定义的value 的数据类型(String, Int)。可以看到后面的其他函数也是这样的。
所以acc: (String, Int), v: (String, Int)) => (v._1+":"+acc._1,acc._2+v._2)这里的v._1和acc._1都是指经过map函数转化之后的得到的元组value中的第一个。
https://www.it610.com/article/1282391701956083712.htm
groupby函数的输出结果是自己设置的key:seq。
这里的seq是原来的序列数据中的满足key 的各项。也就是,如果不对原来序列中的各项进行转换操作的话,key后面的list就是和原来数据中的项是一样的。只是把各项整合在一个list中的,然后变成了一个key-value键值对的形式。
首先根据两个方法的名字,我们大概可以了解到:
两个方法的差异就在于有没有 key这个单词,所以说:groupBy()方法是根据用户自定义的情况进行分组,而groupByKey()则是根据key值进行分组的,也就是说,进行groupByKey()方法的数据本身就是一种key-value类型的,并且数据的分组方式就是根据这个key值相同的进行分组的
那么groupBy()分组的方法呢?就是工具groupBy()传入的方法返回的值进行分组
所以,groupByKey的输出结果和上面写的groupBy的结果会是一样的形式。