HIVE的CTAS用法探究

文章转载自:量子恒道官方博客

HIVE的CTAS用法探究

最近在使用ADM系统的时候遇到一个问题,ADM在自动将HIVE QL包装成CTAS之后,由于HIVE内部缺省使用’N’来存储NULL,这样就会产生一个问题,因为我们处理的很多结果数据是需要导出附件来给下游客户使用的,而导出数据时很少会使用这样一个特殊的字符串来代表NULL值。

这种情况下,HIVE为我们提供了重新定义NULL值存储格式的方法,使用serialization.null.format参数。

一、CTAS功能探究

对于已经创建成功的hive表,如果希望修改NULL值的存储格式,可以使用以下语句修改空字串定义:

alter table table_name set serdeproperties(‘serialization.null.format’ = ”);

目前,HIVE新版本(0.6.0)已经开始支持CTAS功能,我们希望能够在CTAS动态建表的同时完成缺省NULL串的转化。

首先,来看一下CTAS的语法规则:

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name

[(col_name data_type [COMMENT col_comment], …)]

[COMMENT table_comment]

[PARTITIONED BY (col_name data_type [COMMENT col_comment], …)]

[CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name [ASC|DESC], …)] INTO num_buckets BUCKETS]

[

[ROW FORMAT row_format] [STORED AS file_format]

| STORED BY ‘storage.handler.class.name’ [ WITH SERDEPROPERTIES (...) ]  (Note:  only available starting with 0.6.0)

]

[LOCATION hdfs_path]

[TBLPROPERTIES (property_name=property_value, ...)]  (Note:  only available starting with 0.6.0)

[AS select_statement]  (Note: this feature is only available starting with 0.5.0.)

row_format

: DELIMITED [FIELDS TERMINATED BY char] [COLLECTION ITEMS TERMINATED BY char]

[MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]

SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value, property_name=property_value, ...)]

上面标红部分就是我们所需要用到的特性,简单解释一下SerDe,SerDe是Serialize/Deserilize的简称,目的是用于序列化和反序列化。用户在建表时可以用自定义的SerDe或使用Hive自带的SerDe,SerDe能为表指定列,且对列指定相应的数据。在脚本中为SerDe设置相应的键值对就可以达到目的,以下两个SerDe是比较常用的:

field.delim是分隔符参数

serialization.null.format 用于null值的存储格式设置

注意:上面两个是表的全局参数,这意味着一旦对单个表指定了这一参数,它将对表的所有分区有效。其中属性名和属性值都必须用单引号括起来。

接下来我们测试一下这个新功能:

1、CATS并设置null的存储格式为空

create table gv_test_tmp

ROW FORMAT SERDE ‘org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe’

WITH SERDEPROPERTIES(‘serialization.null.format’=”)

stored as textfile

as

select col1,col2 from fact_tmp_d where dt=’20110427′ limit 5;

2、查看表gv_test_tmp对应的hadoop文件内容,如下:

1^A/N

2^A/N

3^A3

4^A4

5^A5

可以看出,NULL的存储格式并没有变成我们预想的’’,还是缺省的’N’。难道我们设置的SerDe参数没有起作用?

二、追根溯源

1、  Desc来描述表的属性

hive> desc extended gv_test_tmp ;

OK

col1  bigint

col2  bigint

Detailed Table Information      Table(tableName:gv_test_tmp, dbName:default, owner:gvora, createTime:1303893563, lastAccessTime:0, retention:0, sd:StorageDescriptor(cols:[FieldSchema(name:col1, type:bigint, comment:null), FieldSchema(name:col2, type:bigint, comment:null)], location:hdfs://hdpnn:****/gv_test_tmp, inputFormat:org.apache.hadoop.mapred.TextInputFormat, outputFormat:org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat, compressed:false, numBuckets:-1, serdeInfo:SerDeInfo(name:null, serializationLib:org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe, parameters:{serialization.null.format=, serialization.format=1}), bucketCols:[], sortCols:[], parameters:{}), partitionKeys:[], parameters:{transient_lastDdlTime=1303893563}, viewOriginalText:null, viewExpandedText:null, tableType:MANAGED_TABLE)

Time taken: 4.505 seconds

可以看出“serialization.null.format=”已经改成’’,不是缺省的’N’了,这说明选项设置起到了作用,实际的数据存储却没有变。

2、接下来查看该CTAS语句的执行计划:

hive> explain create table gv_test_tmp

> ROW FORMAT SERDE ‘org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe’

> WITH SERDEPROPERTIES(‘serialization.null.format’=”)

> stored as textfile

> as

> select col1,col2 from fact_tmp_d where dt=‘20110427’ limit 10;

OK

……

STAGE DEPENDENCIES:

Stage-1 is a root stage

Stage-0 depends on stages: Stage-1

Stage-2 depends on stages: Stage-0

STAGE PLANS:

Stage: Stage-1

Map Reduce

Alias -> Map Operator Tree:

…… (此处省略500字)

Reduce Operator Tree:

Extract

Limit

File Output Operator

compressed: true

GlobalTableId: 0

table:

input format: org.apache.hadoop.mapred.TextInputFormat

output format: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat

Stage: Stage-0

Move Operator

files:

hdfs directory: true

destination: /group/tbdev/gvora/hive/gv_test_tmp

Stage: Stage-2

Create Table Operator:

Create Table

columns: col1 bigint, col2 bigint

if not exists: false

input format: org.apache.hadoop.mapred.TextInputFormat

# buckets: -1

output format: org.apache.hadoop.hive.ql.io.IgnoreKeyTextOutputFormat

serde name: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe

serde properties:

serialization.null.format

name: gv_test_tmp

isExternal: false

Time taken: 0.683 seconds

从执行计划不难看出,整个CTAS脚本的执行过程主要分为三个阶段:

Stage-1:执行select语句

Stage-0:move查询结果至缺省hadoop目录

Stage-2:创建表指向对应的查询结果目录

很明显,创建表对象的过程被放到了select语句完成之后,这就不难推出为啥表定义中显示的存储格式改变了,而实际的hadoop文件结果却没变的原因。

三、可能的替代方案

针对这个问题,为了能够实现ADM系统对于select语句的动态包装,并应用新的null存储格式设定,可以采用如下的替代方案来打破CTAS默认的执行步骤:

1、实现基于动态查询SQL的表结构及待修正的NULL存储格式

hive> create table gv_test_tmp

> ROW FORMAT SERDE ‘org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe’

> WITH SERDEPROPERTIES (

> ‘serialization.null.format’=”

> )

> as

> select col1,col2 from fact_tmp_d where dt=‘20110427’ limit 5;

2、新建一张表gv_test_tmp2,表结构及列定义等copy 表gv_test_tmp。

hive> create table gv_test_tmp2 like gv_test_tmp;

3、接下来实现表数据的insert

hive> insert overwrite table gv_test_tmp2 select * from gv_test_tmp;

通过查看生成的hadoop结果文件,NULL的存储格式已改变:

1^A

2^A

3^A3

4^A4

5^A5

总结,本文主要介绍了HIVE的CTAS功能,通过测试发现问题,最终采用一种折中的方式解决问题。文中的方案多了一次重新insert结果数据至新表的过程,性能上会有折扣,有待HIVE继续完善CTAS功能。

你可能感兴趣的:(hive)