hive:orc file

参考如下:

http://www.colabug.com/thread-1063815-1-1.html

http://www.cnblogs.com/cxzdy/p/5910760.html

http://www.lai18.com/content/24596520.html

http://blog.csdn.net/liuzhoulong/article/details/52048105



一、定义

ORC File,(Optimized Row Columnar)File,是对RCFile的优化。ORC文件格式是从Hive-0.11版本开始的.


二、目的:

          1、大幅度降低磁盘占用

           2、大幅提高执行效率


三、和RCFile格式相比,ORC File格式有以下优点: 

(1)、每个task只输出单个文件,这样可以减少NameNode的负载; 
(2)、支持各种复杂的数据类型,比如: datetime, decimal, 以及一些复杂类型(struct, list, map, and union); 
(3)、在文件中存储了一些轻量级的索引数据; 
(4)、基于数据类型的块模式压缩

a、integer类型的列用行程长度编码(run-length encoding);

b、String类型的列用字典编码(dictionary encoding); 
(5)、用多个互相独立的RecordReaders并行读相同的文件; 
(6)、无需扫描markers就可以分割文件; 
(7)、绑定读写所需要的内存; 
(8)、metadata的存储是用 Protocol Buffers的,所以它支持添加和删除一些列。 


- 1、ORC中的特定的序列化与反序列化操作可以使ORC file writer根据数据类型进行写出。 

- 2、提供了多种RCFile中没有的indexes,这些indexes可以使ORC的reader很快的读到需要的数据,并且跳过无用数据,这使得ORC文件中的数据可以很快的得到访问。 

- 3、由于ORC file writer可以根据数据类型进行写出,所以ORC可以支持复杂的数据结构(比如Map等)。 

- 4、除了上面三个理论上就具有的优势之外,ORC的具体实现上还有一些其他的优势,比如ORC的stripe默认大小更大,为ORC writer提供了一个memory manager来管理内存使用情况。 






四、ORC File文件结构

ORC File包含一组组的行数据,称为stripes。在默认情况下,一个stripe的大小为250MB。大尺寸的stripes使得从HDFS读数据更高效。 


ORC File的file footer还包含一些额外的辅助信息。包含了该ORC File文件中stripes的信息,每个stripe中有多少行,以及每列的数据类型。当然,它里面还包含了列级别的一些聚合的结果,比如:count, min, max, and sum。


在ORC File文件的最后,有一个被称为postscript的区,它主要是用来存储压缩参数及压缩页脚的大小。 

Hive:ORC File Format存储格式详解-2 (互联网,主题,文章,file,博客)

五、stripe结构

每个Stripe都包含index data、row data以及stripe footer。

Stripe footer包含流位置的目录;

Row data在表扫描的时候会用到。 
Index data包含每列的最大和最小值以及每列所在的行。行索引里面提供了偏移量,它可以跳到正确的压缩块位置。具有相对频繁的行索引,使得在stripe中快速读取的过程中可以跳过很多行,尽管这个stripe的大小很大。在默认情况下,最大可以跳过10000行。拥有通过过滤谓词而跳过大量的行的能力,你可以在表的 secondary keys 进行排序,从而可以大幅减少执行时间。比如你的表的主分区是交易日期,那么你可以对次分区(state、zip code以及last name)进行排序。 


六、hive中如何使用ORCFile

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

所有关于ORCFile的参数都是在Hive QL语句的TBLPROPERTIES字段里面出现,他们是:
  

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  


下面的例子是建立一个没有启用压缩的ORCFile的表
create table Addresses ( 

name string,

 street string, 

city string,

 state string,

 zip int

stored as orc

tblproperties ("orc.compress"="NONE");


七、序列号和压缩

对ORCFile文件中的列进行压缩基于这列的数据类型是integer或者string


  Integer Column Serialization 
Integer columns are serialized in two streams. 
1、present bit stream: is the value non-null? 
2、data stream: a stream of integers 
Integer data is serialized in a way that takes advantage of the common distribution of numbers: 
1、Integers are encoded using a variable-width encoding that has fewer bytes for small integers. 
2、Repeated values are run-length encoded. 
3、Values that differ by a constant in the range (-128 to 127) are run-length encoded. 
The variable-width encoding is based on Google’s protocol buffers and uses the high bit to represent whether this byte is not the last and the lower 7 bits to encode data. To encode negative numbers, a zigzag encoding is used where 0, -1, 1, -2, and 2 map into 0, 1, 2, 3, 4, and 5 respectively. 
  Each set of numbers is encoded this way: 
1、If the first byte (b0) is negative: 
-b0 variable-length integers follow. 
2、If the first byte (b0) is positive: 
it represents b0 + 3 repeated integers 
the second byte (-128 to +127) is added between each repetition 
1 variable-length integer. 
In run-length encoding , the first byte specifies run length and whether the values are literals or duplicates. Duplicates can step by -128 to +128. Run-length encoding uses protobuf style variable-length integers. 
  String Column Serialization 
Serialization of string columns uses a dictionary to form unique column values The dictionary is sorted to speed up predicate filtering and improve compression ratios.
  String columns are serialized in four streams. 
1、present bit stream: is the value non-null? 
2、dictionary data: the bytes for the strings 
3、dictionary length: the length of each entry 
4、row data: the row values 
Both the dictionary length and the row values are run length encoded streams of integers.


八、ORC数据存储方法

在ORC格式的hive表中,记录首先会被横向的切分为多个stripes,然后在每一个stripe内数据以为单位进行存储所有列的内容都保存在同一个文件中。每个stripe的默认大小为256MB,相对于RCFile每个4MB的stripe而言,更大的stripe使ORC的数据读取更加高效。 

  对于复杂数据类型,比如Map,ORC文件会将一个复杂数据类型字段解析成多个子字段。下表中列举了ORC文件中对于复杂数据类型的解析

 
Data type Chile columns
Array 一个包含所有数组元素的子字段
Map 两个子字段,一个key字段,一个value字段
Struct 每一个属性对应一个子字段
Union 每一个属性对应一个子字段

  当字段类型都被解析后,会由这些字段类型组成一个字段树,只有树的叶子节点才会保存表数据,这些叶子节点中的数据形成一个数据流,如上图中的Data Stream。 

  为了使ORC文件的reader更加高效的读取数据,字段的metadata会保存在Meta Stream中。在字段树中,每一个非叶子节点记录的就是字段的metadata,比如对一个array来说,会记录它的长度。下图根据表的字段类型生成了一个对应的字段树。 


在Hive-0.13中,ORC文件格式只支持读取指定字段,还不支持只读取特殊字段类型中的指定部分。 

  使用ORC文件格式时,用户可以使用HDFS的每一个block存储ORC文件的一个stripe。对于一个ORC文件来说,stripe的大小一般需要设置得比HDFS的block小,如果不这样的话,一个stripe就会分别在HDFS的多个block上,当读取这种数据时就会发生远程读数据的行为。如果设置stripe的只保存在一个block上的话,如果当前block上的剩余空间不足以存储下一个strpie,ORC的writer接下来会将数据打散保存在block剩余的空间上,直到这个block存满为止。这样,下一个stripe又会从下一个block开始存储。 

三、索引

  在ORC文件中添加索引是为了更加高效的从HDFS读取数据。在ORC文件中使用的是稀疏索引(sparse indexes)。在ORC文件中主要有两种用途的索引,一个是数据统计(Data Statistics)索引,一个是位置指针(Position Pointers)索引

1. Data Statistics数据统计索引

  ORC reader用这个索引来跳过读取不必要的数据,在ORC writer生成ORC文件时会创建这个索引文件。这个索引中统计的信息主要有记录的条数,记录的max, min, sum值,以及对text类型和binary类型字段还会记录其长度。对于复杂数据类型,比如Array, Map, Struct, Union,它们的子字段中也会记录这些统计信息。 

  在ORC文件中,Data Statistics有三个level。 

(1)file level statistics 

  在ORC文件的末尾会记录文件级别的统计信息,会记录整个文件中columns的统计信息。这些信息主要用于查询的优化,也可以为一些简单的聚合查询比如max, min, sum输出结果。 

(2)stripe level statistics 

  ORC文件会保存每个字段stripe级别的统计信息,ORC reader使用这些统计信息来确定对于一个查询语句来说,需要读入哪些stripe中的记录。比如说某个stripe的字段max(a)=10,min(a)=3,那么当where条件为a >10或者a <3时,那么这个stripe中的所有记录在查询语句执行时不会被读入。 

(3)index group level statistics 

  为了进一步的避免读入不必要的数据,在逻辑上将一个column的index以一个给定的值(默认为10000,可由参数配置)分割为多个index组。以10000条记录为一个组,对数据进行统计。Hive查询引擎会将where条件中的约束传递给ORC reader,这些reader根据组级别的统计信息,过滤掉不必要的数据。如果该值设置的太小,就会保存更多的统计信息,用户需要根据自己数据的特点权衡一个合理的值。 

  

2. Position Pointers位置指针索引

  当读取一个ORC文件时,ORC reader需要有两个位置信息才能准确的进行数据读取操作。 

(1)metadata streams和data streams中每个group的开始位置 

  由于每个stripe中有多个group,ORC reader需要知道每个group的metadata streams和data streams的开始位置。图1中右边的虚线代表的就是这种pointer。 

(2)stripes的开始位置 

  由于一个ORC文件可以包含多个stripes,并且一个HDFS block也能包含多个stripes。为了快速定位指定stripe的位置,需要知道每个stripe的开始位置。这些信息会保存在ORC file的File Footer中。如图1中间位置的虚线所示。


四、文件压缩

  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。

五、内存管理

  当ORC writer写数据时,会将整个stripe保存在内存中。由于stripe的默认值一般比较大,当有多个ORC writer同时写数据时,可能会导致内存不足。为了现在这种并发写时的内存消耗,ORC文件中引入了一个内存管理器。在一个Map或者Reduce任务中内存管理器会设置一个阈值,这个阈值会限制writer使用的总内存大小。当有新的writer需要写出数据时,会向内存管理器注册其大小(一般也就是stripe的大小),当内存管理器接收到的总注册大小超过阈值时,内存管理器会将stripe的实际大小按该writer注册的内存大小与总注册内存大小的比例进行缩小。当有writer关闭时,内存管理器会将其注册的内存从总注册内存中注销。

六、参数

 
参数名 默认值 说明
hive.exec.orc.default.stripe.size 256*1024*1024 stripe的默认大小
hive.exec.orc.default.block.size 256*1024*1024 orc文件在文件系统中的默认block大小,从hive-0.14开始
hive.exec.orc.dictionary.key.size.threshold 0.8 String类型字段使用字典编码的阈值
hive.exec.orc.default.row.index.stride 10000 stripe中的分组大小
hive.exec.orc.default.compress ZLIB ORC文件的默认压缩方式
hive.exec.orc.skip.corrupt.data false 遇到错误数据的处理方式,false直接抛出异常,true则跳过该记录



本文在Hive-ORC文件存储格式的理论基础上,进一步分析一个实际的Hive ORC表中的数据存储形式。

一、表结构

  库名+表名:fileformat.test_orc

 
字段类型
category_idstring
product_idint
brand_idint
pricedouble
category_id_2string
   

  在hive中命令
desc formatted fileformat.test_orc;
的结果如下图: 

   

  



   

  根据上图中的location信息,查看在HDFS上的文件: 

  



  

二、查看dump文件

  hive提供了一个
--orcfiledump
参数用于查看HDFS上ORC表格的文件信息,在hive-0.13版本中的使用方法为:
hive --orcfiledump <location-of-orc-file>
,其他版本的使用方法可以去官方文档中查找。 

  下面是命令
hive --orcfiledump /user/hive/warehouse/fileformat.db/test_orc/000000_0
的查询结果 

  


三、dump文件分析

  接下来的分析,请对照着文章 Hive-ORC文件存储格式 中的图1-ORC文件结构图进行。 

  使用hql语句,统计出各字段的count, min, max, sum信息如下:

 
字段COUNTMINMAXSUM
category_id100000050119756734.0222868968E11
product_id10000009685099777027158964508399
brand_id99913001026427774991825568
price1000000-0.0092358000.01.8953626711045265E8
category_id_21000000501059965.183530839E9
   

  从dump文件的图片中可以看出,大致分成四个部分:

1、表结构信息

  记录整张表的记录数,压缩方式,压缩大小,以及表结构。在表结构部分,ORC将整张表的所有字段构造成一个大的struct结构。对应图1-ORC文件结构图中的Postscript部分。

2、Stripe统计信息

  统计当前HDFS文件对应Stripe的信息,包括各个字段的count,min, max, sum信息。对于最外层的Struct,只统计其count值。由于这张表数据量不大,当前HDFS文件中只有一个Stripe。对应图1-ORC文件结构图中的Stripe Footer部分。 

  

3、File统计信息

  统计内容和第二部分一致,不过这里统计的整张表的每个字段count, min, max, sum信息。对应图1-ORC文件结构图中的FileFooter部分。 

  这里我们将dump文件中的统计信息,与各字段实际统计信息作对比。通过与上面表格中各字段统计信息对比,发现对于int类型和double类型的字段,min, max, sum的结果都是匹配的。但是对于string类型的字段,仅仅只有min, max统计结果一致,sum的结果不相同。

4、Stripe详细信息

  统计各Stripe的offset,总记录行数等Stripe层次的信息。该Stripe中各字段的Index Data和Row Data,以及每个字段的编码方式。 

  前面一行Stripe: offset: 3 data: 7847351 rows: 1000000 tail: 132 index: 7936应该也是保存在FileFooter中,后面各个字段统计信息对应图1-ORC文件结构图中的Index Data和Row Data部分。 

  从dump文件中的数据可以看出,每个字段的ROW_INDEX以及DATA信息是保存在一块连续空间中的,这块文件从offset=3开始。这也说明图1-ORC文件结构图中Row Data区的数据紧随Index Data区数据之后。 

  Index Data数据统计:

 
起始位置字段
3……21STRUCT
22……1141category_id
1142……3056product_id
3057……5135brand_id
5136……7201price
7202……7938category_id_2
  Row Data数据统计:

 
起始位置字段描述
7939……59887category_id字段对应词条int流
59888……59898category_id词条长度int流
59899……60989category_id字典词条数据
60990……3525432product_id实际数据int流
3525433……3527085brand_id标识IF NULL的byte流
3527086……5708142brand_id实际数据int流
5708143……7855016pricedouble类型
7855017……7855212category_id_2字段对应词条int流
7855213……7855219category_id_2词条长度int流
7855220……7855289category_id_2字典词条数据
  在ORC文件的int类型和string类型保存时,会有一个byte流用于记录字段的某个记录是否为null,根据统计只有brand_id 字段的count值不足100000条,也就是说除了brand_id 字段之外,其他字段中没有null值。所以在上面Row Data表中,只有brand_id有一个对应的IF NULL标识流。一个String类型,会将词条数据保存在字节流中,然后一个int流记录每个词条的长度,另外一个int流用于指定字段某个记录对应字典词条中的哪一个。 

   

  这部分最后记录了每一个字段的存储方式,统计如下

 
字段类型存储方式
STRUCT DIRECT
category_idStringDICTIONARY_V2
product_idIntDIRECT_V2
brand_idIntDIRECT_V2
priceDoubleDIRECT
category_id_2StringDICTIONARY_V2




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值