1. 程式人生 > >SPARK SQL一些坑

SPARK SQL一些坑

現在的spark sql程式設計通常使用scala api 以及 java api的方式,相比於直接使用 spark sql語句,spark api靈活很多,畢竟可以基於dataset以及rdd兩種方式進行操作,不過spark sql的坑就有點多了。

1,getClass.getResourceAsStream這個類,網上通常說的是不加"/"是從當前包讀取,加了"/"是從根class路徑讀取,但是根路徑並不是在idea或者檔案下看到的諸如src/main/resource/這樣的路徑,而是最終打包時候生成的jar的時候的格式,在生成jar的時候resource資料夾下會被展開到根路徑下,所以如果要載入resource下的資源,只需要"/資源名"就可以了

2、select crossInfo, split(crossInfo, '|') as jda from tem_test_yy lateral view explode(split(jdaList, '#')) tmpTable as crossInfo

這個語句有bug,返回的結果是

jda1|1|time1    ["j","d","a","1","|","1","|","t","i","m","e","1",""]
jda1|1|time1    ["j","d","a","1","|","1","|","t","i","m","e","1",""]
jda2|1|time2    ["j","d","a","2","|","1","|","t","i","m","e","2",""]
|jda3|0|time3   ["|","j","d","a","3","|","0","|","t","i","m","e","3",""]

主要原因是hive裡面|字元要使用轉義符號!!,所以正確用法是split(crossInfo, '\\|');

3、spark persist不能亂用,尤其是

MEMORY_AND_DISK_SER

級別,對於大表來說,persist效率遠不如多執行一遍。。對於幾十億級別的表,效率可降低數倍。。

4、dataframe = dataset[row]  ,spark map裡面的匿名函式返回值不能是dataset[row],否則會包序列化錯誤,它只支援dataset[class]的形式,需要在返回以後 在driver端通過 dataset[row].toDF()轉成 dataframe也就是dataset[row]才行。但是dataset[row]可以作為map的輸入。

5、scala selet("_1.*")和select($"_1"),如果處理的是Tuple[_1,_2]型別的dataset,

後者會生成如下的schema

|-- _1: struct (nullable = true)
 |    |-- all_jda: string (nullable = true)
 |    |-- user_visit_ip: string (nullable = true)
 |    |-- sequence_num: integer (nullable = true)
前者是生成如下的schema

 | -- all_jda: string (nullable = true)
 | -- user_visit_ip: string (nullable = true)
 | -- sequence_num: integer (nullable = true)

這絕對是一個坑=。=,後者會把多一層schema結構,而在spark sql語句中是能直接取到非頂層的列的。。

6、spark sql的一些問題

(1), hive支援使用正則語句,spark sql 不支援
(2), left out join on A.column = B.column 而不能寫成 left out join on column;
(3),  select * from A left out join B on cloumn會造成ambigious錯誤 需要小心
(4),  concat_ws不支援對除String外的其他型別陣列的連線,需要自己實現一個udf