Carbondata源码系列(二)文件格式详解
在上一章当中,写了文件的生成过程。这一章主要讲解文件格式(V3版本)的具体细节。
1、字典文件格式详解
字典文件的作用是在存储的时候将字符串等类型转换为int类型,好处主要有两点:
1、减少存储占用空间
2、用在需要group by的字段上比较合适,可以减少计算时的shuffle的数据量。
每一个字典列都有对应的三种文件.dict, .sortindex, .dictmeta文件,输出格式都是thrift格式
1.1 .dict文件
字典的值每满1000就作为一个chunk输出一次,具体的类是ColumnDictionaryChunk
相关参数:
carbon.dictionary.chunk.size
1.2 .sortindex文件
把字段的值sort了一下之后,计算出每个值的sortIndex和invertedIndex,具体的类是ColumnSortInfo
1、List<SortIndex>,记录着每个字典值的surrogate,从1开始
2、List<SortInvertedIndex>,记录着每个字典surrogate在数组中的位置,从1开始
它们的关系如下:
sortIndex[i] = dictionarySortModel.getKey();
// the array index starts from 0 therefore -1 is done to avoid wastage
// of 0th index in array and surrogate key starts from 1 there 1 is added to i
// which is a counter starting from 0
sortIndexInverted[dictionarySortModel.getKey() - 1] = i + 1;
假设字典值是beijing,shenzhen,shanghai
城市 |
surrogate |
sortIndex |
invertIndex |
---|---|---|---|
beijing |
1 |
1 |
1 |
shenzhen |
2 |
3 |
3 |
shanghai |
3 |
2 |
2 |
1.3 .dictmeta文件
该文件主要记录字典的以下属性,具体的类是ColumnDictionaryChunkMeta
1、最小key
2、最大的key
3、开始offset
4、结束offset
5、chunk的数量
2、数据文件详解
2.1 数据块的组成部分
CarbonRow在sort阶段会被分成3个部分:
1、字典列
2、非字典维度列和高基数列
3、度量值列
在写入的时候,先写入到TablePage里,TablePage会把数据拆分成4部分
// one vector to make it efficient for sorting
private ColumnPage[] dictDimensionPages;
private ColumnPage[] noDictDimensionPages;
private ComplexColumnPage[] complexDimensionPages;
private ColumnPage[] measurePages;
每个TablePage都会记录以下几个Key:
private byte[][] currentNoDictionaryKey;
// MDK start key
private byte[] startKey;
// MDK end key
private byte[] endKey;
// startkey for no dictionary columns
private byte[][] noDictStartKey;
// endkey for no diciotn
private byte[][] noDictEndKey;
// startkey for no dictionary columns after packing into one column
private byte[] packedNoDictStartKey;
// endkey for no dictionary columns after packing into one column
private byte[] packedNoDictEndKey;
数据在一行一行写到TablePage之后,最后会做一次统一的编码,详细的方法请看TablePage的encode方法。
Page的meta信息
private DataChunk2 buildPageMetadata(ColumnPage inputPage, byte[] encodedBytes)
throws IOException {
DataChunk2 dataChunk = new DataChunk2();
dataChunk.setData_page_length(encodedBytes.length);
fillBasicFields(inputPage, dataChunk);
fillNullBitSet(inputPage, dataChunk);
fillEncoding(inputPage, dataChunk);
fillMinMaxIndex(inputPage, dataChunk);
fillLegacyFields(dataChunk);
return dataChunk;
}
一个blocket的阈值是64MB,一个blocket包括N个TablePage,当写满一个TablePage之后,就把blocket写入到文件当中。
carbondata的BTree索引,是一个记录着每个Blocklet的mdk的startKey和endKey,以及Blocklet当中所有TablePage的列的最大最小值
那么数据文件的详细格式,基本和官网上介绍的是一致的
2.2 What is MDK
mdk和hbase的rowkey是一个性质的,详细可以看下面这张图,排序方式跟hbase没有任何区别。但是carbondata的mdk只能是字典列,如果我没有设置字典列的话,只是设置了SORT_COLUMN,Carbondata的过滤只是靠列的最大最小值
3、索引文件详解
索引文件以.carbonindex结尾
索引文件包括三个部分:索引头,索引两部分
索引头包括:
1、文件格式版本(当前版本是V3)
2、Segment信息(有多少列,列的基数)
3、列的信息
4、bucket ID
索引信息包括以下信息:
1、Blocket的记录数
2、数据文件名
3、Blocket的meta信息offset
3、BlockletIndex (BTree索引,包含blocket的startKey、endKey,以及每一列的最大最小值,这个前面已经讲过了)
4、BlocketInfo(记录数,每个TablePage的offset,每个TablePage的长度,维度列dimension_offsets的起始位置,度量值measure_offsets的起始位置,有多少个TablePagenumber_number_of_pages)
索引文件的信息在文件的footer当中也是存在的,在carbondata1.2当中索引文件还是有很多个,感觉有点多余。
到carbondata1.3会被合并成一个文件,这样就能大大缩短启动的时候加载索引的开销。
- 如何解决分布式系统中的跨时区问题[原理篇]
- 什么是区块链:块的结构
- Spring读书笔记——bean创建(下)
- 当区块链遇上传统行业 我们的生活和工作会改变吗?
- 如何设计开发好一个 HTTP API?
- [WCF权限控制]基于Windows用户组的授权方式[下篇]
- Spring读书笔记——bean解析
- 10个大数据误区,看看你中了几个?
- 从数据到代码——通过代码生成机制实现强类型编程[上篇]
- Spring读书笔记——bean加载
- Java8-初识Lambda
- 我的WCF之旅(5):面向服务架构(SOA)和面向对象编程(OOP)的结合——如何实现Service Contract的重载(Overloading)
- WCF技术剖析之三十:一个很有用的WCF调用编程技巧[下篇]
- 谈谈WCF中的Data Contract(3):WCF Data Contract对Collection & Dictionary的支持
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法