14、Hive壓縮、存儲原理詳解與實戰

在這裏插入圖片描述

1、Hive 壓縮

1.1數據壓縮說明

壓縮模式評價:

(1)壓縮比

(2)壓縮時間

(3)已經壓縮的是否可以再分割;可以分割的格式允許單一文件有多個Mapper程序處理,纔可以更好的並行化。

Hadoop編碼/解碼器方式:

1.2數據壓縮使用

  • 壓縮模式評價

    • 可使用以下三種標準對壓縮方式進行評價
    • 1、壓縮比:壓縮比越高,壓縮後文件越小,所以壓縮比越高越好
    • 2、壓縮時間:越快越好
    • 3、已經壓縮的格式文件是否可以再分割:可以分割的格式允許單一文件由多個Mapper程序處理,可以更好的並行化
  • 常見壓縮格式
壓縮方式 壓縮比 壓縮速度 解壓縮速度 是否可分割
gzip 13.4% 21 MB/s 118 MB/s
bzip2 13.2% 2.4MB/s 9.5MB/s
lzo 20.5% 135 MB/s 410 MB/s
snappy 22.2% 172 MB/s 409 MB/s

Hadoop編碼/解碼器方式

壓縮格式 對應的編碼/解碼器
DEFLATE org.apache.hadoop.io.compress.DefaultCodec
Gzip org.apache.hadoop.io.compress.GzipCodec
BZip2 org.apache.hadoop.io.compress.BZip2Codec
LZO com.hadoop.compress.lzo.LzopCodec
Snappy org.apache.hadoop.io.compress.SnappyCodec

1.3、壓縮配置參數

要在Hadoop中啓用壓縮,可以配置如下參數(mapred-site.xml文件中):

參數 默認值 階段 建議
io.compression.codecs (在core-site.xml中配置) org.apache.hadoop.io.compress.DefaultCodec, org.apache.hadoop.io.compress.GzipCodec, org.apache.hadoop.io.compress.BZip2Codec, org.apache.hadoop.io.compress.Lz4Codec 輸入壓縮 Hadoop使用文件擴展名判斷是否支持某種編解碼器
mapreduce.map.output.compress false mapper輸出 這個參數設爲true啓用壓縮
mapreduce.map.output.compress.codec org.apache.hadoop.io.compress.DefaultCodec mapper輸出 使用LZO、LZ4或snappy編解碼器在此階段壓縮數據
mapreduce.output.fileoutputformat.compress false reducer輸出 這個參數設爲true啓用壓縮
mapreduce.output.fileoutputformat.compress.codec org.apache.hadoop.io.compress. DefaultCodec reducer輸出 使用標準工具或者編解碼器,如gzip和bzip2
mapreduce.output.fileoutputformat.compress.type RECORD reducer輸出 SequenceFile輸出使用的壓縮類型:NONE和BLOCK

1.4、開啓Map輸出階段壓縮

開啓map輸出階段壓縮可以減少job中map和Reduce task間數據傳輸量。具體配置如下:

案例實操:

1)開啓hive中間傳輸數據壓縮功能
hive (default)>set hive.exec.compress.intermediate=true;

2)開啓mapreduce中map輸出壓縮功能
hive (default)>set mapreduce.map.output.compress=true;

3)設置mapreduce中map輸出數據的壓縮方式
hive (default)>set mapreduce.map.output.compress.codec= org.apache.hadoop.io.compress.SnappyCodec;

4)執行查詢語句
select count(1) from score;

1.5、開啓Reduce輸出階段壓縮

當Hive將輸出寫入到表中時,輸出內容同樣可以進行壓縮。屬性hive.exec.compress.output控制着這個功能。用戶可能需要保持默認設置文件中的默認值false,這樣默認的輸出就是非壓縮的純文本文件了。用戶可以通過在查詢語句或執行腳本中設置這個值爲true,來開啓輸出結果壓縮功能。

1)開啓hive最終輸出數據壓縮功能
hive (default)>set hive.exec.compress.output=true;

2)開啓mapreduce最終輸出數據壓縮
hive (default)>set mapreduce.output.fileoutputformat.compress=true;

3)設置mapreduce最終數據輸出壓縮方式
hive (default)> set mapreduce.output.fileoutputformat.compress.codec = org.apache.hadoop.io.compress.SnappyCodec;

4)設置mapreduce最終數據輸出壓縮爲塊壓縮
hive (default)>set mapreduce.output.fileoutputformat.compress.type=BLOCK;

5)測試一下輸出結果是否是壓縮文件
insert overwrite local directory '/kkb/install/hivedatas/snappy' select * from score distribute by s_id sort by s_id desc;

2、Hive 存儲

2.1、hive表的文件存儲格式

Hive支持的存儲數的格式主要有:TEXTFILE(行式存儲) 、SEQUENCEFILE(行式存儲)、ORC(列式存儲)、PARQUET(列式存儲)。

1、列式存儲和行式存儲

在這裏插入圖片描述
上圖左邊爲邏輯表,右邊第一個爲行式存儲,第二個爲列式存儲。

行存儲的特點: 查詢滿足條件的一整行數據的時候,列存儲則需要去每個聚集的字段找到對應的每個列的值,行存儲只需要找到其中一個值,其餘的值都在相鄰地方,所以此時行存儲查詢的速度更快。select *

列存儲的特點: 因爲每個字段的數據聚集存儲,在查詢只需要少數幾個字段的時候,能大大減少讀取的數據量;每個字段的數據類型一定是相同的,列式存儲可以針對性的設計更好的設計壓縮算法。select某些字段效率更高

TEXTFILE和SEQUENCEFILE的存儲格式都是基於行存儲的;

ORC和PARQUET是基於列式存儲的。

2.1.1、TEXTFILE格式

默認格式,數據不做壓縮,磁盤開銷大,數據解析開銷大。可結合Gzip、Bzip2使用(系統自動檢查,執行查詢時自動解壓),但使用這種方式,hive不會對數據進行切分,從而無法對數據進行並行操作。

2.1.2、ORC格式

Orc (Optimized Row Columnar)是hive 0.11版裏引入的新的存儲格式。

可以看到每個Orc文件由1個或多個stripe組成,每個stripe250MB大小,這個Stripe實際相當於RowGroup概念,不過大小由4MB->250MB,這樣能提升順序讀的吞吐率。每個Stripe裏有三部分組成,分別是Index Data,Row Data,Stripe Footer:
在這裏插入圖片描述
一個orc文件可以分爲若干個Stripe

一個stripe可以分爲三個部分

indexData:某些列的索引數據

rowData :真正的數據存儲

StripFooter:stripe的元數據信息

1)Index Data:一個輕量級的index,默認是每隔1W行做一個索引。這裏做的索引只是記錄某行的各字段在Row Data中的offset。

​ 2)Row Data:存的是具體的數據,先取部分行,然後對這些行按列進行存儲。對每個列進行了編碼,分成多個Stream來存儲。

​ 3)Stripe Footer:存的是各個stripe的元數據信息

每個文件有一個File Footer,這裏面存的是每個Stripe的行數,每個Column的數據類型信息等;每個文件的尾部是一個PostScript,這裏面記錄了整個文件的壓縮類型以及FileFooter的長度信息等。在讀取文件時,會seek到文件尾部讀PostScript,從裏面解析到File Footer長度,再讀FileFooter,從裏面解析到各個Stripe信息,再讀各個Stripe,即從後往前讀。

2.1.3、PARQUET格式

Parquet是面向分析型業務的列式存儲格式,由Twitter和Cloudera合作開發,2015年5月從Apache的孵化器裏畢業成爲Apache頂級項目。

Parquet文件是以二進制方式存儲的,所以是不可以直接讀取的,文件中包括該文件的數據和元數據,因此Parquet格式文件是自解析的。

通常情況下,在存儲Parquet數據的時候會按照Block大小設置行組的大小,由於一般情況下每一個Mapper任務處理數據的最小單位是一個Block,這樣可以把每一個行組由一個Mapper任務處理,增大任務執行並行度。Parquet文件的格式如下圖所示。

2.2、主流文件存儲格式對比實驗

從存儲文件的壓縮比和查詢速度兩個角度對比。

存儲文件的壓縮比測試:

測試數據 參見log.data

1)TextFile

(1)創建表,存儲數據格式爲TEXTFILE

use myhive;
create table log_text (
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS TEXTFILE ;

(2)向表中加載數據

load data local inpath '/kkb/install/hivedatas/log.data' into table log_text ;

(3)查看錶中數據大小,大小爲18.1M

dfs -du -h /user/hive/warehouse/myhive.db/log_text;
18.1 M  /user/hive/warehouse/log_text/log.data
2)ORC

(1)創建表,存儲數據格式爲ORC

create table log_orc(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS orc ;

(2)向表中加載數據

insert into table log_orc select * from log_text ;

(3)查看錶中數據大小

dfs -du -h /user/hive/warehouse/myhive.db/log_orc;

2.8 M  /user/hive/warehouse/log_orc/123456_0

orc這種存儲格式,默認使用了zlib壓縮方式來對數據進行壓縮,所以數據會變成了2.8M,非常小

3)Parquet

(1)創建表,存儲數據格式爲parquet

create table log_parquet(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS PARQUET ;  

(2)向表中加載數據

insert into table log_parquet select * from log_text ;

(3)查看錶中數據大小

dfs -du -h /user/hive/warehouse/myhive.db/log_parquet;

13.1 M  /user/hive/warehouse/log_parquet/123456_0

存儲文件的壓縮比總結:

ORC >  Parquet >  textFile

存儲文件的查詢速度測試:

1)TextFile
hive (default)> select count(*) from log_text;
_c0
100000
Time taken: 21.54 seconds, Fetched: 1 row(s)  

2)ORC
hive (default)> select count(*) from log_orc;
_c0
100000
Time taken: 20.867 seconds, Fetched: 1 row(s)  

3)Parquet
hive (default)> select count(*) from log_parquet; 
_c0
100000
Time taken: 22.922 seconds, Fetched: 1 row(s)

存儲文件的查詢速度總結:
ORC > TextFile > Parquet

3、存儲和壓縮結合

**

1)TextFile
hive (default)> select count(*) from log_text;
_c0
100000
Time taken: 21.54 seconds, Fetched: 1 row(s)  

2)ORC
hive (default)> select count(*) from log_orc;
_c0
100000
Time taken: 20.867 seconds, Fetched: 1 row(s)  

3)Parquet
hive (default)> select count(*) from log_parquet; 
_c0
100000
Time taken: 22.922 seconds, Fetched: 1 row(s)

存儲文件的查詢速度總結:
ORC > TextFile > Parquet

2、存儲和壓縮結合

官網:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+ORC

ORC存儲方式的壓縮:

Key Default Notes
orc.compress ZLIB high level compression (one of NONE, ZLIB, SNAPPY)
orc.compress.size 262,144 number of bytes in each compression chunk
orc.stripe.size 67,108,864 number of bytes in each stripe
orc.row.index.stride 10,000 number of rows between index entries (must be >= 1000)
orc.create.index true whether to create row indexes
orc.bloom.filter.columns "" comma separated list of column names for which bloom filter should be created
orc.bloom.filter.fpp 0.05 false positive probability for bloom filter (must >0.0 and <1.0)

1)創建一個非壓縮的的ORC存儲方式

(1)建表語句

create table log_orc_none(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS orc tblproperties ("orc.compress"="NONE");

(2)插入數據

insert into table log_orc_none select * from log_text ;

(3)查看插入後數據

dfs -du -h /user/hive/warehouse/myhive.db/log_orc_none;

7.7 M  /user/hive/warehouse/log_orc_none/123456_0

2)創建一個SNAPPY壓縮的ORC存儲方式

(1)建表語句

create table log_orc_snappy(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS orc tblproperties ("orc.compress"="SNAPPY");

(2)插入數據

insert into table log_orc_snappy select * from log_text ;

(3)查看插入後數據

dfs -du -h /user/hive/warehouse/myhive.db/log_orc_snappy ;
3.8 M  /user/hive/warehouse/log_orc_snappy/123456_0

3)上一節中默認創建的ORC存儲方式,導入數據後的大小爲

2.8 M  /user/hive/warehouse/log_orc/123456_0

比Snappy壓縮的還小。原因是orc存儲文件默認採用ZLIB壓縮。比snappy壓縮的小。

4)存儲方式和壓縮總結:

​ 在實際的項目開發當中,hive表的數據存儲格式一般選擇:orc或parquet。壓縮方式一般選擇snappy。

3、Hiv SerDe

3.1、SerDe介紹

​ Serde是 ==Serializer/Deserializer==的簡寫。hive使用Serde進行行對象的序列與反序列化。最後實現把文件內容映射到 hive 表中的字段數據類型。

​ 爲了更好的闡述使用 SerDe 的場景,我們需要了解一下 Hive 是如何讀數據的(類似於HDFS 中數據的讀寫操作):

HDFS files –> InputFileFormat –> <key, value> –> Deserializer –> Row object

Row object –> Serializer –> <key, value> –> OutputFileFormat –> HDFS files

3.2、Hive的SerDe 類型

  • Hive 中內置==org.apache.hadoop.hive.serde2== 庫,內部封裝了很多不同的SerDe類型。
  • hive創建表時, 通過自定義的SerDe或使用Hive內置的SerDe類型指定數據的序列化和反序列化方式。
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name 
[(col_name data_type [COMMENT col_comment], ...)] [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] 
[ROW FORMAT row_format] 
[STORED AS file_format] 
[LOCATION hdfs_path]
  • 如上創建表語句, 使用==row format 參數說明SerDe的類型。==

  • 你可以創建表時使用用戶自定義的Serde或者native Serde如果 ROW FORMAT沒有指定或者指定了 ROW FORMAT DELIMITED就會使用native Serde
  • Hive SerDes:
    • Avro (Hive 0.9.1 and later)
    • ORC (Hive 0.11 and later)
    • RegEx
    • Thrift
    • Parquet (Hive 0.13 and later)
    • CSV (Hive 0.14 and later)
    • MultiDelimitSerDe

3.3、Hive的SerDe案列

1 通過MultiDelimitSerDe 解決多字符分割場景
  • 1、創建表
use myhive;
create  table t1 (id String, name string)
row format serde 'org.apache.hadoop.hive.contrib.serde2.MultiDelimitSerDe'
WITH SERDEPROPERTIES ("field.delim"="##");
  • 2、準備數據 t1.txt
cd /kkb/install/hivedatas
vim t1.txt

1##xiaoming
2##xiaowang
3##xiaozhang
  • 3、加載數據
load data local inpath '/kkb/install/hivedatas/t1.txt' into table t1;
  • 4、查詢數據
0: jdbc:hive2://node1:10000> select * from t1;
+--------+------------+--+
| t1.id  |  t1.name   |
+--------+------------+--+
| 1      | xiaoming   |
| 2      | xiaowang   |
| 3      | xiaozhang  |
+--------+------------+--+
2 通過RegexSerDe 解決多字符分割場景
  • 1、創建表
create  table t2(id int, name string)
row format serde 'org.apache.hadoop.hive.serde2.RegexSerDe' 
WITH SERDEPROPERTIES ("input.regex" = "^(.*)\\#\\#(.*)$");
  • 2、準備數據 t1.txt
1##xiaoming
2##xiaowang
3##xiaozhang
  • 3、加載數據
load data local inpath '/kkb/install/hivedatas/t1.txt' into table t2;
  • 4、查詢數據
0: jdbc:hive2://node1:10000> select * from t2;
+--------+------------+--+
| t2.id  |  t2.name   |
+--------+------------+--+
| 1      | xiaoming   |
| 2      | xiaowang   |
| 3      | xiaozhang  |
+--------+------------+--+

hadoop.hive.serde2.RegexSerDe'
WITH SERDEPROPERTIES ("input.regex" = "^(.)\#\#(.)$");


- 2、準備數據 t1.txt

1##xiaoming
2##xiaowang
3##xiaozhang


- 3、加載數據

```sql
load data local inpath '/kkb/install/hivedatas/t1.txt' into table t2;
  • 4、查詢數據
0: jdbc:hive2://node1:10000> select * from t2;
+--------+------------+--+
| t2.id  |  t2.name   |
+--------+------------+--+
| 1      | xiaoming   |
| 2      | xiaowang   |
| 3      | xiaozhang  |
+--------+------------+--+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章