ORC的全称是(Optimized Row Columnar),ORC文件格式是一种Hadoop生态圈中的列式存储格式,它的产生早在2013年初,最初产生自Apache Hive,用于降低Hadoop数据存储空间和加速Hive查询速度。
orc文件有如下结构快:block,stripe,row_group,stream,index data,Row data,fileFooter,postscript
orc在hdfs上存储,为适应hdfs区块存储思想会将orc文件划分成block块,orc的block块大小一般和hdfs的block块大小一致通过配置( hive.exec.orc.default.block.size 默认256M)指定。每个block块中包含多个stipe,stipe大小通过参数( hive.exec.orc.default.stripe.size 默认64M)指定。应尽量避免strip跨hdfs:block存储,否则在解析stipe时会存在IO跨节点的数据请求,从而增加了系统资源开销。所以,一般orc:block块大小是orc:stripe大小的整数倍。但是,在有些情况下还是会出现block块不能够被整数个stipe完整填满,需要关闭跨hdfs:block的数据存储,需要指定(hive.exec.orc.default.block.padding=false)关闭块存储。另外需要指定最小磁盘利用空间( hive.exec.orc.block.padding.tolerance 默认0.05,例如orc:block=256M,256*0.05=12.5M),hdfs:block块剩余磁盘空间低于此值将放弃使用。
df.write.option(“”,””).orc(“path”)
df.write.format(“”).option(“”,””).save(“path”)
df.write.format(“”).option(“”,””).saveAsTable(“”)
create table tablename(
col1 STRING,
col2 STRING
)stored as orc tblproperties ("orc.compress"="NONE");
Orc配置 |
Hive别名 |
默认值 |
描述 |
---|---|---|---|
orc.stripe.size |
hive.exec.orc.default.stripe.size |
64M |
Stripe大小 |
orc.block.size |
hive.exec.orc.default.block.size |
256M |
默认bolck块大小 |
orc.create.index |
orc.create.index |
true |
是否创建索引 |
orc.row.index.stride |
hive.exec.orc.default.row.index.stride |
10000 |
默认索引块大小 |
orc.compress.size |
hive.exec.orc.default.buffer.size |
256kb |
读写缓冲区大小 |
orc.base.delta.ratio |
hive.exec.orc.base.delta.ratio |
8 |
Stripe_size/buffer_size |
orc.block.padding |
hive.exec.orc.default.block.padding |
true |
Stripe不跨block块 |
orc.compress |
hive.exec.orc.default.compress |
ZLIB |
默认压缩 |
orc.write.format |
hive.exec.orc.write.format |
0.12 |
写文件的版本Hive 0.12 使用RLE |
orc.encoding.strategy |
hive.exec.orc.encoding.strategy |
speed/compression |
编码策略:只影响数值格式,不会改变高级编码(zlib,snappy) |
orc.compression.strategy |
hive.exec.orc.compression.strategy |
speed/compression |
压缩策略,会改变高级压缩解码器的的压缩级别(zlib,snappy) |
orc.block.padding.tolerance |
hive.exec.orc.block.padding.tolerance |
0.05D |
最小block碎片填充阈值(hdfs block=256::12.5M,64M::3.2M |
orc.bloom.filter.fpp |
orc.default.bloom.fpp |
0.05D |
布隆过滤器误差概率 |
orc.use.zerocopy |
hive.exec.orc.zerocopy |
false |
开启零拷贝 |
orc.skip.corrupt.data |
hive.exec.orc.skip.corrupt.data |
false |
跳过不正确的数据 |
orc.tolerate.missing.schema |
hive.exec.orc.tolerate.missing.schema |
true |
修复bug: HIVE-4243 |
orc.memory.pool |
hive.exec.orc.memory.pool |
0.5D |
写orc时使用的最大堆空间比例 |
orc.dictionary.key.threshold |
hive.exec.orc.dictionary.key.size.threshold |
0.8D |
基元数据与数据条数比例查过阈值将关闭字典编码 |
orc.dictionary.early.check |
hive.orc.row.index.stride.dictionary.check |
true |
在10000行之后是否开启字典检查 |
orc.bloom.filter.columns |
orc.bloom.filter.columns |
|
布隆过滤器的列 |
orc.bloom.filter.write.version |
orc.bloom.filter.write.version |
original/utf-8 |
布隆过滤器的版本,original:使用两个版本的布隆过滤器,否则只是用utf-8 |
orc.bloom.filter.ignore.non-utf8 |
orc.bloom.filter.ignore.non-utf8 |
false |
是否忽略过时的非utf-8过滤器 |
orc.max.file.length |
orc.max.file.length |
long.max |
支持最大orc文件大小 |
orc.mapred.input.schema |
(String)null |
(Object)null |
Hadoop,mapRed读取orc |
orc.mapred.map.output.key.schema |
(String)null |
(Object)null |
|
orc.mapred.map.output.value.schema |
(String)null |
(Object)null |
|
orc.mapred.output.schema |
(String)null |
(Object)null |
|
orc.include.columns |
hive.io.file.readcolumn.ids |
(Object)null |
|
orc.kryo.sarg |
orc.kryo.sarg |
(Object)null |
|
orc.sarg.column.names |
org.sarg.column.names |
(Object)null |
|
orc.force.positional.evolution |
orc.force.positional.evolution |
false |
hive2.1之后支持(使用位置匹配,而不是不使用列名称匹配顶级列) |
orc.write.variable.length.blocks |
|
false |
是否使用可变长度的hdfs块,hdfs2.7之后支持 |
spark.sql.orc.filterPushdown | false | spark查询orc时是否开启位于下推功能 |
1. 异常 java.io.EOFException:缓存(ArrayBuffer)分配出错
2. Malformed ORC file /xx/xx/xx.orc. Invalid postscript length
原因:文件损坏/文件为非orc文件
原因分析:读取orc时,先从文件的最后读取16kb。而最后一个字节存放postScript的长度,如果最后一个字节的长度小于length("orc")+1,说明文件已经postScript已经损坏,会抛出以上异常。因为即使空的orc文件,在postScript至少包含“orc”和压缩格式 长度一定大于4
解决方案:1:重新执行一次:在读取的16kb出现系统抖动,导致读取错误。
2.重新生成数据文件
源码展示:
public static final String MAGIC = "ORC";
int psLen = buffer.get(readSize - 1) & 0xff;
int len = OrcFile.MAGIC.length(); if (psLen < len + 1) { throw new IOException("Malformed ORC file " + path + ". Invalid postscript length " + psLen); }
3.Malformed ORC file /xx/xx.orc . Invalid postscript
原因:要读取的文件不是ORC文件/文件损坏
原因分析:在2过程校验完成后,接着校验16kb中的[0,4]序列化后的数据是否为"ORC"字符串。因为ORC格式的文件在序列化后最后16kb中的[0,4]序列化后为“ORC"。
解决方案:1.检查hive的数据文件是否为orc格式,有可能数据文件中的一个或几个为非orc文件,hive中序列化和反序列化方式却是orc,尝试用spark-shell中的spark.read.orc("报错文件").count,是否依然报错
2.文件损坏,重新生成相应文件
源码展示:
if (!Text.decode(header, 0 , len).equals(OrcFile.MAGIC)) { throw new IOException("Malformed ORC file " + path + ". Invalid postscript."); }
原因:Orc文件的序列化版本小于当前规定版本,可能会导致数据错误,提示警告
原因分析:文件生成和使用不是同一个版本OrcFile
解决方案:1. 降低hive/spark版本,2.按照当前读取的hive版本重新生成orc文件
源码展示:
V_0_11("0.11", 0, 11), V_0_12("0.12", 0, 12); public static final Version CURRENT = V_0_12;
if (major > OrcFile.Version.CURRENT.getMajor() || (major == OrcFile.Version.CURRENT.getMajor() && minor > OrcFile.Version.CURRENT.getMinor())) { log.warn("ORC file " + path + " was written by a future Hive version " + versionString(version) + ". This file may not be readable by this version of Hive."); }
5.Unknown compression
原因:写数据时使用了不支持的压缩格式,暂时只支持 NONE ZLIB SNAPPY LZO。文件损坏
原因分析:序列化出现问题,导致postscript出现错误,读取postscript的压缩配置出现问题
解决方案:重新生成数据文件,使用支持的压缩格式
源码展示:
switch (ps.getCompression()) {
case NONE: break; case ZLIB: break; case SNAPPY: break; case LZO: break; default: throw new IllegalArgumentException("Unknown compression");
6:LZO is not available. ClassNotFoundException
LZO is not available. IllegalArgumentException
Problem initializing LZO IllegalArgumentException
Insufficient access to LZO IllegalArgumentException
原因:使用LZO作为压缩格式,却在系统中无法找到/无法初始化压缩器
原因分析:其他的压缩格式是通过new的方式初始化压缩器,在源码打包时就能做依赖完整性校验。但是lzo却是通过反射的方式获取,spark唯独没有重写lzo的压缩器。而是通过反射复用hive保重的lzo压缩器。当版本不匹配,或者依赖包不完整时,就有如下异常。
解决方式:1. 检查依赖包, 2.检查hive和spark的版本是否匹配
源码展示:
switch (kind) { case NONE: return null; case ZLIB: return new ZlibCodec(); case SNAPPY: return new SnappyCodec(); case LZO: try { Class lzo = (Class) JavaUtils.loadClass("org.apache.hadoop.hive.ql.io.orc.LzoCodec"); return lzo.newInstance(); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("LZO is not available.", e); } catch (InstantiationException e) { throw new IllegalArgumentException("Problem initializing LZO", e); } catch (IllegalAccessException e) { throw new IllegalArgumentException("Insufficient access to LZO", e); }