第十一篇:Spark SQL 源码分析之 External DataSource外部数据源
上周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注册流程
三、External DataSource解析流程
四、External Datasource Interfaces
- 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。
- 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定义示例
- 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
- }
- 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)
- }
- }
原创文章,转载请注明:
转载自:OopsOutOfMemory盛利的Blog,作者: OopsOutOfMemory
本文链接地址:http://blog.csdn.net/oopsoom/article/details/42064075
注:本文基于署名-非商业性使用-禁止演绎 2.5 中国大陆(CC BY-NC-ND 2.5 CN)协议,欢迎转载、转发和评论,但是请保留本文作者署名和文章链接。如若需要用于商业目的或者与授权方面的协商,请联系我。
第十一篇:Spark SQL 源码分析之 External DataSource外部数据源的更多相关文章
- 【Spark SQL 源码分析系列文章】
从决定写Spark SQL源码分析的文章,到现在一个月的时间里,陆陆续续差不多快完成了,这里也做一个整合和索引,方便大家阅读,这里给出阅读顺序 :) 第一篇 Spark SQL源码分析之核心流程 第二 ...
- 第七篇:Spark SQL 源码分析之Physical Plan 到 RDD的具体实现
/** Spark SQL源码分析系列文章*/ 接上一篇文章Spark SQL Catalyst源码分析之Physical Plan,本文将介绍Physical Plan的toRDD的具体实现细节: ...
- 第十篇:Spark SQL 源码分析之 In-Memory Columnar Storage源码分析之 query
/** Spark SQL源码分析系列文章*/ 前面讲到了Spark SQL In-Memory Columnar Storage的存储结构是基于列存储的. 那么基于以上存储结构,我们查询cache在 ...
- 第九篇:Spark SQL 源码分析之 In-Memory Columnar Storage源码分析之 cache table
/** Spark SQL源码分析系列文章*/ Spark SQL 可以将数据缓存到内存中,我们可以见到的通过调用cache table tableName即可将一张表缓存到内存中,来极大的提高查询效 ...
- 第一篇:Spark SQL源码分析之核心流程
/** Spark SQL源码分析系列文章*/ 自从去年Spark Submit 2013 Michael Armbrust分享了他的Catalyst,到至今1年多了,Spark SQL的贡献者从几人 ...
- Spark SQL源码解析(二)Antlr4解析Sql并生成树
Spark SQL原理解析前言: Spark SQL源码剖析(一)SQL解析框架Catalyst流程概述 这一次要开始真正介绍Spark解析SQL的流程,首先是从Sql Parse阶段开始,简单点说, ...
- Spark SQL源码解析(四)Optimization和Physical Planning阶段解析
Spark SQL原理解析前言: Spark SQL源码剖析(一)SQL解析框架Catalyst流程概述 Spark SQL源码解析(二)Antlr4解析Sql并生成树 Spark SQL源码解析(三 ...
- Spark SQL源码解析(五)SparkPlan准备和执行阶段
Spark SQL原理解析前言: Spark SQL源码剖析(一)SQL解析框架Catalyst流程概述 Spark SQL源码解析(二)Antlr4解析Sql并生成树 Spark SQL源码解析(三 ...
- Spark SQL源码解析(三)Analysis阶段分析
Spark SQL原理解析前言: Spark SQL源码剖析(一)SQL解析框架Catalyst流程概述 Spark SQL源码解析(二)Antlr4解析Sql并生成树 Analysis阶段概述 首先 ...
随机推荐
- Notice: Undefined index: wjs_cookie
w执行顺序. ok <!doctype html> <html> <head> <meta charset="UTF-8"> < ...
- Mac 下,Redis(集群)的安装和配置
1. Redis 安装步骤 1. 到github下载redis,我下载的是3.0.4 下载地址:GitHub 2. 将下载下来的redis-3.0.4.tar.gz拷贝到 /usr/local 目录下 ...
- pandas.read_csv() 部分参数解释
read_csv()所有参数 pandas.read_csv( filepath_or_buffer, sep=',', delimiter=None, header='infer', names=N ...
- python web 程序的9种部署方式
python有很多web 开发框架,代码写完了,部署上线是个大事,通常来说,web应用一般是三层结构 Web Server====> Application=====> DB S ...
- python web框架 MVC MTV
WEB框架 MVC Model View Controller 数据库 模板文件 业务处理 MTV Model Template View 数据库 模板文件 业务处理
- 小技巧-如何加快github下载代码的速度(转)
作为开发人员,github是大家的标配了,常常会苦恼于gitclone某个项目的时候速度太慢,看着控制台那几K十几K的龟速,吐血!! 原因很简单:github的CDN被伟大的墙屏蔽所致. 所以解决方案 ...
- 【开发者笔记】java 利用jna调用c#的dll
一.需求阐述: 如果我们的项目利用c#开发,到了开发后期需要和java组进行合作,其中有一部分业务逻辑利用c#已经code completed,那么我们可能会考虑用java来调用现成的c#dll实现需 ...
- sap 动态字段的使用
1.sap中的动态字段其实类似c#里面的指针,都是指向的地址. 只是写法不同,sap 中的field-symbols就是类似指针. , b TYPE i. FIELD-SYMBOLS <fs&g ...
- 20165324《Java程序设计》第五周
学号 2016-2017-2 <Java程序设计>第五周学习总结 教材学习内容总结 第七章:内部类与异常类 内部类:java支持在类中定义另一个类,这个类为内部类,包含内部类的类称为外嵌类 ...
- HomeBrew的安装详细步骤
1)终端输入:/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master ...