Spark SQL是Spark用来处理结构化数据的一个模块,它提供了2个编程抽象:DataFrame和DataSet,并且作为分布式SQL查询引擎的作用。
之前Hive是将hql转换成MapReduce然后放在集群上执行,简化了编写MapReduce的复杂性,但是由于MapReduce执行的效率比较慢,所以产生了SparkSQL,它是将SQL转换成RDD,然后提交到集群执行,效率就会变快。
DataFrame也是一个分布式容器。类似于数据库中的二维表格。但是它又比二维表格多了一些记录数据结构的信息 :schema
DataFrame提供了详细的结构信息,使得Spark SQL可以清楚地知道该数据集中包含哪些列,每列的名称和类型各是什么。DataFrame是为数据提供了Schema的视图。可以把它当做数据库中的一张表来对待,
例:
val df: DataFrame = spark.read.json("F:\\datas\\a.json")
df.createOrReplaceTempView("t_user")
val sqlDF: DataFrame = spark.sql("select * from t_user")
sqlDF.show()
例:
import spark.implicits._
val df = spark.read.json("F:\\datas\\a.json")
df.printSchema()//打印Schema结构
//指定列查询
df.select($"name",$"age").show()
//查询大于20岁的
df.filter($"age">20).show()
//根据年龄分组,统计个数
df.groupBy("age").count().show()
数据:
{"name":"zhangsan","age":20}
{"name":"李四","age":22}
{"name":"wanguw","age":24}
val spark: SparkSession =
SparkSession.builder()
.appName("ceshi")
.master("local[*]")
.getOrCreate()
val df: DataFrame = spark.read.json("F:\\datas\\a.json")
df.show()
spark.stop()
//定义case class
case class Person(name:String,age:Long)
//创建List集合,转换为DataSet对象
import spark.implicits._
val ds: Dataset[Person] = List(Person("zhangsan",20),Person("lisi",22)).toDS()
ds.show()
import spark.implicits._
val rdd1: RDD[String] = spark.sparkContext.textFile("F:\\datas\\a.txt")
rdd1.map(v=>{
val arr: Array[String] = v.split("\t")
Person(arr(0),arr(1).toLong)
}).toDS().show()
val ds: Dataset[Person] = List(Person("zhangsan",20),Person("lisi",23)).toDS()
val rdd: RDD[Person] = ds.rdd
import spark.implicits._
val df: DataFrame = spark.read.json("F:\\datas\\a.json")
val ds: Dataset[Person] = df.as[Person]
ds.show()
import spark.implicits._
val ds: Dataset[Person] = List(Person("zhangsan",20),Person("lisi",23)).toDS()
val df: DataFrame = ds.toDF()
df.show()
import spark.implicits._
val df: DataFrame = List(("zhangsan", 20, 1), ("lisi", 20, 1), ("xiaohong", 18, 0)).toDF("name", "age", "sex")
df.createOrReplaceTempView("t_user")
spark.udf.register("convert_sex",(sex:Int)=>{
sex match {
case 0 => "女"
case 1 => "男"
}
})
spark.sql("select name,age,convert_sex(sex) sex from t_user").show()
class CustomSum extends UserDefinedAggregateFunction{
//函数输入参数的类型
override def inputSchema: StructType = {
new StructType().add("input1",IntegerType)
}
//缓冲区中值的数据类型
override def bufferSchema: StructType = {
new StructType().add("sum",IntegerType)
}
//返回值的数据类型
override def dataType: DataType = IntegerType
//对于相同的输入是否一直返回相同的输出
override def deterministic: Boolean = true
//初始化,
override def initialize(buffer: MutableAggregationBuffer): Unit = {
buffer(0) = 0
}
//将缓冲区的数据加上输入的数据,然后更新到缓冲区中
override def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
val d1: Int = buffer.getAs[Int](0)
val d2: Int = input.getAs[Int](0)
buffer.update(0,d1+d2)
}
//合并缓冲区的数据
override def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
val d1: Int = buffer1.getAs[Int](0)
val d2: Int = buffer2.getAs[Int](0)
buffer1.update(0,d1+d2)
}
//返回最终结果
override def evaluate(buffer: Row): Any = {
buffer.getAs[Int](0)
}
}
使用:
val df: DataFrame = List(("zhangsan", 20, 1), ("lisi", 20, 1), ("xiaohong", 18, 0))
.toDF("name", "age", "sex")
df.createOrReplaceTempView("t_user")
spark.udf.register("customSum",new CustomSum)
spark.sql("select customSum(age) sex from t_user").show()
对于Spark SQL的DataFrame来说,无论是从什么数据源创建出来的DataFrame,都有一些共同的load和save操作。
load操作主要用于加载数据,创建出DataFrame
save操作,主要用于将DataFrame中的数据保存到文件中
Parquet是一种流行的列式存储格式,可以高效地存储具有嵌套字段的记录。Parquet格式经常在Hadoop生态圈中被使用,它也支持Spark SQL的全部数据类型。Spark SQL 提供了直接读取和存储 Parquet 格式文件的方法。
//保存数据
import spark.implicits._
val df: DataFrame = List((1,"zhangsan",20),(2,"lisi",23),(3,"wangwu",23)).toDF("id","name","age")
df.write.parquet("f:\\datas\\parquet")
//读取数据
spark.read.parquet("f:\\datas\\parquet").show()
Spark SQL可以通过JDBC从关系型数据库中读取数据的方式创建DataFrame,通过对DataFrame一系列的计算后,还可以将数据再写回关系型数据库中。
val properties = new Properties()
properties.put("user", "root")
properties.put("password", "123456")
val df: DataFrame = List((1,"zhangsan",20),(2,"lisi",23),(3,"wangwu",23)).toDF("id","name","age")
df.write.jdbc("jdbc:mysql://localhost:3306/test1", "df_user", properties)
spark.read.jdbc("jdbc:mysql://localhost:3306/test1","df_user",properties).show()
步骤
spark.sql("use spark")
spark.sql("select * from t_user").show
代码中使用HIVE
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive_2.11</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
import org.apache.spark.sql.SparkSession
object HiveDemo {
def main(args: Array[String]): Unit = {
val spark: SparkSession = SparkSession
.builder()
.master("local[*]")
.appName("Test")
.enableHiveSupport()
.getOrCreate()
import spark.implicits._
spark.sql("use spark")
spark.sql("select * from t_user").show
spark.stop()
}
}