1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Hive - ORC 文件存儲格式詳細(xì)解析

        共 7851字,需瀏覽 16分鐘

         ·

        2021-03-26 11:08

        一、ORC File文件結(jié)構(gòu)

        ORC的全稱是(Optimized Row Columnar),ORC文件格式是一種Hadoop生態(tài)圈中的列式存儲格式,它的產(chǎn)生早在2013年初,最初產(chǎn)生自Apache Hive,用于降低Hadoop數(shù)據(jù)存儲空間和加速Hive查詢速度。和Parquet類似,它并不是一個(gè)單純的列式存儲格式,仍然是首先根據(jù)行組分割整個(gè)表,在每一個(gè)行組內(nèi)進(jìn)行按列存儲。ORC文件是自描述的,它的元數(shù)據(jù)使用Protocol Buffers序列化,并且文件中的數(shù)據(jù)盡可能的壓縮以降低存儲空間的消耗,目前也被Spark SQL、Presto等查詢引擎支持,但是Impala對于ORC目前沒有支持,仍然使用Parquet作為主要的列式存儲格式。2015年ORC項(xiàng)目被Apache項(xiàng)目基金會提升為Apache頂級項(xiàng)目。ORC具有以下一些優(yōu)勢:

        1. ORC是列式存儲,有多種文件壓縮方式,并且有著很高的壓縮比。

        2. 文件是可切分(Split)的。因此,在Hive中使用ORC作為表的文件存儲格式,不僅節(jié)省HDFS存儲資源,查詢?nèi)蝿?wù)的輸入數(shù)據(jù)量減少,使用的MapTask也就減少了。

        3. 提供了多種索引,row group index、bloom filter index。

        4. ORC可以支持復(fù)雜的數(shù)據(jù)結(jié)構(gòu)(比如Map等)

        列式存儲  

        由于OLAP查詢的特點(diǎn),列式存儲可以提升其查詢性能,但是它是如何做到的呢?這就要從列式存儲的原理說起,從圖1中可以看到,相對于關(guān)系數(shù)據(jù)庫中通常使用的行式存儲,在使用列式存儲時(shí)每一列的所有元素都是順序存儲的。由此特點(diǎn)可以給查詢帶來如下的優(yōu)化:

        • 查詢的時(shí)候不需要掃描全部的數(shù)據(jù),而只需要讀取每次查詢涉及的列,這樣可以將I/O消耗降低N倍,另外可以保存每一列的統(tǒng)計(jì)信息(min、max、sum等),實(shí)現(xiàn)部分的謂詞下推。

        • 由于每一列的成員都是同構(gòu)的,可以針對不同的數(shù)據(jù)類型使用更高效的數(shù)據(jù)壓縮算法,進(jìn)一步減小I/O。

        • 由于每一列的成員的同構(gòu)性,可以使用更加適合CPU pipeline的編碼方式,減小CPU的緩存失效。

          

         

        關(guān)于Orc文件格式的官網(wǎng)介紹,見:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+ORC

        需要注意的是,ORC在讀寫時(shí)候需要消耗額外的CPU資源來壓縮和解壓縮,當(dāng)然這部分的CPU消耗是非常少的。

        數(shù)據(jù)模型

        和Parquet不同,ORC原生是不支持嵌套數(shù)據(jù)格式的,而是通過對復(fù)雜數(shù)據(jù)類型特殊處理的方式實(shí)現(xiàn)嵌套格式的支持,例如對于如下的hive表:


        CREATE TABLE `orcStructTable`(  `name` string,  `course` struct<course:string,score:int>,  `score` map<string,int>,  `work_locations` array<string>)

        在ORC的結(jié)構(gòu)中包含了復(fù)雜類型列和原始類型,前者包括LIST、STRUCT、MAP和UNION類型,后者包括BOOLEAN、整數(shù)、浮點(diǎn)數(shù)、字符串類型等,其中STRUCT的孩子節(jié)點(diǎn)包括它的成員變量,可能有多個(gè)孩子節(jié)點(diǎn),MAP有兩個(gè)孩子節(jié)點(diǎn),分別為key和value,LIST包含一個(gè)孩子節(jié)點(diǎn),類型為該LIST的成員類型,UNION一般不怎么用得到。每一個(gè)Schema樹的根節(jié)點(diǎn)為一個(gè)Struct類型,所有的column按照樹的中序遍歷順序編號。

        ORC只需要存儲schema樹中葉子節(jié)點(diǎn)的值,而中間的非葉子節(jié)點(diǎn)只是做一層代理,它們只需要負(fù)責(zé)孩子節(jié)點(diǎn)值得讀取,只有真正的葉子節(jié)點(diǎn)才會讀取數(shù)據(jù),然后交由父節(jié)點(diǎn)封裝成對應(yīng)的數(shù)據(jù)結(jié)構(gòu)返回。

        文件結(jié)構(gòu)

        和Parquet類似,ORC文件也是以二進(jìn)制方式存儲的,所以是不可以直接讀取,ORC文件也是自解析的,它包含許多的元數(shù)據(jù),這些元數(shù)據(jù)都是同構(gòu)ProtoBuffer進(jìn)行序列化的。ORC的文件結(jié)構(gòu)如下圖,其中涉及到如下的概念:

        • ORC文件:保存在文件系統(tǒng)上的普通二進(jìn)制文件,一個(gè)ORC文件中可以包含多個(gè)stripe,每一個(gè)stripe包含多條記錄,這些記錄按照列進(jìn)行獨(dú)立存儲,對應(yīng)到Parquet中的row group的概念。

        • 文件級元數(shù)據(jù):包括文件的描述信息PostScript、文件meta信息(包括整個(gè)文件的統(tǒng)計(jì)信息)、所有stripe的信息和文件schema信息。

        • stripe:一組行形成一個(gè)stripe,每次讀取文件是以行組為單位的,一般為HDFS的塊大小,保存了每一列的索引和數(shù)據(jù)。

        • stripe元數(shù)據(jù):保存stripe的位置、每一個(gè)列的在該stripe的統(tǒng)計(jì)信息以及所有的stream類型和位置。

        • row group:索引的最小單位,一個(gè)stripe中包含多個(gè)row group,默認(rèn)為10000個(gè)值組成。

        • stream:一個(gè)stream表示文件中一段有效的數(shù)據(jù),包括索引和數(shù)據(jù)兩類。索引stream保存每一個(gè)row group的位置和統(tǒng)計(jì)信息,數(shù)據(jù)stream包括多種類型的數(shù)據(jù),具體需要哪幾種是由該列類型和編碼方式?jīng)Q定。

        在ORC文件中保存了三個(gè)層級的統(tǒng)計(jì)信息,分別為文件級別、stripe級別和row group級別的,他們都可以用來根據(jù)Search ARGuments(謂詞下推條件)判斷是否可以跳過某些數(shù)據(jù),在統(tǒng)計(jì)信息中都包含成員數(shù)和是否有null值,并且對于不同類型的數(shù)據(jù)設(shè)置一些特定的統(tǒng)計(jì)信息。

        (1)file level
        在ORC文件的末尾會記錄文件級別的統(tǒng)計(jì)信息,會記錄整個(gè)文件中columns的統(tǒng)計(jì)信息。這些信息主要用于查詢的優(yōu)化,也可以為一些簡單的聚合查詢比如max, min, sum輸出結(jié)果。 

        (2)stripe level
        ORC文件會保存每個(gè)字段stripe級別的統(tǒng)計(jì)信息,ORC reader使用這些統(tǒng)計(jì)信息來確定對于一個(gè)查詢語句來說,需要讀入哪些stripe中的記錄。比如說某個(gè)stripe的字段max(a)=10,min(a)=3,那么當(dāng)where條件為a >10或者a <3時(shí),那么這個(gè)stripe中的所有記錄在查詢語句執(zhí)行時(shí)不會被讀入。 

        (3)row level 
        為了進(jìn)一步的避免讀入不必要的數(shù)據(jù),在邏輯上將一個(gè)column的index以一個(gè)給定的值(默認(rèn)為10000,可由參數(shù)配置)分割為多個(gè)index組。以10000條記錄為一個(gè)組,對數(shù)據(jù)進(jìn)行統(tǒng)計(jì)。Hive查詢引擎會將where條件中的約束傳遞給ORC reader,這些reader根據(jù)組級別的統(tǒng)計(jì)信息,過濾掉不必要的數(shù)據(jù)。如果該值設(shè)置的太小,就會保存更多的統(tǒng)計(jì)信息,用戶需要根據(jù)自己數(shù)據(jù)的特點(diǎn)權(quán)衡一個(gè)合理的值。

        數(shù)據(jù)訪問

        讀取ORC文件是從尾部開始的,第一次讀取16KB的大小,盡可能的將Postscript和Footer數(shù)據(jù)都讀入內(nèi)存。文件的最后一個(gè)字節(jié)保存著PostScript的長度,它的長度不會超過256字節(jié),PostScript中保存著整個(gè)文件的元數(shù)據(jù)信息,它包括文件的壓縮格式、文件內(nèi)部每一個(gè)壓縮塊的最大長度(每次分配內(nèi)存的大小)、Footer長度,以及一些版本信息。在Postscript和Footer之間存儲著整個(gè)文件的統(tǒng)計(jì)信息(上圖中未畫出),這部分的統(tǒng)計(jì)信息包括每一個(gè)stripe中每一列的信息,主要統(tǒng)計(jì)成員數(shù)、最大值、最小值、是否有空值等。

        接下來讀取文件的Footer信息,它包含了每一個(gè)stripe的長度和偏移量,該文件的schema信息(將schema樹按照schema中的編號保存在數(shù)組中)、整個(gè)文件的統(tǒng)計(jì)信息以及每一個(gè)row group的行數(shù)。

        處理stripe時(shí)首先從Footer中獲取每一個(gè)stripe的其實(shí)位置和長度、每一個(gè)stripe的Footer數(shù)據(jù)(元數(shù)據(jù),記錄了index和data的的長度),整個(gè)striper被分為index和data兩部分,stripe內(nèi)部是按照row group進(jìn)行分塊的(每一個(gè)row group中多少條記錄在文件的Footer中存儲),row group內(nèi)部按列存儲。每一個(gè)row group由多個(gè)stream保存數(shù)據(jù)和索引信息。每一個(gè)stream的數(shù)據(jù)會根據(jù)該列的類型使用特定的壓縮算法保存。在ORC中存在如下幾種stream類型:

        • PRESENT:每一個(gè)成員值在這個(gè)stream中保持一位(bit)用于標(biāo)示該值是否為NULL,通過它可以只記錄部位NULL的值

        • DATA:該列的中屬于當(dāng)前stripe的成員值。

        • LENGTH:每一個(gè)成員的長度,這個(gè)是針對string類型的列才有的。

        • DICTIONARY_DATA:對string類型數(shù)據(jù)編碼之后字典的內(nèi)容。

        • SECONDARY:存儲Decimal、timestamp類型的小數(shù)或者納秒數(shù)等。

        • ROW_INDEX:保存stripe中每一個(gè)row group的統(tǒng)計(jì)信息和每一個(gè)row group起始位置信息。

        在初始化階段獲取全部的元數(shù)據(jù)之后,可以通過includes數(shù)組指定需要讀取的列編號,它是一個(gè)boolean數(shù)組,如果不指定則讀取全部的列,還可以通過傳遞SearchArgument參數(shù)指定過濾條件,根據(jù)元數(shù)據(jù)首先讀取每一個(gè)stripe中的index信息,然后根據(jù)index中統(tǒng)計(jì)信息以及SearchArgument參數(shù)確定需要讀取的row group編號,再根據(jù)includes數(shù)據(jù)決定需要從這些row group中讀取的列,通過這兩層的過濾需要讀取的數(shù)據(jù)只是整個(gè)stripe多個(gè)小段的區(qū)間,然后ORC會盡可能合并多個(gè)離散的區(qū)間盡可能的減少I/O次數(shù)。然后再根據(jù)index中保存的下一個(gè)row group的位置信息調(diào)至該stripe中第一個(gè)需要讀取的row group中。

        ORC文件格式只支持讀取指定字段,還不支持只讀取特殊字段類型中的指定部分。 

        使用ORC文件格式時(shí),用戶可以使用HDFS的每一個(gè)block存儲ORC文件的一個(gè)stripe。對于一個(gè)ORC文件來說,stripe的大小一般需要設(shè)置得比HDFS的block小,如果不這樣的話,一個(gè)stripe就會分別在HDFS的多個(gè)block上,當(dāng)讀取這種數(shù)據(jù)時(shí)就會發(fā)生遠(yuǎn)程讀數(shù)據(jù)的行為。如果設(shè)置stripe的只保存在一個(gè)block上的話,如果當(dāng)前block上的剩余空間不足以存儲下一個(gè)strpie,ORC的writer接下來會將數(shù)據(jù)打散保存在block剩余的空間上,直到這個(gè)block存滿為止。這樣,下一個(gè)stripe又會從下一個(gè)block開始存儲。

        由于ORC中使用了更加精確的索引信息,使得在讀取數(shù)據(jù)時(shí)可以指定從任意一行開始讀取,更細(xì)粒度的統(tǒng)計(jì)信息使得讀取ORC文件跳過整個(gè)row group,ORC默認(rèn)會對任何一塊數(shù)據(jù)和索引信息使用ZLIB壓縮,因此ORC文件占用的存儲空間也更小,這點(diǎn)在后面的測試對比中也有所印證。

        文件壓縮

        ORC文件使用兩級壓縮機(jī)制,首先將一個(gè)數(shù)據(jù)流使用流式編碼器進(jìn)行編碼,然后使用一個(gè)可選的壓縮器對數(shù)據(jù)流進(jìn)行進(jìn)一步壓縮。 
        一個(gè)column可能保存在一個(gè)或多個(gè)數(shù)據(jù)流中,可以將數(shù)據(jù)流劃分為以下四種類型: 
        ? Byte Stream 
        字節(jié)流保存一系列的字節(jié)數(shù)據(jù),不對數(shù)據(jù)進(jìn)行編碼。 

        ? Run Length Byte Stream 
        字節(jié)長度字節(jié)流保存一系列的字節(jié)數(shù)據(jù),對于相同的字節(jié),保存這個(gè)重復(fù)值以及該值在字節(jié)流中出現(xiàn)的位置。 

        ? Integer Stream 
        整形數(shù)據(jù)流保存一系列整形數(shù)據(jù)。可以對數(shù)據(jù)量進(jìn)行字節(jié)長度編碼以及delta編碼。具體使用哪種編碼方式需要根據(jù)整形流中的子序列模式來確定。 

        ? Bit Field Stream 
        比特流主要用來保存boolean值組成的序列,一個(gè)字節(jié)代表一個(gè)boolean值,在比特流的底層是用Run Length Byte Stream來實(shí)現(xiàn)的。 

        接下來會以Integer和String類型的字段舉例來說明。 

        (1)Integer 
        對于一個(gè)整形字段,會同時(shí)使用一個(gè)比特流和整形流。比特流用于標(biāo)識某個(gè)值是否為null,整形流用于保存該整形字段非空記錄的整數(shù)值。 

        (2)String 
        對于一個(gè)String類型字段,ORC writer在開始時(shí)會檢查該字段值中不同的內(nèi)容數(shù)占非空記錄總數(shù)的百分比不超過0.8的話,就使用字典編碼,字段值會保存在一個(gè)比特流,一個(gè)字節(jié)流及兩個(gè)整形流中。比特流也是用于標(biāo)識null值的,字節(jié)流用于存儲字典值,一個(gè)整形流用于存儲字典中每個(gè)詞條的長度,另一個(gè)整形流用于記錄字段值。 

        如果不能用字典編碼,ORC writer會知道這個(gè)字段的重復(fù)值太少,用字典編碼效率不高,ORC writer會使用一個(gè)字節(jié)流保存String字段的值,然后用一個(gè)整形流來保存每個(gè)字段的字節(jié)長度。 

        在ORC文件中,在各種數(shù)據(jù)流的底層,用戶可以自選ZLIB, Snappy和LZO壓縮方式對數(shù)據(jù)流進(jìn)行壓縮。編碼器一般會將一個(gè)數(shù)據(jù)流壓縮成一個(gè)個(gè)小的壓縮單元,在目前的實(shí)現(xiàn)中,壓縮單元的默認(rèn)大小是256KB。

        二、Hive+ORC建立數(shù)據(jù)倉庫

        在建Hive表的時(shí)候我們就應(yīng)該指定文件的存儲格式。所以你可以在Hive QL語句里面指定用ORCFile這種文件格式,如下:


        CREATE TABLE ... STORED AS ORC

        ALTER TABLE ... [PARTITION partition_spec] SET FILEFORMAT ORC

        SET hive.
        default.fileformat=Orc

        所有關(guān)于ORCFile的參數(shù)都是在Hive QL語句的TBLPROPERTIES字段里面出現(xiàn),他們是:

        三、Java操作ORC

        到https://orc.apache.org官網(wǎng)下載orc源碼包,然后編譯獲取orc-core-1.3.0.jar、orc-mapreduce-1.3.0.jar、orc-tools-1.3.0.jar,將其加入項(xiàng)目中

        import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.Path;import org.apache.hadoop.hive.ql.exec.vector.LongColumnVector;import org.apache.hadoop.hive.ql.exec.vector.VectorizedRowBatch;import org.apache.orc.CompressionKind;import org.apache.orc.OrcFile;import org.apache.orc.TypeDescription;import org.apache.orc.Writer;
        public class TestORCWriter {
        public static void main(String[] args) throws Exception { Path testFilePath = new Path("/tmp/test.orc"); Configuration conf = new Configuration(); TypeDescription schema = TypeDescription.fromString("struct<field1:int,field2:int,field3:int>"); Writer writer = OrcFile.createWriter(testFilePath, OrcFile.writerOptions(conf).setSchema(schema).compress(CompressionKind.SNAPPY)); VectorizedRowBatch batch = schema.createRowBatch(); LongColumnVector first = (LongColumnVector) batch.cols[0]; LongColumnVector second = (LongColumnVector) batch.cols[1]; LongColumnVector third = (LongColumnVector) batch.cols[2];
        final int BATCH_SIZE = batch.getMaxSize(); // add 1500 rows to file for (int r = 0; r < 15000000; ++r) { int row = batch.size++; first.vector[row] = r; second.vector[row] = r * 3; third.vector[row] = r * 6; if (row == BATCH_SIZE - 1) { writer.addRowBatch(batch); batch.reset(); } } if (batch.size != 0) { writer.addRowBatch(batch); batch.reset(); } writer.close(); }}

        大多情況下,還是建議在Hive中將文本文件轉(zhuǎn)成ORC格式,這種用JAVA在本地生成ORC文件,屬于特殊需求場景。

        參考:

        http://lxw1234.com/archives/2016/04/630.htm

        https://www.iteblog.com/archives/1014.html

        http://blog.csdn.net/dabokele/article/details/51542327

        http://blog.csdn.net/dabokele/article/details/51813322

        http://blog.csdn.net/nysyxxg/article/details/52241848

        http://blog.csdn.net/yu616568/article/details/51868447

        瀏覽 53
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            天天射天天噜 | 99re这里只有精品在线观看 | 欧洲中文字幕日韩精品成人 | 天天天久久久 | 欧美一品道| 午夜男女福利 | 97一区二区三区 | 91麻豆精品一区二区三区 | 亚洲页 | 国产在线麻豆秘 二次 |