調研系列第一篇:Orcfile數據文件


最近項目需要調研了下orcfile文件的格式、hive執行流程、hactalog等,整理和大家分享下,歡迎拍磚和探討 。

廢話少說,第一篇orcfile  

Orcfile

一些優點

http://docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.0.0.2/ds_Hive/orcfile.html#ORCFiles-ORCFileFormat

 

 

Orcfile存儲格式

orfile

各部分結構

Ø  整個文件的存儲中,row data是自定義的編碼,其余的都是使用protobuf進行編碼成byte[],然后存儲的,均為結構化數據。

Ø  最后一個字節是postscript的長度,也決定了post的長度不超過255unsigned byte

Ø  Postscript數據類型

主要信息 file footer的長度、文件壓縮類型、orcfile版本以及magic等信息 

Ø  File footer ,整個文件的概述  

主要信息:一些orcfile的參數、orcfile文件的column類型、key-value個人信息、Stripe信息以及每個stripe的各個數據部分數據長度信息..

Ø  待補充

每個stripe的結構

Ø  Stripe腳(StripeFooter

這個stripe中的stream的概要信息  

RowIndex,同樣采用protobuf的格式來存儲


data
信息,采用自己編碼的方式來存儲 data的分類  

  

紅色的為index的信息,黑色的都為data中的不同類型stream

Presentbit數組,針對null值的優化

Data:具體的data信息

Length:字符串的長度

dictionary_data:字典編碼的字典

secondary:針對於timestamp的優化

Ø  Index的統計信息

 

Ø  待補充

orcfile的讀寫

orcfile的寫 

Ø  創建write方法

Orcfile的配置項:

http://docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.0.0.2/ds_Hive/orcfile.html#ORCFiles-HiveQLSyntax

最終寫key-value數據的wrieter,和rcfilesquencefile一樣keynull

Ø  關於OrcSerdeRow,通過OrcSerdeinitialize方法,或者自己創建:

    private Object realRow;

private ObjectInspector inspector;

兩個變量,realRow真實的一行,是一個writable[]類型,里面存儲的是各個列的值  

   Inspector是一個OrcStructInspector類型,里面存儲這每個filedObjectInspectorhive中的一個概念,我現在的理解是將數據交換用的類型轉換為Java的基本類型的一個東東,將存儲和計算中的數值解耦開,個人可以自定義以適應不同的存儲類型,例如writableavro等類型)

realRow  OrcStruct類型,其 private Object[] fields 存儲的是writable類型的數據。

Ø  關於writer:實現的類為WriterImpl,主要的是創建TreeWriter,負責寫各個列的是數據,與其對應的是在讀的時候有個TreeReader,負責具體的各個列數據的讀取

Ø  關於orcfileTreeWriter:具體負責寫各個列的writer,是一棵樹的結構(以下以table中都是基本類型數據為類),基本的列類型為:int:string:timestampe:short:date:double

IntegerTreeWriter:

byteshortintlong均轉換為該類型的write,最底層的為一個RunLengthIntegerWriter(V2) stream 

StringTreeWriter 

一般分為兩種情況:直接寫,寫每個字符串的長度,char數組;使用字典編碼:字典字符串(長度+char數組)、字符在字典中的位置 

寫的時候兩種流同時寫,最后計算所有已寫的字符串中non-null字符串  字典個數的比例,若是超過一點的閥值(比如說1,就是沒有重復的字符串,字典大小和字符串一直)就只寫寫,廢棄字典 

TimestampTreeWriter

精確的時間讀寫,將時間分成秒數(linux時間)+好描述,兩個RunLengthInteger Stream數組流,利於壓縮 

DateTreeWriter

轉換成linux時間的秒數,最終使用RunLengthInteger Stream來存儲  

DoubleTreeWriter

沒有特殊處理,直接轉換成byte數組 

從低位到高位依次寫入stream  

Orcfile的寫對於一個stripe數據是全部寫入內存stream buffer 后,在fulsh硬盤上的,對於讀去也是,整個stripe讀取到內存buffer中的 

其它方式待補充,感興趣可以參考相應的類

orcfile的讀

Ø  創建基本的RecordReader<NullWritable, OrcStruct> ,然后按照hadoop的基本模型,一條條的讀取具體的數據 

Split方法直接繼承自fileInputFormat,按照文件和大小兩個因素來拆分 

關於inputFormat.getRecordReader

然后OrcFile.createReader ,這個方法其實就是讀取一個orcfile文件的PostScript以及file footer信息:一些orcfile的參數、orcfile文件的column類型、key-value個人信息、Stripe信息以及每個stripe的各個數據部分數據長度信息,詳述見上面 。無論文件一個orcfile被拆成基本split(一個map處理,有文件的offset length),但是這部分信息都是讀取的同一個orcfile的文件尾部 

接着OrcRecordReader的構造函數,利用conf中的hive.io.filter.expr.serialized(謂詞下推的條件數hive.io.file.readcolumn.idshive.io.file.readcolumn.names(需要的列),計算出需要讀取的存儲列以及需要過濾掉的行, 構造本次讀取的Stream 

最終通過OrcRecordReader.nex()讀出來的是OrcStruct 

fields是所有列存儲數組,實際是writable[]類型 

關於謂詞下推pushdown ,將謂詞條件數轉換成orcfileSearchArgument對象 

SearchArgumentImp的實現中有兩個屬性:

ExpressionTree 一棵謂詞的條件樹 

PredicateLeaf 類:一個具體的謂詞判斷條件 ,在后續做謂詞下推的判斷條件時候可以將index中的信息帶入這里面,然后得出一個判斷值  TruthValue 

 

 

兩個枚舉類介紹

謂詞表達式符號 

謂詞判斷邏輯結果類TruthValue 

 

對於一個完整的SearchArgumentImpl demo如下

謂詞邏輯樹是:((prodline_id>100 and  st_date>'20130101' ) or ad_src_id in(15 ,20 ,30) or alb_cust_id between 0 and 200000) and  contract_line_id > prodline_id ,其數據結結構如下:

 

RecordReaderImpl. pickRowGroups(),判斷一個stripe中多少個index對應的數據段應該被過濾,得到一個boolean[]result ,若是result[i]==false ,則表示第i個小塊的數據被過濾 

RecordReaderImpl. readAllDataStreams(),不需要過濾的時候將整個stripe讀取到內存buffer中,使用InStream(orc自定義的一個內存inputStream,里面有)來存儲 

RecordReaderImpl. readPartialDataStreams() ,讀取過濾后的一些小塊 ,通過index得到的過濾結果,判斷哪些位置的數據需要讀,讀取出來到一個bytebuffer[]中,然后再計算每個column的一系列不連續的塊的offsetendoffset ,然后封裝成InStream ,主要的幾個方法 

planReadPartialDataStreams():計算每個列的哪些位置數據應該被讀出來;

mergeDiskRanges() :將連續的數據合並起來,讀到一個bytebuffer中;

createStreams(streamList, chunks, bytes, included, codec, bufferSize,streams):根據上面計算的未知信息,將所有數據讀出來並構造需要的InStream 

 

demo ,以下數據在一個orcfile中的數據結構(data部分和footerstreams)

id(long)

Name(string)

Sex(string)

Socre(double)

Address(string)

14

lili

male

98.75

Street.5

15

xiaoming

male

80.25

Null

16

lucy

fmale

85.7

Street.7

25

leke

male

79

Null

27

null

male

83.25

Street.9.shangdi

Stripte-data

StripeFooter   List<Stream> :indexdata中的stream              

Col

Stream類型

Stream長度(byte[]的長度)

1

ROW_INDEX

 

……

 

 

5

ROW_INDEX

 

1

DATA(long,以run-longth存儲)

 

2

PRESENT

 

2

LENGTHlong,每列字符串的char個數)

 

2

DATA(一個個的char

 

3

LENGTH(long,字段的每個單詞包含的char)

 

3

DICTIONARY_DATA(字典的char集,和上面一個構成字典)

 

3

DATA(long,一個field在字典中的未知)

 

4

DATA(double,以64位定長編碼double)

 

5

PRESENT

 

5

LENGTH(long,每列字符串的char個數)

 

5

DATA(一個個的char

 

Data

 

 

 

14 15 16 25 27

11110

4 8 4 4

Lilixiaominglucyleke

3 4

malefmale

0 0 1 0 0

98.75 80.25 85.7 79 83.25

10101

7 7 15

Street.5Street.7Street.9.shangdi

 

測試數據結果,在總共4200萬行的數據中過濾選擇,數據大小在3G左右

測試分為兩種:

一:按照某一列排序,然后按照這列的條件來做過濾,這樣就會出現的是從某一個index開始后的所有數據被連續讀出來,避免不斷的隨機尋址

 :修改部分orc謂詞下推的代碼,在所有的index中隨機間隔的選出一個作為命中塊,這樣會出現數據過濾了一下,但是會出現多次磁盤尋址在讀取(有的可能是讀取很小的數據段)的情況,具體測試如下:

Row num

Cost(s)

Read buffer count

順序讀數據

42064498

117

47

40634498

112

46

38559498

106

43

36024498

103

41

31924498

88

36

27399498

75

31

22034498

63

25

14359498

41

16

12209498

35

14

隨機讀數據

42064498

118

47

37929498

122

171

33454498

121

401

29215000

122

637

25189498

116

877

21449498

110

1090

16725000

96

1291

13030000

84

1382

8354498

66

1411

4130000

45

1303

 

 

 

后續使用OrcFile的一些改進想法

1、 在保證計算性能的前提下,擴展orcfile的統計信息,用作table數據統計畫像改進謂詞下推過濾

2、 在擴展統計信息的基礎上改進謂詞下推的算法.

3、 可以參考infobright<<Infobright_–_Analytic_Database_Engine>><Brighthouse_An_Analytic_Data_Warehouse_for_Ad-hoc_Queries>論文以及infobright的一些查詢優化 .

4、 針對hdfsblock大小,來控制stripe文件大小,以盡量保證local .

5、 待補充.

 

 

相關的ppt

http://files.cnblogs.com/serendipity/Orcfile%E7%AE%80%E4%BB%8B.pptx

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM