12 月 3 日,2023 IoTDB 用户大会在北京成功举行,收获强烈反响。本次峰会汇集了超 20 位大咖嘉宾带来工业互联网行业、技术、应用方向的精彩议题,多位学术泰斗、企业代表、开发者,深度分享了工业物联网时序数据库 IoTDB 的技术创新、应用效果,与各行业标杆用户的落地实践、解决方案,并共同探讨时序数据管理领域的行业趋势。
我们邀请到天谋科技高级开发工程师,Apache IoTDB PMC Member 张金瑞参加此次大会,并做主题报告——《筑其形:如何轻松搞定 IoTDB 数据建模》。以下为内容全文。
大家下午好,今天我给大家介绍的题目是《筑其形:如何轻松搞定 IoTDB 数据建模》。
对于数据进行建模这个话题肯定是大家使用 IoTDB 的时候第一个会问到的问题,就是我怎么把我的数据存入到你们的系统中?我在存储的时候需要定义一个什么样的数据结构,定义一个什么样的数据模型?大家肯定都非常熟悉我们常用的关系型数据库,而大家想到的肯定就是,我要把我的业务模型先映射成几张表,然后再根据我的业务模型去做一些表的关联等等这些操作。
那如果我们使用 IoTDB 的话,应该怎么做呢?比如说我有一个业务场景,我想把数据存储到 IoTDB 中,那今天我主要从四个方面给大家介绍一下在 IoTDB 当中如何对数据进行建模。第一个就是时序数据库中的基础的数据结构;第二个就是我们在 IoTDB 中的数据建模方法;第三个是建模的一些优化的方案,比如我们使用元数据模板;第四项是一些拓展功能,比如说我们去使用 IoTDB 当中的视图的功能。
01 时序数据的基础数据结构
首先我给大家讲第一部分,就是时序数据库中的基础的数据结构,主要包括数据库、设备、物理量这三个概念。
在介绍这些概念之前,我还是想先跟大家简单介绍一下,我相信在场的同学肯定都已经非常了解了,就是说什么是时序数据。时序数据指的是时间序列数据,就是按照时间顺序记录的数据列。在工业物联网当中,机器设备、传感器它们都会实时地产生非常海量的时序数据。比如说中间这个图显示了一个风力发电机当中的时序数据,不同的设备随着时间的推移,它会产生一些不同的发电量,并被记录下来,那这些就是时序数据。
下图当中展示的内容就是,如果我们把一个二维的坐标,把它的纵坐标当作是一个物理量,把它的横坐标用时间来标识,那么随着时间的推移,物理量会发生不同的变化,这个变化会形成一个曲线,那这个就是大家脑海中对于时间序列数据的一种印象,也可以通过这样的方式去理解它。
好,回到我们的主题当中来。第一个概念就是数据库是什么?这里的数据库是一个狭义的数据库的概念,是说在 IoTDB 当中的 Database 这样一个概念。在 IoTDB 当中,数据库我们又把它叫做存储组,它就类似于我们使用一些关系型数据库中提到的,比如说 Database 或者是 Schema 的概念。它通常是用来对数据进行大的分组,我们可以在一个数据库当中去管理和存储一批的时间序列数据。
比如说在 IoTDB 当中,用户是可以在一个 IoTDB 当中创建多个 Database 的,并在每个 Database 当中管理和存储不同的时间序列数据,这都是可以根据用户的业务场景去做这些调整的。然后每个 Database 都具有一些自己独立的属性,比如说 TTL,或者是副本数,大家可以进行配置。
右图中给了一个例子,比如说在一个智能安防家居的场景当中,如果用户希望把这个数据存储到 IoTDB 当中,那么他可以在 IoTDB 当中创建一个叫做 DB_home 的 Database,作为他的数据存储的一个单元。然后智能家居系统当中可能会有照明系统,或者是有安防系统等等,都会产生不同的数据,那这些数据都可以存到同样的一个 Database 当中,这就是一个使用场景。
创建数据库在 IoTDB 当中非常简单,只需要使用简单的 SQL 语句就可以做到。比如说 create database,然后指定一个名字;show database 可以列出这个数据库当中所有的 Database;或者是 delete database,把某一个已经创建的 Database 删掉。通过 show database 我们也可以看到,每个 Database 其实都是包含一些特定的属性的,在用户使用不同的 Database 的时候,可以做一些区分。
第二个概念应该是大家接触得最多的一个概念,就是设备,设备是什么呢?其实我们可以通过它的直观的中文语义来理解它,它其实指的就是一个物理设备。但是在 IoTDB 当中,或者说在时序数据领域,我们也给它一个更为广泛的定义,叫做实体,就是说在实际场景当中,拥有物理量的设备或装置。在 IoTDB 当中,所有的物理量都会有它对应所归属的设备。
那么我们可以这么理解,一个设备,其实它就是管理的一小组时间序列,它是一个时间序列的组合,比如它可以是一个物理设备,是一个测量装置,是一个传感器的集合等等。比如说在下面的这三张图当中,一台风力发电机它是一个设备,一辆汽车它其实也可以定义成一个设备,甚至说在一些工程领域,一座桥梁我们也可以把它叫做一个设备,可以通过这样的概念来映射到这个模型当中。
在刚才的设备介绍当中,其实我们也提到了物理量这个词,那物理量又是什么呢?这个名字好像在我们日常生活中不太常见,但其实我们可以通过另外一个词汇去理解它,那就是测点。测点又怎么理解呢?我们可以简单地去这么想,时间序列数据肯定是由很多很多的东西来产生的,而产生时间序列数据的最基本的一个单元,它就是一个测点,或者我们叫做一个物理量。
通常这些物理量或者这些测点,都是按照定频或者是非定频的方式去产生数据。尤其是在工业领域当中,我们可能接触最多的就是各种各样的传感器,或者我们在家里可能就会有一些物品,比如一些集成了很多功能的小钟表,它可能就会带有可以显示房间内温度的功能,可以显示房间内湿度的功能,那这个钟表我可以认为它是一个设备,而它里面肯定包含检测温度或者湿度的一些小的传感器单元,而这些小的传感器单元,我们就可以把它叫做物理量。
比如说在我们刚才提到的三种不同类型的设备示例当中,比如风力发电机,随着时间推移,它肯定要记录自己的功率,或者是记录自己的电压值等等信息,因为它上面肯定会有很多传感器。那这些功率、电压值,我们就可以认为它是物理量,它是由这些传感器产生的。那一辆汽车,它肯定会有车速,它的水温,以及汽车上面其它的一些信息,这些信息也可以被当作物理量。对于桥梁来说,它有一些工程界的监测指标,比如它的振动,它的支座位移等等,这种都可以看作是物理量,来作为我们 IoTDB 数据存储时候的一些方式。
物理量介绍完之后,我还要说一下设备跟物理量是一个什么样的关系。刚才讲到了设备会拥有多个物理量,一个物理设备通常会具有一定的标识或者是从属关系,从而唯一确认一个设备,或者是快速地查找一批设备。这个其实与我们日常生活中或者是在工业领域中的一些直觉的思维是相似的。
以风力发电机为例,我们怎么样去定位到一台风力发电机呢?首先我们可能会想,它是属于某一个集团的,这个集团可能在某个国家,这个国家可能有不同的区域,比如有西北地区,还有东北大区,或者西南大区。然后每个区域又可能会建立很多不同的风厂,每个风厂可能会包含几十台,甚至成百上千台的风力发电机,每个风力发电机就包含它所对应的物理量。那按照这样的一种思维去想的话,我们会发现它是一种自上而下层次的结构。
比如说某个集团,我们就假设它的集团名叫 LN,“LN 集团的,西北大区的,1 号风厂的,5 号风机”,我们通过这样的一种描述,其实就能唯一的去找到一台设备。
以汽车这个例子来讲,我们说某个集团公司,它底下肯定会有很多不同的品牌,每个品牌下又会有不同的生产线,每个生产线肯定会生产出一台一台的汽车,汽车又包含它所对应的物理量。那在这样一种场景下,我们如何去定位到一台具体的汽车呢?我们可能就会这么说:“大众集团下的,奥迪品牌的,A4 生产线的,具有某个序列号的,一台汽车”。在这样的定义场景下,我们其实就能唯一地确定一个设备,这个设备也带有了它相应的一些属性,比如它是属于某个集团的,属于某个品牌的,我们也可以通过这些信息反过来去进行检索。
在第三个例子当中,桥梁和前面两个例子也是非常类似的。比如说某一个省份,它下面按照我们国家的行政区划,可能会分为地级市,地级市下又会分为县区,每个县区可能会有很多桥梁,桥梁会有它的名字,然后每个桥梁又会有它不同的物理量。那在这样一个实际的应用场景当中,我们可能就会说,比如“河北省的,邢台市的,赵县的,赵州桥”这样我们就能够定位到这个桥梁。比如某一天,统计方面的单位想知道这个县区有多少座桥梁,它可能就会说:“河北省邢台市下一共有多少桥?”或者说:“赵县下一共有多少桥梁?”它都会通过这样的方式来统计,这也是非常符合我们的一些查询思维的。
02 建模基础:IoTDB 建模方法
第一章节主要是给大家讲了在 IoTDB 的使用过程当中,数据建模的一些基本的概念,就是数据库、设备、物理量,以及它们的一些关系,包括我们在工业生产当中如何去使用它们,以及它们之间的联系。那在第二部分中,我会跟大家分享一下具体的我们如何在 IoTDB 当中去做数据的建模,主要包括测点的创建,测点的管理和查询。
我们依然以这样的一个风力发电的场景为例子,左边我们看到了给出的一个示例,依然是分为集团公司,它有某个区域,有不同的风场,不同风场又有不同的风力发电机。假设集团公司有两个,一个叫 ln ,一个叫 sgcc;区域有一种,比如就叫 northwest 西北大区;风场有两个,wf 开头的 01 和 02,风机都是以 wt 开头的,带上两个数字作为它的标号。
假设我们现在有三台风机想去记录,而这三台风机在集团公司、区域、风场、风机这四个维度下具有不同的值,我们如果把它列出来,就能看到右上角的这个表格,我们如何去描述这台设备呢?就是 ln 的 northwest 的 wf01 的 wt01,这就唯一确定了 wt01 这台风机。当然这个 wt01 它的属性是属于 wf01 这个风场的,因为在第二行我们可以看到,有别的风机的标号可能也叫 wt01,但是它的风场的名字不一样。那通过这些不同维度的属性,我们其实就能唯一地确定一台设备。
假设不同的风机都具有两个物理量,也就是测点,一个叫功率 power,另外一个叫速度 speed,在这种场景下,我们就会得到 3*2 共 6 个时间序列,对吧?因为每个时间序列对应的都是一个测点产生的数据。那么在 IoTDB 当中,我们怎么去描述这些具体的时间序列呢?这里面我们就可以用一个简单的规则,把我们刚才用自然语言描述的“的” 这个汉字换成英文符号“.”,然后把它们其它的属性连起来,这样就形成了我们在 IoTDB 当中去描述一个设备,描述一个物理量的方法,那就是下面这个表格中列出的 6 个具体的时间序列。
而且在这些时间序列之前,我们为了统一的管理,都会默认的给它加上“root”这样一个默认的层级作为开头,那么所有的这 6 个时间序列,听起来就是 root.ln.northwest.wf01.wt01.power 或者 root.ln.northwest.wf01.wt01.speed。这就是在 IoTDB 当中去描述一个时间序列的方法,那就是把自然语言中的"的"换成“.”这样来描述,然后做层级的划分。
那在这种描述下,大家可能非常自然的就会想到一个事情,比如说还是以刚才这 6 个时间序列为例,我们可能会想,这个“.”前面的好多层级信息好像都是重复的。比如在这个风力发电的场景下,所有的设备肯定都是属于我们一个集团公司的,我们的大区其实可能也没有几个,比如只有 northwest 或者 southwest,大区下的风场可能也没有很多。但如果我们按照前缀“树”的这个思路,把所有的时间序列组装起来进行可视化,我们其实就能得到右边这个图,也就是说我们发现,所有的设备好像能够通过一种树形结构建立起关联,而这种关联从另外一个维度又展示了一种设备层次的关系,这个关系就是我们常说的树形结构。
其实我们通过这个例子可以看到,我们并不是一开始就想到了这个树形结构,然后再把这个树形结构建立到 IoTDB 当中的,而是我们一开始想的还是业务场景,按照我们的业务场景中设备的层级的划分,对它去做描述、归类之后,最后我们发现其实它本质上就是一个这样的树形的层级,然后可以直接方便地存到我们的 IoTDB 当中,在 IoTDB 中进行数据建模。所以通过这样的思路,大家再去理解这个事情,可能就会更加地顺畅和直接。
那么具体的命令是怎么来的呢?比如说我们要在 IoTDB 当中创建一条时间序列,其实也很简单,我们已经知道这个序列的描述了,我们换一个词,叫做它的路径,就是从这个“树”上,从根节点到叶子节点的这样一条路径,其实就是它在 IoTDB 当中时间序列的描述。然后每个序列会有对应的数据类型以及编码方法,我们把它转化成右下角这样的 create timeseries 的命令,就可以在 IoTDB 当中非常方便地把这些时间序列的模型建立出来。
当我们建立完这些时间序列模型之后,我们可以通过其它命令做一些简单的查询,比如说 show timeseries,我们就可以看到系统中所有的时间序列,同时系统会把这个时间序列对应的数据类型、编码方式等等信息都展示出来。
当然,我们的时间序列在一个 db 中是非常多的,那我们也可以像查询数据一样做一些特定的查询,比如可以按照前缀做一些特定时间序列的查询,比如说 show timeseries 加上一个前缀,我们就可以看到查询出的数据都是以这个前缀为开头的。
或者是我们可以通过一些关键字匹配的方式去做匹配,比如说我们可以看到,我们想查询包含某个字符的时间序列,在这个例子当中,我们要查询包含“pow”这样一个短语的时间序列,那我们查询出来的三条时间序列,它们都是包含 power 这个词的,这又是一种时间序列上的较为好用的查询方法。
03 建模优化:IoTDB 模板功能
讲完时间序列的创建、查询之后,大家应该能够有一个基本的概念,即如果想在 IoTDB 当中做数据建模,我应该先怎么样去分析我的业务场景,怎么样把我所有的设备、物理量描述出来,再把它们转化成 IoTDB 的描述语言,然后根据它们的数据类型、编码方法,把它们去用对应的 create timeseries 的语句创建到 IoTDB 当中。在这个基础上,我会发现所有的时间序列最终形成了一棵前缀树,而我就可以非常方便地在这棵树上,按照树的结构去做一些检索,或者是对序列进行一些分组。
那在这个背景下,我们可以做哪些优化呢?在这里我想给大家引入一个非常好用的 IoTDB 的建模优化功能,也就是元数据模板功能,我们可以通过元数据模板去批量地创建时间序列。
那我们来看一下元数据模板是什么,以及我们为什么需要去创建这个元数据模板。还是以风力发电为例,在一台风机中假设有两个物理量,我们一共需要创建 6 个时间序列,一共包含了 3 台风机,那么我可以写 6 个创建时间序列的语句,create timeseries 等等,列出来就好了。同时我们在系统中,也需要把它们 6 个时间序列都存储在元数据模块当中。这个时候可能有的同学就会问了,假如我的业务场景下的设备数量非常多,比如说有几千台风机,甚至是几万台风机,每个风机又包含很多数据测点,那我是不是需要去重复地创建它们,并且重复地去把它们存储在 IoTDB 的元数据模块当中呢?答案当然是:不需要。那我们就可以通过元数据模板去做到这个事情。
我们回到刚才的这个树型结构当中,以这个结构为例子,在这个风力发电的树型模型下,我们假设有这样一个场景:比如在西北大区下,所有的风机都是同一个型号,它们的物理测点也都是一样的。那在这种场景下,我是不是能够有一种操作,给这个层级定义一个模板,规定这个层级下新增的所有设备,都具有相同的某些指定的物理量,而这些物理量是通过模板去定义的,那我们应该怎么做?其实直接使用元数据模板就可以做到这个事情。
比如说在 northwest 下一共有 3 个设备,wt01 以及 wf02 下的两个设备,它们都具有相同的物理量。假设这个时候我又需要在 wf02 下增加另外 2 个或者是 200 个设备,而且希望它们都具有功率和速度这两个物理量,其实我就可以在 northwest 下去创建一个元数据模板,定义所有的设备都是具有功率和速度这些物理量的,然后我只需要在 northwest 这个节点下去新增设备就好了,而不需要再给它们单独指定物理量。而且在我们实际的系统实现当中,也可以节省相对应的存储空间,因为我们也不会对它们进行重复的存储。
所以说元数据模板,就像刚才跟大家讲过的,可以实现同类型不同设备下的物理量元数据的共享,可以非常有效地减少数据的内存占用,同时可以简化同类型设备所对应的时间序列的管理。它的使用方法其实也非常的简单,首先就是创建一个元数据模板,定义一类设备的物理量,然后把它挂载到某个层级下,就是刚才我们树形结构中的某个层级,然后再去激活它,直接写入数据,或者是通过手动在该层级下创建设备的方式,都可以把这个元数据模版应用起来。
具体的步骤我们通过一个简单的例子来演示。假如我们要创建一个名为 turbine 的元数据模板,同时它具有两个物理量,power 和 speed,我们再通过下面第二个语句 set schema to,可以把它去挂载到某一个具体的叶子节点、中间节点上。在挂载到这个中间节点上之后,我们只需要直接地使用 create timeseries using schema,即我们使用某一个模板去创建这个时间序列,就可以通过这样的方式,在 northwest 下直接创建出我们需要的一些设备。
或者,IoTDB 其实也支持自动创建,只要我们写入数据的时候,它的时间序列的描述是在这个节点下的,那它对应的物理量也会被自动的创建出来。通过这样的方式,我们既可以节省用户去手动操作创建元数据的额外工作,同时又能节省系统对于元数据成倍的重复存储的空间,可以做到比较好的优化。
那我们创建完之后,可以直接去 show timeseries,就和我们不使用元数据模板创建出来的 timeseries 是一样的。我们可以看到在这个示例当中,我们有来自 4 个设备的 8 个时间序列,每个时间序列的物理量和模板中定义的都是一样的。
04 建模扩展:IoTDB 视图功能
讲完元数据模板之后,我会给大家分享最后一个话题,即 IoTDB 当中元数据建模的一个拓展功能,我们把它叫做视图。大家在其它的数据库中可能也接触过视图,也对视图有一定的理解,我们这边也是有差不多的功能。
那我们去怎么理解它呢?就是元数据视图可以为现有的元数据创建不同的视图功能,它可以提供比如序列分组、序列逻辑映射,或者是序列计算的功能。具体的比如说,我们按照刚才的建模方式,把所有的元数据都已经创建出来之后,在实际的业务使用的时候,我们也许会希望把某个序列的名字改变一下,使查询更方便;或者是我建模的时候用了一套命名的方法,但是在不同的业务场景下,我希望使用不同的名字,或者是另外一种分组去实现;或者说我把元数据模板创建出来了,但是我希望对不同层次的设备,设定不同的权限管理方式。以上这些我们都可以通过视图的方法去实现。
比如说我们看这样的一个例子,在我们最开始做数据建模的时候,比如这是数据采集团队做的建模。在实际的生产活动当中,数据采集团队会按照设备的基本信息去做元数据树的定义,比如他们定义出了 root,下面有某个设备(设备 1、设备 3、设备 4),它们有温度、压力这样的一些概念,然后数据采集团队就把数据按照这种模式写进去了。但是在实际的使用当中,我们发现业务团队那边好像要换一种方式来做查询,比如说他们期望的是把所有的温度传感器放在一起,他们要做归类;比如说负责温度监测业务的团队希望把所有设备的温度都能够放在一起,同时还希望在数据库当中有平均温度这样一个新的衍生序列,他们就能够直接拿里面的值做计算,那这个时候他们其实就可以用到视图功能了。
就像这个图中给的例子一样,可以把原始的树型模型当中的这些设备做二次的映射,映射成一种新的层次结构,而这个新的层次结构完全是可以由我们自己来定义的,可以根据业务需求来定义,也可以根据一些业务需求中的计算来对原始的数据做衍生的计算,形成一条新的、原本不存在的序列,这都是可以做到的。
在这种情况下,我们其实能做到一些优势,比如说我们可以把视图做分离,因为数据采集团队其实不需要关心业务逻辑,他们只需要按照设备最基本的概念和逻辑关系做数据采集就可以了;而业务团队也不需要去了解设备在生产环境中到底是怎么分布的,只需要按照他们建立出来的业务模型的视图来做业务的分析、数据的查询,把数据提供给更上层的团队就好了。
在这种情况下,同时我们可以做到计算增强,也就是说我们可以在原有序列的基础上,直接预计算出来一些衍生的序列,供这个团队去直接地查询结果,非常方便。另外一方面,从安全性的角度来讲,我们可以把一些特定的设备或者是同种类型的设备做不同的分组,而给不同的分组加上不同的权限管理,让我们的整个业务更加的可控。以上这些就是 IoTDB 中的视图功能介绍,具体的使用方法,有兴趣的同学可以去我们的官网上,或者是官方文档上查看它的具体的使用、操作流程,在这里我就不展开跟大家讲了。
这就是我今天主要给大家分享的四个方面,给大家介绍一下 IoTDB 中的数据建模,谢谢大家。
更多内容推荐:
• 回顾 IoTDB 2023 大会全内容