一文搞懂Hive的數(shù)據(jù)存儲與壓縮

行存儲與列存儲
行存儲的特點(diǎn)
列存儲的特點(diǎn)
常見的數(shù)據(jù)格式
TextFile
SequenceFile
RCfile
ORCfile
Parquet
測試
準(zhǔn)備測試數(shù)據(jù)
存儲空間大小
測試SQL 執(zhí)行效率
總結(jié)
Hive 壓縮
Hive中間數(shù)據(jù)壓縮
最終輸出結(jié)果壓縮
常見的壓縮格式
演示
總結(jié)
行存儲與列存儲
當(dāng)今的數(shù)據(jù)處理大致可分為兩大類,聯(lián)機(jī)事務(wù)處理 OLTP(on-line transaction processing)聯(lián)機(jī)分析處理 OLAP(On-Line Analytical Processing)=,OLTP 是傳統(tǒng)關(guān)系型數(shù)據(jù)庫的主要應(yīng)用來執(zhí)行一些基本的、日常的事務(wù)處理比如數(shù)據(jù)庫記錄的增、刪、改、查等等而OLAP則是分布式數(shù)據(jù)庫的主要應(yīng)用它對實時性要求不高,但處理的數(shù)據(jù)量大通常應(yīng)用于復(fù)雜的動態(tài)報表系統(tǒng)上

所以一般OLTP 都是使用行式存儲的,因為實時性要求高,而且有大量的更新操作,OLAP 都是使用列式存儲的,因為實時性要求不高,主要是要求性能好
行存儲的特點(diǎn)
查詢滿足條件的一整行數(shù)據(jù)的時,只需要找到其中一個值,其余的值都在相鄰地方,所以此時行存儲查詢的速度更快。 傳統(tǒng)的關(guān)系型數(shù)據(jù)庫,如 Oracle、DB2、MySQL、SQL SERVER 等采用行式存儲法(Row-based),在基于行式存儲的數(shù)據(jù)庫中, 數(shù)據(jù)是按照行數(shù)據(jù)為基礎(chǔ)邏輯存儲單元進(jìn)行存儲的, 一行中的數(shù)據(jù)在存儲介質(zhì)中以連續(xù)存儲形式存在。 TEXTFILE和SEQUENCEFILE的存儲格式都是基于行存儲的 這種存儲格式比較方便進(jìn)行INSERT/UPDATE操作,不足之處就是如果查詢只涉及某幾個列,它會把整行數(shù)據(jù)都讀取出來,不能跳過不必要的列讀取。當(dāng)然數(shù)據(jù)比較少,一般沒啥問題,如果數(shù)據(jù)量比較大就比較影響性能,還有就是由于每一行中,列的數(shù)據(jù)類型不一致,導(dǎo)致不容易獲得一個極高的壓縮比,也就是空間利用率不高
列存儲的特點(diǎn)
查詢時,只有涉及到的列才會被查詢,不會把所有列都查詢出來,即可以跳過不必要的列查詢,在查詢只需要少數(shù)幾個字段的時候,能大大減少讀取的數(shù)據(jù)量;因為每一列的數(shù)據(jù)都是存儲在一起的,每個字段的數(shù)據(jù)類型一定是相同的,列式存儲可以針對性的設(shè)計更好的設(shè)計壓縮算法,高效的壓縮率,不僅節(jié)省儲存空間也節(jié)省計算內(nèi)存和CPU
不足之處是INSERT/UPDATE很麻煩或者不方便,不適合掃描小量的數(shù)據(jù)
列式存儲(Column-based)是相對于行式存儲來說的,新興的Hbase、HPVertica、EMCGreenplum等分布式數(shù)據(jù)庫均采用列式存儲。在基于列式存儲的數(shù)據(jù)庫中, 數(shù)據(jù)是按照列為基礎(chǔ)邏輯存儲單元進(jìn)行存儲的,一列中的數(shù)據(jù)在存儲介質(zhì)中以連續(xù)存儲形式存在。

列存儲的特點(diǎn):因為每個字段的數(shù)據(jù)聚集存儲,在查詢只需要少數(shù)幾個字段的時候,能大大減少讀取的數(shù)據(jù)量;每個字段的數(shù)據(jù)類型一定是相同的,列式存儲可以針對性的設(shè)計更好的設(shè)計壓縮算法。ORC和PARQUET是基于列式存儲的。
舉個例子吧不然還是太抽象,假設(shè)一個表有10億行數(shù)據(jù),按照列式存儲的定義,應(yīng)該先將某個字段的10億條數(shù)據(jù)存儲完之后,再存儲其他字段。
常見的數(shù)據(jù)格式
Hive 支持一下幾種存儲格式,下面我們會對每種格式的特點(diǎn)進(jìn)行簡單介紹
Text File SequenceFile RCFile Avro Files ORC Files Parquet Custom INPUTFORMAT and OUTPUTFORMAT(用戶自定義格式)
Hive 默認(rèn)使用的實Text File,也就是說當(dāng)你建表的時候不指定文件的存儲格式的時候,它就使用的就是Text File,Hive 是支持指定默認(rèn)存儲格式的
<property>
<name>hive.default.fileformat</name>
<value>TextFile</value>
<description>
Expects one of [textfile, sequencefile, rcfile, orc, parquet].
Default file format for CREATE TABLE statement. Users can explicitly override it by CREATE TABLE ... STORED AS [FORMAT]
</description>
</property>
TextFile
存儲方式:行存儲
默認(rèn)的存儲格式,數(shù)據(jù)不做壓縮,磁盤開銷大,數(shù)據(jù)解析開銷大。可結(jié)合Gzip、Bzip2使用(系統(tǒng)自動檢查,執(zhí)行查詢時自動解壓),但使用這種方式,壓縮后的文件不支持split,Hive不會對數(shù)據(jù)進(jìn)行切分,從而無法對數(shù)據(jù)進(jìn)行并行操作。
并且在反序列化過程中,必須逐個字符判斷是不是分隔符和行結(jié)束符,因此反序列化開銷會比SequenceFile高幾十倍。
SequenceFile
SequenceFile是Hadoop API提供的一種二進(jìn)制文件支持,,存儲方式為行存儲,其具有使用方便、可分割、可壓縮的特點(diǎn)。
壓縮數(shù)據(jù)文件可以節(jié)省磁盤空間,但Hadoop中有些原生壓縮文件的就是不支持分割,所以Hadoop 猜提供了SequenceFile 這種格式,支持分割的文件可以并行的有多個mapper程序處理大數(shù)據(jù)文件,大多數(shù)文件不支持可分割是因為這些文件只能從頭開始讀。
SequenceFile支持三種壓縮選擇:NONE,RECORD,BLOCK。Record壓縮率低,一般建議使用BLOCK壓縮,RECORD是默認(rèn)選項,通常BLOCK會帶來較RECORD更好的壓縮性能。
SequenceFile的優(yōu)勢是文件和hadoop api中的MapFile是相互兼容的。
注:建表使用這個格式,導(dǎo)入數(shù)據(jù)時會直接把數(shù)據(jù)文件拷貝到hdfs上不進(jìn)行處理。SequenceFile、RCFile、ORC格式的表不能直接從本地文件導(dǎo)入數(shù)據(jù),數(shù)據(jù)要先導(dǎo)入到TextFile格式的表中,然后再從TextFile表中用insert導(dǎo)入到SequenceFile、RCFile表中
RCfile
存儲方式:數(shù)據(jù)按行分塊,每塊按列存儲
Record Columnar的縮寫,是Hadoop中第一個列式存儲格式。能夠很好的壓縮和快速的查詢性能,但是不支持模式演進(jìn)。是一種行列存儲相結(jié)合的存儲方式。
首先,其將數(shù)據(jù)按行分塊,保同一行的數(shù)據(jù)位于同一個塊上,避免讀一個記錄需要讀取多個block。其次,塊數(shù)據(jù)列式存儲,有利于數(shù)據(jù)壓縮和快速的列存取,并且能跳過不必要的列讀取
ORCfile
存儲方式:數(shù)據(jù)按行分塊 每塊按照列存儲(不是真正意義上的列存儲,可以理解為分段列存儲,你可以對照我們講的那個例子來理解)
ORC的全稱是(Optimized Row Columnar),ORC文件格式是一種Hadoop生態(tài)圈中的列式存儲格式,它的產(chǎn)生早在2013年初,最初產(chǎn)生自Apache Hive,用于降低Hadoop數(shù)據(jù)存儲空間和加速Hive查詢速度。和Parquet類似,它并不是一個單純的列式存儲格式,仍然是首先根據(jù)行組分割整個表,在每一個行組內(nèi)進(jìn)行按列存儲。
ORC文件是自描述的,它的元數(shù)據(jù)使用Protocol Buffers序列化,并且文件中的數(shù)據(jù)盡可能的壓縮以降低存儲空間的消耗,目前也被Spark SQL、Presto等查詢引擎支持,但是Impala對于ORC目前沒有支持,仍然使用Parquet作為主要的列式存儲格式。2015年ORC項目被Apache項目基金會提升為Apache頂級項目。
ORC文件特點(diǎn)是壓縮快 快速列存取,是rcfile的改良版本,相比RC能夠更好的壓縮,能夠更快的查詢,支持各種復(fù)雜的數(shù)據(jù)類型,比如datetime,decimal,以及復(fù)雜的struct是以二進(jìn)制方式存儲的,所以是不可以直接讀取,ORC文件也是自解析的,它包含許多的元數(shù)據(jù),這些元數(shù)據(jù)都是同構(gòu)ProtoBuffer進(jìn)行序列化的。
需要注意的是 ORC在讀寫時候需要消耗額外的CPU資源來壓縮和解壓縮,當(dāng)然這部分的CPU消耗是非常少的。
格式
ORC文件:保存在文件系統(tǒng)上的普通二進(jìn)制文件,一個ORC文件中可以包含多個stripe,每個Orc文件由1個或多個stripe組成,每個stripe一般為HDFS的塊大小,每一個stripe包含多條記錄,這些記錄按照列進(jìn)行獨(dú)立存儲,對應(yīng)到Parquet中就是row group的概念。每個Stripe里有三部分組成,分別是Index Data,Row Data,Stripe Footer;
stripe:一組行形成一個stripe,每次讀取文件是以行組為單位的,一般為HDFS的塊大小,保存了每一列的索引和數(shù)據(jù)。
文件級元數(shù)據(jù):包括文件的描述信息PostScript、文件meta信息(包括整個文件的統(tǒng)計信息)、所有stripe的信息和文件schema信息。
stripe元數(shù)據(jù):保存stripe的位置、每一個列的在該stripe的統(tǒng)計信息以及所有的stream類型和位置。
row group:索引的最小單位,一個stripe中包含多個row group,默認(rèn)為10000個值組成。每次讀取文件是以行組為單位的,一般為HDFS的塊大小,保存了每一列的索引和數(shù)據(jù)。

在ORC文件中保存了三個層級的統(tǒng)計信息,分別為文件級別、stripe級別和row group級別的,他們都可以用來根據(jù)Search ARGuments(謂詞下推條件)判斷是否可以跳過某些數(shù)據(jù),在統(tǒng)計信息中都包含成員數(shù)和是否有null值,并且對于不同類型的數(shù)據(jù)設(shè)置一些特定的統(tǒng)計信息。
file level:在ORC文件的末尾會記錄文件級別的統(tǒng)計信息,會記錄整個文件中columns的統(tǒng)計信息。這些信息主要用于查詢的優(yōu)化,也可以為一些簡單的聚合查詢比如max, min, sum輸出結(jié)果。
**stripe level:**ORC文件會保存每個字段stripe級別的統(tǒng)計信息,ORC reader使用這些統(tǒng)計信息來確定對于一個查詢語句來說,需要讀入哪些stripe中的記錄。比如說某個stripe的字段max(a)=10,min(a)=3,那么當(dāng)where條件為a >10或者a <3時,那么這個stripe中的所有記錄在查詢語句執(zhí)行時不會被讀入
row level: 為了進(jìn)一步的避免讀入不必要的數(shù)據(jù),在邏輯上將一個column的index以一個給定的值(默認(rèn)為10000,可由參數(shù)配置)分割為多個index組。以10000條記錄為一個組,對數(shù)據(jù)進(jìn)行統(tǒng)計。Hive查詢引擎會將where條件中的約束傳遞給ORC reader,這些reader根據(jù)組級別的統(tǒng)計信息,過濾掉不必要的數(shù)據(jù)。如果該值設(shè)置的太小,就會保存更多的統(tǒng)計信息,用戶需要根據(jù)自己數(shù)據(jù)的特點(diǎn)權(quán)衡一個合理的值
數(shù)據(jù)訪問
讀取ORC文件是從尾部開始的,第一次讀取16KB的大小,盡可能的將Postscript和Footer數(shù)據(jù)都讀入內(nèi)存。文件的最后一個字節(jié)保存著PostScript的長度,它的長度不會超過256字節(jié),PostScript中保存著整個文件的元數(shù)據(jù)信息,它包括文件的壓縮格式、文件內(nèi)部每一個壓縮塊的最大長度(每次分配內(nèi)存的大小)、Footer長度,以及一些版本信息。在Postscript和Footer之間存儲著整個文件的統(tǒng)計信息(上圖中未畫出),這部分的統(tǒng)計信息包括每一個stripe中每一列的信息,主要統(tǒng)計成員數(shù)、最大值、最小值、是否有空值等。
接下來讀取文件的Footer信息,它包含了每一個stripe的長度和偏移量,該文件的schema信息(將schema樹按照schema中的編號保存在數(shù)組中)、整個文件的統(tǒng)計信息以及每一個row group的行數(shù)。
處理stripe時首先從Footer中獲取每一個stripe的其實位置和長度、每一個stripe的Footer數(shù)據(jù)(元數(shù)據(jù),記錄了index和data的的長度),整個striper被分為index和data兩部分,stripe內(nèi)部是按照row group進(jìn)行分塊的(每一個row group中多少條記錄在文件的Footer中存儲),row group內(nèi)部按列存儲。每一個row group由多個stream保存數(shù)據(jù)和索引信息。每一個stream的數(shù)據(jù)會根據(jù)該列的類型使用特定的壓縮算法保存。在ORC中存在如下幾種stream類型:
PRESENT:每一個成員值在這個stream中保持一位(bit)用于標(biāo)示該值是否為NULL,通過它可以只記錄部位NULL的值 DATA:該列的中屬于當(dāng)前stripe的成員值。 LENGTH:每一個成員的長度,這個是針對string類型的列才有的。 DICTIONARY_DATA:對string類型數(shù)據(jù)編碼之后字典的內(nèi)容。 SECONDARY:存儲Decimal、timestamp類型的小數(shù)或者納秒數(shù)等。 ROW_INDEX:保存stripe中每一個row group的統(tǒng)計信息和每一個row group起始位置信息。
在初始化階段獲取全部的元數(shù)據(jù)之后,可以通過includes數(shù)組指定需要讀取的列編號,它是一個boolean數(shù)組,如果不指定則讀取全部的列,還可以通過傳遞SearchArgument參數(shù)指定過濾條件,根據(jù)元數(shù)據(jù)首先讀取每一個stripe中的index信息,然后根據(jù)index中統(tǒng)計信息以及SearchArgument參數(shù)確定需要讀取的row group編號,再根據(jù)includes數(shù)據(jù)決定需要從這些row group中讀取的列,通過這兩層的過濾需要讀取的數(shù)據(jù)只是整個stripe多個小段的區(qū)間,然后ORC會盡可能合并多個離散的區(qū)間盡可能的減少I/O次數(shù)。然后再根據(jù)index中保存的下一個row group的位置信息調(diào)至該stripe中第一個需要讀取的row group中。
使用ORC文件格式時,用戶可以使用HDFS的每一個block存儲ORC文件的一個stripe。對于一個ORC文件來說,stripe的大小一般需要設(shè)置得比HDFS的block小,如果不這樣的話,一個stripe就會分別在HDFS的多個block上,當(dāng)讀取這種數(shù)據(jù)時就會發(fā)生遠(yuǎn)程讀數(shù)據(jù)的行為。如果設(shè)置stripe的只保存在一個block上的話,如果當(dāng)前block上的剩余空間不足以存儲下一個strpie,ORC的writer接下來會將數(shù)據(jù)打散保存在block剩余的空間上,直到這個block存滿為止。這樣,下一個stripe又會從下一個block開始存儲。
由于ORC中使用了更加精確的索引信息,使得在讀取數(shù)據(jù)時可以指定從任意一行開始讀取,更細(xì)粒度的統(tǒng)計信息使得讀取ORC文件跳過整個row group,ORC默認(rèn)會對任何一塊數(shù)據(jù)和索引信息使用ZLIB壓縮,因此ORC文件占用的存儲空間也更小
Parquet
Parquet能夠很好的壓縮,有很好的查詢性能,支持有限的模式演進(jìn)。但是寫速度通常比較慢。這中文件格式主要是用在Cloudera Impala上面的。Parquet文件是以二進(jìn)制方式存儲的,所以是不可以直接讀取的,文件中包括該文件的數(shù)據(jù)和元數(shù)據(jù),因此Parquet格式文件是自解析的。
Parquet的設(shè)計方案,整體來看,基本照搬了Dremel中對嵌套數(shù)據(jù)結(jié)構(gòu)的打平和重構(gòu)算法,通過高效的數(shù)據(jù)打平和重建算法,實現(xiàn)按列存儲(列組),進(jìn)而對列數(shù)據(jù)引入更具針對性的編碼和壓縮方案,來降低存儲代價,提升計算性能。想要了解這一算法邏輯的,可以看Dremel的論文:Dremel: Interactive Analysis of WebScaleDatasets
測試
準(zhǔn)備測試數(shù)據(jù)
首先我們生成一份測試數(shù)據(jù),這是生成數(shù)據(jù)的測試代碼
public class ProduceTestData {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:MM:ss");
@Test
public void testRandomName() throws IOException {
Faker faker = new Faker(Locale.CHINA);
final Name name = faker.name();
final Address address = faker.address();
Number number = faker.number();
PhoneNumber phoneNumber = faker.phoneNumber();
BufferedWriter out = new BufferedWriter(new FileWriter("/Users/liuwenqiang/access.log"));
int num=0;
while (num<10000000){
int id = number.randomDigitNotZero();
String userName = name.name();
String time = simpleDateFormat.format(new Date(System.currentTimeMillis()));
String city = address.city();
String phonenum = phoneNumber.cellPhone();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(id);
stringBuilder.append("\t");
stringBuilder.append(userName);
stringBuilder.append("\t");
stringBuilder.append(city);
stringBuilder.append("\t");
stringBuilder.append(phonenum);
stringBuilder.append("\t");
stringBuilder.append(time);
out.write(stringBuilder.toString());
out.newLine();
}
out.flush();
out.close();
}
}
下面準(zhǔn)備三張表,分別是log_text、log_orc和log_parquet
create table log_text(
id int,
name string,
city string,
phone string,
acctime string)
row format delimited fields terminated by '\t'
stored as textfile;
LOAD DATA LOCAL INPATH '/Users/liuwenqiang/access.log' OVERWRITE INTO TABLE ods.log_text;
create table log_orc(
id int,
name string,
city string,
phone string,
acctime string)
row format delimited fields terminated by '\t'
stored as orc;
insert overwrite table ods.log_orc select * from ods.log_text;
create table log_parquet(
id int,
name string,
city string,
phone string,
acctime string)
row format delimited fields terminated by '\t'
stored as parquet;
insert overwrite table ods.log_parquet select * from ods.log_text;
所有關(guān)于ORCFile的參數(shù)都是在Hive SQL語句的TBLPROPERTIES字段里面出現(xiàn)
| 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.compress.size | 262,144 | number of bytes in each compression chunk |
| orc.row.index.stride | 10,000 | number of rows between index entries (must be >= 1000) |
| orc.create.index | true | whether to create row indexes |
存儲空間大小
text

orc

parquet

測試SQL 執(zhí)行效率
測試SQL select city,count(1) as cnt from log_text group by city order by cnt desc;
text

orc

parquet

總結(jié)
介紹了行式存儲和列式存儲的特點(diǎn),以及適用場景 介紹了Hive 常見的存儲格式,Parquet 和 ORC都是二進(jìn)制存儲的,都是不可直接讀取的,Parquet和ORC 都是Apache 頂級項目,Parquet不支持ACID 不支持更新,ORC支持有限的ACID 和 更新 我們簡單對比了一下Text、ORCfile 和Parquet的存儲占用和查詢性能,因為我們的查詢比較簡單加上數(shù)據(jù)本身不是很大,所以查詢性能差異不是很大,但是占用空間存儲的差異還是很大的
Hive 壓縮
對于數(shù)據(jù)密集型任務(wù),I/O操作和網(wǎng)絡(luò)數(shù)據(jù)傳輸需要花費(fèi)相當(dāng)長的時間才能完成。通過在 Hive 中啟用壓縮功能,我們可以提高 Hive 查詢的性能,并節(jié)省 HDFS 集群上的存儲空間。
HiveQL語句最終都將轉(zhuǎn)換成為hadoop中的MapReduce job,而MapReduce job可以有對處理的數(shù)據(jù)進(jìn)行壓縮。
首先說明mapreduce哪些過程可以設(shè)置壓縮:需要分析處理的數(shù)據(jù)在進(jìn)入map前可以壓縮,然后解壓處理,map處理完成后的輸出可以壓縮,這樣可以減少網(wǎng)絡(luò)I/O(reduce通常和map不在同一節(jié)點(diǎn)上),reduce拷貝壓縮的數(shù)據(jù)后進(jìn)行解壓,處理完成后可以壓縮存儲在hdfs上,以減少磁盤占用量。

Hive中間數(shù)據(jù)壓縮
提交后,一個復(fù)雜的 Hive 查詢通常會轉(zhuǎn)換為一系列多階段 MapReduce 作業(yè),這些作業(yè)將通過 Hive 引擎進(jìn)行鏈接以完成整個查詢。因此,這里的 ‘中間輸出’ 是指前一個 MapReduce 作業(yè)的輸出,將會作為下一個 MapReduce 作業(yè)的輸入數(shù)據(jù)。
可以通過使用 Hive Shell 中的 set 命令或者修改 hive-site.xml 配置文件來修改 hive.exec.compress.intermediate 屬性,這樣我們就可以在 Hive Intermediate 輸出上啟用壓縮。
hive.exec.compress.intermediate:默認(rèn)為false,設(shè)置true為激活中間數(shù)據(jù)壓縮功能,就是MapReduce的shuffle階段對mapper產(chǎn)生中間壓縮。可以使用 set 命令在 hive shell 中設(shè)置這些屬性
set hive.exec.compress.intermediate=true
set mapred.map.output.compression.codec= org.apache.hadoop.io.compress.SnappyCodec
或者
set hive.exec.compress.intermediate=true
set mapred.map.output.compression.codec=com.hadoop.compression.lzo.LzoCodec
也可以在配置文件中進(jìn)行配置
<property>
<name>hive.exec.compress.intermediate</name>
<value>true</value>
<description>
This controls whether intermediate files produced by Hive between multiple map-reduce jobs are compressed.
The compression codec and other options are determined from Hadoop config variables mapred.output.compress*
</description>
</property>
<property>
<name>hive.intermediate.compression.codec</name>
<value>org.apache.hadoop.io.compress.SnappyCodec</value>
<description/>
</property>
最終輸出結(jié)果壓縮
hive.exec.compress.output:用戶可以對最終生成的Hive表的數(shù)據(jù)通常也需要壓縮。該參數(shù)控制這一功能的激活與禁用,設(shè)置為true來聲明將結(jié)果文件進(jìn)行壓縮。
mapred.output.compression.codec:將hive.exec.compress.output參數(shù)設(shè)置成true后,然后選擇一個合適的編解碼器,如選擇SnappyCodec。設(shè)置如下(兩種壓縮的編寫方式是一樣的):
set hive.exec.compress.output=true
set mapred.output.compression.codec=org.apache.hadoop.io.compress.SnappyCodec
或者
set mapred.output.compress=true
set mapred.output.compression.codec=org.apache.hadoop.io.compress.LzopCodec
同樣可以通過配置文件配置
<property>
<name>hive.exec.compress.output</name>
<value>true</value>
<description>
This controls whether the final outputs of a query (to a local/HDFS file or a Hive table) is compressed.
The compression codec and other options are determined from Hadoop config variables mapred.output.compress*
</description>
</property>
常見的壓縮格式
Hive支持的壓縮格式有bzip2、gzip、deflate、snappy、lzo等。Hive依賴Hadoop的壓縮方法,所以Hadoop版本越高支持的壓縮方法越多,可以在$HADOOP_HOME/conf/core-site.xml中進(jìn)行配置:
<property>
<name>io.compression.codecs</name>
<value>org.apache.hadoop.io.compress.GzipCodec,org.apache.hadoop.io.compress.DefaultCodec,com.hadoop.compression.lzo.LzoCodec,com.hadoop.compression.lzo.LzopCodec,org.apache.hadoop.io.compress.BZip2Codec
</value>
</property>
<property>
<property>
<name>io.compression.codec.lzo.class</name>
<value>com.hadoop.compression.lzo.LzoCodec</value>
</property>
需要注意的是在我們在hive配置開啟壓縮之前,我們需要配置讓Hadoop 支持,因為hive 開啟壓縮只是指明了使用哪一種壓縮算法,具體的配置還是需要在Hadoop 中配置
常見的壓縮格式有:

其中壓縮比bzip2 > zlib > gzip > deflate > snappy > lzo > lz4,在不同的測試場景中,會有差異,這僅僅是一個大概的排名情況。bzip2、zlib、gzip、deflate可以保證最小的壓縮,但在運(yùn)算中過于消耗時間。
從壓縮性能上來看:lz4 > lzo > snappy > deflate > gzip > bzip2,其中l(wèi)z4、lzo、snappy壓縮和解壓縮速度快,壓縮比低。
所以一般在生產(chǎn)環(huán)境中,經(jīng)常會采用lz4、lzo、snappy壓縮,以保證運(yùn)算效率。
| 壓縮格式 | 對應(yīng)的編碼/解碼 |
|---|---|
| DEFAULT | org.apache.hadoop.io.compress.DefaultCodec |
| Gzip | org.apache.hadoop.io.compress.GzipCodec |
| Bzip | org.apache.hadoop.io.compress.BzipCodec |
| Snappy | org.apache.hadoop.io.compress.SnappyCodec |
| Lzo | org.apache.hadoop.io.compress.LzopCodec |
對于使用 Gzip or Bzip2 壓縮的文件我們是可以直接導(dǎo)入到text 存儲類型的表中的,hive 會自動幫我們完成數(shù)據(jù)的解壓
CREATE TABLE raw (line STRING)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\n';
LOAD DATA LOCAL INPATH '/tmp/weblogs/20090603-access.log.gz' INTO TABLE raw;
Native Libraries
Hadoop由Java語言開發(fā),所以壓縮算法大多由Java實現(xiàn);但有些壓縮算法并不適合Java進(jìn)行實現(xiàn),會提供本地庫Native Libraries補(bǔ)充支持。Native Libraries除了自帶bzip2, lz4, snappy, zlib壓縮方法外,還可以自定義安裝需要的功能庫(snappy、lzo等)進(jìn)行擴(kuò)展。而且使用本地庫Native Libraries提供的壓縮方式,性能上會有50%左右的提升。
使用命令可以查看native libraries的加載情況:
hadoop checknative -a

完成對Hive表的壓縮,有兩種方式:配置MapReduce壓縮、開啟Hive表壓縮功能。因為Hive會將SQL作業(yè)轉(zhuǎn)換為MapReduce任務(wù),所以直接對MapReduce進(jìn)行壓縮配置,可以達(dá)到壓縮目的;當(dāng)然為了方便起見,Hive中的特定表支持壓縮屬性,自動完成壓縮的功能。
Hive中的可用壓縮編解碼器
要在 Hive 中啟用壓縮,首先我們需要找出 Hadoop 集群上可用的壓縮編解碼器,我們可以使用下面的 set 命令列出可用的壓縮編解碼器。
hive> set io.compression.codecs;
io.compression.codecs=
org.apache.hadoop.io.compress.GzipCodec,
org.apache.hadoop.io.compress.DefaultCodec,
org.apache.hadoop.io.compress.BZip2Codec,
org.apache.hadoop.io.compress.SnappyCodec,
com.hadoop.compression.lzo.LzoCodec,
com.hadoop.compression.lzo.LzopCodec
演示
首先我們創(chuàng)建一個未經(jīng)壓縮的表tmp_no_compress
CREATE TABLE tmp_no_compress ROW FORMAT DELIMITED LINES TERMINATED BY '\n'
AS SELECT * FROM log_text;
我們看一下不設(shè)置壓縮屬性的輸出

在 Hive Shell 中設(shè)置壓縮屬性:
set hive.exec.compress.output=true;
set mapreduce.output.fileoutputformat.compress=true;
set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.GzipCodec;
set mapreduce.output.fileoutputformat.compress.type=BLOCK;
根據(jù)現(xiàn)有表 tmp_order_id 創(chuàng)建一個壓縮后的表 tmp_order_id_compress:
CREATE TABLE tmp_compress ROW FORMAT DELIMITED LINES TERMINATED BY '\n'
AS SELECT * FROM log_text;
我們在看一下設(shè)置壓縮屬性后輸出:

總結(jié)
數(shù)據(jù)壓縮可以發(fā)生在哪些階段 1 輸入數(shù)據(jù)可以壓縮后的數(shù)據(jù) 2 中間的數(shù)據(jù)可以壓縮 3 輸出的數(shù)據(jù)可以壓縮 hive 僅僅是配置了開啟壓縮和使用哪種壓縮方式,真正的配置是在hadoop 中配置的,而數(shù)據(jù)的壓縮是在MapReduce 中發(fā)生的 對于數(shù)據(jù)密集型任務(wù),I/O操作和網(wǎng)絡(luò)數(shù)據(jù)傳輸需要花費(fèi)相當(dāng)長的時間才能完成。通過在 Hive 中啟用壓縮功能,我們可以提高 Hive 查詢的性能,并節(jié)省 HDFS 集群上的存儲空間。
