SparkSQL檢視除錯生成程式碼
網站和一些書籍都有介紹SparkSQL(DataFrame)會根據相應的操作生成最終執行的語句。這裡從一個簡單的、低階的問題入手到最後通過檢視生成的程式碼查詢問題的根源,並簡單介紹怎麼來除錯SparkSQL。
問題來源:
1 2 3 4 5 6 7 8 9 |
|
執行之後 compute 總是報 NullPointerException 異常。按RDD以及Scala的操作都是沒法理解的,怎麼就變成 Access(null,null,null)
了呢?後面儘管改成 df.flatMap(Access(_)).map(_.compute)
後執行正常了,但是還是想看看SparkSQL到底幹了啥!!!
SparkSQL幹了什麼
Spark RDD是在 RDD#compute 中明確定義好了操作的。而SparkSQL的操作最終轉換成了LogicalPlan,看不出它做了什麼東東。
其實,與資料庫SQL的explain看執行計劃類似,SparkSQL也有explain的方法來檢視程式的執行計劃。(這裡程式碼全部貼出來了,根據情況自己去掉註釋啊)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
|
執行上面的程式碼,在console視窗輸出了任務的執行計劃:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
OK,看到執行計劃了,那生成的程式碼長什麼樣呢?以及怎麼除錯這些生成的程式碼呢?
Hack 原始碼
在進行除錯之前,先改一下程式碼重新編譯下catalyst用於除錯,並替換maven下面的spark-catalyst_2.11 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
SparkSQL生成程式碼用的是janino,官網文件有提供debugging的資料:http://janino-compiler.github.io/janino/#debugging 。簡單說明下三處修改:
- 檢視org.codehaus.janino.Scanner構造方法,如果配置了debugging以及optionalFileName==null就會把原始碼儲存到臨時檔案。
- 一開始沒想到要註釋掉setClassName的,後面把CodeGenerator#doCompile拷貝出來慢慢和官網提供的例子對,就把setClassName換成setExtendedClass竟然成了彈出了原始碼頁面。又看到下面就setExtendedClass就註釋掉setClassName就ok了。
- 原始碼裡面的引數不能檢視的,就是編譯的時刻把這個選項去掉了。把debugVars設定為true。
執行除錯
先做好除錯準備工作:
- 在compute方法裡面打一個斷點然後除錯執行
- 修改log4j日誌級別: log4j.logger.org.apache.spark.sql.catalyst.expressions.codegen=DEBUG
- 把專案匯入eclipse(IDEA彈不出原始碼)
然後執行。點選Debug檢視的GeneratedIterator,在彈出的程式碼檢視點選查詢原始碼按鈕,再彈出的新增原始碼對話方塊(Edit Source Lookup Path)新增路徑target/generated-sources(注意這裡要用絕對路徑)!接下來就一步步的調就行了。
除錯著生成的程式碼能更好的理解前面explain的執行計劃。看到程式碼就好理解最開始的Access(null,null,null)了:物件到欄位反序列化的問題。
from:http://www.winseliu.com/blog/2016/10/12/sparksql-view-and-debug-generatecode/