spark2.2.0原始碼學習過程記錄:Day8
阿新 • • 發佈:2019-02-01
1、《apache spark 原始碼剖析》瀏覽第六、七、八、九章
後面的幾章中只准備學習其中的spark sql部分,所以首先全部瀏覽了一下,再回過頭來看第七章
2、讀《apache spark 原始碼剖析》第七章第1節、第2.1節
SQL語句在分析執行過程中會經理幾個步驟:(1)語法解析。(2)操作繫結。(3)優化執行策略。(4)交付執行。
3、原始碼學習
從書中看出入口類為SparkContext,但是看程式碼中,在新版本已經被SparkSession代替,所以直接看SparkSession,書中sql方法返回的SchemaRdd,現在也已經變成了DataFrame
類SparkSession
sql方法首先呼叫sessionState.sqlParser.parsePlan(sqlText)方法生成LogicalPlan
那麼首先要找到這個sqlParser的具體例項類
看sessionState建立的地方,先呼叫SparkSession.sessionStateClassName方法來確定BaseSessionStateBuilder的具體實現類,我這裡假定使用的hive,那麼具體類為HiveSessionStateBuilder;然後呼叫SparkSession.instantiateSessionState,用反射方法建立一個HiveSessionStateBuilder,並呼叫他的build方法建立一個SessionState例項
類HiveSessionStateBuilder 繼承自BaseSessionStateBuilder
類BaseSessionStateBuilder
在BaseSessionStateBuilder中,建立一個sqlParser要呼叫extensions.buildParser(session, new SparkSqlParser(conf))方法,SparkSqlParser類是一個spark sql的解析器
類SparkSessionExtensions
SparkSessionExtensions的buildParser是處理所有的外部注入的sqlParser,如果沒有的話,就是返回剛才建立的SparkSqlParser
小細節
type
在SparkSessionExtensions類的開頭有type ParserBuilder = (SparkSession, ParserInterface) => ParserInterface,程式碼看了半天沒明白,網上找了解釋
說的非常明白,把後面的 ParserBuilder都替換成(SparkSession, ParserInterface) => ParserInterface就一目瞭然了
比如建立ParserInterface的buildParser方法(從上下文可以知道這個builder就是ParserBuilder ):
parserBuilders.foldLeft(initial) { (parser, builder) =>
builder(session, parser)
}
替換以後就很明白了,其實就是一個建構函式
parserBuilders.foldLeft(initial) { (parser, (SparkSession, ParserInterface) => ParserInterface) =>
(SparkSession, ParserInterface) => ParserInterface(session, parser)
}
foldleft
在SparkSessionExtensions類的buildParser方法中用到了buildParser函式
網上摘錄的fold解釋,foldleft類似
List中的fold方法需要輸入兩個引數:初始值以及一個函式。輸入的函式也需要輸入兩個引數:累加值和當前item的索引。那麼上面的程式碼片段發生了什麼事?
程式碼開始執行的時候,初始值0作為第一個引數傳進到fold函式中,list中的第一個item作為第二個引數傳進fold函式中。
1、fold函式開始對傳進的兩個引數進行計算,在本例中,僅僅是做加法計算,然後返回計算的值;
2、Fold函式然後將上一步返回的值作為輸入函式的第一個引數,並且把list中的下一個item作為第二個引數傳進繼續計算,同樣返回計算的值;
3、第2步將重複計算,直到list中的所有元素都被遍歷之後,返回最後的計算值,整個過程結束;
類AbstractSqlParser
下面接著前面的說,呼叫了sqlParser(即SparkSqlParser)的parsePlan方法,這個類中沒有,在他的父類AbstractSqlParser中找到,這個方法為給定的sql語句建立LogicalPlan
在這個方法中首先呼叫了parse(sqlText)方法
在這個方法中,首先建立ANTLRNoCaseStringStream物件,這個物件繼承自ANTLRInputStream,不同之處是ANTLRNoCaseStringStream把所有字串改成了大寫
建立ANTLRNoCaseStringStream物件後,連續建立了SqlBaseLexer、CommonTokenStream、SqlBaseParser物件,其中SqlBaseLexer、SqlBaseParser物件在原始碼中找不到,於是上網查了一下,發現是antler自動生成的(連結http://www.jianshu.com/p/0aa4b1caac2e)
生成SqlBaseParser後,呼叫傳入的toResult,在這裡呼叫了sqlBaseParser的singleStatement方法建立一個SqlBaseParser.SingleStatementContext物件,然後將其作為引數,呼叫astBuilder.visitSingleStatement,這個astBuilder的具體實現類是SparkSqlAstBuilder,但是其中沒有visitSingleStatement方法,該方法在其父類AstBuilder中,其中呼叫了visit方法,最終呼叫了AbstractParseTreeVisitor類的visit方法,後面有點亂了,需要學習antler才能繼續,先不鑽了
最終在SparkSession的sqlParser.parsePlan方法裡取得了LogicalPlan,然後呼叫Dataset.ofRows方法,這個方法屬於書中下一節的內容
類ANTLRInputStream
這個類是antlr包中的,從maven下載原始碼沒下成功,於是直接到github下載了zip包,作為原始碼匯入