Spark SQL是spark套件中一个模板,它将数据的计算任务通过SQL的形式转换成了RDD的计算,类似于Hive通过SQL的形式将数据的计算任务转换成了MapReduce。
Spark SQL的特点:
1、和Spark Core的无缝集成,可以在写整个RDD应用的时候,配置Spark SQL来完成逻辑实现。
2、统一的数据访问方式,Spark SQL提供标准化的SQL查询。
3、Hive的继承,Spark SQL通过内嵌的hive或者连接外部已经部署好的hive案例,实现了对hive语法的继承和操作。
4、标准化的连接方式,Spark SQL可以通过启动thrift Server来支持JDBC、ODBC的访问,将自己作为一个BI Server使用
Spark SQL数据抽象:
1、RDD(Spark1.0)->DataFrame(Spark1.3)->DataSet(Spark1.6)
2、Spark SQL提供了DataFrame和DataSet的数据抽象
3、DataFrame就是RDD+Schema,可以认为是一张二维表格,劣势在于编译器不进行表格中的字段的类型检查,在运行期进行检查
4、DataSet是Spark最新的数据抽象,Spark的发展会逐步将DataSet作为主要的数据抽象,弱化RDD和DataFrame.DataSet包含了DataFrame所有的优化机制。除此之外提供了以样例类为Schema模型的强类型
5、DataFrame=DataSet[Row]
6、DataFrame和DataSet都有可控的内存管理机制,所有数据都保存在非堆上,都使用了catalyst进行SQL的优化。
Spark SQL客户端查询:
1、可以通过Spark-shell来操作Spark SQL,spark作为SparkSession的变量名,sc作为SparkContext的变量名
2、可以通过Spark提供的方法读取json文件,将json文件转换成DataFrame
3、可以通过DataFrame提供的API来操作DataFrame里面的数据。
4、可以通过将DataFrame注册成为一个临时表的方式,来通过Spark.sql方法运行标准的SQL语句来查询。
日常开发中可根据需要选择hive或者sparksql,本人更偏向使用sparksql代码写起来比hive要简单许多,先上一段代码
package com.debug;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.function.VoidFunction;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
public class SparkSql01 {
public static void main(String[] args) {
SparkSession spark = SparkSession.builder().appName("json文件读取1").master("local").getOrCreate();
//Dataset<Row> row=spark.read().json("./data/json");
Dataset<Row> row=spark.read().format("json").load("./data/json");
row.printSchema();
row.createOrReplaceTempView("t1");
Dataset<Row> row1=spark.sql("select name,age from t1");
//Dataset转成RDD
JavaRDD<Row> rdd=row1.javaRDD();
rdd.foreach(new VoidFunction<Row>() {
public void call(Row r) throws Exception {
String name=r.getAs("name").toString();
//Long age=r.getLong(r.fieldIndex("age"));
long age=r.getAs("age")!=null?r.getAs("age"):0;
System.out.println(name+","+age);
}
});
spark.stop();
}
}
sparksql执行后返回Row类型的DataSet, spark2.X之后官方建议使用DataSet因为DataSet在RDD的基础上做了很多优化,使用起来也和RDD大同小异,来看下对应的json文件
{"name":"zhangsan","age":20}
{"name":"lisi"}
{"name":"wangwu","age":18}
{"name":"wangwu","age":18}
执行结果如下
sparksql除了可以读取普通json格式外还可以读取嵌套的json或者嵌套的JsonArray,先上一个读取单层嵌套的例子,数据如下
{"name":"王大锤","address":{"city":"昆明","detailAddress":"五华区拓东路"}}
{"name":"黄小明","address":{"city":"上海","detailAddress":"浦东新区川沙路"}}
{"name":"蔡依林","address":{"city":"北京","detailAddress":"东城区"}}
{"name":"周杰伦","address":{"city":"杭州","detailAddress":"萧山区"}}
{"name":"李现","address":{"city":"广州","detailAddress":"白云区xxx路"}}
这种情况下要取得city和detailAddress在sql的表现形式就是address.city和address.detailAddress
package com.debug;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
public class ReadJson01 {
public static void main(String[] args) {
SparkSession spark = SparkSession.builder().appName("读取嵌套json").master("local").getOrCreate();
Dataset<Row> row=spark.read().format("json").load("./data/userInfo.txt");
//row.printSchema();
//row.show();
row.createOrReplaceTempView("t1");
Dataset<Row> row1=spark.sql("select name,address.city,address.detailAddress from t1 order by name desc");
row1.show();
spark.stop();
}
}
运行结果如下:
接着就是嵌套的为json数组的情况,数据如下:
{"name":"王大锤","myScore":[{"score1":89,"score2":91},{"score1":78,"score2":81}]}
{"name":"黄小明","myScore":[{"score1":75,"score2":90},{"score1":63,"score2":55}]}
这种情况相对来说要复杂一些,我们需要把name和myScore使用toDF转换成DataFrame,myScore为数组不能直接转换,需要使用explode先解析
package com.debug;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
import org.apache.spark.sql.functions;
public class ReadJson02 {
public static void main(String[] args) {
SparkSession spark = SparkSession.builder().appName("嵌套json数组").master("local").getOrCreate();
Dataset<Row> ds=spark.read().format("json").load("./data/userList.txt");
Dataset<Row> res=ds.select(ds.col("name"),functions.explode(ds.col("myScore"))).toDF("name","score");
res.printSchema();
res.createOrReplaceTempView("t1");
//Dataset<Row> row1=spark.sql("select name,score.score1,score.score2 from t1 order by name desc");
Dataset<Row> row1=spark.sql("select name,avg(score.score1) avgS1,avg(score.score2) avgS2 from t1 group by name");
row1.show();
spark.stop();
}
}
下面是运行效果图: