Spark 2.x不支持ALTER TABLE ADD COLUMNS,没关系,我们改进下
SparkSQL从2.0开始已经不再支持ALTER TABLE table_name ADD COLUMNS (col_name data_type [COMMENT col_comment], ...)这种语法了(下文简称add columns语法)。如果你的Spark项目中用到了SparkSQL+Hive这种模式,从Spark1.x升级到2.x很有可能遇到这个问题。
为了解决这个问题,我们一般有3种方案可以选择:
- 启动一个hiveserver2服务,通过jdbc直接调用hive,让hive执行add columns语句。这种应该是改起来最为方便的一种方式了,缺点就是,我们还需要在启动一个hiveserver服务,多一个服务依赖,会增加整个系统的维护成本。
- SparkSQL+Hive这种模式,要求我们启动一个HiveMetastore服务,给SparkSQL用,我们也可以在代码中直接直接连接HiveMetastore去执行add columns语句。这种方式的好处是不需要额外依赖其他服务,缺点就是我们要自己调用HiveMetastore相关接口,自己管理SessionState,用起来比较麻烦。
- 最后一种方式就是直接修改Spark,让他支持add columns语法。这种方式最大的好处就是我们原有的业务逻辑代码不用动,问题就在于,要求对Spark源码有一定的了解,否则改起来还是挺费劲的。这也是我写这篇文章的目的:让大家能够参考本文自行为Spark添加add columns语法支持。
OK,接下来,我们进入主题。
为Spark添加add columns语法支持
本文基于最新版的Spark 2.1.0,源码地址:https://github.com/apache/spark/tree/branch-2.1
1. 改进语法定义
Spark2.1开始使用ANTLR来解析SQL语法,它的语法定义文件借鉴的Presto项目,我们在Spark源码中找到这个文件sql/catalyst/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBase.g4,做如下改动:
@@ -127,6 +127,8 @@ statement
('(' key=tablePropertyKey ')')? #showTblProperties
| SHOW COLUMNS (FROM | IN) tableIdentifier
((FROM | IN) db=identifier)? #showColumns
+ | ALTER TABLE tableIdentifier ADD COLUMNS
+ ('(' columns=colTypeList ')')? #addColumns
| SHOW PARTITIONS tableIdentifier partitionSpec? #showPartitions
| SHOW identifier? FUNCTIONS
(LIKE? (qualifiedName | pattern=STRING))? #showFunctions
@@ -191,7 +193,6 @@ unsupportedHiveNativeCommands
| kw1=ALTER kw2=TABLE tableIdentifier partitionSpec? kw3=COMPACT
| kw1=ALTER kw2=TABLE tableIdentifier partitionSpec? kw3=CONCATENATE
| kw1=ALTER kw2=TABLE tableIdentifier partitionSpec? kw3=SET kw4=FILEFORMAT
- | kw1=ALTER kw2=TABLE tableIdentifier partitionSpec? kw3=ADD kw4=COLUMNS
| kw1=ALTER kw2=TABLE tableIdentifier partitionSpec? kw3=CHANGE kw4=COLUMN?
| kw1=ALTER kw2=TABLE tableIdentifier partitionSpec? kw3=REPLACE kw4=COLUMNS
| kw1=START kw2=TRANSACTION
194行的kw1=ALTER kw2=TABLE tableIdentifier partitionSpec? kw3=ADD kw4=COLUMNS是在unsupportedHiveNativeCommands列表中,我们首先把它去掉。
为了让Spark能解析ALTER TABLE table_name ADD COLUMNS (col_name data_type [COMMENT col_comment], ...),我们还需要在129行处新增| ALTER TABLE tableIdentifier ADD COLUMNS ('(' columns=colTypeList ')')? #addColumns最后的#addColumns是为了让ANTLR插件(这个插件定义在sql/catalyst/pom.xml中)为我们自动生成addColumns相关方法,便于我们做语法解析处理。这个语法中有2个参数需要我们处理table_name和columns。
2. 改进SparkSqlAstBuilder,使其能处理addColumns
SparkSqlAstBuilder的作用是将ANTLR的语法树翻译为LogicalPlan/Expression/TableIdentifier
要修改的文件为:sql/core/src/main/scala/org/apache/spark/sql/execution/SparkSqlParser.scala,我们在178行处,新增如下方法:
override def visitAddColumns(ctx: AddColumnsContext): LogicalPlan = withOrigin(ctx) {
val tableName = visitTableIdentifier(ctx.tableIdentifier())
val dataCols = Option(ctx.columns).map(visitColTypeList).getOrElse(Nil)
AlterTableAddColumnsCommand(tableName, dataCols)
}
visitAddColumns方法是ANTLR插件自动为我们生成的方法,定义在SparkSqlAstBuilder的父类AstBuilder中(AST,Abstract Syntax Tree ,抽象语法树),这个方法用来处理我们在SqlBase.g4中定义的| ALTER TABLE tableIdentifier ADD COLUMNS ('(' columns=colTypeList ')')? #addColumns,我们这里重载了visitAddColumns方法用来提取表名及新增的字段列表,并返回一个LogicalPlan:AlterTableAddColumnsCommand,这个类我们接下来会说明。
3. 新增一个为表添加字段的命令
修改sql/core/src/main/scala/org/apache/spark/sql/execution/command/tables.scala,在120行处,新增AlterTableAddColumnsCommand类:
case class AlterTableAddColumnsCommand(
tableName: TableIdentifier,
newColumns: Seq[StructField]) extends RunnableCommand {
override def run(sparkSession: SparkSession): Seq[Row] = {
val catalog = sparkSession.sessionState.catalog
val table = catalog.getTableMetadata(tableName)
DDLUtils.verifyAlterTableType(catalog, table, isView = false)
val newSchema = StructType(table.schema.fields ++ newColumns)
val newTable = table.copy(schema = newSchema)
catalog.alterTable(newTable)
Seq.empty[Row]
}
}
RunnableCommand类继承自LogicalPlan,run方法用于执行addColumns语法对应的执行逻辑。这个类的处理逻辑比较简单,就不详细介绍了。
4. 修复HiveExternalCatalog无法修改表schema的问题
我们在第3步的AlterTableAddColumnsCommand中,虽然调用了catalog.alterTable(newTable)来修改表信息,但实际上并不能将新的字段添加到表中,因为Spark代码写死了,不能改Hive表的schema,我们还需要修改HiveExternalCatalog类(sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveExternalCatalog.scala),改动如下:
@@ -588,7 +588,8 @@ private[spark] class HiveExternalCatalog(conf: SparkConf, hadoopConf: Configurat
val newTableProps = oldDataSourceProps ++ withStatsProps.properties + partitionProviderProp
val newDef = withStatsProps.copy(
storage = newStorage,
- schema = oldTableDef.schema,
+ // allow `alter table xxx add columns(xx)`
+ schema = tableDefinition.schema,
partitionColumnNames = oldTableDef.partitionColumnNames,
bucketSpec = oldTableDef.bucketSpec,
properties = newTableProps)
我们将591行的schema = oldTableDef.schema替换为schema = tableDefinition.schema即可。
至此,我们完成了整个代码的调整。
最后参考Spark的编译文档:http://spark.apache.org/docs/latest/building-spark.html#building-a-runnable-distribution,将Spark编译打包即可。
Spark 2.x会将编译后的assembly放到jars目录下,我们这次的改动会影响到以下几个jar包:
- spark-catalyst_2.11-2.1.0.jar
- spark-sql_2.11-2.1.0.jar
- spark-hive_2.11-2.1.0.jar
如果Spark已经部署过了,可以直接将以上3个jar替换掉。
更新Spark后,我们就可以使用alter table xxx add columns(xx)了。
Spark 2.x不支持ALTER TABLE ADD COLUMNS,没关系,我们改进下的更多相关文章
- 自己动手为Spark 2.x添加ALTER TABLE ADD COLUMNS语法支持
SparkSQL从2.0开始已经不再支持ALTER TABLE table_name ADD COLUMNS (col_name data_type [COMMENT col_comment], .. ...
- 【待整理】MySQL alter table modify vs alter table add产生state不一样
MySQL:5.6.35 OS:redhat5.8 今天更新数据库某些表字段,有如下两SQL: ①alter table xx modify xxxx;(表大概是77w) ②alter table s ...
- create index 与 alter table add index 区别
众所周知,MySQL创建索引有两种语法,即:ALTER TABLE HeadOfState ADD INDEX (LastName, FirstName);CREATE INDEX index_nam ...
- alter table add constraint 用法
1.主键约束: 要对一个列加主键约束的话,这列就必须要满足的条件就是分空 因为主键约束:就是对一个列进行了约束,约束为(非空.不重复) 以下是代码 要对一个列加主键,列名为id,表名为emp 格式 ...
- alter table *** add constraint *** 用法---约束
1.主键约束:要对一个列加主键约束的话,这列就必须要满足的条件就是分空因为主键约束:就是对一个列进行了约束,约束为(非空.不重复)以下是代码 要对一个列加主键,列名为id,表名为emp 格式为:a ...
- faster alter table add column
Create a new table (using the structure of the current table) with the new column(s) included. execu ...
- [Hive - LanguageManual] Alter Table/Partition/Column
Alter Table/Partition/Column Alter Table Rename Table Alter Table Properties Alter Table Comment Add ...
- alter table添加表约束
翻阅了一下网上关于alter table添加表约束的资料,学习下,然后供自己以后使用. 仅仅供自己使用... 总结alter table ### add constraint ## 使用方法 添加表约 ...
- alter table <表名 > add constraint <主键名>用法
alter table <表名 > add constraint <主键名>用法介绍 1.主键约束: 要对一个列加主键约束的话,这列就必须要满足的条件就是分空 因为主键约束: ...
随机推荐
- 有return如果是try catch finally运行命令
背景: 昨天一个朋友出去采访,遇到这样的问题:"C# catch那里return.finally也弄它运行?" 个人总结实践: 1.无论有木有出现异常.finally块中代码都会 ...
- Object instanceof Function和Function instanceof Object
首先需要确定的是,instanceof是根据原型链来判断是否为某引用类型的实例.所以需要明白Object和Function之间的关系,以下为引用某博客的图片,阐述了javascript对象体系的关系 ...
- 在PHP中如何连接到数据库
首先我们先运行WampServer中的phpMyAdmin随即弹出phpMyAdmin页面 在弹出的页面中左边是数据库列表 右边是相应的设置 选择一个数据库 在里面创建一张数据表 注意创建数 ...
- VS生产的编辑方法和编辑窗体
MVC5入门学习系列⑤ 检查VS生产的编辑方法和编辑窗体 前面我们一步使用强类型,然后创建Controller(控制器)的时候,VS默认已经给我们把CURD都简单的实现了.这篇的话就简单的看下它默 ...
- NodeJs技术
我的NodeJs技术总结——第一篇 既然是我的技术总结,那就是以我的技术水平为基础的,写浅了大家不要笑话,如果有错误的地方还望指正. 这第一篇就谈谈NodeJs的一些编程细节吧. 1.遍历数组 f ...
- 我看TDD测试驱动开发
今天在实验室给大家介绍了一下TDD和Docker,大家对TDD都比较感兴趣,包括老板,也问了一些问题. 还是从头来说TDD吧,TDD作为敏捷开发领域的领头军,充满魅力,同时也充满争议.一切从三大军规说 ...
- 【分享】史上最全的Python电子书教程资源下载
网上搜集的,点击即可下载,希望提供给有需要的人^_^ O'Reilly.Python.And.XML.pdf 2.02 MB OReilly - Programming Python 2nd. ...
- Objective-c 总结(一):OC类的设计
(一)学习目标: 1.面向对象基本概念: OOP的主要思想是把构成问题的各个事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述一个事物在整个解决问题步骤中的行为. 2.熟悉OC类的定 ...
- WebApi HttpMsgHanler的执行顺序
原来忘记在哪个大牛的博客上看到的,说添加顺序与执行顺序是相反的,事实在下边:直接上代码: //STEP10,不论如何先记录下来请求信息 if (msgHandlerSettings.LoggingHa ...
- [google面试CTCI] 1-4.判断两个字符串是否由相同字符组成
[字符串与数组] Q:Write a method to decide if two strings are anagrams or not 题目:写一个算法来判断两个字符串是否为换位字符串.(换位字 ...