第十一篇:Spark SQL 源碼分析之 External DataSource外部資料源

來源:互聯網
上載者:User

標籤:man   sys   spark   ble   預設   abstract   而不是   record   comm   

上周Spark1.2剛發布,周末在家沒事,把這個特性給瞭解一下,順便分析下源碼,看一看這個特性是如何設計及實現的。

    /** Spark SQL源碼分析系列文章*/

  (Ps: External DataSource使用篇地址:Spark SQL之External DataSource外部資料源(一)樣本 http://blog.csdn.net/oopsoom/article/details/42061077)

一、Sources包核心

    Spark SQL在Spark1.2中提供了External DataSource API,開發人員可以根據介面來實現自己的外部資料源,如avro, csv, json, parquet等等。

    在Spark SQL原始碼的org/spark/sql/sources目錄下,我們會看到關於External DataSource的相關代碼。這裡特別介紹幾個:

    1、DDLParser 

    專門負責解析外部資料源SQL的SqlParser,解析create temporary table xxx using options (key ‘value‘, key ‘value‘) 建立載入外部資料源表的語句。

 

[java] view plain copy 
  1. protected lazy val createTable: Parser[LogicalPlan] =  
  2.    CREATE ~ TEMPORARY ~ TABLE ~> ident ~ (USING ~> className) ~ (OPTIONS ~> options) ^^ {  
  3.      case tableName ~ provider ~ opts =>  
  4.        CreateTableUsing(tableName, provider, opts)  
  5.    }  

 

    2、CreateTableUsing

   一個RunnableCommand,通過反射從外部資料源lib中執行個體化Relation,然後註冊到為temp table。

 

[java] view plain copy 
  1. private[sql] case class CreateTableUsing(  
  2.     tableName: String,  
  3.     provider: String,  // org.apache.spark.sql.json   
  4.     options: Map[String, String]) extends RunnableCommand {  
  5.   
  6.   def run(sqlContext: SQLContext) = {  
  7.     val loader = Utils.getContextOrSparkClassLoader  
  8.     val clazz: Class[_] = try loader.loadClass(provider) catch { //do reflection  
  9.       case cnf: java.lang.ClassNotFoundException =>  
  10.         try loader.loadClass(provider + ".DefaultSource") catch {  
  11.           case cnf: java.lang.ClassNotFoundException =>  
  12.             sys.error(s"Failed to load class for data source: $provider")  
  13.         }  
  14.     }  
  15.     val dataSource = clazz.newInstance().asInstanceOf[org.apache.spark.sql.sources.RelationProvider] //json包DefaultDataSource  
  16.     val relation = dataSource.createRelation(sqlContext, new CaseInsensitiveMap(options))//建立JsonRelation  
  17.   
  18.     sqlContext.baseRelationToSchemaRDD(relation).registerTempTable(tableName)//註冊  
  19.     Seq.empty  
  20.   }  
  21. }  

    2、DataSourcesStrategy

    在 Strategy 一文中,我已講過Streategy的作用,用來Plan產生物理計劃的。這裡提供了一種專門為瞭解析外部資料源的策略。

    最後會根據不同的BaseRelation生產不同的PhysicalRDD。不同的BaseRelation的scan策略下文會介紹。

 

[java] view plain copy 
  1. private[sql] object DataSourceStrategy extends Strategy {  
  2.   def apply(plan: LogicalPlan): Seq[SparkPlan] = plan match {  
  3.     case PhysicalOperation(projectList, filters, l @ LogicalRelation(t: CatalystScan)) =>  
  4.       pruneFilterProjectRaw(  
  5.         l,  
  6.         projectList,  
  7.         filters,  
  8.         (a, f) => t.buildScan(a, f)) :: Nil  
  9.     ......  
  10.     case l @ LogicalRelation(t: TableScan) =>  
  11.       execution.PhysicalRDD(l.output, t.buildScan()) :: Nil  
  12.   
  13.     case _ => Nil  
  14.   }  

   3、interfaces.scala 

 

    該檔案定義了一系列可擴充的外部資料源介面,對於想要接入的外部資料源,我們只需實現該介面即可。裡面比較重要的trait RelationProvider 和 BaseRelation,下文會詳細介紹。

    4、filters.scala

    該Filter定義了如何在載入外部資料源的時候,就進行過濾。注意哦,是載入外部資料源到Table裡的時候,而不是Spark裡進行filter。這個有點像hbase的coprocessor,查詢過濾在Server上就做了,不在Client端做過濾。

   5、LogicalRelation

   封裝了baseRelation,繼承了catalyst的LeafNode,實現MultiInstanceRelation。

        

二、External DataSource註冊流程用spark sql下sql/json來做樣本, 畫了一張流程圖,如下:  註冊外部資料源的表的流程:1、提供一個外部資料源檔案,比如json檔案。2、提供一個實現了外部資料源所需要的interfaces的類庫,比如sql下得json包,在1.2版本後改為了External Datasource實現。3、引入SQLContext,使用DDL建立表,如create temporary table xxx using options (key ‘value‘, key ‘value‘) 4、External Datasource的DDLParser將對該SQL進行Parse5、Parse後封裝成為一個CreateTableUsing類的對象。該類是一個RunnableCommand,其run方法會直接執行建立表語句。6、該類會通過反射來建立一個org.apache.spark.sql.sources.RelationProvider,該trait定義要createRelation,如json,則建立JSONRelation,若avro,則建立AvroRelation。7、得到external releation後,直接調用SQLContext的baseRelationToSchemaRDD轉換為SchemaRDD8、最後registerTempTable(tableName) 來註冊為Table,可以用SQL來查詢了。 三、External DataSource解析流程先看圖,圖如下: Spark SQL解析SQL流程如下:1、Analyzer通過Rule解析,將UnresolvedRelation解析為JsonRelation。2、通過Parse,Analyzer,Optimizer最後得到JSONRelation(file:///path/to/shengli.json,1.0)  3、通過sources下得DataSourceStrategy將LogicalPlan映射到物理計劃PhysicalRDD。4、PhysicalRDD裡包含了如何查詢外部資料的規則,可以調用execute()方法來執行Spark查詢。 四、External Datasource Interfaces在第一節我已經介紹過,主要的interfaces,主要看一下BaseRelation和RelationProvider。如果我們要實現一個外部資料源,比如avro資料來源,支援spark sql操作avro file。那麼久必須定義AvroRelation來繼承BaseRelation。同時也要實現一個RelationProvider。 BaseRelation:是外部資料源的抽象,裡面存放了schema的映射,和如何scan資料的規則。[java] view plain copy 
  1. abstract class BaseRelation {  
  2.   def sqlContext: SQLContext  
  3.   def schema: StructType  
[java] view plain copy 
  1. abstract class PrunedFilteredScan extends BaseRelation {  
  2.   def buildScan(requiredColumns: Array[String], filters: Array[Filter]): RDD[Row]  
  3. }  
1、schema我們如果自訂Relation,必須重寫schema,就是我們必須描述對於外部資料源的Schema。2、buildScan我們定義如何查詢外部資料源,提供了4種Scan的策略,對應4種BaseRelation。  我們支援4種BaseRelation,分為TableScan, PrunedScan,PrunedFilterScan,CatalystScan。   1、TableScan:          預設的Scan策略。   2、PrunedScan:          這裡可以傳入指定的列,requiredColumns,列裁剪,不需要的列不會從外部資料源載入。   3、PrunedFilterScan:          在列裁剪的基礎上,並且加入Filter機制,在載入資料也的時候就進行過濾,而不是在用戶端請求返回時做Filter。   4、CatalystScan:           Catalyst的支援傳入expressions來進行Scan。支援列裁剪和Filter。 RelationProvider:我們要實現這個,接受Parse後傳入的參數,來產生對應的External Relation,就是一個反射生產外部資料源Relation的介面。[java] view plain copy 
  1. trait RelationProvider {  
  2.   /** 
  3.    * Returns a new base relation with the given parameters. 
  4.    * Note: the parameters‘ keywords are case insensitive and this insensitivity is enforced 
  5.    * by the Map that is passed to the function. 
  6.    */  
  7.   def createRelation(sqlContext: SQLContext, parameters: Map[String, String]): BaseRelation  
  8. }  

五、External Datasource定義樣本在Spark1.2之後,json和parquet也改為通過實現External API來進行外部資料源查詢的。下面以json的外部資料源定義為樣本,說明是如何?的: 1、JsonRelation 定義處理對於json檔案的,schema和Scan策略,均基於JsonRDD,細節可以自行閱讀JsonRDD。 [java] view plain copy 
  1. private[sql] case class JSONRelation(fileName: String, samplingRatio: Double)(  
  2.     @transient val sqlContext: SQLContext)  
  3.   extends TableScan {  
  4.   
  5.   private def baseRDD = sqlContext.sparkContext.textFile(fileName) //讀取json file  
  6.   
  7.   override val schema =  
  8.     JsonRDD.inferSchema(  // jsonRDD的inferSchema方法,能自動識別json的schema,和類型type。  
  9.       baseRDD,  
  10.       samplingRatio,  
  11.       sqlContext.columnNameOfCorruptRecord)  
  12.   
  13.   override def buildScan() =  
  14.     JsonRDD.jsonStringToRow(baseRDD, schema, sqlContext.columnNameOfCorruptRecord) //這裡還是JsonRDD,調用jsonStringToRow查詢返回Row  
  15. }  
 2、DefaultSourceparameters中可以擷取到options中傳入的path等自訂參數。
這裡接受傳入的參數,來狗仔JsonRelation。[java] view plain copy 
  1. private[sql] class DefaultSource extends RelationProvider {  
  2.   /** Returns a new base relation with the given parameters. */  
  3.   override def createRelation(  
  4.       sqlContext: SQLContext,  
  5.       parameters: Map[String, String]): BaseRelation = {  
  6.     val fileName = parameters.getOrElse("path", sys.error("Option ‘path‘ not specified"))  
  7.     val samplingRatio = parameters.get("samplingRatio").map(_.toDouble).getOrElse(1.0)  
  8.   
  9.     JSONRelation(fileName, samplingRatio)(sqlContext)  
  10.   }  
  11. }  
六、總結  External DataSource源碼分析下來,可以總結為3部分。  1、外部資料源的註冊流程  2、外部資料源Table查詢的計劃解析流程  3、如何自訂一個外部資料源,重寫BaseRelation定義外部資料源的schema和scan的規則。定義RelationProvider,如何產生外部資料源Relation。    External Datasource此部分API還有可能在後續的build中改動,目前只是涉及到了查詢,關於其它的操作還未涉及。——EOF—— 

原創文章,轉載請註明:

轉載自:OopsOutOfMemory盛利的Blog, OopsOutOfMemory

本文連結地址:http://blog.csdn.net/oopsoom/article/details/42064075  

註:本文基於署名-非商業性使用-禁止演繹 2.5 中國大陸(CC BY-NC-ND 2.5 CN)協議,歡迎轉載、轉寄和評論,但是請保留本文作者署名和文章連結。如若需要用於商業目的或者與授權方面的協商,請聯絡我。

轉自:http://blog.csdn.net/oopsoom/article/details/42064075

第十一篇:Spark SQL 源碼分析之 External DataSource外部資料源

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.