Hive编程指南学习笔记(2),hive编程指南


我们可以使用describe extended financial.employee命令来查看这个表的详细表结构信息(如果当前所处的工作数据库就是financial,那可以不佳finanacial)。
如果使用formatted替代关键字extended的话,那可以得到更多的输出信息。
如果用户只想查看某一列的信息,那么只要在表名后增加这个字段的名称即可。这种情况下,使用extended关键字也不会增加更多的输出信息:
hive> describe financial.employee.salary
salary float employee salary

外部表
下面的语句将创建一个外部表,其可以读取所有位于/data/stocks目录下的以逗号分隔的数据:
create external table if not exists stocks (
exchange  string,
symbol string,
ymd    string,
price_open     float,
price_high     float,
price_low      float,
price_close    float,
volume    int,
price_adj_close     float
)
row format delimited fields terminated by ','
location '/data/stocks';
关键字external告诉hive这个表是外部的,而后面的location子句则用于告诉hive数据位于哪个路径下。
因为表是外部的,所以hive并非认为其完全拥有这份数据。因此,删除该表并不会删除掉这份素和据,不过描述表的元数据信息会被删除掉。
管理表和外部表有一些小小的区别,那就是,有些HiveQL语法结构并不适用于外部表。

用户可以在describe extended tablename语句中的输出中查看到表是否是管理表或外部表。在末尾的详细表信息输出中,对于管理表,用户可以看到如下信息:
... tableType:MANAGED_TABLE)
对于外部表,用户可以查看到如下信息:
... tableType:EXTERNAL_TABLE)

对于管理表,用户还可以对一张存在的表进行表结构复制(而不会复制数据):
create external table if not exists financial.employee1
like financial.employee
location '/path/data'

如果上面的语句省略掉external关键字而且源表是外部表,那么生成的新表也是外部表。如果语句中省略掉external关键字而且源表是管理表,那么新表也是管理表。但是,如果语句中包含有external关键字而且源表是管理表,那么生成的新表将是外部表。即使在这种场景下,location子句同样是可选的。

分区表、管理表
hive中有分区表的概念,我们可以看到分区表有重要的性能优势,而且分区表还可以将数据以一种符合逻辑的方式进行组织。比如分层存储。

我们重新看一下之前那张employee表并假设我们在一个很大的跨国公司工作。HR会经常执行一些带where语句的查询。这样可以将结果限定在某个特定的国家或某个特定的第一级细分(比如中国的省)。为了简单,我们只用到了province(省)。在address字段我们已经重复包含了省信息。这和province分区是不同的。我们可以在字段address中删除province元素。我们先按照country(国家)再按照province(省)来对数据进行分区。
create table if not exists employee (
     name    string,
     age     tinyint,
     salary    float,
     subordinates   array<string>,
     address   struct<city:string,street:string>
)
partitioned by (country string, province string);
分区改变了hive对数据存储的组织方式。如果我们是在financial数据库中创建的这个表,那么对于这个表只会有一个employee目录与之对应:
hdfs://master-server/user/hive/warehouse/financial.db/employee
但是,hive现在将会创建好反映分区结构的子目录。例如:
.../employee/country=CN/provice=SHANNXI
.../employee/country=CN/provice=HEBEI
...
这些是实际的目录名称,省目录下将会包含0个或多个文件。这些文件中存放着那些省份的雇员信息。

分区字段(该例中是country和province)一旦创建好,就表现的和普通字段一样。事实上,除非需要优化查询性能,否则使用这些表的用户不需要关心这些“字段”是否是分区字段。
下面这个查询语句将会查找出在中国河北省的所有雇员:
select * from employee where country = 'CN' and province = 'HEBEI';
需要注意的是,因为country和province的值已经包含在文件目录名称中了,所以也就没必要将这些值存放到它们目录下的文件中了。
对数据进行分区,最重要的原因就是为了更快的查询。在上面那个将结果范围限制在中国河北省的例子中,就进需要扫描一个目录下的内容。如果我们有很多个国家和省份目录,就不用再扫描其他目录下的文件了。
当我们在where子句中增加谓词来按照分区值进行过滤时,这些谓词被称为分区过滤器。

如果表中的数据以及分区个数都非常大,执行包含所有分区的查询会触发一个巨大的mapreduce任务,一个高度建议的安全措施是将hive设置为“strict(严格)”模式。这样如果对分区表进行查询而where子句没有加分区过滤的话,会禁止提交这个任务。用户也可以按照下面的方式将属性设置为"nostrict(非严格)":
hive> set hive.mapred.mode=strict;
...
hive> set hive.mapred.mode=nostrict;

可以通过show partitions命令查看表中存在的所有分区:
hive> show partitions employee;
...
country=CN/provice=SHANNXI
country=CN/provice=HEBEI
...

还可以指定过滤条件:
hive> show partitions employee partition(country='CN',province='HEBEI');
country=CN/provice=HEBEI

使用describe extended employee命令也会显示出分区键:
hive> describe extended employee;
...
partitionKeys:[FieldSchema(name:country, type:string,comment:null),FieldSchema(name:province, type:string,comment:null)],
...

在管理表中用户可以通过载入数据的方式创建分区。如下面的例子中可以从一个本地目录($HOME/hebei-employee)载入数据到表中的时候,将会创建一个CN和HEBEI分区。用户需要为每个分区字段指定一个值:
load data local inpath '$(env:HOME)/hebei-employee' into table employee partition (country = 'CN', province = 'HEBEI');

hive将会创建这个分区对应的目录.../employee/country=CN/provice=HEBEI,而且$HOME/hebei-employee目录下的数据会被拷贝到上述分区目录下。

外部分区表
外部表同样可以使用分区。这种结合给用户提供了一个可以和其他工具共享数据的方式,同时也可以优化查询性能。
因为用户可以自己定义目录结构,因此用户对于目录结构的使用具有了更多的灵活性。我们以日志文件分析为例。日志信息的记录有时间戳、日志级别(ERROR、WARNING等),甚至还有服务器名称和进程ID,然后跟着一个文本信息。
我们可以按照如下方式来定义对应的hive表:
create external table if not exists log_message(
hms int,
serverity string,
server string,
process_id int,
message string
) partitioned by (year int, month int, day int)
row format delimited fields terminated by '\t';

我们将日志数据按照天进行划分,划分数据的尺寸合适,而且按天这个粒度进行查询,速度也够快。之前创建的非分区外部表(stocks)要求使用location子句。对于外部分区表则没有这样的要求。有一个alter table语句可以单独进行增加分区。这个语句需要为每一个分区键指定一个值。本例中,需要为year、month和day这3个分区都指定值。下面的例子演示如何增加一个2012年1月2日的分区:
alter table log_message add partition(year = 2014, month = 11, day = 17)location 'hdfs://master_server/data/log_message/2014/11/07';

hive不关心一个分区对应的分区目录是否存在或者分区目录下是否有文件。如果分区目录不存在或者分区目录下没有文件,则对于这个过滤分区的查询将没有返回结果。
和非分区外部表一样,hive并不控制这些数据。即使表被删除,数据也不会被删除。
可以使用show partitions命令来查看一个外部表的分区:
hive> show partitions log_message;
...
year=2014/month=11/day=16
...

这个输出没有分区数据实际存在的路径。这里有一个路径字段,但它仅仅表示如果表是管理表,它会使用到的hive默认路径。我们可以通过如下方式查看分区数据所在的路径:
hive> describe extended log_message partition (year=2014, month=11, day=17);
...
location:hdfs://master_server/data/log_message/2014/11/17
...

删除表
hive只是和sql中的drop table命令类似的操作:
drop table if exists employee;

修改表
大多数的表属性可以通过alter table语句来进行修改。这种操作会修改元数据,但不会修改数据本身。
1)表重命名
alter table log_message rename to logmsg

该语句将表log_message重命名为logmsg
2)增加、修改和删除表分区
alter table log_message add if not exists
partition(year = 2014, month = 1, day = 1) location '/logs/2014/01/01'
partition(year = 2014, month = 1, day = 2) location '/logs/2014/01/02'
...;
还可以高效的移动位置来修改某个分区的路径:
alter table log_message partition(year = 2014, month = 1, day = 1) set location 'hdfs://master_server/data/log_message/logs/2014/01/01';
用户还可以删除某个分区:
alter table log_message drop if exists partition(year = 2014, month = 1, day = 1);
3)修改列信息
用户可以对某个字段进行重命名,并修改其位置、类型或注释:
alter table log_message
change column hms hours_munites_seconds int 
comment 'THe hours , minutes, and seconds part of the timestamp'
after serverity;
即使字段名或字段类型没有改变,用户也需要完全指定旧的字段名,并给出新的字段名及新的字段类型。关键字column和comment子句都是可选的。上面的例子将字段转移到了serverity字段之后。如果用户想将这个字段移动到第一个位置,那么只需要使用first关键字替代after other_column子句即可。
4)增加列
用户可以在分区字段之前增加新的字段到已有的字段之后。
alter table log_message add columns (
app_name string comment 'Application name',
session_id long comment 'The current session id'
);
5)删除或替换列
下面这个例子移除了之前所有的字段并重新指定了新的字段:
alter table log_message replace columns (
hours_mins_secs int comment 'hour, minute, seconds from timestamp',
servertity string comment 'The rest of the message'
);
这个语句实际上重命名了之前的hms字段并且从之前的表定义的模式中移除了字段server和process_id。因为是alter语句,所以只有表的元数据信息改变了。
replace语句只能用于使用了如下2中内置SerDe模块的表:DynamicSerDe或者MetadataTypedColumnsetSerDe。SerDe决定了记录是如何分解成字段的(反序列化过程)以及字段是如何写入到存储中的(序列化过程)。
7)修改表属性
用户可以增加附加的表属性或者修改已经存在的属性,但是无法删除属性。
alter table log_message set tblproperties (
'notes' = 'The process id is no longer captured; this column is always NULL'
);
8)修改存储属性
将一个分区的存储格式修改成sequencefile:
alter table log_message partition(year = 2014, month = 1, day = 1)
set fileformat sequencefilel;

如果表是分区表,那么需要使用partition子句。

转载请注明出处:http://blog.csdn.net/iAm333


相关内容