1. 程式人生 > >Spark-SparkSQL深入學習系列二(轉自OopsOutOfMemory)

Spark-SparkSQL深入學習系列二(轉自OopsOutOfMemory)

    Spark SQL的核心執行流程我們已經分析完畢,可以參見Spark SQL核心執行流程,下面我們來分析執行流程中各個核心元件的工作職責。

    本文先從入口開始分析,即如何解析SQL文字生成邏輯計劃的,主要設計的核心元件式SqlParser是一個SQL語言的解析器,用scala實現的Parser將解析的結果封裝為Catalyst TreeNode ,關於Catalyst這個框架後續文章會介紹。

一、SQL Parser入口

    Sql Parser 其實是封裝了scala.util.parsing.combinator下的諸多Parser,並結合Parser下的一些解析方法,構成了Catalyst的元件UnResolved Logical Plan。

    先來看流程圖:

     

     一段SQL會經過SQL Parser解析生成UnResolved Logical Plan(包含UnresolvedRelation、 UnresolvedFunction、 UnresolvedAttribute)。

    在原始碼裡是:  

  1. def sql(sqlText: String): SchemaRDD = new SchemaRDD(this, parseSql(sqlText))//sql("select name,value from temp_shengli") 例項化一個SchemaRDD
  2. protected
    [sql] def parseSql(sql: String): LogicalPlan = parser(sql) //例項化SqlParser
  3. class SqlParser extends StandardTokenParsers with PackratParsers {  
  4.   def apply(input: String): LogicalPlan = {  //傳入sql語句呼叫apply方法,input引數即sql語句
  5.     // Special-case out set commands since the value fields can be
  6.     // complex to handle without RegexParsers. Also this approach
  7.     // is clearer for the several possible cases of set commands.
  8.     if (input.trim.toLowerCase.startsWith("set")) {  
  9.       input.trim.drop(3).split("="2).map(_.trim) match {  
  10.         case Array("") => // "set"
  11.           SetCommand(None, None)  
  12.         case Array(key) => // "set key"
  13.           SetCommand(Some(key), None)  
  14.         case Array(key, value) => // "set key=value"
  15.           SetCommand(Some(key), Some(value))  
  16.       }  
  17.     } else {  
  18.       phrase(query)(new lexical.Scanner(input)) match {  
  19.         case Success(r, x) => r  
  20.         case x => sys.error(x.toString)  
  21.       }  
  22.     }  
  23.   }  

    1.  當我們呼叫sql("select name,value from temp_shengli")時,實際上是new了一個SchemaRDD

    2. new SchemaRDD時,構造方法呼叫parseSql方法,parseSql方法例項化了一個SqlParser,這個Parser初始化呼叫其apply方法。

    3. apply方法分支:

         3.1 如果sql命令是set開頭的就呼叫SetCommand,這個類似Hive裡的引數設定,SetCommand其實是一個Catalyst裡TreeNode之LeafNode,也是繼承自LogicalPlan,關於Catalyst的TreeNode庫這個暫不詳細介紹,後面會有文章來詳細講解。

         3.2 關鍵是else語句塊裡,才是SqlParser解析SQL的核心程式碼:

  1. phrase(query)(new lexical.Scanner(input)) match {  
  2.        case Success(r, x) => r  
  3.        case x => sys.error(x.toString)  
  4.      }  
        可能 phrase方法大家很陌生,不知道是幹什麼的,那麼我們首先看一下SqlParser的類圖:

      SqlParser類繼承了scala內建集合Parsers,這個Parsers。我們可以看到SqlParser現在是具有了分詞的功能,也能解析combiner的語句(類似p ~> q,後面會介紹)。

     Phrase方法:

  1. /** A parser generator delimiting whole phrases (i.e. programs). 
  2.  * 
  3.  *  `phrase(p)` succeeds if `p` succeeds and no input is left over after `p`. 
  4.  * 
  5.  *  @param p the parser that must consume all input for the resulting parser 
  6.  *           to succeed. 
  7.  *  @return  a parser that has the same result as `p`, but that only succeeds 
  8.  *           if `p` consumed all the input. 
  9.  */
  10. def phrase[T](p: Parser[T]) = new Parser[T] {  
  11.   def apply(in: Input) = lastNoSuccessVar.withValue(None) {  
  12.     p(in) match {  
  13.     case s @ Success(out, in1) =>  
  14.       if (in1.atEnd)  
  15.         s  
  16.       else
  17.           lastNoSuccessVar.value filterNot { _.next.pos < in1.pos } getOrElse Failure("end of input expected", in1)  
  18.       case ns => lastNoSuccessVar.value.getOrElse(ns)  
  19.     }  
  20.   }  
  21. }  

Phrase是一個迴圈讀取輸入字元的方法,如果輸入in沒有到達最後一個字元,就繼續對parser進行解析,直到最後一個輸入字元。

     我們注意到Success這個類,出現在Parser裡, 在else塊裡最終返回的也有Success:

  1. /** The success case of `ParseResult`: contains the result and the remaining input. 
  2.   * 
  3.   *  @param result The parser's output 
  4.   *  @param next   The parser's remaining input 
  5.   */
  6.  caseclass Success[+T](result: T, override val next: Input) extends ParseResult[T] {  
    通過原始碼可知,Success封裝了當前解析器的解析結果result, 和還沒有解析的語句。

   所以上面判斷了Success的解析結果中in1.atEnd? 如果輸入流結束了,就返回s,即Success物件,這個Success包含了SqlParser解析的輸出。

二、Sql Parser核心

在SqlParser裡phrase接受2個引數:

第一個是query,一種帶模式的解析規則,返回的是LogicalPlan。

第二個是lexical詞彙掃描輸入。

SqlParser parse的流程是,用lexical詞彙掃描接受SQL關鍵字,使用query模式來解析符合規則的SQL。

2.1 lexical keyword

在SqlParser裡定義了KeyWord這個類:
  1. protectedcaseclass Keyword(str: String)  
在我使用的spark1.0.0版本里目前只支援了一下SQL保留字:
  1. protected val ALL = Keyword("ALL")  
  2.  protected val AND = Keyword("AND")  
  3.  protected val AS = Keyword("AS")  
  4.  protected val ASC = Keyword("ASC")  
  5.  protected val APPROXIMATE = Keyword("APPROXIMATE")  
  6.  protected val AVG = Keyword("AVG")  
  7.  protected val BY = Keyword("BY")  
  8.  protected val CACHE = Keyword("CACHE")  
  9.  protected val CAST = Keyword("CAST")  
  10.  protected val COUNT = Keyword("COUNT")  
  11.  protected val DESC = Keyword("DESC")  
  12.  protected val DISTINCT = Keyword("DISTINCT")  
  13.  protected val FALSE = Keyword("FALSE")  
  14.  protected val FIRST = Keyword("FIRST")  
  15.  protected val FROM = Keyword("FROM")  
  16.  protected val FULL = Keyword("FULL")  
  17.  protected val GROUP = Keyword("GROUP")  
  18.  protected val HAVING = Keyword("HAVING")  
  19.  protected val IF = Keyword("IF")  
  20.  protected val IN = Keyword("IN")  
  21.  protected val INNER = Keyword("INNER")  
  22.  protected val INSERT = Keyword("INSERT")  
  23.  protected val INTO = Keyword("INTO")  
  24.  protected val IS = Keyword("IS")  
  25.  protected val JOIN = Keyword("JOIN")  
  26.  protected val LEFT = Keyword("LEFT")  
  27.  protected val LIMIT = Keyword("LIMIT")  
  28.  protected val MAX = Keyword("MAX")  
  29. 相關推薦

    Spark-SparkSQL深入學習系列OopsOutOfMemory

        Spark SQL的核心執行流程我們已經分析完畢,可以參見Spark SQL核心執行流程,下面我們來分析執行流程中各個核心元件的工作職責。     本文先從入口開始分析,即如何解析SQL文字生成邏輯計劃的,主要設計的核心元件式SqlParser是

    Spark-SparkSQL深入學習系列OopsOutOfMemory

      我們都知道一段sql,真正的執行是當你呼叫它的collect()方法才會執行Spark Job,最後計算得到RDD。 lazy val toRdd: RDD[Row] = executedPlan.execute()     Spark Plan基本包含4種操作型別

    Spark-SparkSQL深入學習系列OopsOutOfMemory

        Spark SQL 可以將資料快取到記憶體中,我們可以見到的通過呼叫cache table tableName即可將一張表快取到記憶體中,來極大的提高查詢效率。     這就涉及到記憶體中的資料的儲存形式,我們知道基於關係型的資料可以儲存為基於行儲存結構 或 者基於列儲存結構,或者基於行和列的

    Spark-SparkSQL深入學習系列十一OopsOutOfMemory

      上週Spark1.2剛釋出,週末在家沒事,把這個特性給瞭解一下,順便分析下原始碼,看一看這個特性是如何設計及實現的。     /** Spark SQL原始碼分析系列文章*/ 一、Sources包核心     Spark SQL在Spark1.2中提供了Exte

    多線程學習系列使用System.Threading

    設定 進行 運行時 art lowest 模擬 state 執行 png 一、什麽是System.Threading.Thread?如何使用System.Threading.Thread進行異步操作 System.Threading.Thread:操作系統實現線程並提供各

    Java學習路線圖[]

    <br />一)、工具篇<br />一、 JDK (Java Development Kit) <br />JDK是整個Java的核心,包括了Java執行環境(Java Runtime

    Maven學習筆記配置本地倉庫

    maven學習筆記 Maven的默認本地倉庫在: ${user.home}/.m2/repository; 如果需要自定義倉庫路徑,可以找到maven文件夾下的conf下的setting.xml文件進行修改, 以下自定義倉庫路徑為E:\java\Maven\apache-maven-3

    python 學習筆記 列表推導式

      2018年年初寫了第一篇部落格,說要做一個認真的技術人 https://www.cnblogs.com/yingchen/p/8455507.html 今天已經是11月19日了,這是第二篇部落格,看來堅持確實是個好難的東西。雖然沒寫筆記,今年一年對python的使用還是可以的, 今天繼續:

    SVN初學者學習使用文章文件

    方法/步驟 簽出原始碼到本機 在本機建立資料夾StartKit,右鍵點選Checkout,彈出如下圖的窗體: 在上圖中URL of Repository:下的文字框中輸入svn server中的程式碼庫的地址,其他預設,點選OK按鈕,就開始簽出原始碼了。 說明:上

    資料庫系統實現學習筆記資料庫關係建模--by穆晨

    前言         ER建模環節完成後,需求就被描述成了ER圖。之後,便可根據這個ER圖設計相應的關係表了。         但從ER圖到具體關係表的建立還需要經過兩個步驟: 邏輯模型設計:將ER圖對映為邏輯意義上的

    JUC學習系列訊號量 Semaphore

    一個計數訊號量。從概念上講,訊號量維護了一個許可集。Semaphore 通常用於限制可以訪問某些資源(物理或邏輯的)的執行緒數目。通常,應該將用於控制資源訪問的訊號量初始化為公平的,以確保所有執行緒都可訪問資源。為其他的種類的同步控制使用訊號量時,非公平排序的吞吐量優勢通常要

    JUC學習系列非同步計算 FutureTask

    public interface Future<V> Future 表示非同步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,並獲取計算的結果。計算完成後只能使用 get 方法來獲取結果,如有必要,計算完成前可以阻塞此方法。取消則由 cancel 方

    SVN 學習筆記一口氣學會SVN

    我打算一口氣講完SVN的使用,所以,在看之前呢,請先深深的吸一口氣(怎麼聽著像黑龍公主),當然吸完後還是要撥出來的。不要憋著了。 我們可能希望一來就直接操作。列出一堆命令。詳細的命令引數等資訊,我們都可以加入 --help 選項獲取,下面不會詳細介紹。除非必要。現在先看下

    Fiddler抓包工具總結自小坦克

    修改用戶名 ins 結果 包含 tomat asp.net 優化 視頻教程 了解 -- 此文章是轉載小坦克的;直接復制文章的目的是因為原文章地址經常被重置,找不到原來的文章。小坦克博客園主頁:https://home.cnblogs.com/u/TankXiao/ 目錄

    資料結構與算法系列複雜度分析

    1.引子 1.1.為什麼要學習資料結構與演算法? 有人說,資料結構與演算法,計算機網路,與作業系統都一樣,脫離日常開發,除了面試這輩子可能都用不到呀! 有人說,我是做業務開發的,只要熟練API,熟練框架,熟練各種中介軟體,寫的程式碼不也能“飛”起來嗎? 於是問題來了:為什麼還要學習資料結構與演算法呢?

    HTTP狀態碼大全wiki

    成對 節點 而是 沒有 redirect port multiple 許可 sta 1xx消息 這一類型的狀態碼,代表請求已被接受,需要繼續處理。這類響應是臨時響應,只包含狀態行和某些可選的響應頭信息,並以空行結束。由於HTTP/1.0協議中沒有定義任何1xx狀態碼,所以除

    RPG遊戲設計Gameres

    工作量 我們 初始化 共享 世人 生命 置疑 年輕 動作 目錄:   第一章 概述  第二章 場景  第三章 角色  第四章 道具  第五章 事件  第六章 對白  第七章 語音和音效  第八章 音樂  第九章 界面  第十章 規則  第十一章 命名第一章:概述RPG遊戲即

    ubuntu中安裝meld工具-sukhoi27smk

    插件 edit ges -s election load nbsp 輸入 eight Ubuntu下文件/目錄對比的軟件Meld可能有很多用戶還不是很熟悉,下文就給大家介紹如何安裝Meld和移植到Gedit下。具體內容如下所述。 Meld允許用戶查看文件、目錄間的變化。很容

    ASP.NET Core 中的 WebSocket 支持MSDN

    ocs 接收 緩沖 任務 ica uget 本地服務器 tcp msdn 本文介紹 ASP.NET Core 中 WebSocket 的入門方法。 WebSocket (RFC 6455) 是一個協議,支持通過 TCP 連接建立持久的雙向信道。 它用於從快速實時通信中獲益的

    EF Core中DeleteBehavior的介紹MSDN

    then defined nec div values tomat ack practice blank Delete behaviors Delete behaviors are defined in the DeleteBehavior enumerator type