【转载】Spark SQL之External DataSource外部数据源
http://blog.csdn.net/oopsoom/article/details/42061077
一、Spark SQL External DataSource简介
随着Spark1.2的发布,Spark SQL开始正式支持外部数据源。Spark SQL开放了一系列接入外部数据源的接口,来让开发者可以实现。
这使得Spark SQL支持了更多的类型数据源,如json, parquet, avro, csv格式。只要我们愿意,我们可以开发出任意的外部数据源来连接到Spark SQL。之前大家说的支持HBASE,Cassandra都可以用外部数据源的方式来实现无缝集成。
二、External DataSource
拿Spark1.2的json为例,它支持已经改为了实现了外部数据源的接口方式。所以除了先前我们操作json的API,又多了一种DDL创建外部数据源的方式。
parquetFile的操作方式也如下类似,就不一一列举了。
2.1 SQL方式 CREATE TEMPORARY TABLE USING OPTIONS
在Spark1.2之后,支持了一种CREATE TEMPORARY TABLE USING OPTIONS的DDL语法来创建外部数据源的表。
CREATE TEMPORARY TABLE jsonTable
USING org.apache.spark.sql.json
OPTIONS (
path '/path/to/data.json'
)
1、操作示例:
我们拿example下people.json文件来做示例。
shengli-mac$ cat /Users/shengli/git_repos/spark/examples/src/main/resources/people.json
{"name":"Michael"}
{"name":"Andy", "age":30}
{"name":"Justin", "age":19}
2、DDL创建外部数据源表jsonTable:
14/12/21 16:32:14 INFO repl.SparkILoop: Created spark context..
Spark context available as sc. scala> import org.apache.spark.sql.SQLContext
import org.apache.spark.sql.SQLContext scala> val sqlContext = new SQLContext(sc)
sqlContext: org.apache.spark.sql.SQLContext = org.apache.spark.sql.SQLContext@7be62956 scala> import sqlContext._
import sqlContext._
//创建jsonTable外部数据源表,并且指定其数数据源文件是people.json这个json文件,同时指定使用org.apache.spark.sql.json该类型的隐式转化类(这个后续文章会介绍)
scala> val jsonDDL = s"""
| |CREATE TEMPORARY TABLE jsonTable
| |USING org.apache.spark.sql.json
| |OPTIONS (
| | path 'file:///Users/shengli/git_repos/spark/examples/src/main/resources/people.json'
| |)""".stripMargin
jsonDDL: String =
"
CREATE TEMPORARY TABLE jsonTable
USING org.apache.spark.sql.json
OPTIONS (
path 'file:///Users/shengli/git_repos/spark/examples/src/main/resources/people.json'
)" scala> sqlContext.sql(jsonDDL).collect() //创建该外部数据源表jsonTable
14/12/21 16:44:27 INFO scheduler.DAGScheduler: Job 0 finished: reduce at JsonRDD.scala:57, took 0.204461 s
res0: Array[org.apache.spark.sql.Row] = Array()
我们来看下该schemaRDD:
scala> val jsonSchema = sqlContext.sql(jsonDDL)
jsonSchema: org.apache.spark.sql.SchemaRDD =
SchemaRDD[7] at RDD at SchemaRDD.scala:108
== Query Plan ==
== Physical Plan ==
ExecutedCommand (CreateTableUsing jsonTable, org.apache.spark.sql.json, Map(path -> file:///Users/shengli/git_repos/spark/examples/src/main/resources/people.json))
ExecutedCommand来取把数据用spark.sql.json的方式从path加载到jsonTable中。涉及到得类是CreateTableUsing,后续源码分析会讲到。
各阶段执行计划情况:
scala> sqlContext.sql("select * from jsonTable").queryExecution
res6: org.apache.spark.sql.SQLContext#QueryExecution =
== Parsed Logical Plan ==
'Project [*]
'UnresolvedRelation None, jsonTable, None == Analyzed Logical Plan ==
Project [age#0,name#1]
Relation[age#0,name#1] JSONRelation(file:///Users/shengli/git_repos/spark/examples/src/main/resources/people.json,1.0) == Optimized Logical Plan ==
Relation[age#0,name#1] JSONRelation(file:///Users/shengli/git_repos/spark/examples/src/main/resources/people.json,1.0) == Physical Plan ==
PhysicalRDD [age#0,name#1], MapPartitionsRDD[27] at map at JsonRDD.scala:47 Code Generation: false
== RDD ==
至此,创建加载外部数据源到Spark SQL已经完成。
3、SQL查询方式:
scala> sqlContext.sql("select * from jsonTable")
21 16:52:13 INFO spark.SparkContext: Created broadcast 6 from textFile at JSONRelation.scala:39
res2: org.apache.spark.sql.SchemaRDD =
SchemaRDD[20] at RDD at SchemaRDD.scala:108
== Query Plan ==
== Physical Plan ==
PhysicalRDD [age#2,name#3], MapPartitionsRDD[24] at map at JsonRDD.scala:47
执行查询:
scala> sqlContext.sql("select * from jsonTable").collect()
res1: Array[org.apache.spark.sql.Row] = Array([null,Michael], [30,Andy], [19,Justin])
2.2 API方式
sqlContext.jsonFile
scala> val json = sqlContext.jsonFile("file:///Users/shengli/git_repos/spark/examples/src/main/resources/people.json")
scala> json.registerTempTable("jsonFile") scala> sql("select * from jsonFile").collect()
res2: Array[org.apache.spark.sql.Row] = Array([null,Michael], [30,Andy], [19,Justin])
总的来说,Spark SQL 在努力的向各种数据源靠拢,希望让Spark SQL能和其它许多类型的数据源的集成。
Spark SQL提供的了一种创建加载外部数据源表的DDL语法:CREATE TEMPORARY TABLE USING OPTIONS
Spark SQL对外开放了一系列的扩展接口,能够通过实现这些接口,来实现对不同的数据源接入,如avro, csv, parquet,json, etc
三、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]
}
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之External DataSource外部数据源(二)源代码分析
上周Spark1.2刚公布,周末在家没事,把这个特性给了解一下,顺便分析下源代码,看一看这个特性是怎样设计及实现的. /** Spark SQL源代码分析系列文章*/ (Ps: External Da ...
- 第十一篇:Spark SQL 源码分析之 External DataSource外部数据源
上周Spark1.2刚发布,周末在家没事,把这个特性给了解一下,顺便分析下源码,看一看这个特性是如何设计及实现的. /** Spark SQL源码分析系列文章*/ (Ps: External Data ...
- 大数据技术之_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 ...
- Spark SQL 之自定义删除外部表
前言 Spark SQL 在删除外部表时,本不能删除外部表的数据的.本篇文章主要介绍如何修改Spark SQL 源码实现在删除外部表的时候,可以带额外选项来删除外部表的数据. 本文的环境是我一直使用的 ...
- Spark SQL External DataSource简介
随着Spark1.2的发布,Spark SQL开始正式支持外部数据源.这使得Spark SQL支持了更多的类型数据源,如json, parquet, avro, csv格式.只要我们愿意,我们可以开发 ...
- Spark SQL 源代码分析系列
从决定写Spark SQL文章的源代码分析,到现在一个月的时间,一个又一个几乎相同的结束很快,在这里也做了一个综合指数,方便阅读,下面是读取顺序 :) 第一章 Spark SQL源代码分析之核心流程 ...
- 【Spark SQL 源码分析系列文章】
从决定写Spark SQL源码分析的文章,到现在一个月的时间里,陆陆续续差不多快完成了,这里也做一个整合和索引,方便大家阅读,这里给出阅读顺序 :) 第一篇 Spark SQL源码分析之核心流程 第二 ...
- Spark SQL 官方文档-中文翻译
Spark SQL 官方文档-中文翻译 Spark版本:Spark 1.5.2 转载请注明出处:http://www.cnblogs.com/BYRans/ 1 概述(Overview) 2 Data ...
- Spark SQL 之 Data Sources
#Spark SQL 之 Data Sources 转载请注明出处:http://www.cnblogs.com/BYRans/ 数据源(Data Source) Spark SQL的DataFram ...
随机推荐
- jqgrid在页面出来竖型滚动条自动调整列宽
在项目中使用jqgrid的时候,需要设置在页面竖型滚动条出来的时候,列宽进行调整 1. 判断jqgrid的宽度是否和页面的宽度不一致(判断滚动条是否出来) 2. 调整jqgrid的列宽,因为jqgri ...
- Barcode記錄
.net開源框架 Barcode Rendering Framework URL:http://barcoderender.codeplex.com/releases/view/91902 可產生BR ...
- EntityFramework更新多条数据【8万】
此文主要用做记录用: 原因:数据库迁移,需要转换大量用户资料,两数据某字段加密方式不一致需要批量转换 注:转换程序用了EntityFramework 过程: 1.读取所有需要转换数据至List 2.采 ...
- SQL2008--行号的得到
WITH DataTable AS( select *, ROW_NUMBER() OVER(order by ID) as Rowno from (select * from UserInfo) a ...
- [OC Foundation框架 - 7] NSArray的创建与遍历
NSArray是不可变的,不能先创建再添加元素 NSArray可以放入任何OC对象,但不能放入基本数据类型.结构体.枚举等非OC对象 不能存储nil A.常用方法1 创建 返回用量 是否含有某元素 ...
- Windows 窗体启动和关闭的事件顺序
本文系转载学习. 对于关注对 Windows 窗体应用程序中引发的每个事件按次序进行处理的开发人员来说,事件引发的顺序特别重要.当某种情况需要小心处理事件时(如重绘窗体的某些部分时),必须知道事件在运 ...
- JAVA常用设计模式整理
设计模式:一个程序员对设计模式的理解:“不懂”为什么要把很简单的东西搞得那么复杂.后来随着软件开发经验的增加才开始明白我所看到的“复杂”恰恰就是设计模式的精髓所在,我所理解的“简单”就是一把钥匙开一把 ...
- ECshop数据库的访问统计和管理员日志的清空
ECshop是个不错的系统,但是它有一定漏洞,若是访问量巨大的话,大量的访问统计代码会存入数据库的ecs_stats表中,甚至几天就可以达到几百兆,严重的网站直接就崩溃了.数据备份的时候也有很多不便, ...
- Android v4 包和v7包问题
昨天新建了一个android项目,加入了一个bootstrap的外部依赖和一个底部导航栏的外部依赖.结果jj 了,老是提醒我v4包v7包冲突: 事实是这样的,首先我的底部导航依赖库里面有一个v4包,那 ...
- Central Authentication Service
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...