1. 程式人生 > >Hive-命令列基本操作和java API訪問hive資料庫

Hive-命令列基本操作和java API訪問hive資料庫

安裝

首先說明hive的安裝。
連結: http://pan.baidu.com/s/1DleVG 密碼: mej4
這個連結是一個視訊的連結,視訊中講解了如何安裝hive。
關於視訊中用到的資料檔案,我已經上傳到CSDN,請點選這裡下載。
按照視訊中的講解步驟,完全可以完成hive的安裝和除錯。

命令列基本操作

命令列基本操作無非就是增刪改查。
這裡寫圖片描述
進入hive的命令列模式,命令:hive
建議進入命令列模式使用Hive的安裝目錄下的bin目錄下,因為可能當執行命令的當前目錄下生成一些日誌檔案,時間久了,自己都不知道這些檔案是做什麼的了。

這裡寫圖片描述
命令:show databases;


分號作為命令列結束符。

這裡寫圖片描述
命令:use default;
show tables;

這裡寫圖片描述
建立表,並查詢。
create table ti(id string);
show tables;
select * from ti;

這裡寫圖片描述
向表中載入資料
load data local inpath ‘/usr/local/id’ into table tb1;

沒有local的話:
load data inpath ‘HDFS檔案路徑’ into table [tablename]
,則檔案路徑指的是HDFS檔案系統

這裡寫圖片描述
載入資料之後,進行查詢驗證。

這裡寫圖片描述
刪除表:
drop table tb1;

這裡寫圖片描述
這幅圖是通過瀏覽器遠端訪問HDFS所看到的Hive管理的資料庫的檔案。HIve管理的資料庫是使用HDFS檔案系統的方式進行的。所以資料庫的資料都是檔案,並可以通過HDFS檢視到。圖中看到的就是資料表tb1的資料。

製表符進行分割
CREATE TABLE t2(id int, name string) ROW FORMAT DELIMITED FIELDS TERMINATED BY ‘\t’;

分割槽表命令
CREATE TABLE t3(id int) PARTITIONED BY (day int);
LOAD DATA LOCAL INPATH ‘/root/id’ INTO TABLE t1 PARTITION (day=22);

桶表命令
create table t4(id int) clustered by(id) into 4 buckets;
set hive.enforce.bucketing = true;
使用桶載入資料 不能使用load data方式載入資料
insert into table t4 select id from t3;

外部表命令
create external table t5(id int) location ‘/external’;

連線查詢

Hive支援連線查詢,但有一些條件必須遵守,比如只支援相等查詢,其它查詢如不等式查詢則不支援,還支援外連線,左半連線查詢。另外Hive支援多於兩個表以上的連線查詢

join_table:
table_reference JOIN table_factor [join_condition]
| table_reference {LEFT|RIGHT|FULL} [OUTER] JOIN table_reference join_condition
| table_reference LEFT SEMI JOIN table_reference join_condition
| table_reference CROSS JOIN table_reference [join_condition] (as of Hive 0.10)

table_reference:
table_factor
| join_table

table_factor:
tbl_name [alias]
| table_subquery alias
| ( table_references )

join_condition:
ON equality_expression ( AND equality_expression )*

equality_expression:
expression = expression

首先是Hive中的連線查詢只支援相等連線而不支援不等連線查詢
//有效的連線查詢,相等連線查詢
SELECT a.* FROM a JOIN b ON (a.id = b.id AND a.department = b.department)
//無效的連線查詢,Hive不支援不等連線查詢
SELECT a.* FROM a JOIN b ON (a.id <> b.id)

其次是Hive支援兩個表以上的連線查詢

SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2) 

如果所有jion子句都使用了某個表的相同列,Hive將多個表的連線查詢轉換為一個map/reduce作業。如下所示:
//由於jion子句中使用了表b的key1列,該查詢轉換為一個作業

SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)  

//由於表b的key1列用在第一個jion子句中,key2列用在第二個jion子句中,該查詢被轉換為兩個作業,第一個作業執行表a和b的連線查詢,第二個作業將第一個作業的結果與第二個jion子句進行連線查詢

SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)  

在每個join的map/reduce階段,序列中的最後一個表是以流的方式通過reducers,而其它表則快取在reducers的記憶體中。這樣通過將最大的表放在序列的最後有助於減少reducers的記憶體需求。如:
//下面的查詢中,從a和b中滿足條件的行中提取a.val和b.val,並快取在reducers的記憶體中,對於從c中提取的每行記錄,與快取中的行進行連線計算

SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)  

//下面的查詢包含兩個作業,第一個作業快取a的值,將b的值以流的方式通過reducers,第二個作業快取結果,並將c的值以流的方式通過reducers。

SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2) 

在每個join的map/reduce階段,可以通過提示指定要流處理的表:
//下面的查詢中b.val和c.val快取在reducers的記憶體中,對於從a中提取的每行記錄,與快取中的行進行連線計算。如果省略STREAMTABLE提示,jion中最右邊的表被流處理

SELECT /*+ STREAMTABLE(a) */ a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)

LEFT,RIGHT和FULL OUTER,即左連線,右連線和全連線,為當ON從句不匹配時提供了更多的控制,如:

SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key)

該查詢將返回a中的所有行,當a.key=b.key時返回a.val,b.val,沒有對應的b.key時返回a.val,NULL,b中沒有對應的a.key的行將會丟掉。”FROM a LEFT OUTER JOIN b”必須寫在一行中為了理解該語句是如何工作的—a在b的左側,a中的所有行被保留。RIGHT OUTER JOIN將保留b中所有的行,FULL OUTER JOIN將保留a中的所有行和b中的所有行。
Join出現在WHERR子句之前。因此如果想限制連線查詢的輸出,限制條件應該出現在WHERE子句中,否則應該出現在JOIN子句中。當在分割槽表上執行連線查詢時或許會有一些困惑:
//ds為分割槽列

SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key)  
WHERE a.ds='2009-07-07' AND b.ds='2009-07-07'  

當該左外連線在a中發現key而在b中沒有發現key時,b中的列將為null,包括分割槽列ds,也就是將會過濾掉連線查詢輸出中沒有有效b.key的列,或者說左外連線與WHERE子句中引用的b中的任何列無關。相反下面的語句將會提前根據條件過濾:

SELECT a.val, b.val FROM a LEFT OUTER JOIN b  
ON (a.key=b.key AND b.ds='2009-07-07' AND a.ds='2009-07-07') 

Join連線是不可以交換的,無論是LEFT還是RIGHT連線都是左結合的。看下面的示例:

SELECT a.val1, a.val2, b.val, c.val  
FROM a  
JOIN b ON (a.key = b.key)  
LEFT OUTER JOIN c ON (a.key = c.key)  

第一個連線a和b,丟掉所有不滿足條件的記錄,結果再與c進行左外連線。如果當key存在於a和c中但不在b中時,結果不是直觀的。A中包含key的行丟棄掉,應為b中沒有與key對應的行,這樣結果將不包含key,再與c進行左外連線時將不包含c.val,該值將為null。如果是RIGHT OUTER JOIN的話,結果將為null,null,null,c.val,分析方法同分析左外連線一樣。
左半連線以高效的方式實現了IN/EXISTS子查詢。左半連線的限制是右側的表只能出現在ON子句中,不能出現在WHERE或者SELECT子句中,如:

SELECT a.key, a.value  
FROM a  
WHERE a.key in  
 (SELECT b.key  
  FROM B);  
//兩者是等價的  
SELECT a.key, a.val  
FROM a LEFT SEMI JOIN b on (a.key = b.key)  

如果除了一個表以外的所有正在連線的表都比較小,連線操作可以只作為map作業執行,如:

SELECT /*+ MAPJOIN(b) */ a.key, a.value  
FROM a join b on a.key = b.key

該查詢不需要reducer任務,對於A的每個mapper,B被完全讀取。但a FULL/RIGHT OUTER JOIN b不能被執行。如果正在連線查詢的表在連線列上進行了分桶,並且一個表的桶數是另一個表的桶的倍數,桶可以彼此連線。如果表a有4個桶,b有4個桶,那麼下面的連線查詢可以僅適用mapper任務完成:

SELECT /*+ MAPJOIN(b) */ a.key, a.value  
FROM a join b on a.key = b.key  

與對於a的每個mapper任務都讀取整個b不同,只讀取被要求的桶。對於上面的查詢,處理a的桶1的mapper任務只讀取b的桶1,但這不是預設行為,可以使用下面的引數進行配置管理:

hive.optimize.bucketmapjoin = true     //預設值為false  

如果表在排序和分桶的列上進行連線查詢,且它們有相同的桶,那麼合併查詢可以被執行。對應的桶在mapper任務中彼此連線,該過程同上。但需要設定下面的引數:

hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;//預設為org.apache.hadoop.hive.ql.io.CombineHiveInputFormat  
hive.optimize.bucketmapjoin = true; //預設值為false  
hive.optimize.bucketmapjoin.sortedmerge = true;  //預設值為false  

子查詢語法

SELECT ... FROM (subquery) name ...

Hive只在FROM字句支援子查詢。子查詢必須給一個名字,因為每個表在FROM字句必須有一個名字。子查詢的查詢列表的列,必須有唯一的名字。子查詢的查詢列表,在外面的查詢是可用的,就像表的列。子查詢也可以一個UNION查詢表示式.Hive支援任意層次的子查詢。

簡單子查詢的例子:

SELECT col  FROM (
  SELECT a+b AS col FROM t1
) t2

包含UNION ALL的子查詢例子:

SELECT t3.col FROM (
  SELECT a+b AS col FROM t1
    UNION ALL
  SELECT c+d AS col FROM t2
) t3

檢視view

Hive 0.6版本及以上支援檢視
Hive View具有以下特點:
1. View是邏輯存在,Hive暫不支援物化檢視(1.0.3)
2. View只讀,不支援LOAD/INSERT/ALTER。需要改變View定義,可以是用Alter View
3. View內可能包含ORDER BY/LIMIT語句,假如一個針對view的查詢也包含這些語句, 則view中的語句優先順序高。例如,定義view資料為limit 10, 針對view的查詢limit 20,則最多返回10條資料。
4. Hive支援迭代檢視

建立View
CREATE VIEW [IF NOT EXISTS] view_name [(column_name [COMMENT column_comment], ...) ]  
[COMMENT view_comment]  
[TBLPROPERTIES (property_name = property_value, ...)]  
AS SELECT ... 
刪除view
DROP VIEW [IF EXISTS] view_name 
修改view
ALTER VIEW view_name SET TBLPROPERTIES table_properties  
table_properties:  
  : (property_name = property_value, property_name = property_value, ...)  
查詢檢視的定義資訊
DESCRIBER EXTENDED viewname

EXPLAIN語法

Hive提供EXPLAIN命令,顯示查詢的執行計劃。語法如下:

EXPLAIN [EXTENDED] query

EXPLAIN語句使用EXTENDED,提供執行計劃關於操作的額外的資訊。這是典型的物理資訊,如檔名。

Hive查詢被轉換成序列(這是一個有向無環圖)階段。這些階段可能是mapper/reducer階段,或者做metastore或檔案系統的操作,如移動和重新命名的階段。 EXPLAIN的輸出包括三個部分:

查詢的抽象語法樹

執行計劃計劃的不同階段之間的依賴關係

每個場景的描述

場景的描述,顯示了與元資料相關操作的操作序列。元資料會包括FilterOperator的過濾器表示式,或SelectOperator的查詢表示式,或FileSinkOperator的檔案輸出名字。

排序和聚集

//where和having的區別:
//where是先過濾再分組(對原始資料過濾),where限定聚合函式
hive> select count(*),age from tea where id>18 group by age;

//having是先分組再過濾(對每個組進行過濾,having後只能跟select中已有的列)
hive> select age,count(*) c from tea group by age having c>2;

//group by後面沒有的列,select後面也絕不能有(聚合函式除外)
hive> select ip,sum(load) as c from logs  groupby ip sort by c desc limit 5;

//distinct關鍵字返回唯一不同的值(返回age和id均不相同的記錄)
hive> select distinct age,id from tea;

//hive只支援Union All,不支援Union
//hive的Union All相對sql有所不同,要求列的數量相同,並且對應的列名也相同,但不要求類的型別相同(可能是存在隱式轉換吧)
select name,age from tea where id<80
union all
select name,age from stu where age>18;

Order By特性:

對資料進行全域性排序,只有一個reducer task,效率低下。
與mysql中 order by區別在於:在 strict 模式下,必須指定 limit,否則執行會報錯
使用命令set hive.mapred.mode; 查詢當前模式
使用命令set hive.mapred.mode=strick; 設定當前模式

hive>select*from logs where date='2015-01-02'orderby te;
FAILED: SemanticException 1:52In strict mode,
 ifORDERBYis specified, LIMIT must also be specified. 
Error encountered near token 'te'

對於分割槽表,還必須顯示指定分割槽欄位查詢

hive>select*from logs orderby te limit 5;                
FAILED: SemanticException [Error 10041]: 
No partition predicate found for Alias "logs" Table "logs"

order by 時,desc NULL 值排在首位,ASC時NULL值排在末尾

Sort BY特性:

可以有多個Reduce Task(以DISTRIBUTE BY後欄位的個數為準)。也可以手工指定:set mapred.reduce.tasks=4;
每個Reduce Task 內部資料有序,但全域性無序

set mapred.reduce.tasks =2;
insert overwrite local directory '/root/hive/b'select*from logs                         
    sort by te;

上述查詢語句,將結果儲存在本地磁碟 /root/hive/b ,此目錄下產生2個結果檔案:000000_0 + 000001_0 。每個檔案中依據te欄位排序。

Distribute by特性:

按照指定的欄位對資料進行劃分到不同的輸出 reduce 檔案中
distribute by相當於MR 中的paritioner,預設是基於hash 實現的
distribute by通常與Sort by連用

set mapred.reduce.tasks =2;
insert overwrite local directory '/root/hive/b'select*from logs
    distribute by date
    sort by te;

Cluster By特性:

如果 Sort By 和 Distribute By 中所有的列相同,可以縮寫為Cluster By以便同時指定兩者所使用的列。
注意被cluster by指定的列只能是降序,不能指定asc和desc。一般用於桶表

set mapred.reduce.tasks =2;
insert overwrite local directory '/root/hive/b'select*from logs
    cluster by date;

JAVA API操作Hive資料庫

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class HiveDemo {
    public static void main(String[] args) throws Exception {
        Class.forName("org.apache.hadoop.hive.jdbc.HiveDriver");
        Connection connection = DriverManager.getConnection("jdbc:hive://centos:10000/default", "", "");
        Statement stmt = connection.createStatement();
        String querySQL="select * from default.tb1";
        ResultSet resut = stmt.executeQuery(querySQL);
        while (resut.next()) {
            System.out.println(resut.getInt(1));
        }
    }

}

以上程式碼就是通過java api操作hive資料庫,獲取資料然後列印。
在執行上面的命令之前,需要在linux系統中啟動hive的遠端服務,命令如下:
hive –service hiveserver >/dev/null 2>/dev/null &

這條命令啟動hive的遠端服務,分毫不差,直接輸入回車就可以了。然後執行上面的java 程式碼,執行結果如下:

這裡寫圖片描述
可以看到結果已經正確打印出來了。
內容引用了網上的比較多的內容。在此感謝眾多同行的付出!如有侵權,請見諒!^_^~~
關於程式碼,如果感興趣,請點選我的github關注整個專案。整個專案中不僅僅本文提到的hive的簡單操作,還有MapReduce,Zookeeper等簡單的應用。歡迎關注。^_^