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等簡單的應用。歡迎關注。^_^

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章