SparkSql使用入門

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();
	}

}

下面是運行效果圖:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章