《Hive权威指南》第四章:数据定义


Hive和MySQL最接近但是两者也存在显著性差异。Hive不支持行级插入操作、更新操作和删除操作。Hive也不支持事务。Hive增加了Hadoop背景下,可以提供高性能的扩展,以及个性化扩展,甚至还增加了一些外部程序。

1.Hive中的数据库

Hive中的数据库概率本质上仅仅是表的一个目录或者命名空间。通常我们使用数据库来将生产表组织成逻辑组。

如果用户没有显示指定数据库,那么将会使用默认的数据库default。

hive> CREATE DATABASE financials;

如果 financials存在就会抛出错误信息,一般我们使用如下语句:

hive> CREATE DATABASE IF NOT EXISTS financials;

在所有数据库相关的命令中,都可以使用SCHEMA这个关键字来替代关键字TABLE

Hive会为每个数据库创建一个目录。数据库中的表将会以这个数据库目录的子目录形式存储。有一个例外就是default数据库中的表,因为这个数据库本身没有自己的目录。

数据库所在的目录位于属性hive.metastore.warehouse.dir所指定的顶层目录之后。假设用户使用的是这个配置型默认的配置,也就是*/user/hive/warehouse*,那么当我们创建一个数据库financials时,Hive将会对应地创建一个目录 /user/hive/warehouse/financials.db

数据库文件目录以 .db结尾

用户可以通过如下命令来修改这个默认的位置:

hive> CREATE DATABASE financials
	> LOCATIOH '/my/preferred/directory';

用户也可以为这个数据库增加一个描述信息,这样通过DESCRIBE DATABASE \<database> 命令就可以查看到改信息。

hive> CREATE DATABASE financials
	> COMMENT 'Holds all financial tables';

hive> DESCRIBE DATABASE financials;
financials Holds all financial tabels
	hdfs://master-server/user/hive/warehouse/financials.db

DESCRIEB DATABASE 可以查看到数据库所在的文件目录位置路径

这个例子中URI的格式是hdfs。如果安装的是MapR,那么这里应该是maprfs。对于亚马逊弹性MapReduce(EMR)集群,这里应该是hdfs,但是用户可以设置hive.metastore.warehouse.dir为亚马逊S3特定的格式(例如,属性值设置为s3n://bucketname…)。用户可以使用s3作为模式,但是如果使用新版s3n会更好。

在hive中使用describe可以查看数据库的详细信息,但是并没有一个命令可以让用户查看当前所在的是哪个数据库!幸运的是,在Hive中可以使重复使用USE…命令,因为Hive中并没有嵌套数据库的概念。在Hive v0.8.0+版本之后可以通过设置以下属性来显示当前所在的数据库:

hive> set hive.cli.print.current.db=true;

最后用户可以删除数据库:

hive> DROP DATABASE IF EXISTS financials;

IF EXISTS 可以省略,加上这句可以防止执行删除语句时,由于目标数据库不存在而抛出警告

默认情况下,Hive是不允许用户删除一个包含有表的数据库的。用户要么先删除数据库中的表,然后在再删除数据库;要么在删除命令的最后加上关键字CASCADE,这样可以使Hive自行先删除数据库中的表:

hive> DROP DATABASE IF EXISTS financials CASCADE;

如果使用RESTRICT这个关键字而不是CASCADE这个关键字的话,那么就和默认情况一样。

总之,如果要删除数据库,那么必须先删除改数据库中的所有表。

2.修改数据库

用户可以使用ALTER DATABASE命令为某个数据库的DBPROPERTIES设置键-值对属性值,来描述这个数据库的属性信息。数据库的其他元数据信息都是不可更改的,包括数据库名和数据库所在的目录位置:

hive> ALTER DATABASE financials SET DBPROPERTIES('edited-by'='Joe Dba');

没有办法可以删除或者“重置”数据库属性

3.创建表

CREATE TABLE语句遵从SQL语法惯例,但是Hive的这个语句中具有显著的功能扩展,使其可以具有更广泛的灵活性。例如:可以定义表的数据文件存储位置、使用什么样的存储格式等。

用户可以在创建表示的时候指定数据库名,如果用户增加可以可选项IF NOT EXITS,那么若表已经存在了,Hive就会忽略掉后面的执行语句,而不会有任何提示。在创建表的脚本中,这么写是非常有用的。

注意:如果用户使用了IF NOT EXISTS,而且这个已经存在的表和CREATE TABLE语句后指定的模式是不同的。Hive会忽略掉这个差异。所以要建一个模式不同的表的时候,需要先删除之前的那张表。

用户可以为每一个字段添加一个注释。和数据库一样,用户也可以为这个表本身添加一个注释,还可以自定义一个或多个表属性。

Hive会自动增加两个表属性:一个是last_modified_by,其保存着最后修改这个表的用户的用户名;另一个是last_modified_time,其保存这个最后一次修改的新纪元时间秒。

Hive v0.10.0版本中增加了 SHOW TBLPROPERTIES table_name命令,用于列举出某个表的TBLPROPERTIES属性信息。

如果用户不想使用默认的表路径,那么最好是使用外部表

用户还可以拷贝一张已存在的表的表模式(而无需拷贝数据):

CREATE TABLE IF NOT EXISTS mydb.employees2
LIKE mydb.employees;

如果你要查看一个数据库中的表可以使用:

hive> SHOW TABLES IN mydb;
employees
table1
table2

如果表太多可以使用正则表达式来过滤出所需要的表明。

hive> SHOW  TABLES 'empl.*';
employees

Hive并非支持所有正则表达式功能。

IN database_name 语句和对表明使用正则表达式两个功能尚不支持同时使用

使用DESCRIBE EXTENDED mydb.employees 命令来查看这个表的详细表结构信息。

hive> DESCRIBE EXTENDED mydb.employees;

使用FORMATTED关键字代替EXTENDED关键字的话,可以提供更加可读的和冗长的输出信息。

一般情况我们使用FORMATTED会多一些,因为输出内容详细而且可读性强

如果想查看某一列的信息,那么只要在表名后增加这个字段的名称即可。这个时候使用EXTENDED关键字也不会增加更多的输出信息:

hive> DESCRIBE mydb.employees.salary;
salary float Employee salary

注意:描述中location:开头的那行描述信息记录了Hive在HDFS中的存储表中数据的完整URL目录路径

warning:
last_modified_by和last_modified_time两个表属性是会自动创建的。如果没有定义任何的用户自定义表属性的话,那么它们也不会显示在表的详细信息中!

3.1管理表

Hive默认情况下会将数据存到hive.metastore.warehouse.dir(例如,/user/hive/warehouse)所定义的目录的子目录下。

当我们删除一个管理表时,Hive也会删除这个表中的数据。

3.2外部表

建表时,通过关键字EXTERNAL告诉Hive这个表是外部的,LOCATION…子句则用于告诉Hive数据位于那个路径。

因为是外部表,所以Hive并非认为其完全拥有这份数据。因此,删除该表并不会删除掉这份数据,不过描述表的元数据信息会被删除掉。

CREATE EXTERNAL TABLE IF NOT EXISTS stocks(
    exchange    STRING,
    symbol      STRING,
    ymd         STRING,
    price_open  STRING,
    price_high  STRING,
    price_low   STRING,
    price_close STRING,
    volume      INT,
    price_adj_close FLOAT)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LOCATION '/data/stocks';

管理表与外部表有一些小小的区别,有些HiveQL语法结构并不适用于外部表。

严格来说Hive管理这些目录和文件,但是其并非对他们有完全控制权。

用户可以使用DESCRIBE EXTENDED tablename语句输出中查看表的类型是管理表还是外部表:

… tableType:MANAGED_TABLE)
… tableType:EXTERNAL_TABLE)

对于管理表,用户可以对一张存在的表进行表结构复制(而不会复制数据):

CREATE EXTERNAL TABLE IF NOT EXISTS mydb.employees3
LIKE mydb.employees
LOCATION '/path/to/data';

提示:

复制的目标表属性复制语句是否带EXTERNAL关键字复制后表属性
外部表外部表
外部表不带外部表
内部表外部表
内部表不带内部表

这个场景下LOCATION子句同样是可选的

4.分区表和管理表

一般咱们使用分区来水平分散压力,将数据从物理上转移到和使用最频繁的用户更近的地方,以及实现其他目的。Hive中有分区表的概念。分区表有重要的性能优势,分区表还可以将数据以一种符合逻辑的方式进行组织,比如分层存储。

分区管理表

假设有个非常的跨国公司, 当HR通过WHERE语句来查询对一些字段进行筛选的时候,使用分区字段会极大提升查询效率。例如HR经常使用country(国家)和state(州)进行过滤查询,那我们可以将两个字段做成分区字段:

CREATE TABLE employees(
    name            STRING,
    salary          FLOAT,
    subordinates    ARRAY<STRING>,
    deductions      MAP<STRING,FLOAT>,
    address         STRUCT<street:STRING,city:STRING,state:STRING,zip:INT>
)
PARTITIONED BY (country STRING, state STRING);

分区改变了Hive对数据的组织方式。如果在mydb数据库中创建的这个表,那么对于这个表只会有一个employees目录与之对应:

hdfs://master_server/user/hive/warehouse/mydb.db/employees

但是,Hive现在将会创建好可以反映分区结构的子目录。例如:

...
.../employees/country=CA/state=AB
.../employees/country=CA/state=BC
...
.../employees/country=US/state=AL
.../employees/country=US/state=AK
...

分区字段变成了实际的目录名称。州目录下将会包含有零个或多个文件,这些文件中存放着那些州的雇员信息。

分区字段(例子中为country和state)一旦创建好,表现得就和普通的字段一样。事实上,除非需要优化查询性能,否则使用这些表的用户不需要关心这些“字段”是否市分区字段。

对数据进行分区最重要的原因是为了更快的查询,当我们使用WHERE子句中增加谓词来按照分区进行过滤时,这些谓词被称为分区过滤器。

即使做一个跨越整个美国的查询,Hive也只会读取65个文件目录,其中包含有50个州,9个地区,以及哥伦比亚特区和6个军事属地。

如果表中的数据以及分区个数读非常大的话,执行这样一个包含有所有分区的查询可能会触发一个巨大的MapReduce任务。如果将Hive设置为“strict(严格)”模式,对分区表进行查询而WHERE子句中没有加分区过滤的话,将会禁止提交任务。用户可以使用下面语句来设置为“nostrict(非严格)”模式:

hive> set hive.mapred.mode=strict;
hive> set hive.mapred.mode=nonstrict;

可以通过SHOW PARTITIONS命令查看表中存在的所有分区:

hive> SHOW PARTITIONS employees;
...
country=CA/state=AB
country=CA/state=BC
...

用户还可以在命令上增加一个指定了一个或多个特定分区字段的PARTITION子句,进行过滤查询:

hive> SHOW PARTITIONS employees PARTITION(country='US')
country=US/state=AL
country=US/state=AK
...

hive> SHOW PARTITIONS employees PARTITION(country='US',state='AK')
country=US/state=AK

DESCRIBE EXTENDED employees命令也会显示分区键

在管理表中用户可以通过载入数据的方式创建分区。如下:

LOAD DATA LOCAL INPATH '${env:HOME/california-employees}'
INTO TABLE employees
PARTITION(country='US',state='CA');

注意在HiveQL中如何引用HOME环境变量

Hive将会创建这个分区对应的目录*…/employees/country=US/state=CA*,而且*$HOME/california-employees*这个目录下的文件将会拷贝到上述分区目录下。

4.1外部分区表

此方式是在管理大型生产数据集最常见,这种结合给用户提供了一个可以和其他工具共享数据的方式,同时也可以优化查询性能。

用户可以自己定义目录结构,因此用户对于目录机构的使用具有更多的灵活性。

例如一个日志表可以使用年月日是三个字段进行分区,然后hms(时分秒)单独作为一个字段,如下:

CREATE EXTERNAL TABLE IF NOT EXISTS log_messages(
    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';

我们现在假设将日志数据按照天进行划分,划分数据尺寸合适,而且按天这个粒度进行查询速度也足够快。

之前非分区外部表只要求使用一个LOCATION子句,对于外部分区表则没有这样的要求 。我们可以通过ALTER TABLE语句单独进行增加分区,这个语句需要为每一个分区键指定一个值,本例中,就是需要为year、month和day这3个分区键都指定值。如下:

ALTER TABLE log_messages ADD PARTITION(year=2012, month=1, day=2)
LOCATION 'hdfs://master_server/data/log_messages/2012/01/02';

我们使用目录组织习惯完全由我们自己定义。这里,我们按照分层目录结构组织,因为这是一个合乎逻辑的数据组织方式,但是并非要求一定如此。

这种灵活的优点是可以使用像Amazon S3这样廉价的存储设备存储旧数据,同时保存较新的更加“有趣的”数据到HDFS中。例如,每天我们可以使用如下过程将一个月前的旧数据转移到S3中 :

  1. 将分区下的数据拷贝到S3中。例如用户使用hadoop distcp命令:

    hadoop distcp /data/log_message/2011/12/02 s3n://ourbucket/logs/2011/12/02
    
  2. 修改表,将分区路径指向S3路径

    ALTER TABLE log_message PARTITION(year=2011, month=12, day=2)
    SET LOCATION 's3n://ourbucket/logs/2011/01/02';
    
  3. 使用hadoop fs -rmr 命令删除掉HDFS中的这个分区数据:

    hadoop fs -rmr /data/log_messages/2011/01/02
    

    同样的分区外部表也和非分去外部表一样,Hive不控制这些数据。即使表被删除,数据也不会被删除。和分区管理表一样,通过SHOW PARTITIONS命令可以查看一个外部表的分区,通过DESCRIBE EXTENDED log_message语句会将分区键作为表的模式的一部分,和partitionKeys列表的内容同时进行显示。

    不过上述方式不可以查看到分区数据实际存在的路径

    可以通过如下方式来查看分区数据实际存在的路径:

    hive> DESCRIBE EXTENDED log_message PARTITION(year=2012, month=1, day=2);
    ...
    location:s3n://ourbucket/logs/2011/01/02,
    ...
    

    我们通常会使用分区外部表,因为它具有非常多的优点,例如逻辑数据管理、高性能的查询等。

4.2自定义表的存储格式

Hive默认是TEXTFILE格式,用户也可以将它替换成其他的Hive所支持的内置文件格式,包括SEQUENCEFILE和RCFILE,这两种文件格式都是使用二进制编码和压缩(可选)来优化磁盘空间使用以及I/O带宽性能的。

Hive使用一个inputformat对象将输入六分割成记录,然后使用一个outputformat对象来将记录格式化为输出流(例如查询的输出结构),再使用一个SerDe在读数据时将记录解析成列,在写数据时将列编码成记录。

用户还可以指定第三方的输入和输出格式以及SerDe,这个功能允许用户自定义Hive本身不支持的其他广泛的文件格式。

5.删除表

Hive支持和SQL中DROP TABLE命令类似的操作:

DROP TABLE IF EXISTS employees;

对于管理表,表的元数据信息和表内的数据都会被删除。

如果用户开启了Hadoop回收站功能(默认是关闭的),那么数据将会转移到用户在分布式文件系统中的用户根目录下的.Trash目录下,也就是HDFS中的*/user/$USER/.Trash*目录。如果想开启这个功能,只需要将配置属性fs.trash.interval的值设置为一个合理的正整数即可。如果误删一张管理表可以重新建表,然后重建分区,在恢复数据(在设置的时间间隔内,数据会保存在回收站)

对于外部表,表的元数据信息会被删除,但是表中的数据不会被删除。

6.修改表

大多数的表属性可以通过ALTER TABLE语句来进行修改。这种操作会修改元数据,但不会修改数据本身。这些语句可用于修改表模式中出现的错误、改变分区路径,以及一些其他操作。

ALTER TABLE仅仅会修改表元数据,表数据本身不会有任何修改。

6.1.表重命名

ALTER TABLE log_messages RENAME TO logmsgs;

6.2.增加、修改和删除表分区

ALTER TABLE table_name ADD PARTITION… 语句用于为表(通常是外部表)增加一个新的分区。这里我们增加可提供的可选项,然后多次重复前面的分区路径语句:

ALTER TABLE log_messages ADD IF NOT EXISTS
PARTITION (year=2011, month=1, day=1) LOCATION '/logs/2011/01/01'
PARTITION (year=2011, month=1, day=2) LOCATION '/logs/2011/01/02'
PARTITION (year=2011, month=1, day=3) LOCATION '/logs/2011/01/03'
...;

当使用Hive v0.8.0或其后的版本时,在同一个查询中可以同时增加多个分区。

警告:Hive v0.7*版本允许用户指定多个分区,但实际上只会使用第一个指定的分区,而将其他的分区默认省略掉了!其代替方案是,对每一个分区都是用***ALTER STATEMENT***语句。

同时,用户还可以通过高效地移动位置来修改某个分区的路径:

ALTER TABLE log_message PARTITION(year=2011, month=12, day=2)
SET LOCATION 's3n://ourbucket/logs/2011/01/02';

这个命令不会将数据从旧的路径转移走,也不会删除旧的数据。

最后,用户可以通过如下语句删除某个分区:

ALTER TABLE log_messages DROP IF EXISTS PARTITION(year=2011, month=12, day=2);

6.3.修改列信息

用户可以对某个字段进行重命名,并修改其位置、类型或注释:

ALTER TABLE log_messages
CHANGE COLUMN hms hours_minutes_seconds INT
COMMENT 'The hours, minutes, and seconds part of the timestamp'
AFTER serverity;

上述例子将字段转移到serverity字段后面,如果想将这个字段移到第一个位置,可以将AFTER关键字换成**FIRST**。

6.4.增加列

用户可以在分区字段之前增加新的字段到已有的字段之后

ALTER TABLE log_message ADD COLUMNS(
	app_name STRING COMMENT 'Application name',
	session_id LONG COMMENT 'The current session id');

如果新增的字段的位置是错误的,需要使用***ALTER COLUMN table_name CHANGE COLUMN*** 语句逐一将字段调整到正确的位置

6.5.删除或者替换列

下面这个例子移除了之前所有的字段并重新指定了新的字段:

ALTER TABLE log_message REPLACE COLUMNS(
    hour_mins_secs  INT COMMENT 'hour, minute, seconds from timestamp',
    severity        STRING  COMMENT 'The message severity',
    message         STRING  COMMENT 'The rest of the message');

REPLACE语句只能用于使用了如下2种内置SerDe模块的表:DynamicSerDe或者MetadataTypedColumnsetSerDe。

6.6.修改表属性

用户可以增加附加的表属性或者修改已经存在的属性,但是无法删除属性:

ALTER TABLE log_message SET TBLPROPERTIES(
	'notes'='The process id is not longer captured; this column is always NULL');

6.7.修改存储属性

有几个ALTER TABLE 语句用于修改存储格式和SerDe属性。

ALTER TABLE log_messages
PARTITION(year=2012, month=1, day=1)
SET FILEFORMAT SEQUENCEFILE;

如果表示分区表,那么需要使用PARTITION子句。

用户可以指定一个新的SerDe,并为其指定SerDe属性,或者修改已存在的SerDe的属性。下面这个例子演示的表使用了一个名为com.example.JSONSerDe的Java类来处理记录使用JSON编码的文件:

ALTER TABLE table_using_JSON_storage
SET SERDE 'com.example.JSONSerDe'
WITH SERDEPROPERTIES(
'prop1'='value1',
'prop2'='value2');

SERDEPROPERTIES中的属性会被传递给SerDe模块(本例中,也就是com.example.JSONSerDe这个Java类)。需要注意的是,属性名(例如prop1)和属性值(例如value1)都应当是带引号的字符串。

SERDEPROPERTIES这个功能是一种方便的机制,它是的SerDe的各个实现都允许用户进行自定义。

6.8.众多的修改表语句

我们讨论一种为各种操作增加执行“钩子(hook)”的技巧。

**ALTER TABLE ... TOUCH**语句用于触发这些hook:

ALTER TABLE log_messages TOUCH
PARTITION(year=2012, month=1, day=1);

PARTITION子句用于分区表。这种语句的一个典型的应用场景是,当表中存储的文件在Hive之外被修改了,就会触发钩子的执行。例如,某个脚本往分区2012/01/01中写入了新的日志信息文件,可以在Hive CLI中进行下面的调用:

hive -e 'ALTER TABLE log_messages TOUCH PARTITION(year=2012, month=1, day=1)'

如果表或者分区并不存在,那么这个语句也不会创建表或者分区。在这种情况下要使用合适的创建策略。

ALTER TABLE… ARCHIVE PARTITION语句会将这个分区内的文件打成一个Hadoop压缩包(HAR)文件。但是这样仅仅可以降低文件系统中的文件数以及减轻NameNode压力,而不会减少任何的存储空间(例如,通过压缩):

ALTER TABLE log_messages ARCHIVE
PARTITION(year=2012, month=1, day=1);

使用UNARCHIVE替换ARCHIVE就可以反向操作。这个功能只能用于分区表中独立的分区。

最后,Hive提供了各种保护。下面的语句可以分别防止分区被删除和被查询:

ALTER TABLE log_messages
PARTITION(year=2012, month=1, day=1) ENABLE NO_DROP;
ALTER TABLE log_messages
PARTITION(year=2012, month=1, day=1) ENABLE OFFLINE;

使用ENABLE替换DISABLE可以到达反向操作的目的。这些操作也都不可用于非分区表。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值