DataSet是spark2.0提出来的新东西,我们来玩一下:
这次我们就不用SparkContext了,所以我们也不需要SparkConf了。
DataSet使用的是SparkSession.SparkSession其实是一个单例。
我们可以通过同样的方式创建schema,可是没有了SparkContext我们怎么创建RDD读取文件呢?我们可以通过SparkSession得到SparkContext,这样就好操作了。通过这个我们就可以看出来,SparkSession是对SparkContext的包装,SparkSession中持有SparkContext的引用。
在SparkSession中就不是创建表了,而是创建视图,
什么是视图呢?就是一个虚表,可以简化复杂的查询。
什么是DataFrame?就是将RDD与schema关联起来。我们查看一下DataFrame的源码可以发现:
DataFrame其实是DataSet。这个其实是Spark1.6之后新出现的,在1.6之前这里应该是RDD。而DateSet号称要比RDD快100倍,这是为什么呢?
其实DataSet是一个优化之后的RDD。他的底层调用的还是RDD。只不过在执行之前,他有一个执行计划,优化器,他会对RDD进行优化然后再执行。
DateSet比RDD的好处就是,他里面的数据类型都是强类型。而以前我们RDD里面默认装的都是String类型。没有具体指定是什么类型。如果用之前的我们切分完数据之后如果想和Int类型进行比较的话还需要使用toInt等操作进行转换。
但是以后我们的DateSet就是强类型的,我们可以进行指定。
并且一旦指定是什么类型的我们就可以用lambda表达式的方式对DataSet进行处理。
一个DataFrame也是一个DateSet,他在DataSet中是以被命名的列的形式组织的。也就是说在spark中DataFrame其实是DataSet中装的row他在概念上和我们关系型数据库中的表是类似的。我们之所以可以进行优化,是因为一旦我们知道了有哪些列,我们就可以只加载我们需要的列,而不用全部加载。
DataSet是在RDD基础之上进行优化过的分布式数据集,里面的数据是强类型的,每一个字段都会有一个类型和名字。
通过DataSet可以创建DataFrame,在spark2.0,DataSet里面装的Row即DataSet[Row]。
接下来我们就来感受一下DataSet,我们使用spark2.x的方式来写个WordCount:
我们使用SparkSession读取数据之后,也可以使用collect来查看,这样就和RDD没什么区别了,运行之后的结果为:
我们最好使用show方法:
接下来我们先切分:
这样就会报错:
这个错误告诉我们,如果我们想直接调用DataSet上面的算子还不行。我们还需要导入session对象中的隐式转换。
导入之后的运行结果:
写到这一步我们就有两种选择,一种是写sql,另一种就是写DSL.
我们接下来先写DSL:
我们在语句中写的$意思是告诉他这是一列
为了可以使用agg中的聚合函数,我们还需要导入spark sql中的函数
代码如下:
package com.test.SparkSQL
import org.apache.spark.sql.{Dataset, Row, SparkSession}
object DataSetWordCount {
def main(args: Array[String]): Unit = {
//创建一个sparkSession
val session: SparkSession = SparkSession.builder()
.appName("DataSetWordCount")
.master("local[*]")
.getOrCreate()
import session.implicits._
val lines: Dataset[String] = session.read.textFile("D:/a/word.txt")
val words: Dataset[String] = lines.flatMap(_.split(" "))
import org.apache.spark.sql.functions._
val result: Dataset[Row] = words.groupBy($"value" as "word")
.agg(count("*") as "counts")
.sort($"counts" desc)
result.show()
}
}
成功截图:
或者我们也可以这样实现:
成功截图:
接着我们通过sql的方式来写WordCount
withColumnRenamed是从RDD得到DataFrame的一种手段
代码如下:
package com.test.SparkSQL
import org.apache.spark.sql.{DataFrame, Dataset, SparkSession}
object sqlWordCount {
def main(args: Array[String]): Unit = {
val session: SparkSession = SparkSession.builder()
.appName("sqlWordCount")
.master("local[*]")
.getOrCreate()
//指定读取数据的位置
val lines: Dataset[String] = session.read.textFile("D:/a/word.txt")
//导入sparksession中的隐式转换
import session.implicits._
val words: Dataset[String] = lines.flatMap(_.split(" "))
val df: DataFrame = words.withColumnRenamed("value","word")
//先创建视图,再执行sql
df.createTempView("v_wc")
val result: DataFrame = session.sql("select word,count(*) counts from v_wc group by word order by counts desc")
result.show()
}
}
运行结果如下:
我们除了使用
这种方式,还可以使用上面提到的
session.read.format("text").load("D:/a/word.txt")
这种方式接下来的做法可以这样:
val words: Dataset[String] = lines.flatMap(_.getAs[String]("value").split(" "))
这种方式直接拿到的是DataFrame,DataFrame是什么东西?
通过这个我们可以看到,DataFrame就是DataSet中装的Row
所以就意味着我们拿出来的是一个row,而row中有可能有多个字段。我们可以将我们想要的字段拿出来,并转换成对应的类型。
DSL方式:
object sqlWordCount {
def main(args: Array[String]): Unit = {
val session: SparkSession = SparkSession.builder()
.appName("sqlWordCount")
.master("local[*]")
.getOrCreate()
//指定读取数据的位置
//val lines: Dataset[String] = session.read.textFile("D:/a/word.txt")
val lines: DataFrame = session.read.format("text").load("D:/a/word.txt")
//导入sparksession中的隐式转换
import session.implicits._
val words: Dataset[String] = lines.flatMap(_.getAs[String]("value").split(" "))
// val df: DataFrame = words.withColumnRenamed("value","word")
// //先创建视图,再执行sql
// df.createTempView("v_wc")
// val result: DataFrame = session.sql("select word,count(*) counts from v_wc group by word order by counts desc")
// result.show()
//DSL方式
import org.apache.spark.sql.functions._
val result: Dataset[Row] = words.groupBy($"value").agg(count("*") as "counts").sort($"counts" desc)
result.show()
//val df = words.toDF()
}
}
SQL方式:
val df = words.toDF()
df.createTempView("v_wc")
val result: DataFrame =
session.sql("select value word,count(*) counts from v_wc group by word order by counts desc")
result.show()
我们也可以将执行的结果写入数据库: