Hive的基本理論與安裝可參看作者上一篇博文《Apache Hive 基本理論與安裝指南》。
一、Hive命令行
所有的hive命令都可以通過hive命令行去執行,hive命令行中仍有許多選項。使用$hive -H查看:
-e 選項后面可以直接接一個hql語句,不用進入到hive命令行用戶接口再輸入hql語句。
-f 選項后面接一個hql語句的文件。
-i 選項在hql語句執行之前的初始化hql文件。例如添加、導入等操作都可以寫在這個hql語句文件中。
在hive使用中,大多是寫很多腳本,在hive命令行中輸入是屬於交互式的,這就必須有工作人員在工作,不適合做批量處理。可以使用-f或-i選項,一次性執行可以將所有的hql語句放在一個hql腳本文件中。例如:
$ mkdir -p /opt/shell/sql $ vim /opt/shell/sql/test.sql
select * from table_name limit 5; select * from table_name where professional="student"; select count(*) from table_name; select count(*) from table_name group by professional; select * from table_name where professional="student" order by age;
將腳本保存退出后,再批量執行:
$ hive -f /opt/shell/sql/test.sql
二、Hive DDL(Data Definition Language)
- Hive Data Definition Language
- Overview
- Keywords, Non-reserved Keywords and Reserved Keywords
- Create/Drop/Alter/Use Database
- Create/Drop/Truncate Table
- Alter Table/Partition/Column
- Create/Drop/Alter View
- Create/Drop/Alter Index
- Create/Drop Macro
- Create/Drop/Reload Function
- Create/Drop/Grant/Revoke Roles and Privileges
- Show
- Describe
- Abort
- HCatalog and WebHCat DDL
詳見官方文檔。重點在於創建表和創建函數。
1. 建表語法
- 建表語句
從官方文檔的Create Table中可以查看hive建表的命令,如下:
CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name -- (Note: TEMPORARY available in Hive 0.14.0 and later) [(col_name data_type [COMMENT col_comment], ... [constraint_specification])] [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] [SKEWED BY (col_name, col_name, ...) -- (Note: Available in Hive 0.10.0 and later)] ON ((col_value, col_value, ...), (col_value, col_value, ...), ...) [STORED AS DIRECTORIES] [ [ROW FORMAT row_format] [STORED AS file_format] | STORED BY 'storage.handler.class.name' [WITH SERDEPROPERTIES (...)] -- (Note: Available in Hive 0.6.0 and later) ] [LOCATION hdfs_path] [TBLPROPERTIES (property_name=property_value, ...)] -- (Note: Available in Hive 0.6.0 and later) [AS select_statement]; -- (Note: Available in Hive 0.5.0 and later; not supported for external tables) CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name LIKE existing_table_or_view_name [LOCATION hdfs_path];
- 數據類型
data_type : primitive_type | array_type | map_type | struct_type | union_type -- (Note: Available in Hive 0.7.0 and later)
data_type,有兩種類型:一種是復雜類型,例如array_type(ARRAY < data_type >)、map_type(MAP < primitive_type, data_type >)、struct_type(STRUCT < col_name : data_type [COMMENT col_comment], ...>)、union_type(UNIONTYPE < data_type, data_type, ... >);簡單類型有SMALLINT(占2個字節的整數)、INT(占4個字節的整數)、BIGINT(占8個字節的整數)、BOOLEAN、FLOAT、DOUBLE、STRING、BINARY、TIMESTAMP、DECIMAL、DATE、VARCHAR(0.12之后)、CHAR(字符,0.13之后)。
primitive_type : TINYINT | SMALLINT | INT | BIGINT | BOOLEAN | FLOAT | DOUBLE | DOUBLE PRECISION -- (Note: Available in Hive 2.2.0 and later) | STRING | BINARY -- (Note: Available in Hive 0.8.0 and later) | TIMESTAMP -- (Note: Available in Hive 0.8.0 and later) | DECIMAL -- (Note: Available in Hive 0.11.0 and later) | DECIMAL(precision, scale) -- (Note: Available in Hive 0.13.0 and later) | DATE -- (Note: Available in Hive 0.12.0 and later) | VARCHAR -- (Note: Available in Hive 0.12.0 and later) | CHAR -- (Note: Available in Hive 0.13.0 and later)
- row_format
row_format : DELIMITED [FIELDS TERMINATED BY char [ESCAPED BY char]] [COLLECTION ITEMS TERMINATED BY char] [MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char] [NULL DEFINED AS char] -- (Note: Available in Hive 0.13 and later) | SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value, property_name=property_value, ...)]
row_format:需要指出每一行是由什么隔開,並且要指出每一行中的每一個字段是用什么隔開的。
對於字段的隔開,復雜數據類型和簡單數據類型不一樣。例如數組類型是復雜類型,其隔開符[COLLECTION ITEMS TERMINATED BY char],Map類型的要使用[MAP KEYS TERMINATED BY char]。[LINES TERMINATED BY char]可以設置行隔開符,如果不寫,默認為回車換行。
- file_format
file_format: : SEQUENCEFILE | TEXTFILE -- (Default, depending on hive.default.fileformat configuration) | RCFILE -- (Note: Available in Hive 0.6.0 and later) | ORC -- (Note: Available in Hive 0.11.0 and later) | PARQUET -- (Note: Available in Hive 0.13.0 and later) | AVRO -- (Note: Available in Hive 0.14.0 and later) | INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname
SEQUENCEFILE表示序列壓縮格式,以及RCFILE、ORC、PARQUET、AVRO都是壓縮格式。TEXTFILE是默認的格式,文本格式。
2. 創建表案例一
- 查看數據
為舉例說明,這里先生成數據文件:
vim /root/person.txt
1,zhangsan,31,books-sports-math,city:shanghai-street:lujiazui-zipcode:313100 2,lisi,35,books-music,city:hangzhou-street:xihu-zipcode:222100 3,wangwu,25,computer-games,city:guangzhou-street:baiyun-zipcode:212300
- 創建表
根據數據創建一個人類表,包含人的編號、姓名、年齡、愛好、地址五個字段。
vim /opt/shell/sql/t_person.sql
create table t_person ( id int, name string, age int, likes array<string>, address map<string,string> ) row format delimited fields terminated by ',' collection items terminated by '-' map keys terminated by ':' lines terminated by '\n' stored as textfile;
根據表結構,字段之間按,隔開;likes的類型是array,所以可以有多個愛好,元素之間按-隔開,以,作為數組的結束;地址是map類型,也是collection類型, key和value按:隔開,每對key和value之間用-隔開(和collection一致);回車代表換行符。
執行創建表腳本:
$ hive -f /opt/shell/sql/t_person.sql
- 將數據從本地導入到hive
hive> load data local inpath '/root/person.txt' into table t_person;
- 查看數據
3. 創建表案例二(分區表)
當我們要在關系型數據庫中查找某一數據時,一般需要匹配數據庫中的所有數據,所以可以通過分區來提高查詢效率。把常用的查詢條件作為一種分區,例如要查某一天的數據,事實上就是可以只匹配當天的數據,其他數據不匹配。下面以建一個日志管理表為例:
- 數據文件
文件經常按照天、小時等進行分割。故在此創建多個文件如下:
vim /root/log_2016-03-11.txt
111,1,200,2016-03-11 135,4,100,2016-03-11 211,3,300,2016-03-11 141,1,200,2016-03-11 131,2,400,2016-03-11
vim /root/log_2016-03-12.txt
121,2,300,2016-03-12 125,3,400,2016-03-12 211,1,400,2016-03-12 161,3,100,2016-03-12 171,5,200,2016-03-12
- 創建表結構
create table t_log (id string,type int,pid string,logtime string) partitioned by (day string) row format delimited fields terminated by ',' stored as textfile;
這里指定了按照天做分區。
- 裝載數據
hive> load data local inpath '/root/log_2016-03-11.txt' into table t_log partition (day='2016-03-11'); hive> load data local inpath '/root/log_2016-03-12.txt' into table t_log partition (day='2016-03-12');
- 查看數據
hive> select * from t_log;
從上圖可以看出,數據增加了一個字段,左邊是logtime,右邊是分區day。所以,添加一個分區可以理解為添加一個字段;但是又不同於添加一個字段,因為查詢按照分區做限定(查詢分區day='2016-03-11')時其他分區的數據不讀取,而如果是字段的話,需要每一條數據進行匹配過濾。也可以從瀏覽器看出創建分區表的目錄結構如下:
創建分區,就會為每一個分區建一個目錄,所以在查詢時,只在限定的分區目錄里查詢。
查看某一天的數據量
hive> select count(*) from t_log where day='2016-03-11';
查看某一個月的數據量
hive>select count(*) from t_log where day between 'xxx' and 'xxx';
當然,這里需要先轉換格式,略。
三、Hive DML(Data Manipulation Language)
- Hive Data Manipulation Language
詳見官方文檔。DML是對數據進行增刪改的腳本。但是數據在hdfs中,實際上不提供修改,只提供追加(insert),支持刪除。
1. Loading files into tables
- 語法
load file將數據導入到表中。其語法為:
hive> LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
local:如果導入的數據在Linux主機本地,就要添加[local],如果數據已經在hdfs上就不能加local;overwrite:覆蓋;partition:如果表有分區就要加partition。
- 實例
- 將hdfs中的數據裝載到hive
首先,上傳Linux文件到hdfs
$ hdfs dfs -put /root/log_2016-03-1* /usr/input
其次,在hive中執行導入
hive>load data inpath '/usr/input/log_2016-03-12.txt' into table t_log partition (day='2016-03-12');
hive>load data inpath '/usr/input/log_2016-03-12.txt' overwrite into table t_log partition (day='2016-03-12');
注意:導入的分區要存在,導入到hive表后原來hdfs路徑下的文件就不復存在了,即存在hdfs的目錄變了,實際就是元數據變了,block的位置沒有變。如果使用overwrite,則原來該表中指定分區的數據將全部清空,然后上傳該文件。如果load相同文件名名到表中時,會默認生成副本filename_copy_1。文件中的數據格式要和表的結構相吻合。
-
- 將Linux本地的數據裝載到hive
hive>load data local inpath '/root/log_2016-03-11.txt' into table t_log partition (day='2016-03-11');
2. Inserting data into hive tables from queries
- 語法
hive> INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...) [IF NOT EXISTS]] select_statement1 FROM from_statement;
hive> INSERT INTO TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1 FROM from_statement;
其中的select_statement1 FROM from_statement;是一個sql語句。這是用於查詢hive中已經存在的數據,將查詢結果給到一張新表中。
hive> INSERT INTO TABLE tablename [PARTITION (partcol1[=val1], partcol2[=val2] ...)] VALUES values_row [, values_row ...]
這個語句是和關系型數據庫的insert語句用法是一樣的。區別有三:一是,有partition;二是,可以一次插入多條數據;三是,這種語句是轉成MapReduce去執行的。
因為hive是一個工具,其作用是查詢和統計hdfs上的數據的,對於查詢結果一般就在控制台上顯示,所以這個insert語句作用就是將查詢的結果保存下來,用於后期的展示。
- 實例
hive> insert into table t_log partition (day='2016-03-13’) values ('888',2,'100','2016-03-13’);
這個會啟動MapReduce,因為數據在文件中不存在,要插到文件中相當於上傳,會生成一個新的文件。這個不常用。所以實際上inset into語句的實際意義在於將查詢結果放到新的表中。
3. Delete
刪除數據一般可以不在hive中刪除,直接在hdfs上刪除文件。因為刪數據實際上就是刪除文件。例如要刪除之前插入到hive的t_log表day=2016-03-11分區下的log_2016-03-11.txt,可以執行如下命令:
#hdfs dfs -rm /user/hive/warehouse/t_log/day=2016-03-11/t_log-2016-03-11.txt
四、Hive UDF(Operators and User-Defined functions)
- Hive Operators and User-Defined Functions (UDFs)
詳見官方文檔。
1. 內置運算符
- 關系運算符
見文檔
- 算術運算符
見文檔
- 邏輯運算符
見文檔
- 復雜類型構造函數(Complex Type Constructors)
- 復雜類型函數或對象的構建
【1】map(構造map對象)
Creates a map with the given key/value pairs. (key1,value1,key2,value2,…)
【2】struct(創建架構數組)
Creates a struct with the given field values. (val1,val2,val3,…)。Struct的屬性名和列名相對應。struct可以認為是面向對象的對象類型,是一個構造體,里面可以定義屬性的值,field的名稱是預先定義的,就像Java類的屬性預先定義好了。
【3】named_struct
Creates a struct with the given field names and values. (name1,val1,name2,val2, …)。根據給定的Struct的屬性名來創建構建數組
【4】array(創建數組對象)
Creates an array with the given elements. (val1,val2,val3,…)。把各(若干)個字段的值變成一個array。
【5】create_union
Creates a union type with value that is being pointes to by the tag parameter.
-
- 復雜類型函數的運算符
【1】A[n]
A是array類型,n是int類型。A[n]表示數組A的第n+1個元素。
【2】M[key]
M是map類型,key是map集合中鍵的類型。M[key]是取map集合中鍵為key的值。注意使用是key需要使用單引號。
【3】S.x
S是struct類型,x表示struct中的某個屬性。S.x,將會返回S這個struct中定義的x屬性型中存儲的值。
2. 內置函數
- 數學函數
- 集合操作函數
- 類型轉換函數
- 日期函數
- 條件/邏輯函數
略。
- 字符串函數
3. UDAF
UDAF和UDF的區別在於傳給函數的參數不一樣。UDF表示傳給函數的參數只有一個值或一行值;UDAF是給函數傳多個值或者多行值的函數,例如count(*),sum(col)等都是多行的值。
UDAF(User- Defined Aggregation Funcation) 聚集函數,多進一出,例如count/max/min等。
4. UDTF
詳見文檔。
5. UDF
HivePlugins,Creating Custom UDFs。自定義函數需要以下幾個步驟:首先要自定義一個類,繼承UDF;其次,打成jar包;第三,將jar包加載到hive的classpath;第四,創建自定義函數;第五,使用函數。
例如,要創建一個將字符串轉成日期的函數。
- 自定義類
package com.huidoo.hive; import java.text.SimpleDateFormat; import java.util.Date; import org.apache.hadoop.hive.ql.exec.UDF; import org.apache.hadoop.hive.serde2.io.TimestampWritable; import org.apache.hadoop.io.Text; public class StringToDate extends UDF { /** * 定義evaluate方法。返回值類型定義為TimestampWritable * @param str * @param datefmt * @return * @throws Exception */ public TimestampWritable evaluate(final Text str,final Text datefmt) throws Exception{ SimpleDateFormat sdf= new SimpleDateFormat(datefmt.toString()); //datefmt是傳入的格式化字符串,需要創建SimpleDateFormat對象,Text類型要轉成Java中的String類型。 Date date= sdf.parse(str.toString()); //將字符串str,按照格式sdf轉成java.util的Date類型 TimestampWritable time=new TimestampWritable();//創建Hadoop的時間戳對象 time.setTime(date.getTime());//將date轉成Timestamp類型,然后使用Hadoop時間戳對象設置成相應的時間。 return time; } }
- 打成jar包並上傳到服務器
略。std.jar
- 將jar包加載到hive的classpath
hive> add jar /path/to/std.jar;
- 創建函數
語法:create 函數名(不能與內置的一樣) as ‘自定義類的全限定名’;
hive> create function std as 'com.huidoo.hive.StringToDate';
這就創建了一個函數,名為std。
- 使用函數
hive> select std('2016-02-06 01:19:30','yyyy-MM-dd HH:mm:ss') from t_log limit 3;
五、Hive Select
1. 簡單查詢和使用/切換數據庫
hive> select * from table_name;
查看當前數據庫:
hive> SELECT current_database();
"db_name.table_name" allows a query to access tables in different databases.可以查詢不同數據庫中的表。
使用某數據庫:
hive> USE database_name;
2. where從句
hive>SELECT * FROM sales WHERE amount > 10 AND region = "US"
3. ALL and DISTINCT從句
使用distinct關鍵字去重查詢,如下列出兩個查詢的區別:
hive> SELECT col1, col2 FROM t1
1 3
1 3
1 4
2 5
hive> SELECT DISTINCT col1, col2 FROM t1
1 3
1 4
2 5
4. Join從句
join用於表連接。兩個表即兩個文件能連接起來就一定有相同點,這就是說其中一個文件中某域的值和另一個文件的某域的值相同,就可以連接。
hive> select col1,col2,col3 from t1 join t2 on+條件;
5. 基於Partition的查詢
這種查詢語法就只要把partition當成一個字段即可。如果查詢時要引入外鍵關聯表也可以使用JION…ON語句。
- 非關聯查詢
語法:
hive> select table_name.* from table_name where table_name.partition_name +條件;
案例:
SELECT page_views.* FROM page_views WHERE page_views.date >= '2016-03-01' AND page_views.date <= '2016-03-31';
- 關聯查詢
語法:
hive> select table_name1.* from table_name1 join table_name2 on (table_name1.外鍵 = table_name2.主鍵 And table_name1.partiton_name +條件);
案例:
SELECT page_views.* FROM page_views JOIN dim_users ON (page_views.user_id = dim_users.id AND page_views.date >= '2016-03-01' AND page_views.date <= '2016-03-31');
6. Group by從句
hive> select col[list] from table_name group by col;
7. Order/Sort by從句
sort by和order by的用法基本一致,都是做排序的,一般用order by。例如:
hive> select * from t_log order by id;
8. Having從句
having從句必須依附於group by從句,在group從句后面接having從句,相當於增加一個條件。having后面可以接聚合函數,例如sum、avg等。
- 單純的group by語句
hive> select day from t_log group by day;
其查詢結果為:
2016-03-11
2016-03-12
- 添加having從句
hive>select day from t_log group by day having avg(id)>150;
其查詢結果為:
2016-03-12
- hiving同效於子查詢
hive> select day from (select day, avg(id) as avgid from t_log group by day) table2 where table2.avgid>150;
這里將t_log表通過select day, avg(id) as avgid from t_log group by day查詢得到的結果作為表再查詢的。和上述的hiving從句得到的結果一樣。
9. Limit從句
限定查詢返回的行數。
hive> select * from t_log limit 5;