在上一章当中,写了文件的生成过程。这一章主要讲解文件格式(V3版本)的具体细节。数组
字典文件的做用是在存储的时候将字符串等类型转换为int类型,好处主要有两点:ui
一、减小存储占用空间编码
二、用在须要group by的字段上比较合适,能够减小计算时的shuffle的数据量。spa
每个字典列都有对应的三种文件.dict, .sortindex, .dictmeta文件,输出格式都是thrift格式code
字典的值每满1000就做为一个chunk输出一次,具体的类是ColumnDictionaryChunkblog
相关参数:排序
carbon.dictionary.chunk.size索引
把字段的值sort了一下以后,计算出每一个值的sortIndex和invertedIndex,具体的类是ColumnSortInfoci
一、List<SortIndex>,记录着每一个字典值的surrogate,从1开始字符串
二、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 |
该文件主要记录字典的如下属性,具体的类是ColumnDictionaryChunkMeta
一、最小key
二、最大的key
三、开始offset
四、结束offset
五、chunk的数量
CarbonRow在sort阶段会被分红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的列的最大最小值
那么数据文件的详细格式,基本和官网上介绍的是一致的
mdk和hbase的rowkey是一个性质的,详细能够看下面这张图,排序方式跟hbase没有任何区别。可是carbondata的mdk只能是字典列,若是我没有设置字典列的话,只是设置了SORT_COLUMN,Carbondata的过滤只是靠列的最大最小值
索引文件以.carbonindex结尾
索引文件包括三个部分:索引头,索引两部分
索引头包括:
一、文件格式版本(当前版本是V3)
二、Segment信息(有多少列,列的基数)
三、列的信息
四、bucket ID
索引信息包括如下信息:
一、Blocket的记录数
二、数据文件名
三、Blocket的meta信息offset
三、BlockletIndex (BTree索引,包含blocket的startKey、endKey,以及每一列的最大最小值,这个前面已经讲过了)
四、BlocketInfo(记录数,每一个TablePage的offset,每一个TablePage的长度,维度列dimension_offsets的起始位置,度量值measure_offsets的起始位置,有多少个TablePagenumber_number_of_pages)
索引文件的信息在文件的footer当中也是存在的,在carbondata1.2当中索引文件仍是有不少个,感受有点多余。
到carbondata1.3会被合并成一个文件,这样就能大大缩短启动的时候加载索引的开销。
岑玉海
转载请注明出处,谢谢!
个人博客即将搬运同步至腾讯云+社区,邀请你们一同入驻:https://cloud.tencent.com/developer/support-plan