數據倉庫Hive簡述

    Hive 是一個構建在 Hadoop 之上的數據倉庫,它可以將HDFS數據文件映射成表,並提供類 SQL 查詢功能,用於查詢的 SQL 語句會被轉化爲 MapReduce 作業提交到 Hadoop 上運行。其實,Hive是用Java編寫的一套基於HDFS分佈式數據存儲,將SQL編譯爲MapReduce任務進行分佈式計算的數據倉庫框架,提供了類似 sql 的查詢語言 hql,簡單、容易上手,使得精通 sql 但是不瞭解 Java 編程的人也能很好地進行大數據分析。Hive具有以下特點:

  • 靈活性高,可以自定義用戶函數 (UDF) 和存儲格式
  • 爲超大的數據集設計的計算和存儲能力,集羣擴展容易
  • 統一的元數據管理,可與 presto/impala/sparksql 等共享數據
  • 執行延遲高,不適合做數據的實時處理,但適合做海量數據的離線處理。hive 的最佳使用場合是大數據集的批處理作業,例如,網絡日誌分析。
    下面記錄一些主要知識點。

HiveServer2

    Hive 內置了 HiveServer 和 HiveServer2 服務,兩者都允許客戶端使用多種編程語言進行連接,但是 HiveServer 不能處理多個客戶端的併發請求,所以產生了 HiveServer2。
    HiveServer2(HS2)允許遠程客戶端可以使用各種編程語言向 Hive 提交請求並檢索結果,支持多客戶端併發訪問和身份驗證。HS2 是由多個服務組成的單個進程,其包括基於 Thrift 的 Hive 服務(TCP 或 HTTP)和用於 Web UI 的 Jetty Web 服務器。
    HiveServer2 擁有自己的 CLI(Beeline),Beeline 是一個基於 SQLLine 的 JDBC 客戶端。由於 HiveServer2 是 Hive 開發維護的重點 (Hive0.15 後就不再支持 hiveserver),所以 Hive CLI 已經不推薦使用了,官方更加推薦使用 Beeline。Beeline連接Hive如下:

$ beeline -u jdbc:hive2://ip:port  -n username -p password 

Metastore元數據

    在 Hive 中,表名、表結構、字段名、字段類型、表的分隔符等統一被稱爲元數據。所有的元數據默認存儲在 Hive 內置的 derby 數據庫中,但由於 derby 只能有一個連接實例,也就是說不能有多個命令行客戶端同時訪問,所以在實際生產環境中,通常使用 Mysql 代替 derby存儲元數據。
    Hive 進行的是統一的元數據管理,就是說你在 Hive 上創建了一張表,然後在impala或者sparksql 中都是可以直接使用的,它們會從 Metastore 中獲取統一的元數據信息,同樣的在impala或sparksql 中創建一張表,在 Hive 中也可以直接使用。

內部表和外部表

    內部表又叫做管理表 (Managed/Internal Table),創建表時不做任何指定,默認創建的就是內部表。想要創建外部表 (External Table),則需要使用 External 進行修飾。 內部表和外部表主要區別如下:

內部表 外部表
存儲位置 內部表數據存儲的位置由 hive.metastore.warehouse.dir 參數指定,默認情況下表的數據存儲在 HDFS 的 /user/hive/warehouse/數據庫名.db/表名/ 目錄下 外部表數據的存儲位置創建表時由 Location 參數指定
導入數據 在導入數據到內部表,內部表將數據移動到自己的數據倉庫目錄下,數據的生命週期由 Hive 來進行管理 外部表不會將數據移動到自己的數據倉庫目錄下,只是在元數據中存儲了數據的位置
刪除表 刪除元數據(metadata)和文件 只刪除元數據(metadata)

分區表

    Hive 中的數據都是存儲在HDFS上,且表對應爲 HDFS 上的指定目錄,在查詢數據時候,默認會對全表進行掃描,這樣時間和性能的消耗都非常大。
    分區爲 HDFS 上表目錄的子目錄,數據按照分區存儲在子目錄中。 如果查詢的 where 字句的中包含分區條件,則直接從該分區去查找,而不是掃描整個表目錄,合理的分區設計可以極大提高查詢速度和性能。
    通常,在管理大規模數據集的時候都需要進行分區,比如將日誌文件按天進行分區,從而保證數據細粒度的劃分,使得查詢性能得到提升。
在 Hive 中可以使用 PARTITIONED BY 子句創建分區表。表可以包含一個或多個分區列,程序會爲分區列中的每個不同值組合創建單獨的數據目錄。下面的我們創建一張僱員表作爲測試:

CREATE EXTERNAL TABLE emp_partition(
    empno INT,
    ename STRING,
    job STRING,
    mgr INT,
    hiredate TIMESTAMP,
    sal DECIMAL(7,2),
    comm DECIMAL(7,2)
    )
    PARTITIONED BY (deptno INT)   -- 按照部門編號進行分區
    ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
    LOCATION '/hive/emp_partition';

加載數據到分區表時候必須要指定數據所處的分區:

# 加載部門編號爲20的數據到表中
LOAD DATA LOCAL INPATH "/usr/file/emp20.txt" OVERWRITE INTO TABLE emp_partition PARTITION (deptno=20)
# 加載部門編號爲30的數據到表中
LOAD DATA LOCAL INPATH "/usr/file/emp30.txt" OVERWRITE INTO TABLE emp_partition PARTITION (deptno=30)

可以看到Hadoop上的表目錄下存在兩個子目錄,分別是 deptno=20 和 deptno=30,這就是分區目錄,分區目錄下才是我們加載的數據文件。這時候當你的查詢語句的 where 包含 deptno=20,則就去對應的分區目錄下進行查找,而不用掃描全表。
    實際上分區這個概念很常見,比如在我們常用的mysql數據庫中,當表中的數據量不斷增大,查詢數據的速度就會下降,這時也可以對錶進行分區。表進行分區後,邏輯上表仍然是一張完整的表,只是將表中的數據存放到多個表空間(物理文件上),這樣查詢數據時,就不必要每次都掃描整張表,從而提升查詢性能。

分桶表

    分區提供了一個隔離數據和優化查詢的可行方案,但是並非所有的數據集都可以形成合理的分區,分區的數量也不是越多越好,過多的分區條件可能會導致很多分區上沒有數據。同時 Hive 會限制動態分區可以創建的最大分區數,用來避免過多分區文件對文件系統產生負擔。鑑於以上原因,Hive 還提供了一種更加細粒度的數據拆分方案:分桶表 (bucket Table)。
    分桶表會將指定列的值進行哈希散列,並對 bucket(桶數量)取餘,然後存儲到對應的 bucket(桶)中。物理上,每個桶就是表(或分區)目錄裏的一個文件。
    對於分桶這個概念,我們可以這樣來理解: Hive 中的分桶概念和 Java 數據結構中的 HashMap 的分桶概念是一致的。當調用 HashMap 的 put() 方法存儲數據時,程序會先對 key 值調用 hashCode() 方法計算出 hashcode,然後對數組長度取模計算出 index,最後將數據存儲在數組 index 位置的鏈表上,鏈表達到一定閾值後會轉換爲紅黑樹 (JDK1.8以上)。
    在 Hive 中,我們可以通過 CLUSTERED BY 指定分桶列,並通過 SORTED BY 指定桶中數據的排序參考列。下面爲分桶表建表語句示例:

CREATE EXTERNAL TABLE emp_bucket(
    empno INT,
    ename STRING,
    job STRING,
    mgr INT,
    hiredate TIMESTAMP,
    sal DECIMAL(7,2),
    comm DECIMAL(7,2),
    deptno INT)
    CLUSTERED BY(empno) SORTED BY(empno ASC) INTO 4 BUCKETS  --按照員工編號散列到四個 bucket 中
    ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
    LOCATION '/hive/emp_bucket';

    分桶不能像分區一樣直接使用 Load 語句向分桶表加載數據,如果用Load雖然數據時可以加載成功的,但是數據並不會分桶。這是由於分桶的實質是對指定字段做了 hash 散列然後存放到對應文件中,這意味着向分桶表中插入數據是必然要通過 MapReduce,且 Reducer 的數量必須等於分桶的數量。由於以上原因,分桶表的數據通常只能使用 CTAS(CREATE TABLE AS SELECT) 方式插入,因爲 CTAS 操作會觸發 MapReduce。加載數據步驟如下:

  1. 設置強制分桶
set hive.enforce.bucketing = true; --Hive 2.x 不需要這一步
  1. CTAS導入數據
INSERT INTO TABLE emp_bucket SELECT *  FROM emp;  --這裏的 emp 表就是一張普通的僱員表

可以從執行日誌看到 CTAS 觸發 MapReduce 操作,且 Reducer 數量和建表時候指定 bucket 數量一致。

分區和分桶結合使用
    分區表和分桶表的本質都是將數據按照不同粒度進行拆分,從而使得在查詢時候不必掃描全表,只需要掃描對應的分區或分桶,從而提升查詢效率。桶是更爲細粒度的數據範圍劃分,兩者可以結合起來使用,從而保證表數據在不同粒度上都能得到合理的拆分。舉個例子:

Create table hive_test(
    id  bigint  comment’編號’,(ps:comment爲註釋)
    name string comment’姓名’
)comment’員工表’
Partitioned by(pdate string)
Clustered by(id)     按id分桶,自動哈希分桶
Sorted by(id)   按id排序
Into 4 buckets   分成4個桶
Row format delimited 設置創建的表在加載數據的時候,支持的列分隔符
Fields terminated by ‘\t’  每個字段按\t分割
Lines terminated by’\n’ stored as textfile; 按\n爲斷行符,指定導入的文件爲純文本
查看錶的結構:
hive> hadoop -ls /user/hive/warehouse/hive_test; 
將顯示有4個新建的文件。文件名如下(文件名包含時間戳,由Hive產生,因此 每次運行都會改變): 
attempt_201701221636_0016_r_000000_0 
attempt_201701221636_0016_r-000001_0 
attempt_201701221636_0016_r_000002_0 
attempt_201701221636_0016_r_000003_0 
第一個桶裏包括用戶ID和4,因爲一個INT的哈希值就是這個整數本身,在這裏 除以桶數(4)以後的餘數:2
讀取數據,看每一個文件的數據:
hive> dfs -cat /user/hive/warehouse/hive_test/*0_0; 
0 Nat 
4 Ann 
用TABLESAMPLE子句對錶進行取樣,我們可以獲得相同的結果。這個子句會將 查詢限定在表的一部分桶內,而不是使用整個表:
. 對桶中的數據進行採樣:
hive> SELECT * FROM hive_test 
>TABLESAMPLE(BUCKET 1 OUT OF 4 ON id); 
0 Nat 
4 Ann 
桶的個數從1開始計數。因此,前面的查詢從4個桶的第一個中獲取所有的用戶。對於一個大規模的、均勻分佈的數據集,這會返回表中約四分之一的數據行。我們 也可以用其他比例對若干個桶進行取樣(因爲取樣並不是一個精確的操作,因此這個 比例不一定要是桶數的整數倍)。例如,下面的查詢返回一半的桶:
7. 查詢一半返回的桶數:
hive> SELECT * FROM hive_test
>    TABLESAMPLE(BUCKET 1 OUT OF 2 ON id)0 Nat 
4 Ann 
2 Joe 
因爲查詢只需要讀取和TABLESAMPLE子句匹配的桶,所以取樣分桶表是非常高效的操作。如果使用rand()函數對沒有劃分成桶的表進行取樣,即使只需要讀取很小一部分樣本,也要掃描整個輸入數據集: 
hive〉 SELECT * FROM hive_test
> TABLESAMPLE(BUCKET 1 OUT OF 4 ON rand()); 
2 Doe  

視圖

Hive 中的視圖和 RDBMS 中視圖的概念一致,都是一組數據的邏輯表示,本質上就是 SELECT 語句的結果集。視圖是純粹的邏輯對象,沒有關聯的存儲 ,當查詢引用視圖時,Hive 可以將視圖的定義與查詢結合起來,例如將查詢中的過濾器推送到視圖中。創建視圖語句:

CREATE VIEW [IF NOT EXISTS] [db_name.]view_name   -- 視圖名稱
  [(column_name [COMMENT column_comment], ...) ]    --列名
  [COMMENT view_comment]  --視圖註釋
  [TBLPROPERTIES (property_name = property_value, ...)]  --額外信息
  AS SELECT ...;

視圖使用中需要注意以下幾點:

  • 視圖是隻讀的,不能用作 LOAD / INSERT / ALTER 的目標;
  • 在創建視圖時候視圖就已經固定,對基表的後續更改(如添加列)將不會反映在視圖;
  • 刪除基表並不會刪除視圖,需要手動刪除視圖;
  • 視圖可能包含 ORDER BY 和 LIMIT 子句。如果引用視圖的查詢語句也包含這類子句,其執行優先級低於視圖對應字句。

索引

    Hive 在 0.7.0 引入了索引的功能,索引的設計目標是提高表某些列的查詢速度。如果沒有索引,帶有where的查詢(如’WHERE table.column = 100’)會加載整個表或分區並處理所有行。但是如果 column 存在索引,則只需要加載和處理文件的一部分。
在指定列上建立索引,會產生一張索引表,表結構如下:

+--------------+----------------+----------+--+
|   col_name   |   data_type    | comment     |
+--------------+----------------+----------+--+
| empno        | int            |  建立索引的列  |   
| _bucketname  | string         |  HDFS 文件路徑  |
| _offsets     | array<bigint>  |  偏移量       |
+--------------+----------------+----------+--+

    表裏面的字段包括:索引列的值、該值對應的 HDFS 文件路徑、該值在文件中的偏移量。在查詢涉及到索引字段時,首先到索引表查找索引列值對應的 HDFS 文件路徑及偏移量,這樣就避免了全表掃描。
創建索引語句如下:

CREATE INDEX index_name     --索引名稱
  ON TABLE base_table_name (col_name, ...)  --建立索引的列
  AS index_type    --索引類型
  [WITH DEFERRED REBUILD]    --重建索引
  [IDXPROPERTIES (property_name=property_value, ...)]  --索引額外屬性
  [IN TABLE index_table_name]    --索引表的名字
  [
     [ ROW FORMAT ...] STORED AS ...  
     | STORED BY ...
  ]   --索引錶行分隔符 、 存儲格式
  [LOCATION hdfs_path]  --索引表存儲位置
  [TBLPROPERTIES (...)]   --索引表表屬性
  [COMMENT "index comment"];  --索引註釋

    索引雖然增加了查詢速度,但是有一個缺陷在於:索引表無法自動 rebuild,這也就意味着如果表中有數據新增或刪除,則必須手動 rebuild,重新執行MapReduce 作業,生成索引表數據。同時按照官方文檔 的說明,Hive 會從 3.0 開始移除索引功能,主要基於以下兩個原因:

  • 具有自動重寫的物化視圖 (Materialized View) 可以產生與索引相似的效果(Hive 2.3.0 增加了對物化視圖的支持,在3.0 之後正式引入)
  • 使用列式存儲文件格式進行存儲時,這些格式支持選擇性掃描,可以跳過不需要的文件或塊,索引的必要性就大大降低了

常用的Hsql命令

beeline -u jdbc:hive2://localhost:10000  -n username -p password   --連接
show databases;
use databasename;
drop database databasename;
show tables;
use tablename;
desc tablename;  --查看錶結構信息
desc formatted tablesname;   --格式化表的結構信息,信息更詳細,包括在hdfs的存儲位置
select *from tablename;
drop table tablename;
truncate table tablename;   --清空表數據
load data local inpath '/home/myDatabase/data/org_info.txt' overwrite into table myDatabase.org_info ;  -- 從文件中導入數據到表中
SHOW FORMATTED INDEX ON table_name; --顯示錶上所有列的索引
hadoop -ls hdfs://crmhdp001/user/tjtel/cep_rule_result  --查看hive在hdfs上的數據文件

參考《Hadoop 權威指南》

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