Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

本章是关于 TsFile 的设计细节。

1.1 变量的存储

    大端存储

    比如: int0x8 将会被存储为 00 00 00 08, 而不是 08 00 00 00
  • 可变长的字符串类型

    • 存储的方式是以一个 int 类型的 Size + 字符串组成。Size 的值可以为 0。

    • Size 指的是字符串所占的字节数,它并不一定等于字符串的长度。

    • 举例来说,"sensor_1" 这个字符串将被存储为 00 00 00 08 + "sensor_1" (ASCII编码)。

    • 另外需要注意的一点是文件签名 "TsFile000001" (Magic String + Version), 因为他的 Size(12) 和 ASCII 编码值是固定的,所以没有必要在这个字符串前的写入 Size 值。

  • 数据类型

    • 0: BOOLEAN

    • 1: INT32 (int)

    • 2: INT64 (long)

    • 3: FLOAT

    • 4: DOUBLE

    • 5: TEXT (String)

  • 编码类型

    为了提高数据的存储效率,需要在数据写入的过程中对数据进行编码,从而减少磁盘空间的使用量。在写数据以及读数据的过程中都能够减少I/O操作的数据量从而提高性能。IoTDB支持多种针对不同类型的数据的编码方法:
    • 0: PLAIN

      • PLAIN编码,默认的编码方式,即不编码,支持多种数据类型,压缩和解压缩的时间效率较高,但空间存储效率较低。

    • 1: DICTIONARY

      • 字典编码是一种无损编码。它适合编码基数小的数据(即数据去重后唯一值数量小)。不推荐用于基数大的数据。
    • 2: RLE

      • 游程编码,比较适合存储某些整数值连续出现的序列,不适合编码大部分情况下前后值不一样的序列数据。

      • 游程编码也可用于对浮点数进行编码,但在创建时间序列的时候需指定保留小数位数(MAX_POINT_NUMBER,具体指定方式参见本文SQL 参考文档)。比较适合存储某些浮点数值连续出现的序列数据,不适合存储对小数点后精度要求较高以及前后波动较大的序列数据。

        游程编码(RLE)和二阶差分编码(TS_2DIFF)对 float 和 double 的编码是有精度限制的,默认保留2位小数。推荐使用 GORILLA。

    • 3: DIFF

    • 4: TS_2DIFF

      • 二阶差分编码,比较适合编码单调递增或者递减的序列数据,不适合编码波动较大的数据。
    • 5: BITMAP

    • 6: GORILLA_V1

      • GORILLA编码是一种无损编码,它比较适合编码前后值比较接近的数值序列,不适合编码前后波动较大的数据。

      • 当前系统中存在两个版本的GORILLA编码实现,推荐使用GORILLA,不推荐使用GORILLA_V1(已过时)。

      • 使用限制:使用Gorilla编码INT32数据时,需要保证序列中不存在值为Integer.MIN_VALUE的数据点;使用Gorilla编码INT64数据时,需要保证序列中不存在值为Long.MIN_VALUE的数据点。

    • 7: REGULAR

    • 8: GORILLA

    • 9: ZigZag

      • ZigZag编码将有符号整型映射到无符号整型,适合比较小的整数
  • 数据类型与支持编码的对应关系

    数据类型支持的编码
    BOOLEANPLAIN, RLE
    INT32PLAIN, RLE, TS_2DIFF, GORILLA, ZigZag
    INT64PLAIN, RLE, TS_2DIFF, GORILLA, ZigZag
    FLOATPLAIN, RLE, TS_2DIFF, GORILLA
    DOUBLEPLAIN, RLE, TS_2DIFF, GORILLA
    TEXTPLAIN, DICTIONARY

压缩类型

...


1

...

.2 TsFile 概述

TsFile 整体分为两大部分:数据区

...

2: GZIP

...

3: LZO

...

4: SDT

...

5: PAA

...

6: PLA

...

7: LZ4

1.2 TsFile 概述

TsFile 整体分为两大部分:数据区索引区

数据区所包含的概念由小到大有如下三个:

  • Page数据页:一段时间序列,是数据块被反序列化的最小单元;

  • Chunk数据块:包含一条时间序列的多个 Page ,是数据块被IO读取的最小单元;

  • ChunkGroup数据块组:包含一个实体的多个 Chunk。

...

索引树节点的度(即每个节点的最大子节点个数)可以由用户进行配置,配置项为max_degree_of_index_node,其默认值为256。在以下例子中,我们假定 max_degree_of_index_node = 10

需要注意的是,在索引树的每类节点(ENTITY、MEASUREMENT)中,键按照字典序排列。在下面的例子中,若i<j,假设字典序di<dj。(否则,实际上[d1,d2,...d10]的字典序排列应该为[d1,d10,d2,...d9])

其中,例1~4为一元时间序列的例子,例5~6为多元时间序列的例子,例7为综合例子。

...

在150个实体,每个实体中有150个物理量的情况下,物理量和实体个数均超过了 max_degree_of_index_node,形成索引树的物理量层级和实体索引层级。在这两个层级里,每个 IndexNode 均最多由10个 IndexEntry 组成。如前所述,从根节点到实体索引层级的叶子节点,类型分别为INTERNAL_ENTITYLEAF_ENTITY,而每个实体索引层级的叶子节点都是物理量索引层级的根节点,从这里到物理量索引层级的叶子节点,类型分别为INTERNAL_MEASUREMENTLEAF_MEASUREMENT

  • 例5:1个实体,20个物理量,2个多元时间序列组,每个多元时间序列组分别有9个物理量例5:1个实体,18个物理量,2个多元时间序列组,每个多元时间序列组分别有9个物理量

Image Modified

  • 例6:1个实体,30个物理量,2个多元时间序列组,每个多元时间序列组分别有15个物理量

...

  • 注意: 如果没有设置输出文件的存储路径, 将使用 "TsFile_sketch_view.txt" 做为默认值。

在mac系统中的示例:

/iotdb/server/target/iotdb-server-{version}/tools/tsfileToolSet$ ./print-tsfile-sketch.sh test.tsfile
|````````````````````````
Starting Printing the TsFile Sketch
|````````````````````````
TsFile path:test.tsfile
Sketch save path:TsFile_sketch_view.txt
-------------------------------- TsFile Sketch --------------------------------
file path: test.tsfile
file length:

...

15462
14:40:55.619 [main] INFO org.apache.iotdb.tsfile.read.TsFileSequenceReader - Start reading file test.tsfile metadata from 15356, length 96

          POSITION| CONTENT
          -------- -------
                 

...

0|   

...

[magic head] TsFile
                  6|

...

[version number] 

...

3
||||||||||||||||||||| [Chunk Group] of root.

...

sg_

...

1.

...

d1, num of Chunks:

...

4
                  7| [Chunk Group Header]
   

...

               |       [marker] 0
                  |

...

 

...

 

...

 

...

 

...

[deviceID] root.sg_1.d1
                21| [Chunk] of s6, numOfPoints:1000, time range:[0,999], tsDataType:INT64,
                    startTime: 0 endTime: 999 count: 1000 [minValue:6,maxValue:9996,firstValue:6,lastValue:9996,sumValue:5001000.0]
                  | [chunk

...

header] marker=5, measurementId=s6, dataSize=1826, serializedSize=9
                  |

...

 [

...

chunk] java.nio.HeapByteBuffer[pos=0 lim=1826 cap=1826]
                  | [page]

...

CompressedSize:1822, 

...

UncompressedSize:1951

...

  

...

  

...

           1856|   [Chunk] of s4, numOfPoints:1000, time range:[0,999], tsDataType:INT64, 
                    startTime: 0 endTime: 999 count: 1000 [minValue:4,maxValue:9994,firstValue:4,lastValue:9994,sumValue:4999000.0]
                  | [chunk

...

header] marker=5, measurementId=s4, dataSize=1826, serializedSize=9
                  |

...

 [

...

chunk] 

...

java.nio.HeapByteBuffer[pos=0 lim=1826 cap=1826]
                  | [page] CompressedSize:1822, UncompressedSize:1951
         

...

  

...

  

...

 

...

3691| 

...

 

...

 [

...

Chunk] of s2, numOfPoints:1000, time range:[0,999], tsDataType:INT64, 
                    startTime: 0 endTime: 999 count: 1000 [minValue:3,maxValue:9993,firstValue:3,lastValue:9993,sumValue:4998000.0]
                  | [chunk

...

header] marker=5, measurementId=s2, dataSize=1826, serializedSize=9
                  | [chunk]

...

java.nio.HeapByteBuffer[pos=0 lim=1826 cap=1826]
                  |

...

[page]  CompressedSize:1822, UncompressedSize:1951
              5526| [Chunk] of s5, numOfPoints:1000, time range:[0,999], tsDataType:INT64,
                    startTime: 0 endTime: 999 count: 1000 [minValue:5,maxValue:9995,firstValue:5,lastValue:9995,sumValue:5000000.0]
                  | [chunk

...

header] marker=5, measurementId=s5, dataSize=1826, serializedSize=9
                  |

...

  

...

[

...

chunk] java.nio.HeapByteBuffer[pos=0 lim=1826 cap=1826]
                  | [page] CompressedSize:1822, UncompressedSize:1951
||||||||||||||||||||| [Chunk Group] of root.

...

sg_

...

1.

...

d1 ends
||||||||||||||||||||| [Chunk Group] of root.sg_1.d2, num of

...

Chunks:4
         

...

  

...

  

...

 7361|   [Chunk Group Header]
                  |

...

    [marker] 

...

0
                  | [deviceID] root.sg_1.d2
       

...

      

...

 

...

7375|   [Chunk

...

] of

...

 s2, numOfPoints:1000, time range:[

...

0,

...

999], tsDataType:

...

INT64, 
                   

...

startTime: 

...

0 endTime: 

...

999 count: 

...

1000 [minValue:

...

3,maxValue:

...

9993,firstValue:

...

3,lastValue:

...

9993,sumValue:

...

4998000.0]
                  | [chunk

...

header] marker=5, measurementId=s2, dataSize=1826, serializedSize=9
                  | [chunk]

...

java.nio.HeapByteBuffer[pos=0 lim=1826 cap=1826]
                  | [page]

...

CompressedSize:1822, UncompressedSize:1951
              9210|

...

 [Chunk] of 

...

s4, numOfPoints:

...

1000, time range:[

...

0,

...

999], tsDataType:

...

INT64, 
                   

...

startTime: 

...

0 endTime: 

...

999 count: 

...

1000 [minValue:

...

4,maxValue:

...

9994,firstValue:

...

4,lastValue:

...

9994,sumValue:

...

4999000.0]
                  | [chunk

...

header] marker=5, measurementId=s4, dataSize=1826, serializedSize=9
                  | [chunk]

...

java.nio.HeapByteBuffer[pos=0 lim=1826 cap=1826]
                  | [page]

...

CompressedSize:1822, UncompressedSize:1951
           

...

  11045|  

...

 [Chunk] of 

...

s6, numOfPoints:

...

1000, time range:[

...

0,

...

999], tsDataType:

...

INT64, 
                   

...

startTime: 

...

0 endTime: 

...

999 count: 

...

1000 [minValue:

...

6,maxValue:

...

9996,firstValue:

...

6,lastValue:

...

9996,sumValue:

...

5001000.0]
                  | [chunk

...

header] marker=5, measurementId=s6, dataSize=1826, serializedSize=9
                  | [chunk]

...

java.nio.HeapByteBuffer[pos=0 lim=1826 cap=1826]
                  | [page]

...

CompressedSize:1822, UncompressedSize:1951
              12880| [Chunk] of s5, numOfPoints:1000, time

...

range:[0,999], tsDataType:INT64, 
                    startTime: 0 endTime: 999

...

count: 1000 

...

[minValue:5,maxValue:9995,firstValue:5,lastValue:9995,sumValue:5000000.0]
                  | [chunk

...

header] marker=5, measurementId=s5, dataSize=1826, serializedSize=9
                  | [chunk]

...

java.nio.HeapByteBuffer[pos=0 lim=1826 cap=1826]
                  |

...

   [

...

page] 

...

 CompressedSize:1822, UncompressedSize:1951
||||||||||||||||||||| [Chunk Group] of root.

...

sg_

...

1.

...

d2 ends
              14715|

...

[marker] 2
              14716| [TimeseriesIndex]

...

of root.sg_1.d1.s2, tsDataType:INT64
                  | [ChunkIndex] s2, offset=3691
             

...

     

...

|

...

 

...

 

...

 

...

 

...

 

...

 

...

 

...

[startTime:

...

 0 endTime: 999 count: 

...

1000 [minValue:3,maxValue:9993,firstValue:3,lastValue:9993,sumValue:4998000.0]] 
              14788| [TimeseriesIndex] of root.sg_1.d1.s4, tsDataType:INT64
                  | [ChunkIndex] s4, offset=1856
         

...

  

...

  

...

  

...

  

...

 

...

|       [startTime: 0 endTime: 999 count: 1000 [minValue:4,maxValue:9994,firstValue:4,lastValue:9994,sumValue:4999000.0]] 
              14860| [

...

TimeseriesIndex] of root.sg_1.d1.s5, tsDataType:INT64
                 

...

|       

...

[

...

ChunkIndex]

...

 s5, offset=5526
                  |

...

[startTime: 0 endTime: 

...

999 

...

count: 1000 [minValue:5,maxValue:9995,firstValue:5,lastValue:9995,sumValue:5000000.0]] 
             

...

14932|  

...

 [

...

TimeseriesIndex] of 

...

root.sg_1.d1.s6, tsDataType:INT64
                  | [ChunkIndex] s6, offset=21
                  | [startTime:

...

0 endTime: 

...

999 count: 

...

1000 [minValue:6,maxValue:9996,firstValue:

...

6,lastValue:

...

9996,sumValue:5001000.0]] 
              15004| [TimeseriesIndex] of root.sg_1.d2.s2, tsDataType:INT64
         

...

      

...

  

...

 |       [ChunkIndex] s2, offset=7375
                  |

...

    [startTime: 0 endTime: 999 count: 1000 [minValue:3,maxValue:9993,firstValue:3,lastValue:9993,sumValue:4998000.0]] 
              15076|

...

 [TimeseriesIndex] of root.sg_1

...

.d2.s4, tsDataType:INT64
                  |

...

 

...

 

...

 

...

[ChunkIndex]

...

 s4, offset=9210
                  |

...

   [

...

startTime: 0

...

 endTime: 999 count: 1000 [minValue:4,maxValue:9994,firstValue:4,lastValue:9994,sumValue:4999000.0]] 
           

...

  15148|   [

...

TimeseriesIndex] of root.

...

sg_

...

1.d2.s5, tsDataType:INT64
                  |

...

[ChunkIndex] s5, offset=12880
                  | [startTime: 0

...

endTime: 999 count: 

...

1000 [minValue:5,maxValue:9995,firstValue:5,lastValue:9995,sumValue:5000000.0]] 
              15220| [TimeseriesIndex] of root.

...

sg_

...

1.d2.s6, tsDataType:INT64
               

...

   

...

| 

...

 

...

     [ChunkIndex] s6, offset=11045
               

...

   

...

|   

...

 

...

   [startTime: 0 endTime: 999 

...

count: 1000 [minValue:6,maxValue:9996,firstValue:6,lastValue:9996,sumValue:5001000.0]] 
|||||||||||||||||||||

...

  

...

  

...

          15292|   [IndexOfTimerseriesIndex Node] type=LEAF_MEASUREMENT
               

...

   | 

...

 

...

 

...

 

...

 

...

 

...

 <s2, 14716>
                  | <s6, 14932>
   

...

  

...

  

...

  

...

  

...

  

...

     |       <endOffset, 15004>
             

...

15324|   [

...

IndexOfTimerseriesIndex Node] 

...

type=LEAF_MEASUREMENT
                  | <s2, 15004>
     

...

      

...

       |       <s6, 15220>
             

...

     

...

| 

...

      <endOffset, 15292>
             

...

15356| 

...

 

...

 

...

[TsFileMetadata]
                  | [meta offset]

...

14715
   

...

               |       [num of devices] 2
 

...

                 |       2 key&TsMetadataIndex
                  |

...

    [bloom filter bit vector byte array length] 32
                  |

...

   [

...

bloom filter bit vector byte array] 

...


...

                    |       [bloom filter 

...

number 

...

of 

...

bits] 256
                  | [bloom filter

...

number of hash 

...

functions] 

...

5
              15452| [TsFileMetadataSize] 96
              15456| [

...

magic tail] TsFile
              15462| END of TsFile
---------------------------- IndexOfTimerseriesIndex Tree -----------------------------
[MetadataIndex:LEAF_DEVICE]
└───[root.sg_1.d1,15292]
[MetadataIndex:LEAF_MEASUREMENT]

...

└───[s2,14716]
└───[s6,14932]
└───[root.sg_1.d2,15324]
[MetadataIndex:LEAF_MEASUREMENT]

...

    └───[

...

s2,15004]

...


...

└───[s6,15220]]
---------------------------------- TsFile Sketch End ----------------------------------

...


3.4 TsFileSequenceRead

您可以使用示例中的类 example/tsfile/org/apache/iotdb/tsfile/TsFileSequenceRead 顺序打印 TsFile 中的内容.

...

clear all;close all;

% 1. load visdata generated by TsFileExtractVisdata
filePath = 'D:\visdata1.csv';
[timeMap,countMap] = loadVisData(filePath,'ms'); % mind the timestamp unit

% 2. plot figures given the loaded data and two plot parameters:
% `showSpecific` and `isFileOrder`
draw(timeMap,countMap,{},false)
title("draw(timeMap,countMap,\{\},false)")

draw(timeMap,countMap,{},true)
title("draw(timeMap,countMap,\{\},true)")

draw(timeMap,countMap,{'root.vehicle.d0.s0'},false)
title("draw(timeMap,countMap,{'root.vehicle.d0.s0'},false)")

draw(timeMap,countMap,{'root.vehicle.d0.s0','root.vehicle.d0.s1'},false)
title("draw(timeMap,countMap,{'root.vehicle.d0.s0','root.vehicle.d0.s1'},false)")

draw(timeMap,countMap,{'root.vehicle.d0.s0','root.vehicle.d0.s1'},true)
title("draw(timeMap,countMap,{'root.vehicle.d0.s0','root.vehicle.d0.s1'},true)")

绘图结果:

...

.vehicle.d0.s1'},true)
title("draw(timeMap,countMap,{'root.vehicle.d0.s0','root.vehicle.d0.s1'},true)")

绘图结果:

1Image Added2Image Added3Image Added4Image Added

附录

  • 大端存储

    • 比如: int0x8 将会被存储为 00 00 00 08, 而不是 08 00 00 00

  • 可变长的字符串类型

    • 存储的方式是以一个 int 类型的 Size + 字符串组成。Size 的值可以为 0。

    • Size 指的是字符串所占的字节数,它并不一定等于字符串的长度。

    • 举例来说,"sensor_1" 这个字符串将被存储为 00 00 00 08 + "sensor_1" (ASCII编码)。

    • 另外需要注意的一点是文件签名 "TsFile000001" (Magic String + Version), 因为他的 Size(12) 和 ASCII 编码值是固定的,所以没有必要在这个字符串前的写入 Size 值。

  • 压缩类型

    • 0: UNCOMPRESSED

    • 1: SNAPPY

    • 2: GZIP

    • 3: LZO

    • 4: SDT

    • 5: PAA

    • 6: PLA

    • 7: LZ4