Hive 體系結構介紹
阿新 • • 發佈:2018-05-21
led 一個 base 可擴展性 ask back pan 二進制格式 bject
(2)多用戶模式。通過網絡連接到一個數據庫中,是最經常使用到的模式。
Hive的數據模型介紹如下:
(1)Hive數據庫 類似傳統數據庫的DataBase,在第三方數據庫裏實際是一張表。簡單示例命令行 hive > create database test_database; (2)內部表 Hive的內部表與數據庫中的Table在概念上是類似。每一個Table在Hive中都有一個相應的目錄存儲數據。例如一個表pvs,它在HDFS中的 路徑為/wh/pvs,其中wh是在hive-site.xml中由${hive.metastore.warehouse.dir} 指定的數據倉庫的目錄,所有的Table數據(不包括External Table)都保存在這個目錄中。刪除表時,元數據與數據都會被刪除。
內部表簡單示例:
創建數據文件:test_inner_table.txt 創建表:create table test_inner_table (key string)
加載數據:LOAD DATA LOCAL INPATH ‘filepath’ INTO TABLE test_inner_table
查看數據:select * from test_inner_table; select count(*) from test_inner_table
刪除表:drop table test_inner_table (3)外部表 外部表指向已經在HDFS中存在的數據,可以創建Partition。它和內部表在元數據的組織上是相同的,而實際數據的存儲則有較大的差異。內部表的創 建過程和數據加載過程這兩個過程可以分別獨立完成,也可以在同一個語句中完成,在加載數據的過程中,實際數據會被移動到數據倉庫目錄中;之後對數據對訪問 將會直接在數據倉庫目錄中完成。刪除表時,表中的數據和元數據將會被同時刪除。而外部表只有一個過程,加載數據和創建表同時完成(CREATE EXTERNAL TABLE ……LOCATION),實際數據是存儲在LOCATION後面指定的 HDFS 路徑中,並不會移動到數據倉庫目錄中。當刪除一個External Table時,僅刪除該鏈接。
外部表簡單示例:
創建數據文件:test_external_table.txt
創建表:create external table test_external_table (key string)
加載數據:LOAD DATA INPATH ‘filepath’ INTO TABLE test_inner_table
查看數據:select * from test_external_table; •select count(*) from test_external_table
刪除表:drop table test_external_table
(4)分區 Partition對應於數據庫中的Partition列的密集索引,但是Hive中Partition的組織方式和數據庫中的很不相同。在Hive中, 表中的一個Partition對應於表下的一個目錄,所有的Partition的數據都存儲在對應的目錄中。例如pvs表中包含ds和city兩個 Partition,則對應於ds = 20090801, ctry = US 的HDFS子目錄為/wh/pvs/ds=20090801/ctry=US;對應於 ds = 20090801, ctry = CA 的HDFS子目錄為/wh/pvs/ds=20090801/ctry=CA。 分區表簡單示例:
創建數據文件:test_partition_table.txt
創建表:create table test_partition_table (key string) partitioned by (dt string)
加載數據:LOAD DATA INPATH ‘filepath’ INTO TABLE test_partition_table partition (dt=‘2006’)
查看數據:select * from test_partition_table; select count(*) from test_partition_table
刪除表:drop table test_partition_table (5)桶 Buckets是將表的列通過Hash算法進一步分解成不同的文件存儲。它對指定列計算hash,根據hash值切分數據,目的是為了並行,每一個 Bucket對應一個文件。例如將user列分散至32個bucket,首先對user列的值計算hash,對應hash值為0的HDFS目錄為/wh /pvs/ds=20090801/ctry=US/part-00000;hash值為20的HDFS目錄為/wh/pvs/ds=20090801 /ctry=US/part-00020。如果想應用很多的Map任務這樣是不錯的選擇。
桶的簡單示例:
創建數據文件:test_bucket_table.txt
創建表:create table test_bucket_table (key string) clustered by (key) into 20 buckets
加載數據:LOAD DATA INPATH ‘filepath’ INTO TABLE test_bucket_table
查看數據:select * from test_bucket_table; set hive.enforce.bucketing = true;
(6)Hive的視圖
視圖與傳統數據庫的視圖類似。視圖是只讀的,它基於的基本表,如果改變,數據增加不會影響視圖的呈現;如果刪除,會出現問題。•如果不指定視圖的列,會根據select語句後的生成。
示例:create view test_view as select * from test
圖2.1 Hive的執行原理
Hive構建在Hadoop之上,
(1)HQL中對查詢語句的解釋、優化、生成查詢計劃是由Hive完成的
(2)所有的數據都是存儲在Hadoop中
(3)查詢計劃被轉化為MapReduce任務,在Hadoop中執行(有些查詢沒有MR任務,如:select * from table)
(4)Hadoop和Hive都是用UTF-8編碼的 Hive編譯器將一個Hive QL轉換操作符。操作符Operator是Hive的最小的處理單元,每個操作符代表HDFS的一個操作或者一道MapReduce作業。Operator都是hive定義的一個處理過程,其定義有:
protected List <Operator<? extends Serializable >> childOperators;
protected List <Operator<? extends Serializable >> parentOperators;
protected boolean done; // 初始化值為false 所有的操作構成了Operator圖,hive正是基於這些圖關系來處理諸如limit, group by, join等操作。
圖2.2 Hive QL的操作符
操作符如下:
TableScanOperator:掃描hive表數據
ReduceSinkOperator:創建將發送到Reducer端的<Key,Value>對
JoinOperator:Join兩份數據
SelectOperator:選擇輸出列
FileSinkOperator:建立結果數據,輸出至文件
FilterOperator:過濾輸入數據
GroupByOperator:GroupBy語句
MapJoinOperator:/*+mapjoin(t) */
LimitOperator:Limit語句
UnionOperator:Union語句
Hive通過ExecMapper和ExecReducer執行MapReduce任務。在執行MapReduce時有兩種模式,即本地模式和分布式模式 。 Hive編譯器的組成:
圖2.3 Hive編譯器的組成
編譯流程如下:
圖2.4 Hive QL編譯流程
3、Hive和數據庫的異同
由於Hive采用了SQL的查詢語言HQL,因此很容易將Hive理解為數據庫。其實從結構上來看,Hive和數據庫除了擁有類似的查詢語言,再無類似之 處。數據庫可以用在Online的應用中,但是Hive是為數據倉庫而設計的,清楚這一點,有助於從應用角度理解Hive的特性。
Hive和數據庫的比較如下表:
啟動derby數據庫:/home/admin/caona/hive/build/dist/,運行startNetworkServer -h 0.0.0.0。 連接Derby數據庫進行測試:查看/home/admin/caona/hive/build/dist/conf/hive-default.xml。找到
輸入:./ij Connect ‘jdbc:derby://hadoop1:1527/metastore_db;create=true‘;
hive元數據對應的表約有20個,其中和表結構信息有關的有9張,其余的10多張或為空,或只有簡單的幾條記錄,以下是部分主要表的簡要說明。
(3)LIKE允許用戶復制現有的表結構,但是不復制數據。
(4)用戶在建表的時候可以自定義SerDe或者使用自帶的 SerDe ( Serialize/Deserilize 的簡稱,目的是用於序列化和反序列化 )。如果沒有指定 ROW FORMAT 或者 ROW FORMAT DELIMITED,將會使用自帶的SerDe。在建表的時候,用戶還需要為表指定列,用戶在指定表的列的同時也會指定自定義的SerDe,Hive通過 SerDe確定表的具體的列的數據。
(5)如果文件數據是純文本,可以使用STORED AS TEXTFILE。如果數據需要壓縮,使用STORED AS SEQUENCE。
(6)有分區的表可以在創建的時候使用 PARTITIONED BY語句。一個表可以擁有一個或者多個分區,每一個分區單獨存在一個目錄下。而且,表和分區都可以對某個列進行CLUSTERED BY操作,將若幹個列放入一個桶(bucket)中。也可以利用SORT BY對數據進行排序。這樣可以為特定應用提高性能。
(7)表名和列名不區分大小寫,SerDe和屬性名區分大小寫。表和列的註釋是字符串。
Alter Table語句:主要功能包括Add Partitions, Drop Partitions, Rename Table, Change Column, Add/Replace Columns。 Create View語句:創建視圖。格式CREATE VIEW [IF NOT EXISTS] view_name [ (column_name [COMMENT column_comment], ...) ] Show語句:Show tables; Show partitions; describe查看表結構。
Load語句:HIVE裝載數據時沒有做任何轉換,加載到表中的數據只是進入相應的配置單元表的位置。Load操作只是單純的復制/移動操作,將數據文件移動到Hive表對應的位置。 Insert語句:插入數據。Hive不支持一條一條的用 insert 語句進行插入操作,這個應該是與hive的storage layer是有關系的,因為它的存儲層是HDFS,插入一個數據要全表掃描,還不如用整個表的替換來的快些。Hive也不支持update的操作。數據是 以load的方式,加載到建立好的表中。數據一旦導入,則不可修改。要麽drop掉整個表,要麽建立新的表,導入新的數據。 Drop語句:刪除一個內部表的同時會同時刪除表的元數據和數據。刪除一個外部表,只刪除元數據而保留數據。
Limit子句:可以限制查詢的記錄數。查詢的結果是隨機選擇的。下面的查詢語句從 t1 表中隨機查詢5條記錄,SELECT * FROM t1 LIMIT 5。 Top K查詢:下面的查詢語句查詢銷售記錄最大的 5 個銷售代表。
(3)join 時,每次 map/reduce 任務的邏輯: reducer 會緩存 join 序列中除了最後一個表的所有表的記錄, 再通過最後一個表將結果序列化到文件系統。這一實現有助於在reduce端減少內存的使用量。實踐中,應該把最大的那個表寫在最後(否則會因為緩存浪費大 量內存)。
(4)LEFT,RIGHT 和 FULL OUTER 關鍵字用於處理 join 中空記錄的情況。 (5)LEFT SEMI JOIN 是 IN/EXISTS 子查詢的一種更高效的實現。Hive 當前沒有實現 IN/EXISTS 子查詢,所以你可以用 LEFT SEMI JOIN 重寫你的子查詢語句。LEFT SEMI JOIN的限制是, JOIN子句中右邊的表只能在ON子句中設置過濾條件,在WHERE子句、SELECT子句或其他地方過濾都不行。
6、使用HIVE註意點
(1)字符集
Hadoop和Hive都是用UTF-8編碼的,所以, 所有中文必須是UTF-8編碼, 才能正常使用。
備註:中文數據load到表裏面,,如果字符集不同,很有可能全是亂碼需要做轉碼的,但是hive本身沒有函數來做這個。
(2)壓縮
hive.exec.compress.output 這個參數,默認是false,但是很多時候貌似要單獨顯式設置一遍,否則會對結果做壓縮的,如果你的這個文件後面還要在hadoop下直接操作,那麽就不能壓縮了。
(3)count(distinct)
當前的Hive不支持在一條查詢語句中有多Distinct。如果要在Hive查詢語句中實現多Distinct,需要使用至少n+1條查詢語句(n為 distinct的數目),前n條查詢分別對n個列去重,最後一條查詢語句對n個去重之後的列做Join操作,得到最終結果。
(4)JOIN
只支持等值連接
(5)DML操作
只支持INSERT/LOAD操作,無UPDATE和DELTE
(6)HAVING
不支持HAVING操作。如果需要這個功能要嵌套一個子查詢用where限制
(7)子查詢
Hive不支持where子句中的子查詢
(8)Join中處理null值的語義區別
SQL標準中,任何對null的操作(數值比較,字符串操作等)結果都為null。Hive對null值處理的邏輯和標準基本一致,除了Join時的特殊 邏輯。這裏的特殊邏輯指的是,Hive的Join中,作為Join key的字段比較,null=null是有意義的,且返回值為true。 (9)分號字符
分號是SQL語句結束標記,在HiveQL中也是,但是在HiveQL中,對分號的識別沒有那麽智慧,例如:
* 內存中的數據格式: Java Integer/String, Hadoop IntWritable/Text
* 用戶提供的map/reduce腳本:不管什麽語言,利用stdin/stdout傳輸數據
* 用戶自定義函數:Substr, Trim, 1 – 1
* 用戶自定義聚合函數:Sum, Average…… n – 1 (1)數據文件格式
例如使用文件文件格式存儲創建的表:
SerDe是Serialize/Deserilize的簡稱,目的是用於序列化和反序列化。序列化的格式包括:分隔符(tab、逗號、CTRL-A)、Thrift 協議
反序列化(內存內):Java Integer/String/ArrayList/HashMap、Hadoop Writable類、用戶自定義類
其中,LazyObject只有在訪問到列的時候才進行反序列化。 BinarySortable保留了排序的二進制格式。
當存在以下情況時,可以考慮增加新的SerDe: * 用戶的數據有特殊的序列化格式,當前的Hive不支持,而用戶又不想在將數據加載至Hive前轉換數據格式。
* 用戶有更有效的序列化磁盤數據的方法。 用戶如果想為Text數據增加自定義Serde,可以參照contrib/src/java/org/apache/hadoop/hive /contrib/serde2/RegexSerDe.java中的例子。RegexSerDe利用用戶提供的正則表倒是來反序列化數據,例如:
用戶可以自定義Hive使用的Map/Reduce腳本,比如:
用戶可以自定義函數對數據進行處理,例如:
* Hadoop的Writables/Text 具有較高性能。
* UDF可以被重載。
* Hive支持隱式類型轉換。
* UDF支持變長的參數。
* genericUDF 提供了較好的性能(避免了反射)。 (5)UDAF(User-Defined Aggregation Funcation)
例子:
下面是Hive的架構圖。 圖1.1 Hive體系結構 Hive的體系結構可以分為以下幾部分: (1)用戶接口主要有三個:CLI,Client 和 WUI。其中最常用的是CLI,Cli啟動的時候,會同時啟動一個Hive副本。Client是Hive的客戶端,用戶連接至Hive Server。在啟動 Client模式的時候,需要指出Hive Server所在節點,並且在該節點啟動Hive Server。 WUI是通過瀏覽器訪問Hive。 (2)Hive將元存儲在數據庫中,如mysql、derby。Hive中的元數據包括表的名字,表的列和分區及其屬性,表的屬性(是否為外部表等),表的數據所在目錄等。 (3)解釋器、編譯器、優化器完成HQL查詢語句從詞法分析、語法分析、編譯、優化以及查詢計劃的生成。生成的查詢計劃存儲在HDFS中,並在隨後有MapReduce調用執行。 (4)Hive的數據存儲在HDFS中,大部分的查詢、計算由MapReduce完成(包含*的查詢,比如select * from tbl不會生成MapRedcue任務)。 Hive將元數據存儲在RDBMS中,
(2)多用戶模式。通過網絡連接到一個數據庫中,是最經常使用到的模式。
(1)Hive數據庫 類似傳統數據庫的DataBase,在第三方數據庫裏實際是一張表。簡單示例命令行 hive > create database test_database; (2)內部表 Hive的內部表與數據庫中的Table在概念上是類似。每一個Table在Hive中都有一個相應的目錄存儲數據。例如一個表pvs,它在HDFS中的 路徑為/wh/pvs,其中wh是在hive-site.xml中由${hive.metastore.warehouse.dir} 指定的數據倉庫的目錄,所有的Table數據(不包括External Table)都保存在這個目錄中。刪除表時,元數據與數據都會被刪除。
創建數據文件:test_inner_table.txt 創建表:create table test_inner_table (key string)
加載數據:LOAD DATA LOCAL INPATH ‘filepath’ INTO TABLE test_inner_table
查看數據:select * from test_inner_table; select count(*) from test_inner_table
刪除表:drop table test_inner_table (3)外部表 外部表指向已經在HDFS中存在的數據,可以創建Partition。它和內部表在元數據的組織上是相同的,而實際數據的存儲則有較大的差異。內部表的創 建過程和數據加載過程這兩個過程可以分別獨立完成,也可以在同一個語句中完成,在加載數據的過程中,實際數據會被移動到數據倉庫目錄中;之後對數據對訪問 將會直接在數據倉庫目錄中完成。刪除表時,表中的數據和元數據將會被同時刪除。而外部表只有一個過程,加載數據和創建表同時完成(CREATE EXTERNAL TABLE ……LOCATION),實際數據是存儲在LOCATION後面指定的 HDFS 路徑中,並不會移動到數據倉庫目錄中。當刪除一個External Table時,僅刪除該鏈接。
外部表簡單示例:
創建數據文件:test_external_table.txt
創建表:create external table test_external_table (key string)
加載數據:LOAD DATA INPATH ‘filepath’ INTO TABLE test_inner_table
查看數據:select * from test_external_table; •select count(*) from test_external_table
刪除表:drop table test_external_table
(4)分區 Partition對應於數據庫中的Partition列的密集索引,但是Hive中Partition的組織方式和數據庫中的很不相同。在Hive中, 表中的一個Partition對應於表下的一個目錄,所有的Partition的數據都存儲在對應的目錄中。例如pvs表中包含ds和city兩個 Partition,則對應於ds = 20090801, ctry = US 的HDFS子目錄為/wh/pvs/ds=20090801/ctry=US;對應於 ds = 20090801, ctry = CA 的HDFS子目錄為/wh/pvs/ds=20090801/ctry=CA。 分區表簡單示例:
創建數據文件:test_partition_table.txt
創建表:create table test_partition_table (key string) partitioned by (dt string)
加載數據:LOAD DATA INPATH ‘filepath’ INTO TABLE test_partition_table partition (dt=‘2006’)
查看數據:select * from test_partition_table; select count(*) from test_partition_table
刪除表:drop table test_partition_table (5)桶 Buckets是將表的列通過Hash算法進一步分解成不同的文件存儲。它對指定列計算hash,根據hash值切分數據,目的是為了並行,每一個 Bucket對應一個文件。例如將user列分散至32個bucket,首先對user列的值計算hash,對應hash值為0的HDFS目錄為/wh /pvs/ds=20090801/ctry=US/part-00000;hash值為20的HDFS目錄為/wh/pvs/ds=20090801 /ctry=US/part-00020。如果想應用很多的Map任務這樣是不錯的選擇。
桶的簡單示例:
創建數據文件:test_bucket_table.txt
創建表:create table test_bucket_table (key string) clustered by (key) into 20 buckets
加載數據:LOAD DATA INPATH ‘filepath’ INTO TABLE test_bucket_table
查看數據:select * from test_bucket_table; set hive.enforce.bucketing = true;
(6)Hive的視圖
視圖與傳統數據庫的視圖類似。視圖是只讀的,它基於的基本表,如果改變,數據增加不會影響視圖的呈現;如果刪除,會出現問題。•如果不指定視圖的列,會根據select語句後的生成。
示例:create view test_view as select * from test
圖2.1 Hive的執行原理
Hive構建在Hadoop之上,
(1)HQL中對查詢語句的解釋、優化、生成查詢計劃是由Hive完成的
(2)所有的數據都是存儲在Hadoop中
(3)查詢計劃被轉化為MapReduce任務,在Hadoop中執行(有些查詢沒有MR任務,如:select * from table)
(4)Hadoop和Hive都是用UTF-8編碼的 Hive編譯器將一個Hive QL轉換操作符。操作符Operator是Hive的最小的處理單元,每個操作符代表HDFS的一個操作或者一道MapReduce作業。Operator都是hive定義的一個處理過程,其定義有:
protected List <Operator<? extends Serializable >> childOperators;
protected List <Operator<? extends Serializable >> parentOperators;
protected boolean done; // 初始化值為false 所有的操作構成了Operator圖,hive正是基於這些圖關系來處理諸如limit, group by, join等操作。
圖2.2 Hive QL的操作符
操作符如下:
TableScanOperator:掃描hive表數據
ReduceSinkOperator:創建將發送到Reducer端的<Key,Value>對
JoinOperator:Join兩份數據
SelectOperator:選擇輸出列
FileSinkOperator:建立結果數據,輸出至文件
FilterOperator:過濾輸入數據
GroupByOperator:GroupBy語句
MapJoinOperator:/*+mapjoin(t) */
LimitOperator:Limit語句
UnionOperator:Union語句
Hive通過ExecMapper和ExecReducer執行MapReduce任務。在執行MapReduce時有兩種模式,即本地模式和分布式模式 。 Hive編譯器的組成:
圖2.3 Hive編譯器的組成
編譯流程如下:
圖2.4 Hive QL編譯流程
3、Hive和數據庫的異同
由於Hive采用了SQL的查詢語言HQL,因此很容易將Hive理解為數據庫。其實從結構上來看,Hive和數據庫除了擁有類似的查詢語言,再無類似之 處。數據庫可以用在Online的應用中,但是Hive是為數據倉庫而設計的,清楚這一點,有助於從應用角度理解Hive的特性。
Hive和數據庫的比較如下表:
Hive
|
RDBMS | |
查詢語言 | HQL | SQL |
數據存儲 | HDFS | Raw Device or Local FS |
數據格式 | 用戶定義 | 系統決定 |
數據更新 | 不支持 | 支持 |
索引 | 無 | 有 |
執行 | MapReduce | Executor |
執行延遲 | 高 | 低 |
處理數據規模 | 大 | 小 |
可擴展性 | 高 | 低 |
4、Hive元數據庫
啟動derby數據庫:/home/admin/caona/hive/build/dist/,運行startNetworkServer -h 0.0.0.0。 連接Derby數據庫進行測試:查看/home/admin/caona/hive/build/dist/conf/hive-default.xml。找到
- <P style="TEXT-ALIGN: left; PADDING-BOTTOM: 0px; WIDOWS: 2; TEXT-TRANSFORM: none; BACKGROUND-COLOR: rgb(255,255,255); TEXT-INDENT: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; FONT: 14px/26px Arial; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: rgb(0,0,0); WORD-SPACING: 0px; PADDING-TOP: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"> </P>
輸入:./ij Connect ‘jdbc:derby://hadoop1:1527/metastore_db;create=true‘;
hive元數據對應的表約有20個,其中和表結構信息有關的有9張,其余的10多張或為空,或只有簡單的幾條記錄,以下是部分主要表的簡要說明。
表名 | 說明 | 關聯鍵 |
TBLS | 所有hive表的基本信息 | TBL_ID,SD_ID |
TABLE_PARAM | 表級屬性,如是否外部表,表註釋等 | TBL_ID |
COLUMNS | Hive表字段信息(字段註釋,字段名,字段類型,字段序號) | SD_ID |
SDS | 所有hive表、表分區所對應的hdfs數據目錄和數據格式 | SD_ID,SERDE_ID |
SERDE_PARAM | 序列化反序列化信息,如行分隔符、列分隔符、NULL的表示字符等 | SERDE_ID |
PARTITIONS | Hive表分區信息 | PART_ID,SD_ID,TBL_ID |
PARTITION_KEYS | Hive分區表分區鍵 | TBL_ID |
PARTITION_KEY_VALS | Hive表分區名(鍵值) | PART_ID |
從上面表的內容來看,hive整個創建表的過程已經比較清楚了。
(1)解析用戶提交hive語句,對其進行解析,分解為表、字段、分區等hive對象
(2)根據解析到的信息構建對應的表、字段、分區等對象,從 SEQUENCE_TABLE中獲取構建對象的最新ID,與構建對象信息(名稱,類型等)一同通過DAO方法寫入到元數據表中去,成功後將SEQUENCE_TABLE中對應的最新ID+5。
實際上我們常見的RDBMS都是通過這種方法進行組織的,典型的如postgresql,其系統表中和hive元數據一樣裸露了這些id信息
(oid,cid等),而Oracle等商業化的系統則隱藏了這些具體的ID。通過這些元數據我們可以很容易的讀到數據諸如創建一個表的數據字典信息,比
如導出建表語名等。
(3)LIKE允許用戶復制現有的表結構,但是不復制數據。
(4)用戶在建表的時候可以自定義SerDe或者使用自帶的 SerDe ( Serialize/Deserilize 的簡稱,目的是用於序列化和反序列化 )。如果沒有指定 ROW FORMAT 或者 ROW FORMAT DELIMITED,將會使用自帶的SerDe。在建表的時候,用戶還需要為表指定列,用戶在指定表的列的同時也會指定自定義的SerDe,Hive通過 SerDe確定表的具體的列的數據。
(5)如果文件數據是純文本,可以使用STORED AS TEXTFILE。如果數據需要壓縮,使用STORED AS SEQUENCE。
(6)有分區的表可以在創建的時候使用 PARTITIONED BY語句。一個表可以擁有一個或者多個分區,每一個分區單獨存在一個目錄下。而且,表和分區都可以對某個列進行CLUSTERED BY操作,將若幹個列放入一個桶(bucket)中。也可以利用SORT BY對數據進行排序。這樣可以為特定應用提高性能。
(7)表名和列名不區分大小寫,SerDe和屬性名區分大小寫。表和列的註釋是字符串。
Alter Table語句:主要功能包括Add Partitions, Drop Partitions, Rename Table, Change Column, Add/Replace Columns。 Create View語句:創建視圖。格式CREATE VIEW [IF NOT EXISTS] view_name [ (column_name [COMMENT column_comment], ...) ] Show語句:Show tables; Show partitions; describe查看表結構。
Load語句:HIVE裝載數據時沒有做任何轉換,加載到表中的數據只是進入相應的配置單元表的位置。Load操作只是單純的復制/移動操作,將數據文件移動到Hive表對應的位置。 Insert語句:插入數據。Hive不支持一條一條的用 insert 語句進行插入操作,這個應該是與hive的storage layer是有關系的,因為它的存儲層是HDFS,插入一個數據要全表掃描,還不如用整個表的替換來的快些。Hive也不支持update的操作。數據是 以load的方式,加載到建立好的表中。數據一旦導入,則不可修改。要麽drop掉整個表,要麽建立新的表,導入新的數據。 Drop語句:刪除一個內部表的同時會同時刪除表的元數據和數據。刪除一個外部表,只刪除元數據而保留數據。
Limit子句:可以限制查詢的記錄數。查詢的結果是隨機選擇的。下面的查詢語句從 t1 表中隨機查詢5條記錄,SELECT * FROM t1 LIMIT 5。 Top K查詢:下面的查詢語句查詢銷售記錄最大的 5 個銷售代表。
SET mapred.reduce.tasks = 1 SELECT * FROM sales SORT BY amount DESC LIMIT 5正則表達式使用:SELECT語句可以使用正則表達式做列選擇,下面的語句查詢除了ds和h 之外的所有列:
SELECT `(ds|hr)?+.+` FROM sales
SELECT語句:查詢數據。
Group by, Order by, Sort by子句:聚合可進一步分為多個表,甚至發送到 Hadoop 的 DFS 的文件(可以進行操作,然後使用HDFS的utilitites)。可以用hive.map.aggr控制怎麽進行匯總。默認為為true,配置單元會做 的第一級聚合直接在MAP上的任務。這通常提供更好的效率,但可能需要更多的內存來運行成功。 Join語句:連接操作。一些註意事項: (1)Hive只支持等值連接(equality joins)、外連接(outer joins)和(left/right joins)。Hive不支持所有非等值的連接,因為非等值連接非常難轉化到map/reduce任務。 (2)Hive 支持多於2個表的連接。(3)join 時,每次 map/reduce 任務的邏輯: reducer 會緩存 join 序列中除了最後一個表的所有表的記錄, 再通過最後一個表將結果序列化到文件系統。這一實現有助於在reduce端減少內存的使用量。實踐中,應該把最大的那個表寫在最後(否則會因為緩存浪費大 量內存)。
(4)LEFT,RIGHT 和 FULL OUTER 關鍵字用於處理 join 中空記錄的情況。 (5)LEFT SEMI JOIN 是 IN/EXISTS 子查詢的一種更高效的實現。Hive 當前沒有實現 IN/EXISTS 子查詢,所以你可以用 LEFT SEMI JOIN 重寫你的子查詢語句。LEFT SEMI JOIN的限制是, JOIN子句中右邊的表只能在ON子句中設置過濾條件,在WHERE子句、SELECT子句或其他地方過濾都不行。
6、使用HIVE註意點
(1)字符集
Hadoop和Hive都是用UTF-8編碼的,所以, 所有中文必須是UTF-8編碼, 才能正常使用。
備註:中文數據load到表裏面,,如果字符集不同,很有可能全是亂碼需要做轉碼的,但是hive本身沒有函數來做這個。
(2)壓縮
hive.exec.compress.output 這個參數,默認是false,但是很多時候貌似要單獨顯式設置一遍,否則會對結果做壓縮的,如果你的這個文件後面還要在hadoop下直接操作,那麽就不能壓縮了。
(3)count(distinct)
當前的Hive不支持在一條查詢語句中有多Distinct。如果要在Hive查詢語句中實現多Distinct,需要使用至少n+1條查詢語句(n為 distinct的數目),前n條查詢分別對n個列去重,最後一條查詢語句對n個去重之後的列做Join操作,得到最終結果。
(4)JOIN
只支持等值連接
(5)DML操作
只支持INSERT/LOAD操作,無UPDATE和DELTE
(6)HAVING
不支持HAVING操作。如果需要這個功能要嵌套一個子查詢用where限制
(7)子查詢
Hive不支持where子句中的子查詢
(8)Join中處理null值的語義區別
SQL標準中,任何對null的操作(數值比較,字符串操作等)結果都為null。Hive對null值處理的邏輯和標準基本一致,除了Join時的特殊 邏輯。這裏的特殊邏輯指的是,Hive的Join中,作為Join key的字段比較,null=null是有意義的,且返回值為true。 (9)分號字符
分號是SQL語句結束標記,在HiveQL中也是,但是在HiveQL中,對分號的識別沒有那麽智慧,例如:
select concat(cookie_id,concat(‘;‘,’zoo’)) from c02_clickstat_fatdt1 limit 2; FAILED: Parse Error: line 0:-1 cannot recognize input ‘<EOF>‘ in function specification
可以推斷,Hive解析語句的時候,只要遇到分號就認為語句結束,而無論是否用引號包含起來。
解決的辦法是,使用分號的八進制的ASCII碼進行轉義,那麽上述語句應寫成:select concat(cookie_id,concat(‘\073‘,‘zoo‘)) from c02_clickstat_fatdt1 limit 2;
為什麽是八進制ASCII碼?我嘗試用十六進制的ASCII碼,但Hive會將其視為字符串處理並未轉義,好像僅支持八進制,原因不詳。這個規則也適用於 其他非SELECT語句,如CREATE TABLE中需要定義分隔符,那麽對不可見字符做分隔符就需要用八進制的ASCII碼來轉義。
* 內存中的數據格式: Java Integer/String, Hadoop IntWritable/Text
* 用戶提供的map/reduce腳本:不管什麽語言,利用stdin/stdout傳輸數據
* 用戶自定義函數:Substr, Trim, 1 – 1
* 用戶自定義聚合函數:Sum, Average…… n – 1 (1)數據文件格式
TextFile | SequenceFIle | RCFFile | |
Data type | Text Only | Text/Binary | Text/Binary |
Internal Storage Order | Row-based | Row-based | Column-based |
Compression | File Based | Block Based | Block Based |
Splitable | YES | YES | YES |
Splitable After Compression | No | YES | YES |
CREATE TABLE mylog ( user_id BIGINT, page_url STRING, unix_time INT) STORED AS TEXTFILE;
當 用戶的數據文件格式不能被當前Hive所識別的時候,可以自定義文件格式。可以參考contrib/src/java/org/apache /hadoop/hive/contrib/fileformat/base64中的例子。寫完自定義的格式後,在創建表的時候指定相應的文件格式就可 以:
CREATE TABLE base64_test(col1 STRING, col2 STRING) STORED AS INPUTFORMAT ‘org.apache.hadoop.hive.contrib. fileformat.base64.Base64TextInputFormat‘ OUTPUTFORMAT ‘org.apache.hadoop.hive.contrib. fileformat.base64.Base64TextOutputFormat‘;
(2)SerDe
SerDe是Serialize/Deserilize的簡稱,目的是用於序列化和反序列化。序列化的格式包括:分隔符(tab、逗號、CTRL-A)、Thrift 協議
反序列化(內存內):Java Integer/String/ArrayList/HashMap、Hadoop Writable類、用戶自定義類
其中,LazyObject只有在訪問到列的時候才進行反序列化。 BinarySortable保留了排序的二進制格式。
當存在以下情況時,可以考慮增加新的SerDe: * 用戶的數據有特殊的序列化格式,當前的Hive不支持,而用戶又不想在將數據加載至Hive前轉換數據格式。
* 用戶有更有效的序列化磁盤數據的方法。 用戶如果想為Text數據增加自定義Serde,可以參照contrib/src/java/org/apache/hadoop/hive /contrib/serde2/RegexSerDe.java中的例子。RegexSerDe利用用戶提供的正則表倒是來反序列化數據,例如:
CREATE TABLE apache_log( host STRING, identity STRING, user STRING, time STRING, request STRING, status STRING, size STRING, referer STRING, agent STRING) ROW FORMAT SERDE ‘org.apache.hadoop.hive.contrib.serde2.RegexSerDe‘ WITH SERDEPROPERTIES ( "input.regex" = "([^ ]*) ([^ ]*) ([^ ]*) (-|\\[[^\\]]*\\]) ([^ \"]*|\"[^\"]*\") (-|[0-9]*) (-|[0-9]*)(?: ([^ \"]*|\"[^\"]*\") ([^ \"]*|\"[^\"]*\"))?", "output.format.string" = "%1$s %2$s %3$s %4$s %5$s %6$s %7$s %8$s %9$s";) STORED AS TEXTFILE;
用戶如果想為Binary數據增加自定義的SerDe,可以參考例子serde/src/java/org/apache/hadoop/hive/serde2/binarysortable,例如:
CREATE TABLE mythrift_table ROW FORMAT SERDE ‘org.apache.hadoop.hive.contrib.serde2.thrift.ThriftSerDe‘ WITH SERDEPROPERTIES ( "serialization.class" = "com.facebook.serde.tprofiles.full", "serialization.format" = "com.facebook.thrift.protocol.TBinaryProtocol";);
(3)Map/Reduce腳本(Transform)
用戶可以自定義Hive使用的Map/Reduce腳本,比如:
FROM ( SELECT TRANSFORM(user_id, page_url, unix_time) USING ‘page_url_to_id.py‘ AS (user_id, page_id, unix_time) FROM mylog DISTRIBUTE BY user_id SORT BY user_id, unix_time) mylog2 SELECT TRANSFORM(user_id, page_id, unix_time) USING ‘my_python_session_cutter.py‘ AS (user_id, session_info);
Map/Reduce腳本通過stdin/stdout進行數據的讀寫,調試信息輸出到stderr。
(4)UDF(User-Defined-Function)用戶可以自定義函數對數據進行處理,例如:
<P>[sql]</P> <P>add jar build/ql/test/test-udfs.jar; CREATE TEMPORARY FUNCTION testlength AS ‘org.apache.hadoop.hive.ql.udf.UDFTestLength‘; SELECT testlength(src.value) FROM src; DROP TEMPORARY FUNCTION testlength;</P>
UDFTestLength.java為:
package org.apache.hadoop.hive.ql.udf; public class UDFTestLength extends UDF { public Integer evaluate(String s) { if (s == null) { return null; } return s.length(); } }
UDF 具有以下特性: * 用java寫UDF很容易。
* Hadoop的Writables/Text 具有較高性能。
* UDF可以被重載。
* Hive支持隱式類型轉換。
* UDF支持變長的參數。
* genericUDF 提供了較好的性能(避免了反射)。 (5)UDAF(User-Defined Aggregation Funcation)
例子:
<P>[sql]</P> <P>SELECT page_url, count(1), count(DISTINCT user_id) FROM mylog;</P>UDAFCount.java代碼如下:
1 public class UDAFCount extends UDAF { 2 public static class Evaluator implements UDAFEvaluator { 3 private int mCount; 4 5 public void init() { 6 mcount = 0; 7 } 8 9 public boolean iterate(Object o) { 10 if (o!=null) 11 mCount++; 12 13 return true; 14 } 15 16 public Integer terminatePartial() { 17 return mCount; 18 } 19 20 public boolean merge(Integer o) { 21 mCount += o; 22 return true; 23 } 24 25 public Integer terminate() { 26 return mCount; 27 } 28 }
Hive 體系結構介紹