Spark-SQL的Java實踐案例(二)
史上最簡單的spark教程
所有代碼示例地址:https://github.com/Mydreamandreality/sparkResearch
(提前聲明:文章由作者:張耀峯 結合自己生產中的使用經驗整理,最終形成簡單易懂的文章,寫作不易,轉載請註明)
(文章參考:Elasticsearch權威指南,Spark快速大數據分析文檔,Elasticsearch官方文檔,實際項目中的應用場景)
(幫到到您請點點關注,文章持續更新中!)
Git主頁 https://github.com/Mydreamandreality
在這裏我們繼續上一章節SparkSQL的案例啊,沒有看上一章節的兄弟萌 點擊這裏哈https://blog.csdn.net/youbitch1/article/details/88852644
[給盧姥爺上香]
- 上一章節的最開始,我們說爲了實現sparkSQL的功能,spark提供了一種全新的RDD叫做
DataFrame,但是我們的SparkSQL返回值一直是DataSet,可能有些兄弟就有點不理解了啊 - Dataset其實是一個分佈式的數據收集器
- DataFrame可以從廣泛的數據源中構成.比如:結構化的數據文件,Hive的table,外部數據庫和RDD
- DataFrame在Scala,Java,Python和R中都支持,在Java中爲Dataset
- 這就兄弟萌能理解爲啥返回DataSet了吧
- 更具體的東西咱寫到後面再分析一波
-
上一章節的最後,我們以編程的方式運行sparkSQL查詢,把dataframe註冊成爲臨時表運行SQL語句(也可以稱爲臨時視圖)
-
但是它有個很大的問題
- 臨時表是當前使用的SQLContext中的臨時變量,在我們的的應用退出時這些臨時表就不再存在了
- 說白了就是臨時視圖是session級別的,它會隨着session的消息而消失
-
那如果我們想要一個臨時視圖在所有的session中互相傳遞使用,直到spark的應用終結,該咋辦
- 這個時候我們只需要創建一個全局臨時視圖即可
全局臨時視圖
- 全局臨時視圖存在於系統數據庫的
global_temp
中 - 全局臨時視圖的生命週期隨spark程序的運行消失
- 來吧讓我們用代碼說話,代碼案例:
try {
//創建全局臨時視圖
dataset.createGlobalTempView("user");
//全局臨時視圖綁定到系統保存的數據庫“global_temp”
Dataset<Row> globalUser = sparkSession.sql("SELECT * FROM global_temp.user");
sparkSession.newSession().sql("SELECT * FROM global_temp.user");
} catch (AnalysisException e) {
e.printStackTrace();
}
- 代碼還是很簡單的
- 首先創建我們的全局臨時視圖,使用
createGlobalTempView
函數創建(在上一章節中創建臨時視圖使用的函數是createOrReplaceTempView
) - 其次我們說了,我們的全局臨時視圖綁定到我們的系統庫 global_temp中,所以在查詢的時候需要先指定我們的系統庫(系統庫無需關注,系統自帶的)
- 最後呢,我們說過,全局臨時變量是跨會話的,所以你可以在新會話中執行我們的SQL語句
創建DataSet
- DataSet和RDD比較類似,不同的地方就是序列化的方式
- RDD序列化是使用Java的serialization或者kryo實現序列化和反序列化的
- DataSet是使用的encoder來實現對象的序列化和在網絡中的傳輸
- encoder有個動態的特性,Spark在執行比如sorting之類的操作時無需再把字節反序列化成對象
代碼示例:
SparkSession sparkSession = SparkSession.builder().master("local")
.appName("Java Spark SQL")
.getOrCreate();
Person person = new Person("spark",10);
Encoder<Person> encoder = Encoders.bean(Person.class);
Dataset<Person> dataset = sparkSession.createDataset(Collections.singletonList(person),encoder);
dataset.show();
//最終輸出 {name:spark;age:10}
/*常見類型的編碼器*/
Encoder<Integer> integerEncoder = Encoders.INT();
Dataset<Integer> integerDataset = sparkSession.createDataset(Arrays.asList(1,2),integerEncoder);
Dataset<Integer> result = integerDataset.map(new MapFunction<Integer, Integer>() {
@Override
public Integer call(Integer value) {
return value+1;
}
},integerEncoder);
result.collect();
//最終輸出 [2,3]
/*通過提供一個類,可以將數據流轉換爲數據集。基於名稱的映射*/
String url = "/usr/local/text.json";
Dataset<Person> personDataset = sparkSession.read().json(url).as(encoder);
personDataset.show();
//最終輸出 name:... age:,,,,
- 上面這個案例如何理解?
- 靈魂畫手上線:
* - 這樣就很好理解了,下面兩個案例同理,只是數據類型爲基礎類型
這章的最後在這裏總結一下 RDD和dataframe,DataSet的區別
-
RDD
- 彈性分佈式數據集.是Spark對數據進行的一種抽象,可以理解爲Spark對數據的一種組織方式.更簡單些說.RDD就是一種數據結構.裏面包含了數據和操作數據的方法
- 關鍵字:
- 彈性,分佈式,數據集
-
DataFrame
- 理解了RDD.DataFrame就容易理解些
- RDD是一個數據集,DataFrame在RDD的基礎上增加了Schema(描述數據的信息,可以認爲是元數據,DataFrame曾經就叫做schemaRDD)
- 做個對比,如果左邊的數據是RDD,那麼右邊的就是dataframe
- DataFrame比RDD多了一個表頭信息(Schema),像一張表,DataFrame還配套了新的操作數據的方法,DataFrameAPI 比如df.select()和SQL(select id, name from xx_table where …))等等
- 正因爲有了這層抽象,我們開發才能很爽啊,處理數據就變得很簡單了
- 不僅如此.通過DataFrame API或SQL處理數據.會自動經過Spark的優化器(Catalyst)的優化.即使你寫的程序或SQL不高效,也可以運行的很快
- 注意:DataFrame是用來處理結構化數據的
-
DataSet
- 對於RDD而言,DataSet做了強類型支持,在RDD的每一行都做了數據類型約束
- RDD轉換DataFrame後不可逆,但RDD轉換Dataset是可逆的
- 下面這就是DataSet的數據
這章就先到這裏啦,這章我們知道了創建DataSet的方式還有RDD和dataframe,dataset的區別
下一章節寫RDD和DataSet的轉換操作吧