1. 程式人生 > >spark2.2.0原始碼學習過程記錄:Day8

spark2.2.0原始碼學習過程記錄:Day8

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類似
val numbers = List(5, 4, 8, 6, 2)
numbers.fold(0) { (z, i) => z + i } // result = 25
  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包,作為原始碼匯入