1. Hive文件與記錄格式
Create table 有多種用法,例如STORED AS SEQUENCEFILE, ROW FORMAT DELIMITED, SERDE, INPUTFORMAT, OUTPUTFORMAT 這些語法。
某些語法是其他語法的快捷用法,例如:
語法 STORED AS SEQUENCEFILE 的替代方式是:指定INPUTFORMAT 為 org.apache.hadoop.mapred.SequenceFileInputFormat,並指定 OUTPUTFORMAT 為 org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat。
下面創建一些表,然后使用 DESCRIBE TABLE EXTENDED 語句查看下內部實際變化情況。首先創建一個簡單表:
> create table text(x int);
hive> describe extended text;
OK
x int
Detailed Table Information
Table(tableName:text, dbName:default, owner:hadoop, createTime:1559016716, lastAccessTime:0, retention:0,
sd:StorageDescriptor(
cols:[FieldSchema(name:x, type:int, comment:null)],
location:hdfs://ip-10-0-2-70.cn-north-1.compute.internal:8020/user/hive/warehouse/text,
inputFormat:org.apache.hadoop.mapred.TextInputFormat,
outputFormat:org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat,
compressed:false,
numBuckets:-1,
serdeInfo:SerDeInfo(
name:null,
serializationLib:org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe,
parameters:{serialization.format=1}
),
bucketCols:[], sortCols:[], parameters:{},
skewedInfo:SkewedInfo(
skewedColNames:[], skewedColValues:[], skewedColValueLocationMaps:{}
),
storedAsSubDirectories:false),
partitionKeys:[], parameters:{totalSize=0, numRows=0, rawDataSize=0, COLUMN_STATS_ACCURATE={"BASIC_STATS":"true"}, numFiles=0, transient_lastDdlTime=1559016716},
viewOriginalText:null, viewExpandedText:null, tableType:MANAGED_TABLE, rewriteEnabled:false)
Time taken: 0.132 seconds, Fetched: 3 row(s)
然后再使用 STORED AS DEQUENCEFILE 語句創建一張表,用於對比:
> create table seq(x int) stored as sequencefile;
> describe extended seq;
OK
x int
Detailed Table Information
Table(tableName:seq, dbName:default, owner:hadoop, createTime:1559017290, lastAccessTime:0, retention:0,
sd:StorageDescriptor(
cols:[FieldSchema(name:x, type:int, comment:null)],
location:hdfs://ip-10-0-2-70.cn-north-1.compute.internal:8020/user/hive/warehouse/seq,
inputFormat:org.apache.hadoop.mapred.SequenceFileInputFormat,
outputFormat:org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat,
compressed:false, numBuckets:-1,
serdeInfo:SerDeInfo(
name:null, serializationLib:org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe,
parameters:{serialization.format=1}
),
bucketCols:[], sortCols:[], parameters:{},
skewedInfo:SkewedInfo(
skewedColNames:[], skewedColValues:[], skewedColValueLocationMaps:{}
),
storedAsSubDirectories:false
),
partitionKeys:[], parameters:{totalSize=0, numRows=0, rawDataSize=0, COLUMN_STATS_ACCURATE={"BASIC_STATS":"true"}, numFiles=0, transient_lastDdlTime=1559017290}, viewOriginalText:null, viewExpandedText:null, tableType:MANAGED_TABLE, rewriteEnabled:false)
兩者差異很明顯:STORED AS SEQUENCEFILE 與默認的InputFormat 和 OutputFormat的值不一樣:
inputFormat:org.apache.hadoop.mapred.TextInputFormat,
outputFormat:org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat,
inputFormat:org.apache.hadoop.mapred.SequenceFileInputFormat,
outputFormat:org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat,
在從表中讀取數據時,Hive 會使用InputFormat,在向表寫入數據時,會使用OutputFormat。InputFormat會從文件中讀取key-value對。默認情況下,Hive會直接忽略掉key的內容,而是只有value中的數據。因為key來自於TextInputFormat,是每行的字節偏移量,並不是用戶的數據。
2.文件格式
Hive中最簡單的數據格式是文本文件格式,可以使用任意分隔符進行分割,同時它也是默認的文件格式,等價於:在創建時通過STORED AS TEXTFILE 語句指定使用文本存儲格式
文本文件便於與其他工具共享數據,也便於查看和編輯。不過,相對於二進制文件,文本文件存儲的空間要大。我們可以使用壓縮,但是如果使用二進制文件存儲格式的話,則既可以節約存儲空間,也可以提高I/O性能。
2.1 SequenceFile
其中一種存儲格式是SequenceFile文件存儲格式,在定義表結構時可以通過STORED AS SEQUENCEFILE 語句指定。SequenceFile 是Hadoop生態系統中支持的標准文件格式,可以在塊級別和記錄級別進行壓縮,這對於優化磁盤利用率和I/O來說非常有意義。同時仍然可以支持按照塊級別的文件分割,以方便並行處理。Hive 所支持的另一個高效二進制文件是RCFile
2.2 RCFile
大多數Hadoop和Hive都是行式存儲的,大多數場景下,這是比較高效的。高效的原因有:
1. 大多數的表具有的字段個數都不大(一般1到20個字段)
2. 對文件按塊進行壓縮對於需要處理重復數據的情況比較高
3. 很多的處理和調試工具(例如more、head、awk)都可以很好地應用於行式存儲數據
但是對於某些特定類型的數據和應用,列式存儲會更適用。例如,表中有成百上千個字段,但是大多數查詢僅使用其中小部分字段,這時掃描所有的行和過濾掉大部分數據顯然是很浪費的。如果數據存儲是列式存儲,那么僅掃描需要的列數據就可以提高性能。
對於列式存儲,進行壓縮通常會非常高效,特別是在這列的數據具有較低計數的時候。同時,一些列式存儲並不需要物理存儲null值的列。
基於這些場景,Hive中設計了RCFile。
Hive 另外一個優點是:可以很容易地在不同的存儲格式間轉換數據。對一個表執行一個SELECT查詢時,或是向表寫入執行INSERT操作時,Hive會使用這個表的metadata信息,自動執行轉換過程,而不需要額外的程序來對不同存儲格式進行轉換。
這里我們舉一個例子,首先使用ColumarSerDe、RCFileInputFormat和RCFileOutputFormat參數創建表:
> select * from a;
OK
4 5
3 2
> create table columnTable(key int, value int)
> ROW FORMAT SERDE
> 'org.apache.hadoop.hive.serde2.columnar.ColumnarSerDe'
> STORED AS
> INPUTFORMAT 'org.apache.hadoop.hive.ql.io.RCFileInputFormat'
> OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.RCFileOutputFormat';
OK
hive> FROM a INSERT OVERWRITE TABLE columnTable SELECT a.key, a.value;
對於 RCFile 來說,無法使用通常工具打開RCFile,也無法使用通常打開SequenceFile的工具打開。例如:
>cat 000000_0
RCF hive.io.rcfile.column.number2Ч];E3:'c
4352
不過Hive 提供了一個rcfilecat工具,用於展示RCFile文件內容:
> hive --service rcfilecat /user/hive/warehouse/columntable/000000_0
4 5
3 2
3. 記錄格式:SerDe
SerDe是Serializer/Deserializer的簡稱。一個SerDe允許Hive從一個表讀入數據,並以任意用戶定義的格式寫回HDFS。它包含了將一條記錄的非結構化數據轉化成Hive可以使用的一條記錄的過程。
Hive SerDe 庫在 org.apache.hadoop.hive.serde2 中(舊版本的SerDe 庫在 org.apache.hadoop.hive.serde中,已經被棄用),它本身包含了一些內置的SerDes,如:
1. Avro(Hive 0.9.1 及之后版本)
2. ORC(Hive 0.11 及之后版本)
3. RegEx
4. Thrift
5. Parquet(Hive 0.13及之后版本)
6. CSV(Hive 0.14及之后版本)
7. JsonSerDe(Hive 0.12 及之后版本,在hcatalog-core中)
需要注意的是:在Hive 0.12 之前的發行版中,Amazon提供了一個JSON SerDe,位於s3://elasticmapreduce/samples/hive-ads/libs/jsonserde.jar
也有用戶定義的SerDes,不過需要用戶實現,或是使用第三方的SerDe。
SerDe的用途與過程有以下三點:
· Hive 使用SerDe(以及FileFormat)讀寫表中的行
· HDFS文件 --> InputFormat --> <key, value> --> Deserializer --> Row object
· Row object --> Serializer --> <key, value> --> OutputFormat --> HDFS files
這里需要注意的是:這里的key部分在讀入后是被忽略掉的(因為key來自於TextInputFormat,是每行的字節偏移量,並不是用戶的數據),基本上行對象是存在value中的。
在內部,Hive 引擎使用定義的InputFormat來讀取一行條目,然后此記錄會被傳遞給SerDe.Deserializer() 方法進行處理。
以JSON SerDe為例,如果用戶想使用Hive 查詢JSON格式的數據。若是不使用SerDe,且每行為一個json“文件”的話,則可以在使用TextInputFormat 讀入,然后使用一個JSON的SerDe 將JSON文檔作為一條記錄進行解析。例如:
> create external table messages(
> id int,
> message string
> )
> row format serde "org.apache.hive.hcatalog.data.JsonSerDe"
> location 's3://tang-emr/jsonserde/'
> ;
JSON數據為:
{"id":1,"message":"yep"}
{"id":2,"message":"asdf"}
{"id":3,"message":"cddacddc","fa":"asf"}
hive> select * from messages;
OK
1 yep
2 asdf
3 cddacddc
References:
1. Hive 編程指南