介绍
ORC是一种具备高效存储和查询能力的文件格式
在存储方面,ORC为基于strips的列式存储,每个strip包含了N行数据,strip内部是列式存储, 相同的列在一段连续的存储区域内,所以能够用不同的压缩编码来适配数据,也就做到了高效的压缩效率
在查询方面,ORC提供了三层索引:
-
文件层, 文件中每列的统计信息
stripe层, strip内部每列的统计信息
- row group层, 每组默认10000行数据, 每列的统计信息
由于索引的最小层级是row group, 所以读取数据的最小单位应该是row group , 当通过row group索引判断不是所需数据,则可以直接跳过该row group.
写ORC
this.writer = OrcFile.createWriter(new Path("/data/to/path"),
OrcFile.writerOptions(conf)
.setSchema(typeDescription)
.bloomFilterColumns("_col1,_col2")
.stripeSize(128L * 1024 * 1024));
this.batch = typeDescription.createRowBatch(1024 * 1024);
在写ORC文件时就已经很大程度决定了查询效率, 我们知道orc有三级索引, 文件 -> strip -> row group , 数据是顺序写入的, 当达到了设定的strip大小, 就会flush到磁盘上, 如果数据是不做任何方式处理直接写入磁盘的话, 每列不同值的记录大概率会随机落在不同strip的row group里, 我们知道读取数据的最小单位是row group,所以读取效率不会很好.
最好的写入方式是先分析使用场景, 提取出经常使用的字段, 对这些字段先做排序, 或者布隆过滤, 来达到优化读取效率的作用.
我的常用方法这样, 由于我的使用场景第一步是通过时间戳过滤出一部分数据, 然后对数据进行分析, 所以我在写入是会按时间戳排序后写入ORC文件, 这样数据会从小到大分布到不同strip中, 在对时间戳过滤时会将大部分strip过滤掉, 再对我经常用于filter的几个字段做布隆过滤, 这样会进一步达到优化效果.
布隆过滤器
上文提到了ORC文件有三层索引, 默认索引存储字段的max/min/sum值, 如果查询出现 column = 'value' 时, 默认的索引是不生效的, 这时我们对字符串字段做布隆过滤, 使 column = 'value' 条件同样能使用到索引.