This is an automated email from the ASF dual-hosted git repository. sunzesong pushed a commit to branch jira_1455 in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 9d353c21d032f77b8dc4a8e2ae9aa9d7ec40d629 Author: samperson1997 <[email protected]> AuthorDate: Sun Jun 27 19:44:18 2021 +0800 [IOTDB-1455] Update documents for new IoTDB concepts and TsFile structures --- docs/zh/SystemDesign/TsFile/Format.md | 166 +++++++++++---------- .../Data-Concept/Data-Model-and-Terminology.md | 99 ++++++------ 2 files changed, 141 insertions(+), 124 deletions(-) diff --git a/docs/zh/SystemDesign/TsFile/Format.md b/docs/zh/SystemDesign/TsFile/Format.md index 3aa07c9..ec2517a 100644 --- a/docs/zh/SystemDesign/TsFile/Format.md +++ b/docs/zh/SystemDesign/TsFile/Format.md @@ -65,50 +65,64 @@ ### 1.2 TsFile 概述 +<!-- TODO + 下图是关于TsFile的结构图。 <img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://user-images.githubusercontent.com/33376433/123052025-f47aab80-d434-11eb-94c2-9b75429e5c54.png"> 此文件包括两个设备 d1、d2,每个设备包含两个测点 s1、s2,共 4 个时间序列。每个时间序列包含两个 Chunk。 -下图是另一种关于TsFile的结构表示: +--> -<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://user-images.githubusercontent.com/19167280/98808354-ed2f0080-2456-11eb-8e7f-b11a4759d560.png"> +TsFile 整体分为两大部分:**数据区**和**索引区**。 -此文件包括两个设备 d1、d2,每个设备包含三个测点 s1、s2、s3,共 6 个时间序列。每个时间序列包含两个 Chunk。 +**数据区**所包含的概念由小到大有如下三个: -元数据分为三部分 +* **Page数据页**:一段时间序列,是数据块被反序列化的最小单元; -* 按时间序列组织的 ChunkMetadata 列表 -* 按时间序列组织的 TimeseriesMetadata -* TsFileMetadata +* **Chunk数据块**:包含一条时间序列的多个 Page ,是数据块被IO读取的最小单元; -查询流程:以查 d1.s1 为例 +* **ChunkGroup数据块组**:包含一个实体的多个 Chunk。 -* 反序列化 TsFileMetadata,得到 d1.s1 的 TimeseriesMetadata 的位置 -* 反序列化得到 d1.s1 的 TimeseriesMetadata -* 根据 d1.s1 的 TimeseriesMetadata,反序列化其所有 ChunkMetadata -* 根据 d1.s1 的每一个 ChunkMetadata,读取其 Chunk 数据 +**索引区**分为三部分: -#### 1.2.1 文件签名和版本号 +* 按时间序列组织的 **TimeseriesIndex**,包含1个头信息和数据块索引(ChunkIndex)列表。头信息记录文件内某条时间序列的数据类型、统计信息(最大最小时间戳等);数据块索引列表记录该序列各Chunk在文件中的 offset,并记录相关统计信息(最大最小时间戳等); -TsFile文件头由 6 个字节的 "Magic String" (`TsFile`) 和 6 个字节的版本号 (`000002`)组成。 +* **IndexOfTimeseriesIndex**,用于索引各TimeseriesIndex在文件中的 offset; + +* **BloomFilter**,针对实体(Entity)的布隆过滤器。 + +> 注:ChunkIndex 旧称 ChunkMetadata;TimeseriesIndex 旧称 TimeseriesMetadata;IndexOfTimeseriesIndex 旧称 TsFileMetadata。v0.13版本起,根据其索引区的特性和实际所索引的内容重新命名。 + +下图是关于 TsFile 的结构图。 + +<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://user-images.githubusercontent.com/19167280/123542462-6710c180-d77c-11eb-9afb-a1b495c82ea9.png"> -#### 1.2.2 数据文件 +此文件包括两个实体 d1、d2,每个实体分别包含三个物理量 s1、s2、s3,共 6 个时间序列。每个时间序列包含两个 Chunk。 -TsFile文件的内容可以划分为两个部分: 数据(Chunk)和元数据(XXMetadata)。数据和元数据之间是由一个字节的 `0x02` 做为分隔符。 +TsFile 的查询流程,以查 d1.s1 为例: -`ChunkGroup` 存储了一个 *设备(device)* 一段时间的数据。 +* 反序列化 IndexOfTimeseriesIndex,得到 d1.s1 的 TimeseriesIndex 的位置 +* 反序列化得到 d1.s1 的 TimeseriesIndex +* 根据 d1.s1 的 TimeseriesIndex,反序列化其所有 ChunkIndex +* 根据 d1.s1 的每一个 ChunkIndex,读取其 Chunk 数据 -##### ChunkGroup +#### 1.2.1 文件签名和版本号 + +TsFile文件头由 6 个字节的 "Magic String" (`TsFile`) 和 6 个字节的版本号 (`000002`)组成。 + +#### 1.2.2 数据区 -`ChunkGroup` 由若干个 `Chunk`, 一个字节的分隔符 `0x00` 和 一个`ChunkFooter`组成。 +##### ChunkGroup 数据块组 -##### Chunk +`ChunkGroup` 存储了一个实体(Entity) 一段时间的数据。由若干个 `Chunk`, 一个字节的分隔符 `0x00` 和 一个`ChunkFooter`组成。 -一个 `Chunk` 存储了一个 *测点(measurement)* 一段时间的数据,Chunk 内数据是按时间递增序存储的。`Chunk` 是由一个字节的分隔符 `0x01`, 一个 `ChunkHeader` 和若干个 `Page` 构成。 +##### Chunk 数据块 -##### ChunkHeader +一个 `Chunk` 存储了一个物理量(Measurement) 一段时间的数据,Chunk 内数据是按时间递增序存储的。`Chunk` 是由一个字节的分隔符 `0x01`, 一个 `ChunkHeader` 和若干个 `Page` 构成。 + +##### ChunkHeader 数据块头 | 成员 | 类型 | 解释 | | :--------------------------: | :----: | :----: | @@ -119,11 +133,11 @@ TsFile文件的内容可以划分为两个部分: 数据(Chunk)和元数据 | encodingType | TSEncoding | 编码类型 | | numOfPages | int | 包含的page数量 | -##### Page +##### Page 数据页 -一个 `Page` 页存储了 `Chunk` 的一些数据。 它包含一个 `PageHeader` 和实际的数据(time-value 编码的键值对)。 +一个 `Page` 页存储了一段时间序列,是数据块被反序列化的最小单元。 它包含一个 `PageHeader` 和实际的数据(time-value 编码的键值对)。 -PageHeader 结构 +PageHeader 结构: | 成员 | 类型 | 解释 | | :----------------------------------: | :--------------: | :----: | @@ -133,31 +147,31 @@ PageHeader 结构 这里是`statistics`的详细信息: - | 成员 | 描述 | DoubleStatistics | FloatStatistics | IntegerStatistics | LongStatistics | BinaryStatistics | BooleanStatistics | - | :----------------------------------: | :--------------: | :----: | :----: | :----: | :----: | :----: | :----: | - | count | 数据点个数 | long | long | long | long | long | long | - | startTime | 开始时间 | long | long | long | long | long | long | - | endTime | 结束时间 | long | long | long | long | long | long | - | minValue | 最小值 | double | float | int | long | - | - | - | maxValue | 最大值 | double | float | int | long | - | - | - | firstValue | 第一个值 | double | float | int | long | Binary | boolean| - | lastValue | 最后一个值 | double | float | int | long | Binary | boolean| - | sumValue | 和 | double | double | double | double | - | - | - | extreme | 极值 | double | float | int | long | - | - | - -##### ChunkGroupFooter +| 成员 | 描述 | DoubleStatistics | FloatStatistics | IntegerStatistics | LongStatistics | BinaryStatistics | BooleanStatistics | +| :----------------------------------: | :--------------: | :----: | :----: | :----: | :----: | :----: | :----: | +| count | 数据点个数 | long | long | long | long | long | long | +| startTime | 开始时间 | long | long | long | long | long | long | +| endTime | 结束时间 | long | long | long | long | long | long | +| minValue | 最小值 | double | float | int | long | - | - | +| maxValue | 最大值 | double | float | int | long | - | - | +| firstValue | 第一个值 | double | float | int | long | Binary | boolean| +| lastValue | 最后一个值 | double | float | int | long | Binary | boolean| +| sumValue | 和 | double | double | double | double | - | - | +| extreme | 极值 | double | float | int | long | - | - | + +##### ChunkGroupFooter 数据块组结尾 | 成员 | 类型 | 解释 | | :--------------------------------: | :----: | :----: | -| deviceID | String | 设备名称 | +| entityID | String | 实体名称 | | dataSize | long | ChunkGroup 大小 | | numberOfChunks | int | 包含的 chunks 的数量 | -#### 1.2.3 元数据 +#### 1.2.3 索引区 -##### 1.2.3.1 ChunkMetadata +##### 1.2.3.1 ChunkIndex 数据块索引 -第一部分的元数据是 `ChunkMetadata` +第一部分的索引是 `ChunkIndex` : | 成员 | 类型 | 解释 | | :------------------------------------------------: | :------: | :----: | @@ -166,79 +180,79 @@ PageHeader 结构 | tsDataType | TSDataType | 数据类型 | | statistics | Statistics | 统计量 | -##### 1.2.3.2 TimeseriesMetadata +##### 1.2.3.2 TimeseriesIndex 时间序列索引 -第二部分的元数据是 `TimeseriesMetadata`。 +第二部分的索引是 `TimeseriesIndex`: | 成员 | 类型 | 解释 | | :------------------------------------------------: | :------: | :------: | -| measurementUid | String | 传感器名称 | +| measurementUid | String | 物理量名称 | | tsDataType | TSDataType | 数据类型 | -| startOffsetOfChunkMetadataList | long | 文件中 ChunkMetadata 列表开始的偏移量 | -| chunkMetaDataListDataSize | int | ChunkMetadata 列表的大小 | +| startOffsetOfChunkIndexList | long | 文件中 ChunkIndex 列表开始的偏移量 | +| ChunkIndexListDataSize | int | ChunkIndex 列表的大小 | | statistics | Statistics | 统计量 | -##### 1.2.3.3 TsFileMetaData +##### 1.2.3.3 IndexOfTimeseriesIndex 时间序列索引的索引(二级索引) -第三部分的元数据是 `TsFileMetaData`。 +第三部分的索引是 `IndexOfTimeseriesIndex`: | 成员 | 类型 | 解释 | | :-------------------------------------------------: | :---------------------: | :---:| -| MetadataIndex | MetadataIndexNode |元数据索引节点 | -| totalChunkNum | int | 包含的 Chunk 总数 | -| invalidChunkNum | int | 失效的 Chunk 总数 | -| versionInfo | List<Pair<Long, Long>> | 版本信息映射 | -| metaOffset | long | MetaMarker.SEPARATOR偏移量 | +| IndexTree | IndexNode |索引节点 | +| offsetOfIndexArea | long | 索引区的偏移量 | | bloomFilter | BloomFilter | 布隆过滤器 | -元数据索引节点 (MetadataIndexNode) 的成员和类型具体如下: +索引节点 (IndexNode) 的成员和类型具体如下: | 成员 | 类型 | 解释 | | :------------------------------------: | :----: | :---: | -| children | List<MetadataIndexEntry> | 节点元数据索引项列表 | -| endOffset | long | 此元数据索引节点的结束偏移量 | -| nodeType | MetadataIndexNodeType | 节点类型 | +| children | List<IndexEntry> | 节点索引项列表 | +| endOffset | long | 此索引节点的结束偏移量 | +| nodeType | IndexNodeType | 节点类型 | -元数据索引项 (MetadataIndexEntry) 的成员和类型具体如下: +索引项 (MetadataIndexEntry) 的成员和类型具体如下: | 成员 | 类型 | 解释 | | :------------------------------------: | :----: | :---: | -| name | String | 对应设备或传感器的名字 | +| name | String | 对应实体或物理量的名字 | | offset | long | 偏移量 | -所有的元数据索引节点构成一棵**元数据索引树**,这棵树最多由两个层级组成:设备索引层级和传感器索引层级,在不同的情况下会有不同的组成方式。元数据索引节点类型有四种,分别是`INTERNAL_DEVICE`、`LEAF_DEVICE`、`INTERNAL_MEASUREMENT`、`LEAF_MEASUREMENT`,分别对应设备索引层级的中间节点和叶子节点,和传感器索引层级的中间节点和叶子节点。 -只有传感器索引层级的叶子节点(`LEAF_MEASUREMENT`) 指向 `TimeseriesMetadata`。 +所有的索引节点构成一棵类B+树结构的**索引树(二级索引)**,这棵树由两部分组成:实体索引部分和物理量索引部分。索引节点类型有四种,分别是`INTERNAL_ENTITY`、`LEAF_ENTITY`、`INTERNAL_MEASUREMENT`、`LEAF_MEASUREMENT`,分别对应实体索引部分的中间节点和叶子节点,和物理量索引部分的中间节点和叶子节点。 只有物理量索引部分的叶子节点(`LEAF_MEASUREMENT`) 指向 `TimeseriesIndex`。 + +下面,我们使用四个例子来加以详细说明。 + +索引树节点的度(即每个节点的最大子节点个数)可以由用户进行配置,配置项为`max_degree_of_index_node`,其默认值为256。在以下例子中,我们假定 `max_degree_of_index_node = 10`。 -为了更清楚的说明元数据索引树的结构,这里我们使用四个例子来加以详细说明。 +* 例1:5个实体,每个实体有5个物理量 -元数据索引树的最大度(即每个节点的最大子节点个数)是可以由用户进行配置的,配置项为`max_degree_of_index_node`,其默认值为256。在以下例子中,为了简化,我们假定 `max_degree_of_index_node = 10`。 +<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://user-images.githubusercontent.com/19167280/122677230-134e2780-d214-11eb-9603-ac7b95bc0668.png"> -<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://user-images.githubusercontent.com/19167280/81935219-de3fd080-9622-11ea-9aa1-a59bef1c0001.png"> +在5个实体,每个实体有5个物理量的情况下,由于实体数和物理量数均不超过 `max_degree_of_index_node`,因此索引树只有默认的物理量部分。在这部分中,每个 IndexNode 最多由10个 IndexEntry 组成。根节点的 IndexNode 是 `INTERNAL_MEASUREMENT` 类型,其中的5个 IndexEntry 指向对应的实体的 IndexNode,这些节点直接指向 `TimeseriesIndex`,是 `LEAF_MEASUREMENT`。 -在5个设备,每个设备有5个传感器的情况下,由于设备数和传感器树均不超过 `max_degree_of_index_node`,因此元数据索引树只有默认的传感器层级。在这个层级里,每个 MetadataIndexNode 最多由10个 MetadataIndexEntry 组成。根节点的 MetadataIndexNode 是 `INTERNAL_MEASUREMENT` 类型,其中的5个 MetadataIndexEntry 指向对应的设备的 MetadataIndexNode,这些节点直接指向 `TimeseriesMetadata`,是 `LEAF_MEASUREMENT`。 +* 例2:1个实体,150个物理量 -<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://user-images.githubusercontent.com/19167280/81935210-d97b1c80-9622-11ea-8a69-2c2c5f05a876.png"> +<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://user-images.githubusercontent.com/19167280/122677233-15b08180-d214-11eb-8d09-c741cca59262.png"> -在1个设备,设备中有150个传感器的情况下,传感器个数超过了 `max_degree_of_index_node`,元数据索引树有默认的传感器层级。在这个层级里,每个 MetadataIndexNode 最多由10个 MetadataIndexEntry 组成。直接指向 `TimeseriesMetadata`的节点类型均为 `LEAF_MEASUREMENT`;而后续产生的中间节点和根节点不是传感器索引层级的叶子节点,这些节点是 `INTERNAL_MEASUREMENT`。 +在1个实体,实体中有150个物理量的情况下,物理量个数超过了 `max_degree_of_index_node`,索引树有默认的物理量层级。在这个层级里,每个 IndexNode 最多由10个 IndexEntry 组成。直接指向 `TimeseriesIndex`的节点类型均为 `LEAF_MEASUREMENT`;而后续产生的中间节点和根节点不是物理量索引层级的叶子节点,这些节点是 `INTERNAL_MEASUREMENT`。 -<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://user-images.githubusercontent.com/19167280/95592841-c0fd1a00-0a7b-11eb-9b46-dfe8b2f73bfb.png"> +* 例3:150个实体,每个实体有1个物理量 -在150个设备,每个设备中有1个传感器的情况下,设备个数超过了 `max_degree_of_index_node`,形成元数据索引树的传感器层级和设备索引层级。在这两个层级里,每个 MetadataIndexNode 最多由10个 MetadataIndexEntry 组成。直接指向 `TimeseriesMetadata` 的节点类型为 `LEAF_MEASUREMENT`,传感器索引层级的根节点同时作为设备索引层级的叶子节点,其节点类型为 `LEAF_DEVICE`;而后续产生的中间节点和根节点不是设备索引层级的叶子节点,因此节点类型为 `INTERNAL_DEVICE`。 +<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://user-images.githubusercontent.com/19167280/122771008-9a64d380-d2d8-11eb-9044-5ac794dd38f7.png"> -<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://user-images.githubusercontent.com/19167280/81935138-b6e90380-9622-11ea-94f9-c97bd2b5d050.png"> +在150个实体,每个实体中有1个物理量的情况下,实体个数超过了 `max_degree_of_index_node`,形成索引树的物理量层级和实体索引层级。在这两个层级里,每个 IndexNode 最多由10个 IndexEntry 组成。直接指向 `TimeseriesIndex` 的节点类型为 `LEAF_MEASUREMENT`,物理量索引层级的根节点同时作为实体索引层级的叶子节点,其节点类型为 `LEAF_ENTITY`;而后续产生的中间节点和根节点不是实体索引层级的叶子节点,因此节点类型为 `INTERNAL_ENTITY`。 -在150个设备,每个设备中有150个传感器的情况下,传感器和设备个数均超过了 `max_degree_of_index_node`,形成元数据索引树的传感器层级和设备索引层级。在这两个层级里,每个 MetadataIndexNode 均最多由10个 MetadataIndexEntry 组成。如前所述,从根节点到设备索引层级的叶子节点,类型分别为`INTERNAL_DEVICE` 和 `LEAF_DEVICE`,而每个设备索引层级的叶子节点都是传感器索引层级的根节点,从这里到传感器索引层级的叶子节点,类型分别为`INTERNAL_MEASUREMENT` 和 `LEAF_MEASUREMENT`。 +* 例4:150个实体,每个实体有150个物理量 -元数据索引采用树形结构进行设计的目的是在设备数或者传感器数量过大时,可以不用一次读取所有的 `TimeseriesMetadata`,只需要根据所读取的传感器定位对应的节点,从而减少 I/O,加快查询速度。有关 TsFile 的读流程将在本章最后一节加以详细说明。 +<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://user-images.githubusercontent.com/19167280/122677241-1a753580-d214-11eb-817f-17bcf797251f.png"> -##### 1.2.3.4 TsFileMetadataSize +在150个实体,每个实体中有150个物理量的情况下,物理量和实体个数均超过了 `max_degree_of_index_node`,形成索引树的物理量层级和实体索引层级。在这两个层级里,每个 IndexNode 均最多由10个 IndexEntry 组成。如前所述,从根节点到实体索引层级的叶子节点,类型分别为`INTERNAL_ENTITY` 和 `LEAF_ENTITY`,而每个实体索引层级的叶子节点都是物理量索引层级的根节点,从这里到物理量索引层级的叶子节点,类型分别为`INTERNAL_MEASUREMENT` 和 `LEAF_MEASUREMENT`。 -在TsFileMetaData之后,有一个int值用来表示TsFileMetaData的大小。 +索引采用树形结构进行设计的目的是在实体数或者物理量数量过大时,可以不用一次读取所有的 `TimeseriesIndex`,只需要根据所读取的物理量定位对应的节点,从而减少 I/O,加快查询速度。有关 TsFile 的读流程将在本章最后一节加以详细说明。 #### 1.2.4 Magic String -TsFile 是以6个字节的magic string (`TsFile`) 作为结束. +TsFile 是以6个字节的magic string (`TsFile`) 作为结束。 恭喜您, 至此您已经完成了 TsFile 的探秘之旅,祝您玩儿的开心! diff --git a/docs/zh/UserGuide/Data-Concept/Data-Model-and-Terminology.md b/docs/zh/UserGuide/Data-Concept/Data-Model-and-Terminology.md index 469442f..5690847 100644 --- a/docs/zh/UserGuide/Data-Concept/Data-Model-and-Terminology.md +++ b/docs/zh/UserGuide/Data-Concept/Data-Model-and-Terminology.md @@ -23,44 +23,76 @@ ## 数据模型 -本节,我们以电力场景为例,说明如何在IoTDB中创建一个正确的数据模型。 +我们以风电场物联网场景为例,说明如何在 IoTDB 中创建一个正确的数据模型。 -根据属性层级,属性涵盖范围以及数据之间的从属关系,我们可将其数据模型表示为如下图所示的属性层级组织结构,即电力集团层-电厂层-设备层-传感器层。其中ROOT为根节点,传感器层的每一个节点为叶子节点。IoTDB的语法规定,ROOT节点到叶子节点的路径以“.”连接,以此完整路径命名IoTDB中的一个时间序列。例如,下图最左侧路径对应的时间序列名称为`ROOT.ln.wf01.wt01.status`。 +根据企业组织结构和设备实体层次结构,我们将其物联网数据模型表示为如下图所示的属性层级组织结构,即电力集团层-风电场层-实体层-物理量层。其中 ROOT 为根节点,物理量层的每一个节点为叶子节点。IoTDB 采用树形结构定义数据模式,以从ROOT 节点到叶子节点的路径来命名一个时间序列,层次间以“.”连接。例如,下图最左侧路径对应的时间序列名称为`ROOT.ln.wf01.wt01.status`。 -<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://user-images.githubusercontent.com/13203019/51577327-7aa50780-1ef4-11e9-9d75-cadabb62444e.jpg"> +<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://user-images.githubusercontent.com/19167280/123542457-5f511d00-d77c-11eb-8006-562d83069baa.png"> -**属性层级组织结构** +IoTDB模型结构涉及如下基本概念: -得到时间序列的名称之后,我们需要根据数据的实际场景和规模设置存储组。由于在本文所述场景中,每次到达的数据通常以集团为单位(即数据可能为跨电场、跨设备的),为了写入数据时避免频繁切换IO降低系统速度,且满足用户以集团为单位进行物理隔离数据的要求,我们将存储组设置在集团层。 +* 物理量(Measurement,也称工况、字段 field) -根据模型结构,IoTDB中涉及如下基本概念: +**一元或多元物理量**,是在实际场景中检测装置所记录的测量信息,且可以按一定规律变换成为电信号或其他所需形式的信息输出并发送给 IoTDB。在 IoTDB 当中,存储的所有数据及路径,都是以物理量为单位进行组织。 -* 设备 +* 物理分量(SubMeasurement、分量) -设备指的是在实际场景中拥有传感器的装置。在IoTDB当中,所有的传感器都应有其对应的归属的设备。 +在多元物理量中,包括多个分量。如 GPS 是一个多元物理量,包含3个分量:经度、维度、海拔。多元物理量通常被同时采集,共享时间列。 -* 传感器 +一元物理量则将分量名和物理量名字重合。如温度是一个一元物理量。 -传感器是指在实际场景中的一种检测装置,它能感受到被测量的信息,并能将感受到的信息按一定规律变换成为电信号或其他所需形式的信息输出并发送给IoTDB。在IoTDB当中,存储的所有的数据及路径,都是以传感器为单位进行组织。 +* 实体(Entity,也称设备,device) -* 存储组 +**一个物理实体**,是在实际场景中拥有物理量的设备或装置。在IoTDB当中,所有的物理量都有其对应的归属实体。 -用户可以将任意前缀路径设置成存储组。如有4条时间序列`root.vehicle.d1.s1`, `root.vehicle.d1.s2`, `root.vehicle.d2.s1`, `root.vehicle.d2.s2`,路径`root.vehicle`下的两个设备d1,d2可能属于同一个业主,或者同一个厂商,因此关系紧密。这时候就可以将前缀路径`root.vehicle`指定为一个存储组,这将使得IoTDB将其下的所有设备的数据存储在同一个文件夹下。未来`root.vehicle`下增加了新的设备,也将属于该存储组。 +* 存储组(Storage group) -> 注意:不允许将一个完整路径(如上例的`root.vehicle.d1.s1`)设置成存储组。 +**一组物理实体**,用户可以将任意前缀路径设置成存储组。如有4条时间序列`root.ln.wf01.wt01.status`, `root.ln.wf01.wt01.temperature`, `root.ln.wf02.wt02.hardware`, `root.ln.wf02.wt02.status`,路径`root.ln`下的两个实体 `wt01`, `wt02`可能属于同一个业主,或者同一个制造商,这时候就可以将前缀路径`root.ln`指定为一个存储组。未来`root.ln`下增加了新的实体,也将属于该存储组。 -设置合理数量的存储组可以带来性能的提升:既不会因为产生过多的存储文件(夹)导致频繁切换IO降低系统速度(并且会占用大量内存且出现频繁的内存-文件切换),也不会因为过少的存储文件夹(降低了并发度从而)导致写入命令阻塞。 +一个存储组中的所有实体的数据会存储在同一个文件夹下,不同存储组的实体数据会存储在磁盘的不同文件夹下,从而实现物理隔离。 -用户应根据自己的数据规模和使用场景,平衡存储文件的存储组设置,以达到更好的系统性能。(未来会有官方提供的存储组规模与性能测试报告) +> 注意1:不允许将一个完整路径(如上例的`root.ln.wf01.wt01.status`)设置成存储组。 +> +> 注意2:一个时间序列其前缀必须属于某个存储组。在创建时间序列之前,用户必须设定该序列属于哪个存储组(Storage Group)。只有设置了存储组的时间序列才可以被持久化在磁盘上。 -> 注意:一个时间序列其前缀必须属于某个存储组。在创建时间序列之前,用户必须设定该序列属于哪个存储组(Storage Group)。只有设置了存储组的时间序列才可以被持久化在磁盘上。 +一个前缀路径一旦被设定成存储组后就不可以再更改这个存储组的设定。 -一个前缀路径一旦被设定成存储组后就不可以再更改这个存储组的设置。 - -一个存储组设定后,其对应的前缀路径的所有父层级与子层级也不允许再设置存储组(如,`root.ln`设置存储组后,root层级与`root.ln.wf01`不允许被设置为存储组)。 +一个存储组设定后,其对应的前缀路径的祖先层级与孩子及后裔层级也不允许再设置存储组(如,`root.ln`设置存储组后,root 层级与`root.ln.wf01`不允许被设置为存储组)。 存储组节点名只支持中英文字符、数字、下划线和中划线的组合。例如`root.存储组_1-组1` 。 +* 数据点(Data point) + +**一个“时间-值”对**。 + +* 时间序列(一个实体的某个物理量对应一个时间序列,Timeseries,也称测点meter、时间线timeline,实时数据库中常被称作标签tag、参数parameter) + +**一个物理实体的某个物理量在时间轴上的记录**,是数据点的序列。 + +例如,ln电力集团、wf01风电场的实体 wt01有名为 status的物理量,则它的时间序列可以表示为:`root.ln.wf01.wt01.status`。 + +* 一元时间序列(single-variable timeseries 或timeseries,v0.1 起支持) + +一个实体的一个一元物理量对应一个一元时间序列。实体+物理量=时间序列 + +* 多元时间序列(Multi-variable timeseries 或 Aligned timeseries,v0.13 起支持) + +一个实体的一个多元物理量对应一个多元时间序列。这些时间序列称为**多元时间序列**,也叫**对齐时间序列**。 + +多元时间序列需要被同时创建、同时插入值,删除时也必须同时删除。不过在查询的时候,可以对于每一个分量单独查询。 + +通过使用对齐的时间序列,在插入数据时,一组对齐序列的时间戳列在内存和磁盘中仅需存储一次,而不是每个时间序列存储一次: + +<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://user-images.githubusercontent.com/19167280/123542458-62e4a400-d77c-11eb-8c45-ca516f1b7eba.png"> + +在后续数据定义语言、数据操作语言和 Java 原生接口章节,将对涉及到对齐时间序列的各种操作进行逐一介绍。 + +* 物理量模板(Measurement template,v0.13 起支持) + +实际应用中有许多实体所采集的物理量相同,即具有相同的工况名称和类型,可以声明一个**物理量模板**来定义可采集的物理量集合。将物理量模版挂在树形数据模式的任意节点上,表示该节点下的所有实体具有相同的物理量集合。 + +目前每一个路径节点仅允许挂载一个物理量模板,实体将使用其自身或最近祖先的物理量模板作为有效模板。 + * 路径 @@ -89,35 +121,6 @@ LayerName: Identifier | STAR > 注意: storage > group中的LayerName只支持数字,字母,汉字,下划线和中划线。另外,如果在Windows系统上部署,存储组层级名称是大小写不敏感的。例如同时创建`root.ln` > 和 `root.LN` 是不被允许的。 -* 时间序列 - -时间序列是IoTDB中的核心概念。时间序列可以被看作产生时序数据的传感器的所在完整路径,在IoTDB中所有的时间序列必须以root开始、以传感器作为结尾。一个时间序列也可称为一个全路径。 - -例如,vehicle种类的device1有名为sensor1的传感器,则它的时间序列可以表示为:`root.vehicle.device1.sensor1`。 - -> 注意:当前IoTDB支持的时间序列必须大于等于四层(之后会更改为两层)。 - -* 对齐时间序列(v0.13 起支持) - -在同一个时间戳有多个传感器同时采样,会形成具有相同时间戳的多条时间序列,在 IoTDB 中,这些时间序列成为**对齐时间序列**(在学术上也称为**多元时间序列**,即包含多个一元时间序列作为分量, 各个一元时间序列的采样时间点相同)。 - -对齐时间序列可以被同时创建,同时插入值,删除时也必须同时删除。不过在查询的时候,可以对于每一个传感器单独查询。 - -通过使用对齐的时间序列,在插入数据时,一组对齐序列的时间戳列在内存和磁盘中仅需存储一次,而不是时间序列的条数次: - -<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://user-images.githubusercontent.com/19167280/114125919-f4850800-9929-11eb-8211-81d4c04af1ec.png"> - -在后续数据定义语言、数据操作语言和 Java 原生接口章节,将对涉及到对齐时间序列的各种操作进行逐一介绍。 - - -* 设备模板(v0.13 起支持) - -实际场景中有许多设备型号相同,即具有相同的工况名称和类型,为了节省系统资源,可以声明一个**设备模板**表征同一类型的设备,设备模版可以挂在到路径的任意节点上。 - -目前每一个路径节点仅允许挂载一个设备模板,具体的设备将使用其自身或最近祖先的设备模板作为有效模板。 - -在后续数据定义语言、数据操作语言和 Java 原生接口章节,将对涉及到设备模板的各种操作进行逐一介绍。 - * 前缀路径 前缀路径是指一个时间序列的前缀所在的路径,一个前缀路径包含以该路径为前缀的所有时间序列。例如当前我们有`root.vehicle.device1.sensor1`, `root.vehicle.device1.sensor2`, `root.vehicle.device2.sensor1`三个传感器,则`root.vehicle.device1`前缀路径包含`root.vehicle.device1.sensor1`、`root.vehicle.device1.sensor2`两个时间序列,而不包含`root.vehicle.device2.sensor1`。
