Hive - ORC 文件存儲格式【轉】

来源:https://www.cnblogs.com/lxbmaomao/archive/2018/07/18/9333113.html
-Advertisement-
Play Games

一、ORC File文件結構 ORC的全稱是(Optimized Row Columnar),ORC文件格式是一種Hadoop生態圈中的列式存儲格式,它的產生早在2013年初,最初產生自Apache Hive,用於降低Hadoop數據存儲空間和加速Hive查詢速度。和Parquet類似,它並不是一個 ...


一、ORC File文件結構

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

  1. ORC是列式存儲,有多種文件壓縮方式,並且有著很高的壓縮比。
  2. 文件是可切分(Split)的。因此,在Hive中使用ORC作為表的文件存儲格式,不僅節省HDFS存儲資源,查詢任務的輸入數據量減少,使用的MapTask也就減少了。
  3. 提供了多種索引,row group index、bloom filter index。
  4. ORC可以支持複雜的數據結構(比如Map等)

 列式存儲  

  由於OLAP查詢的特點,列式存儲可以提升其查詢性能,但是它是如何做到的呢?這就要從列式存儲的原理說起,從圖1中可以看到,相對於關係資料庫中通常使用的行式存儲,在使用列式存儲時每一列的所有元素都是順序存儲的。由此特點可以給查詢帶來如下的優化:

  • 查詢的時候不需要掃描全部的數據,而只需要讀取每次查詢涉及的列,這樣可以將I/O消耗降低N倍,另外可以保存每一列的統計信息(min、max、sum等),實現部分的謂詞下推。
  • 由於每一列的成員都是同構的,可以針對不同的數據類型使用更高效的數據壓縮演算法,進一步減小I/O。
  • 由於每一列的成員的同構性,可以使用更加適合CPU pipeline的編碼方式,減小CPU的緩存失效。

  

 

關於Orc文件格式的官網介紹,見:

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

  需要註意的是,ORC在讀寫時候需要消耗額外的CPU資源來壓縮和解壓縮,當然這部分的CPU消耗是非常少的。

  數據模型

  和Parquet不同,ORC原生是不支持嵌套數據格式的,而是通過對複雜數據類型特殊處理的方式實現嵌套格式的支持,例如對於如下的hive表:

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

 

  在ORC的結構中包含了複雜類型列和原始類型,前者包括LIST、STRUCT、MAP和UNION類型,後者包括BOOLEAN、整數、浮點數、字元串類型等,其中STRUCT的孩子節點包括它的成員變數,可能有多個孩子節點,MAP有兩個孩子節點,分別為key和value,LIST包含一個孩子節點,類型為該LIST的成員類型,UNION一般不怎麼用得到。每一個Schema樹的根節點為一個Struct類型,所有的column按照樹的中序遍歷順序編號。

ORC只需要存儲schema樹中葉子節點的值,而中間的非葉子節點只是做一層代理,它們只需要負責孩子節點值得讀取,只有真正的葉子節點才會讀取數據,然後交由父節點封裝成對應的數據結構返回。

  文件結構

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

  • ORC文件:保存在文件系統上的普通二進位文件,一個ORC文件中可以包含多個stripe,每一個stripe包含多條記錄,這些記錄按照列進行獨立存儲,對應到Parquet中的row group的概念。
  • 文件級元數據:包括文件的描述信息PostScript、文件meta信息(包括整個文件的統計信息)、所有stripe的信息和文件schema信息。
  • stripe:一組行形成一個stripe,每次讀取文件是以行組為單位的,一般為HDFS的塊大小,保存了每一列的索引和數據。
  • stripe元數據:保存stripe的位置、每一個列的在該stripe的統計信息以及所有的stream類型和位置。
  • row group:索引的最小單位,一個stripe中包含多個row group,預設為10000個值組成。
  • stream:一個stream表示文件中一段有效的數據,包括索引和數據兩類。索引stream保存每一個row group的位置和統計信息,數據stream包括多種類型的數據,具體需要哪幾種是由該列類型和編碼方式決定。

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

(1)file level
  在ORC文件的末尾會記錄文件級別的統計信息,會記錄整個文件中columns的統計信息。這些信息主要用於查詢的優化,也可以為一些簡單的聚合查詢比如max, min, sum輸出結果。 

(2)stripe level
  ORC文件會保存每個欄位stripe級別的統計信息,ORC reader使用這些統計信息來確定對於一個查詢語句來說,需要讀入哪些stripe中的記錄。比如說某個stripe的欄位max(a)=10,min(a)=3,那麼當where條件為a >10或者a <3時,那麼這個stripe中的所有記錄在查詢語句執行時不會被讀入。 

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

 

  ORC元數據

  請參考:更高的壓縮比,更好的性能–使用ORC文件格式優化Hive

  數據訪問

  讀取ORC文件是從尾部開始的,第一次讀取16KB的大小,儘可能的將Postscript和Footer數據都讀入記憶體。文件的最後一個位元組保存著PostScript的長度,它的長度不會超過256位元組,PostScript中保存著整個文件的元數據信息,它包括文件的壓縮格式、文件內部每一個壓縮塊的最大長度(每次分配記憶體的大小)、Footer長度,以及一些版本信息。在Postscript和Footer之間存儲著整個文件的統計信息(上圖中未畫出),這部分的統計信息包括每一個stripe中每一列的信息,主要統計成員數、最大值、最小值、是否有空值等。

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

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

  • PRESENT:每一個成員值在這個stream中保持一位(bit)用於標示該值是否為NULL,通過它可以只記錄部位NULL的值
  • DATA:該列的中屬於當前stripe的成員值。
  • LENGTH:每一個成員的長度,這個是針對string類型的列才有的。
  • DICTIONARY_DATA:對string類型數據編碼之後字典的內容。
  • SECONDARY:存儲Decimal、timestamp類型的小數或者納秒數等。
  • ROW_INDEX:保存stripe中每一個row group的統計信息和每一個row group起始位置信息。

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

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

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

  由於ORC中使用了更加精確的索引信息,使得在讀取數據時可以指定從任意一行開始讀取,更細粒度的統計信息使得讀取ORC文件跳過整個row group,ORC預設會對任何一塊數據和索引信息使用ZLIB壓縮,因此ORC文件占用的存儲空間也更小,這點在後面的測試對比中也有所印證。

 

關於row group index和bloom filter index的性能優化,請參考Hive性能優化之ORC索引–Row Group Index vs Bloom Filter Index

 

文件壓縮

  ORC文件使用兩級壓縮機制,首先將一個數據流使用流式編碼器進行編碼,然後使用一個可選的壓縮器對數據流進行進一步壓縮。 
  一個column可能保存在一個或多個數據流中,可以將數據流劃分為以下四種類型: 
• Byte Stream 
  位元組流保存一系列的位元組數據,不對數據進行編碼。 

• Run Length Byte Stream 
  位元組長度位元組流保存一系列的位元組數據,對於相同的位元組,保存這個重覆值以及該值在位元組流中出現的位置。 

• Integer Stream 
  整形數據流保存一系列整形數據。可以對數據量進行位元組長度編碼以及delta編碼。具體使用哪種編碼方式需要根據整形流中的子序列模式來確定。 

• Bit Field Stream 
  比特流主要用來保存boolean值組成的序列,一個位元組代表一個boolean值,在比特流的底層是用Run Length Byte Stream來實現的。 

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

(1)Integer 
  對於一個整形欄位,會同時使用一個比特流和整形流。比特流用於標識某個值是否為null,整形流用於保存該整形欄位非空記錄的整數值。 

(2)String 
  對於一個String類型欄位,ORC writer在開始時會檢查該欄位值中不同的內容數占非空記錄總數的百分比不超過0.8的話,就使用字典編碼,欄位值會保存在一個比特流,一個位元組流及兩個整形流中。比特流也是用於標識null值的,位元組流用於存儲字典值,一個整形流用於存儲字典中每個詞條的長度,另一個整形流用於記錄欄位值。 

  如果不能用字典編碼,ORC writer會知道這個欄位的重覆值太少,用字典編碼效率不高,ORC writer會使用一個位元組流保存String欄位的值,然後用一個整形流來保存每個欄位的位元組長度。 

  在ORC文件中,在各種數據流的底層,用戶可以自選ZLIB, Snappy和LZO壓縮方式對數據流進行壓縮。編碼器一般會將一個數據流壓縮成一個個小的壓縮單元,在目前的實現中,壓縮單元的預設大小是256KB。

  參數

  參數可參看:https://cwiki.apache.org/confluence/display/Hive/Configuration+Properties#ConfigurationProperties-ORCFileFormat

 

二、Hive+ORC建立數據倉庫

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

CREATE TABLE ... STORED AS ORC
 
ALTER TABLE ... [PARTITION partition_spec] SET FILEFORMAT ORC
 
SET hive.default.fileformat=Orc

所有關於ORCFile的參數都是在Hive QL語句的TBLPROPERTIES欄位裡面出現,他們是:

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

268435456

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

 三、Java操作ORC

  到https://orc.apache.org官網下載orc源碼包,然後編譯獲取orc-core-1.3.0.jar、orc-mapreduce-1.3.0.jar、orc-tools-1.3.0.jar,將其加入項目中

複製代碼
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中將文本文件轉成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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • win7自帶的截圖工具很好,很強大,比從網上下載的截圖工具好用多了,很少會出現問題。但是它能不能像QQ截圖工具一樣可以使用快捷鍵呢?今天小編和大家分享下心得,希望能夠給你的工作帶來快捷。 工具/原料 win7自帶截圖工具 工具/原料 win7自帶截圖工具 win7自帶截圖工具 win7自帶截圖工具 ...
  • 1.準備工具 1).交叉編譯工具 2).下載libcurl和openssl源代碼,我使用的是(openssl 1.0.2o.tar,curl 7.59.0.tar) 3).查看cpu詳細 2.開始編譯 openssl 庫版本 : openssl 1.0.2o march和 D__ARM_MAX_AR ...
  • 功能:用websocket技術,在運維工具的瀏覽器上實時顯示遠程伺服器上的日誌信息 一般我們在運維工具部署環境的時候,需要實時展現部署過程中的信息,或者在瀏覽器中實時顯示程式日誌給開發人員看。你還在用ajax每隔段時間去獲取伺服器日誌?out了,試試用websocket方式吧 我用bottle框架, ...
  • 一、安裝環境及配置yum 二、安裝MongoDB 三、驗證安裝結果 ...
  • 線程介紹 Intro 20世紀60年代人們提出了進程的概念,到20世紀80年代中期人們提出了比進程更小的能獨立運行的基本單位——線程,試圖用它來提高系統內程式併發執行的程度從而進一步提高系統的吞吐量。 線程具有傳統進程所具有的特征,所以稱之為輕型進程或進程元,相應的把傳統進程稱之為重型進程。 一個進 ...
  • 進程是操作系統為了提高系統的併發處理能力,為瞭解決可以“同時”運行多個程式且為了對併發執行的程式加以描述和控制而提出來的。 ...
  • ElasticSearch 學習筆記 Near Realtime(NRT):近實時,先說實時就是數據創建到查詢時間在毫秒級或更少; 和實時不一樣的是近實時數據在創建到查詢最多需要n秒時間,n秒是索引刷新周期(假如設置n為5秒,若你在2秒的時候插入了一條數據,那麼你還需要等3秒才能查詢到這條數據,... ...
  • 占座 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...