上周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') 创建载入外部数据源表的语句。

 protected lazy val createTable: Parser[LogicalPlan] =
CREATE ~ TEMPORARY ~ TABLE ~> ident ~ (USING ~> className) ~ (OPTIONS ~> options) ^^ {
case tableName ~ provider ~ opts =>
CreateTableUsing(tableName, provider, opts)
}

2、CreateTableUsing

一个RunnableCommand。通过反射从外部数据源lib中实例化Relation。然后注冊到为temp table。

private[sql] case class CreateTableUsing(
tableName: String,
provider: String, // org.apache.spark.sql.json
options: Map[String, String]) extends RunnableCommand { def run(sqlContext: SQLContext) = {
val loader = Utils.getContextOrSparkClassLoader
val clazz: Class[_] = try loader.loadClass(provider) catch { //do reflection
case cnf: java.lang.ClassNotFoundException =>
try loader.loadClass(provider + ".DefaultSource") catch {
case cnf: java.lang.ClassNotFoundException =>
sys.error(s"Failed to load class for data source: $provider")
}
}
val dataSource = clazz.newInstance().asInstanceOf[org.apache.spark.sql.sources.RelationProvider] //json包DefaultDataSource
val relation = dataSource.createRelation(sqlContext, new CaseInsensitiveMap(options))//创建JsonRelation sqlContext.baseRelationToSchemaRDD(relation).registerTempTable(tableName)//注冊
Seq.empty
}
}

    2、DataSourcesStrategy

在 Strategy 一文中。我已讲过Streategy的作用,用来Plan生成物理计划的。

这里提供了一种专门为了解析外部数据源的策略。

最后会依据不同的BaseRelation生产不同的PhysicalRDD。

不同的BaseRelation的scan策略下文会介绍。

private[sql] object DataSourceStrategy extends Strategy {
def apply(plan: LogicalPlan): Seq[SparkPlan] = plan match {
case PhysicalOperation(projectList, filters, l @ LogicalRelation(t: CatalystScan)) =>
pruneFilterProjectRaw(
l,
projectList,
filters,
(a, f) => t.buildScan(a, f)) :: Nil
......
case l @ LogicalRelation(t: TableScan) =>
execution.PhysicalRDD(l.output, t.buildScan()) :: Nil case _ => Nil
}

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来做演示样例, 画了一张流程图,例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvb29wc29vbQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

注冊外部数据源的表的流程:
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进行Parse
5、Parse后封装成为一个CreateTableUsing类的对象。

该类是一个RunnableCommand,其run方法会直接运行创建表语句。

6、该类会通过反射来创建一个org.apache.spark.sql.sources.RelationProvider。该trait定义要createRelation。如json。则创建JSONRelation,若avro,则创建AvroRelation。

7、得到external releation后,直接调用SQLContext的baseRelationToSchemaRDD转换为SchemaRDD
8、最后registerTempTable(tableName) 来注冊为Table。能够用SQL来查询了。

三、External DataSource解析流程

先看图,图例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvb29wc29vbQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

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数据的规则。
abstract class BaseRelation {
def sqlContext: SQLContext
def schema: StructType
abstract class PrunedFilteredScan extends BaseRelation {
def buildScan(requiredColumns: Array[String], filters: Array[Filter]): RDD[Row]
}

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机制。在载入数据也的时候就进行过滤。而不是在client请求返回时做Filter。

   4、CatalystScan
           Catalyst的支持传入expressions来进行Scan。支持列裁剪和Filter。

RelationProvider:
我们要实现这个,接受Parse后传入的參数。来生成相应的External Relation,就是一个反射生产外部数据源Relation的接口。
trait RelationProvider {
/**
* Returns a new base relation with the given parameters.
* Note: the parameters' keywords are case insensitive and this insensitivity is enforced
* by the Map that is passed to the function.
*/
def createRelation(sqlContext: SQLContext, parameters: Map[String, String]): BaseRelation
}

五、External Datasource定义演示样例

在Spark1.2之后,json和parquet也改为通过实现External API来进行外部数据源查询的。
以下以json的外部数据源定义为演示样例,说明是怎样实现的:
1、JsonRelation
定义处理对于json文件的,schema和Scan策略,均基于JsonRDD,细节能够自行阅读JsonRDD。
private[sql] case class JSONRelation(fileName: String, samplingRatio: Double)(
@transient val sqlContext: SQLContext)
extends TableScan { private def baseRDD = sqlContext.sparkContext.textFile(fileName) //读取json file override val schema =
JsonRDD.inferSchema( // jsonRDD的inferSchema方法。能自己主动识别json的schema。和类型type。
baseRDD,
samplingRatio,
sqlContext.columnNameOfCorruptRecord) override def buildScan() =
JsonRDD.jsonStringToRow(baseRDD, schema, sqlContext.columnNameOfCorruptRecord) //这里还是JsonRDD,调用jsonStringToRow查询返回Row
}
2、DefaultSource
parameters中能够获取到options中传入的path等自己定义參数。
这里接受传入的參数,来狗仔JsonRelation。

private[sql] class DefaultSource extends RelationProvider {
/** Returns a new base relation with the given parameters. */
override def createRelation(
sqlContext: SQLContext,
parameters: Map[String, String]): BaseRelation = {
val fileName = parameters.getOrElse("path", sys.error("Option 'path' not specified"))
val samplingRatio = parameters.get("samplingRatio").map(_.toDouble).getOrElse(1.0) JSONRelation(fileName, samplingRatio)(sqlContext)
}
}

六、总结
  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)协议,欢迎转载、转发和评论,可是请保留本文作者署名和文章链接。如若须要用于商业目的或者与授权方面的协商,请联系我。

Spark SQL之External DataSource外部数据源(二)源代码分析的更多相关文章

  1. 【转载】Spark SQL之External DataSource外部数据源

    http://blog.csdn.net/oopsoom/article/details/42061077 一.Spark SQL External DataSource简介 随着Spark1.2的发 ...

  2. 第十一篇:Spark SQL 源码分析之 External DataSource外部数据源

    上周Spark1.2刚发布,周末在家没事,把这个特性给了解一下,顺便分析下源码,看一看这个特性是如何设计及实现的. /** Spark SQL源码分析系列文章*/ (Ps: External Data ...

  3. 大数据技术之_19_Spark学习_03_Spark SQL 应用解析 + Spark SQL 概述、解析 、数据源、实战 + 执行 Spark SQL 查询 + JDBC/ODBC 服务器

    第1章 Spark SQL 概述1.1 什么是 Spark SQL1.2 RDD vs DataFrames vs DataSet1.2.1 RDD1.2.2 DataFrame1.2.3 DataS ...

  4. Spark SQL 之自定义删除外部表

    前言 Spark SQL 在删除外部表时,本不能删除外部表的数据的.本篇文章主要介绍如何修改Spark SQL 源码实现在删除外部表的时候,可以带额外选项来删除外部表的数据. 本文的环境是我一直使用的 ...

  5. Spark大师之路:广播变量(Broadcast)源代码分析

    概述 近期工作上忙死了--广播变量这一块事实上早就看过了,一直没有贴出来. 本文基于Spark 1.0源代码分析,主要探讨广播变量的初始化.创建.读取以及清除. 类关系 BroadcastManage ...

  6. Spark技术内幕:Stage划分及提交源代码分析

    当触发一个RDD的action后.以count为例,调用关系例如以下: org.apache.spark.rdd.RDD#count org.apache.spark.SparkContext#run ...

  7. Spark MLlib LDA 基于GraphX实现原理及源代码分析

    LDA背景 LDA(隐含狄利克雷分布)是一个主题聚类模型,是当前主题聚类领域最火.最有力的模型之中的一个,它能通过多轮迭代把特征向量集合按主题分类.眼下,广泛运用在文本主题聚类中. LDA的开源实现有 ...

  8. Spark SQL 源代码分析系列

    从决定写Spark SQL文章的源代码分析,到现在一个月的时间,一个又一个几乎相同的结束很快,在这里也做了一个综合指数,方便阅读,下面是读取顺序 :) 第一章 Spark SQL源代码分析之核心流程 ...

  9. Spark SQL External DataSource简介

    随着Spark1.2的发布,Spark SQL开始正式支持外部数据源.这使得Spark SQL支持了更多的类型数据源,如json, parquet, avro, csv格式.只要我们愿意,我们可以开发 ...

随机推荐

  1. IDA 操作记录

    IDA 操作记录 1.加载文件 windows 下,用ida加载文件后,会在该文件同目录下生成几个文件,含义如下: .id0 : 二叉树数据库 .id1:    文件包含描述每个程序字节的标记 .na ...

  2. FZU——2111Min Number(多次交换得到最小数,水题)

    Problem 2111 Min Number Accept: 760    Submit: 1516 Time Limit: 1000 mSec    Memory Limit : 32768 KB ...

  3. HDU-2853 Assignment

    求二分最大匹配,但还要尽量接近原匹配... 解决方法:对于N个顶点的二分图,每条边同时乘上一个比N稍微大的数N',然后对于在原匹配的边就都+1. 经过这样处理,求得的答案Ans乘除N'即是原图的最大匹 ...

  4. bzoj 2799 [Poi2012]Salaries 性质+二分

    题目大意 给出一棵n个结点的有根树,结点用正整数1~n编号. 每个结点有一个1~n的正整数权值,不同结点的权值不相同, 并且一个结点的权值一定比它父结点的权值小(根结点的权值最大,一定是n). 现在有 ...

  5. Windows server 2008 R2 + IIS7.5,ASP网站设置

    Windows server 2008 R2 + IIS7.5,ASP网站设置 1. 让IIS7支持ASP Win2008 IIS7 默认不安装ASP,如果需要ASP 的支持,需要将这个角色服务选上. ...

  6. 转 Perl函数返回值用法指导

    http://developer.51cto.com/art/201007/213003.htm Perl函数返回值用法指导   Perl编程语言中Perl函数返回值用法你是否比较熟悉,这里向大家简单 ...

  7. Yii命令行模式

    (具体参数描述请使用命令看描述,不过全是英文) 1.Yii提供命令行指令不多,常用的有webapp 和 shell. 1.  message 搜索指定文件信息 yicc message webroot ...

  8. LeetCode OJ--Binary Tree Level Order Traversal

    http://oj.leetcode.com/problems/binary-tree-level-order-traversal/ 树的层序遍历,使用队列 由于树不是满的,还要分出每一层来,刚开始给 ...

  9. 语音按钮功能之UIButton的UIControlEventTouchUpInside没有执行问题

    新版本im功能开发过程中,遇到个奇葩的问题. 就是点击语音按钮,点击一下松开,不执行UIControlEventTouchUpInside的方法.所以导致一直在录音 但是长按2秒以上,是可以执行UIC ...

  10. Wannafly挑战赛2 C.Butterfly(线段树优化枚举)

    题目链接  C.Butterfly 令$fd[i][j]$为以$s[i][j]$为起点开始往下走最大连续的‘X’个数 令$fl[i][j]$为以$s[i][j]$为起点开始往左下走最大连续的‘X’个数 ...