1. 程式人生 > >Hive程式設計(四)【HiveQL:資料定義】

Hive程式設計(四)【HiveQL:資料定義】

HiveQL是Hive查詢語言,和關係型資料庫所使用的SQL方言一樣。但不完全遵守ANSI SQL標準。HiveQL和MySQL最接近。但還是有很大差異。Hive不支援行級別插入、更新和刪除操作。也不支援事務。

4.1 Hive中的資料庫

如果使用者沒有顯式指定資料庫,預設資料庫是default

下面這個例子展示瞭如何建立資料庫

CREATE DATABASE simple;

若資料庫simple已經存在的話,將會報錯誤訊息。可以使用下面的語句避免錯誤資訊

CREATE DATABASE IF NOT EXISTS simple;

使用SHOW DATABASES命令檢視hive中所包含的資料庫

SHOW DATABASES;

如果資料庫比較多,可以使用正則表示式匹配篩選所需要的資料庫名

SHOW DATABASES LIKE 'sim.*';

Hive為每個資料庫建立一個目錄,資料庫中的表將會以這個資料庫目錄的子目錄形式儲存。有一個例外就是default資料庫中的表。因為這個資料庫本身沒有自己的目錄。資料庫所在的目錄位於屬性hive.metastore.warehouse.dir所指定的頂層目錄之後。假若使用者使用的這個配置項的預設配置,也就是/user/hive/warehouse,那麼當我們建立資料庫simple時,Hive將會對應地建立一個目錄為/user/hive/warehouse/simple.db

。這裡請注意,資料庫的檔案目錄名是以.db結尾的。

可以通過如下的命令來修改這個預設的配置

hive > CREATE DATABASE simple LOCATION '/user/myname/directory';

還可以為這個資料庫增加一個描述資訊。這樣通過DESCRIBE DATABASE databasename命令就可以檢視到該資訊.

hive > CREATE DATABASE simple COMMENT 'a simple database';

使用DESCRIBE DATABASE databasename檢視

hive > DESCRIBE DATABASE simple;
simple a simple database
    hdfs://hostname/user/hive/warehouse/simple.db

從上面的例子可以看出DESCRIBE DATABASE不僅會顯示這個資料庫的描述資訊還會顯示這個資料庫所在檔案的目錄位置。若Hadoop是本地模式的話前面的字首為file:///若是分散式模式則字首為hdfs://

此外使用者還可以為資料庫增加一些和其他相關的鍵-值對屬性資訊。可以使用DESCRIBE DATABASE EXTENDED databasename語句顯示這些資訊,如:

hive > CREATE DATABASE simple WITH DBPROERTIES ('creator'='scott','date'='2014-05-05');
hive > DESCRIBE DATABASE simple;
hive > DESCRIBE DATABASE EXTENDED simple;

命令USE用於將某個資料庫設定為當前的工作資料庫。如:

USE simple;

此時可以用SHOW TABLES顯示當前資料庫下所有的表。不幸的是,沒有那個命令讓使用者檢視當前所在的庫。幸運的是在Hive中可以重複使用USE,這是因為在Hive中沒有巢狀資料庫的概念。

hive > set hive.cli.print.current.db=true;
hive (simple) > USE default;
hive (default) > set hive.cli.print.current.db=false;

最後使用者可以刪除資料庫

hive > DROP DATABASE IF EXISTS simple;

IF EXISTS子句是可選的。可以避免因資料庫不存在而丟擲警告資訊。預設情況下Hive是不允許使用者刪除一個包含有表的資料倉庫。要麼使用者先刪除庫中的表,然後再刪資料庫。要麼在刪除命令的最後面加上關鍵字CASCADE,這樣Hive先自行刪除資料庫中的表

hive > DROP DATABASE IF EXISTS simple CASCADE;

若使用的是RESTRICT這個關鍵字,而不是CASCADE這個關鍵字的話,那麼就和預設情況一樣。

如果某個資料庫被刪除了,那麼其對應的目錄也同時會被刪除。

4.2 修改資料庫

使用ALTER DATABASE命令為某個資料庫的DBPROPERTIES設定鍵-值對屬性值,來描述資料庫的屬性資訊。資料庫的其他元資料資訊是不可更改的,包括資料庫名和資料庫所在的目錄位置。

hive > ALTER DATABASE simple SET DBPROPERTIES ('edited-by'='Join');

沒有辦法刪除或者"重置"資料庫屬性。

4.3 建立表

CREATE TABLE IF NOT EXISTS mydb.employees (
name STRING COMMENT 'Employee name',
salary FLOAT COMMENT 'Employee salary',
subordinates ARRAY<STRING> COMMENT 'Names of subordinates',
deductions MAP<STRING, FLOAT>
COMMENT 'Keys are deductions names, values are percentages',
address STRUCT<street:STRING, city:STRING, state:STRING, zip:INT>
COMMENT 'Home address')
COMMENT 'Description of the table'
TBLPROPERTIES ('creator'='me', 'created_at'='2012-01-02 10:00:00')
LOCATION '/user/hive/warehouse/mydb.db/employees';

首先,我們注意到,如果使用者當前所處的資料庫並非是目標資料庫,那麼使用者是可以在表名前增加一個數據庫名來進行指定的,也就是例子中的mydb

如果使用者增加上選項IF NOT EXISTS,那麼若表已經存在了,Hive就會忽略掉後面的執行語句。且不會有任何提示。使用者可以在欄位型別後使用COMMENT為每個欄位增加一個註釋。還可以指定一個或多個表屬性。大多數情況下TBLPROPERTIES的主要作用是按鍵-值對的格式為表增加額外的文件說明。

Hive會自動增加兩個表屬性:一個是last_modified_by,其儲存著最後修改這個表的使用者的使用者名稱;另一個是last_modified_time其儲存著最後一次修改這個表的新紀元時間秒。

使用SHOW TBLPROPERTIES table_name列舉出某個表的TBLPROPERTIES屬性資訊

最後,可以看到我們根據情況為表中的資料指定一個儲存路徑。在這個例子中,我們使用Hive預設的路徑/user/hive/warehouse/mydb.db/employees,其中,/user/hive/warehouse是預設的資料倉庫路徑,mydb.db是資料庫目錄,employees是表目錄。

預設情況下。Hive總是將建立的表的目錄放置在這個表所屬的資料庫目錄之下。不過,default資料庫是個例外,其在/user/hive/warehouse下並沒有對應一個數據庫目錄。因此default資料庫中的表目錄會直接位於/user/hive/warehouse目錄下(使用者明確指定除外).

使用者還可以拷貝一張已經存在的表的模式(無需拷貝資料):

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

該語句可以接受可選的LOCATION子句,但是注意其他的屬性,包括模式都是不可能重新定義的。這些資訊直接從原是表獲得.

SHOW TABLES命令可以列舉出所有的表,如果不增加其他引數,那麼只會顯示當前工作資料庫下的表。假設不在那麼資料庫下,還是可以列出指定資料庫下的表使用SHOW TABLES IN dbname

hive > USE default;
hive > SHOW TABLES IN mydb;
employees
department

如果有很多的表,那麼可以使用正則表示式來過濾出所需要的表名.

hive> USE mydb;
hive> SHOW TABLES 'empl.*';
employees

注意:IN databasename和表名使用正則表示式過濾這個兩個功能尚不支援同時使用.

我們可以使用DESCRIBE EXTENDED mydb.employees命令來檢視這個表的詳細結構資訊(如果當前所處的工作資料庫就是mydb的話,可以不加mydb這個字首).

hive> DESCRIBE EXTENDED mydb.employees;
name string Employee name
salary float Employee salary
subordinates array<string> Names of subordinates
deductions map<string,float> Keys are deductions names, values are percentages
address struct<street:string,city:string,state:string,zip:int> Home address
Detailed Table Information Table(tableName:employees, dbName:mydb, owner:me,
...
location:hdfs://master-server/user/hive/warehouse/mydb.db/employees,
parameters:{creator=me, created_at='2012-01-02 10:00:00',
last_modified_user=me, last_modified_time=1337544510,
comment:Description of the table, ...}, ...)

使用FORMATTED關鍵字替代EXTENDED關鍵字的話,可以提供更加可讀的輸出資訊。在應用中多使用FORMATTED關鍵字

DESCRIBE FORMATTED employees;

如果使用者只想檢視某一個列的資訊,那麼只要在表名後面增加這個欄位的名稱即可.

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

注:last_modified_bylast_modified_time兩個表屬性是自動建立的。如果使用者沒有定義任何的自定義表屬性的話,那麼這兩個表屬性也不會顯示在表的詳細資訊中!

4.3.1 管理表

我們目前所建立的表均屬於管理表,有時也被稱為內部表.因為這種表,Hive會或多或少的控制著資料項的生命週期.如:Hive預設情況下會將這些表的資料儲存在由配置項hive.metastore.warehouse.dir(如/user/hive/warehouse)所定義的目錄的子目錄下.

當我們刪除一個管理表時,Hive也會刪除這個表中的資料.管理表不方便和其他工作共享資料。

4.3.2 外部表

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並非認為其完全擁有這份資料,因此,刪除該表並不會刪除掉這份資料,不過描述表的元資料資訊將會被刪除掉.

使用者可以在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關鍵字,且源表是外部表的話,那麼新生成的表也將是外部表;

若語句中省略掉EXTERNAL關鍵字,且源表是管理表的話,那麼新生成的表也將是管理表;

若語句中含有EXTERNAL關鍵字,且源表是管理表的話,那麼生成的新表將是外部表。即使在這種場景下,LOCATION子句同樣是可選的。

4.4 分割槽表、管理表

Hive中有分割槽表的概念。分割槽表將資料以一種符合邏輯的方式進行組織。比如分層儲存。

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);

如果表中的資料以及分割槽個數非常大的話,執行一個包含所有分割槽的查詢可能會觸發一個巨大的MapReduce任務。建議的安全措施是將Hive設定為“strict”模式,這樣對分割槽表查詢WHERE子句沒有加分割槽過濾的話,將會禁止提交這個任務.可以按照下面的語句將屬性設定為“nonstrict”模式。

hive> set hive.mapred.mode=strict;

hive> SELECT e.name, e.salary FROM employees e LIMIT 100;
FAILED: Error in semantic analysis: No partition predicate found for
Alias "e" Table "employees"

hive> set hive.mapred.mode=nonstrict;

hive> SELECT e.name, e.salary FROM employees e LIMIT 100;

可以通過使用SHOW PARTITIONS命令查看錶中存在的所有分割槽

hive> SHOW PARTITIONS employees;
...
Country=CA/state=AB
country=CA/state=BC
...
country=US/state=AL
country=US/state=AK

如果表中存在很多的分割槽,而只想檢視是否儲存某個特定分割槽鍵的分割槽的話。可以在這個命令上增加一個指定了一個或者多個特定分割槽欄位值的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命令也會顯示出分割槽鍵

hive> DESCRIBE EXTENDED employees;
name string,
salary float,
...
address struct<...>,
country string,
state string
Detailed Table Information...
partitionKeys:[FieldSchema(name:country, type:string, comment:null),
FieldSchema(name:state, type:string, comment:null)],

在管理表中使用者可以通過載入資料的方式建立分割槽。下面的例子將從本地目錄載入資料到表中的時候.將會建立一個US和CA分割槽.使用者需要為每個分割槽欄位指定一個值.注意在HiveQL中是如何引用HOME環境變數的:

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

Hive將會建立這個分割槽對應的目錄/employees/country=US/state=CA$HOME/california-employees目錄下的檔案將會被拷貝到上述分割槽目錄下。

4.4.1 外部分割槽表

CREATE EXTERNAL TABLE IF NOT EXISTS log_messages (
hms INT,
severity 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語句單獨進行增加分割槽.這個語句需要為每一個分割槽鍵指定一個值。如:

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

Hive並不控制這些資料,即使表被刪除,資料也不會被刪除.

和分割槽管理表一樣.通過SHOW PARTITIONS檢視外部表的分割槽。如:

hive> SHOW PARTITIONS log_messages;
...
year=2011/month=12/day=31
year=2012/month=1/day=1
year=2012/month=1/day=2
...

同樣,DESCRIBE EXTENDED log_messages語句會將分割槽鍵作為表的模式一部分和partitionKeys列表的內容同時顯示

hive> DESCRIBE EXTENDED log_messages;
...
message string,
year int,
month int,
day int
Detailed Table Information...
partitionKeys:[FieldSchema(name:year, type:int, comment:null),
FieldSchema(name:month, type:int, comment:null),
FieldSchema(name:day, type:int, comment:null)],
...

這個輸出少了一個非常重要的資訊.那就是分割槽資料實際存在的路徑.

通過以下方式檢視分割槽資料所在路徑

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

通常會使用分割槽外部表.

4.4.2 自定義表的儲存格式

Hive預設的儲存格式是文字檔案格式.可以通過可選的子句STORED AS TEXTFILE顯式指定.同時使用者可以在建立表的時指定各種各樣的分隔符.

CREATE TABLE employees (
name STRING,
salary FLOAT,
subordinates ARRAY<STRING>,
deductions MAP<STRING, FLOAT>,
address STRUCT<street:STRING, city:STRING, state:STRING, zip:INT>
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\001'
COLLECTION ITEMS TERMINATED BY '\002'
MAP KEYS TERMINATED BY '\003'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE;

注:TEXTFILE意味著所有欄位都使用字母、數字、字元編碼,包括那麼國際字符集.Hive預設是使用不可見字元來作為分隔符的。使用TEXTFILE意味著,每一行被認為是一個單獨的記錄.可以使用SEQUENCEFILERCFILE兩種檔案格式來替換TEXTFILE.這兩種檔案格式都是使用二進位制編碼和壓縮來優化磁碟空間及I/O頻寬效能的。

  • 記錄編碼是通過一個input format物件來控制的。Hive使用了一個名為org.apache.hadoop.mapred.TextInputFormat的java類.

  • 記錄的解析是由序列化/反序列化(SerDe)來控制的,對於TEXTFILEHive所使用的SerDeorg.apache.hadoop.hive.serde2.lazy.LazySimpleSerDejava類.

Hive使用一個叫做output format的物件將查詢輸出寫入到檔案中或者輸出到控制檯.對於TEXTFILEHive所使用的輸出類為org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat

可以使用第三方的輸入輸出格式及SerDe,允許使用者自定義Hive本身不支援的其他檔案格式

CREATE TABLE kst
PARTITIONED BY (ds string)
ROW FORMAT SERDE 'com.linkedin.haivvreo.AvroSerDe'
WITH SERDEPROPERTIES ('schema.url'='http://schema_provider/kst.avsc')
STORED AS
INPUTFORMAT 'com.linkedin.haivvreo.AvroContainerInputFormat'
OUTPUTFORMAT 'com.linkedin.haivvreo.AvroContainerOutputFormat';

ROW FORMAT SERDE …指定了使用的SerDe。Hive提供了WITH SERDEPROPERTIES功能,允許使用者傳遞配置資訊給SerDe。每個屬性名稱和值都應該是帶引號的字串.

STORED AS INPUTFORMAT … OUTPUTFORMAT分別定義了用於輸入和輸出格式的java類。如果要指定,必須對輸入和輸出格式都指定.

DESCRIBE EXTENDED table會列出輸入和輸出格式以及SerDeSerDe所自帶的屬性資訊。如:

hive> DESCRIBE EXTENDED kst
...
inputFormat:com.linkedin.haivvreo.AvroContainerInputFormat,
outputFormat:com.linkedin.haivvreo.AvroContainerOutputFormat,
...
serdeInfo:SerDeInfo(name:null,
serializationLib:com.linkedin.haivvreo.AvroSerDe,
parameters:{schema.url=http://schema_provider/kst.avsc})
...

4.5 刪除表

DROP TABLE IF EXISTS employees;

對於管理表,表的元資料資訊和表內的資料都被刪除

對於外部表,表的元資料資訊會被刪除,但是表中的資料不會被刪除

4.6 修改表

大多數的表屬性可以通過使用ALTER TABLE語句來修改.該操作會修改元資料,但不會修改資料本身.用於修改表模式中的錯誤及分割槽路徑.

4.6.1 表重新命名

ALTER TABLE log_messages RENAME TO logmsgs;

4.6.2 增加、修改和刪除表分割槽

  • 增加表分割槽
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'
...;
  • 修改分割槽路徑
ALTER TABLE log_messages 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);

對於管理表分割槽內的資料和元資料會一起被刪除。對應外部表,分割槽內的資料不會被刪除

4.6.3 修改列資訊

可以對欄位重新命名、修改其位置、型別或者註釋:

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

即使欄位名和欄位型別都沒有改變,也需要完全指定舊的欄位名。並給出新的欄位名以及新的欄位型別。若要將欄位移動到第一個位置,只需要使用FIRST關鍵字替代AFTER other_column子句即可.

這個操作,只會修改元資料資訊。要注意資料與模式匹配.

4.6.4 增加列

可以在分割槽欄位前增加新的欄位到已有欄位之後

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

4.6.5 刪除或者替換列

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

4.6.6 修改表屬性

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

可以增加附加的表屬性或者修改已經存在的表屬性。但是無法刪除屬性。

4.6.7 修改儲存屬性

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

如果是分割槽表,需要使用PARTITION子句

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

4.6.8 眾多的修改表語句

ALTER TABLE … TOUCH語句用於觸發鉤子

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);

最後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;