Merge branch '3.0' of github.com:taosdata/TDengine into test/cover1

This commit is contained in:
happyguoxy 2025-03-23 20:55:58 +08:00
commit 864c08d44d
19 changed files with 228 additions and 39 deletions

View File

@ -57,11 +57,11 @@ toc_max_heading_level: 4
### 超级表
采用“一个数据采集点一张表”的设计虽然有助于针对性地管理每个采集点,但随着设备数量不断增加表的数量也会急剧增加,这给数据库管理和数据分析带来了挑战。在进行跨数据采集点的聚合操作时,用户需要面对大量的表,工作变得异常繁重
TDengine 采用“一个数据采集点一张表”的设计虽然有利于高效地管理每个数据采集点,但随着设备数量不断增加,表的数量也会急剧增加,这给表的管理以及表之间的聚合带来了巨大的挑战
为了解决这个问题TDengine 引入超级表Super Table简称为 STable的概念。超级表是一种数据结构它能将某一特定类型的数据采集点聚集在一起,形成一张逻辑上的统一表。这些数据采集点具有相同的表结构,但各自的静态属性(如标签)可能不同。创建超级表时,除了定义采集量外,还需定义超级表的标签。一张超级表至少包含一个时间戳列、一个或多个采集量列以及一个或多个标签列。此外,超级表的标签可以灵活地进行增加、修改或删除操作。
为了解决这个问题TDengine 引入超级表Super Table简称为 STable的概念。超级表是一种数据结构它能将某一特定类型的数据采集点聚集在一起形成一张逻辑上的统一表。这些数据采集点具有相同的表结构但各自的静态属性如标签可能不同。创建超级表时除了定义采集量的结构之外,还需定义超级表的标签。一张超级表至少包含一个时间戳列、一个或多个采集量列以及一个或多个标签列。此外,超级表的标签可以灵活地进行增加、修改或删除操作。
在 TDengine 中,表代表具体的数据采集点,而超级表则代表一组具有相同属性的数据采集点集合。以智能电表为例,我们可以为该类型的电表创建一张超级表,其中包含了所有智能电表的共有属性和采集量。这种设计不仅简化了表的管理,还便于进行跨数据采集点的聚合操作,从而提高数据处理的效率。
在 TDengine 中,表代表具体的数据采集点,而超级表则代表一组具有相同属性的数据采集点集合。以智能电表为例,我们可以为该类型的电表创建一张超级表,其中包含了所有智能电表的共有属性,包括动态的时序数据以及静态的标签数据。这种设计不仅简化了表的管理,还便于进行跨数据采集点的聚合操作,从而提高数据处理的效率。
### 子表
@ -79,19 +79,16 @@ toc_max_heading_level: 4
### 虚拟表
“一个设备一张表”的设计解决了工业和物联网等场景下的大多数时序数据管理和分析难题,但是在遇到更复杂的场景时,这种设计受到了设备复杂性的挑战。根源在于一个设备无法简单的用一个或一组数据采集点来描述或管理,而业务分析往往需要综合多个或多组采集点的数据才能完成。以汽车或发电风机为例,整个设备(汽车或风机)中含有非常大量的传感器(数据采集点),这些传感器的输出和采集频率千差万别。一个超级表只能描述其中一种传感器,当需要综合多个传感器的数据进行分析计算时,只能通过多级关联查询的方式来进行,而这往往会导致易用性和性能方面的问题。
“一个数据采集点一张表”以及“超级表”的设计解决了工业和物联网等场景下的大多数时序数据管理和分析难题。但是在真实的场景中,一个设备往往有多种传感器,而且他们的数据采集频次还相差很大。比如对于一台风机,有电的参数、环境参数、机械参数,各自的传感器和采集频次完全不一样。因此我们很难用一张表来描述一台设备,往往需要多张表。当需要综合多个传感器的数据进行分析计算时,只能通过多级关联查询的方式来进行,而这往往会导致易用性和性能方面的问题。而从用户的角度来看,“一个设备一张表”更为直观,容易操作。但如果我们建模之初,直接采用"一个设备一张表的“的设计,由于采集频次的不同,会导致每一个具体时间戳,大量的列是空值,从而降低存储和查询的效率。
为了解决这个问题TDengine 引入虚拟表Virtual Table简称为 VTable的概念。虚拟表是一种不存储实际数据而可以用于分析计算的表它的数据来源为其它真实存储数据的子表、普通表通过将不同列数据按照时间戳排序、对齐、合并的方式来生成虚拟表。同真实表类似虚拟表也可以分为虚拟超级表、虚拟子表、虚拟普通表。虚拟超级表可以是一个设备或一组分析计算所需数据的完整集合每个虚拟子表可以根据需要引用相同或不同的列因此可以灵活地根据业务需要进行定义最终达到千表千面的效果。虚拟表不能写入、删除数据,在查询使用上同真实表基本相同,支持虚拟超级表、虚拟子表、虚拟普通表上的任何查询。唯一的区别在于虚拟表的数据是每次查询计算时动态生成的,只有一个查询中引用的列才会被合并进虚拟表中,因此同一个虚拟表在不同的查询中所呈现的数据可能是不同的。
为了解决这个问题TDengine 引入虚拟表Virtual Table简称为 VTable的概念。虚拟表是一种不存储实际数据而可以用于分析计算的表它的数据来源为其它真实存储数据的子表、普通表通过将各个原始表的不同列数据按照时间戳排序、对齐、合并的方式来生成虚拟表。同真实表类似,虚拟表也可以分为虚拟超级表、虚拟子表、虚拟普通表。虚拟超级表可以是一个设备或一组分析计算所需数据的完整集合,每个虚拟子表可以根据需要引用相同或不同的列,因此可以灵活地根据业务需要进行定义,最终达到“千人千面”的效果。虚拟表不能写入、删除数据在查询使用上同真实表相同。TDengine 支持虚拟超级表、虚拟子表、虚拟普通表上的任何查询。唯一的区别在于虚拟表的数据是每次查询计算时动态生成的,只有一个查询中引用的列才会被合并进虚拟表中,因此同一个虚拟表在不同的查询中所呈现以及扫描的数据可能是完全不同的。
虚拟超级表的主要功能特点包括:
1. 列选择与拼接 <br />
用户可以从多个原始表中选择指定的列,按需组合到一张虚拟表中,形成统一的数据视图。
2. 基于时间戳对齐 <br />
以时间戳为依据对数据进行对齐,如果多个表在相同时间戳下存在数据,则对应列的值组合成同一行;若部分表在该时间戳下无数据,则对应列填充为 NULL。
3. 动态更新 <br />
虚拟表根据原始表的数据变化自动更新,确保数据的实时性。虚拟表不需实际存储,计算在生成时动态完成。
1. 列选择与拼接:用户可以从多个原始表中选择指定的列,按需组合到一张虚拟表中,形成统一的数据视图。
2. 基于时间戳对齐:以时间戳为依据对数据进行对齐,如果多个表在相同时间戳下存在数据,则对应列的值组合成同一行;若部分表在该时间戳下无数据,则对应列填充为 NULL。
3. 动态更新:虚拟表根据原始表的数据变化自动更新,确保数据的实时性。虚拟表不需实际存储,计算在生成时动态完成。
通过引入虚拟表的概念TDengine 可以非常方便的管理更大更复杂的设备数据。无论每个采集点如何建模(单列 or 多列),无论这些采集点的数据是分布在一个或多个库中,都可以通过定义虚拟表的方式跨库跨表任意指定数据源,通过虚拟超级表的方式进行跨设备、跨分析的聚合运算,从此“一个设备一张表”彻底成为现实。
通过引入虚拟表的概念TDengine 可以非常方便的管理更大更复杂的设备数据。无论每个采集点如何建模(单列 or 多列),无论这些采集点的数据是分布在一个或多个库中,都可以通过定义虚拟表的方式跨库跨表任意指定数据源,通过虚拟超级表的方式进行跨数据采集点、跨分析的聚合运算,从此“一个设备一张表”彻底成为现实。
### 库

View File

@ -113,6 +113,9 @@ TDengine 还支持直接向超级表写入数据。需要注意的是,超级
insert into meters (tbname, ts, current, voltage, phase, location, group_id)
values("d1001", "2018-10-03 14:38:05", 10.2, 220, 0.23, "California.SanFrancisco", 2)
```
### 通过虚拟表写入
TDengine 不支持向虚拟表或虚拟超级表写入,因为虚拟表或虚拟超级表是动态生成的,本身不存储数据。
### 零代码写入

View File

@ -5,14 +5,41 @@ sidebar_label: "安装部署"
### 环境准备
使用 TDgpt 的高级时序数据分析功能需要在 TDengine 集群中安装部署 AI nodeAnode。Anode 运行在 Linux 平台上,并需要 3.10 或以上版本的 Python 环境支持。
> 部署 Anode 需要 TDengine Enterprise 3.3.4.3 及以后版本,请首先确认搭配 Anode 使用的 TDengine 能够支持 Anode。
> 部署 Anode 需要 TDengine 3.3.6.0 及以后版本,请首先确认搭配 Anode 使用的 TDengine 能够支持 Anode。
可以使用以下的命令在 Ubuntu Linux 上安装 Python 3.10 环境
#### 安装 Python
```shell
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt update
sudo apt install python3.10
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.10 2
sudo update-alternatives --config python3
sudo apt install python3.10-venv
sudo apt install python3.10-dev
```
#### 安装 Pip
```shell
curl -sS https://bootstrap.pypa.io/get-pip.py | python3.10
```
####
`~/.local/bin` 路径添加到环境变量中 `~/.bashrc or ~/.bash_profile`
```shell
export PATH=$PATH:~/.local/bin
```
至此 Python 环境准备完成,可以进项 taosanode 的 安装和部署。
### 安装及卸载
使用 Linux 环境下的安装包 TDengine-enterprise-anode-1.x.x.tar.gz 可进行 Anode 的安装部署工作,命令如下:
使用 Linux 环境下的安装包 TDengine-anode-3.3.x.x-Linux-x64.tar.gz 可进行 Anode 的安装部署工作,命令如下:
```bash
tar -xzvf TDengine-enterprise-anode-1.0.0.tar.gz
cd TDengine-enterprise-anode-1.0.0
tar -xzvf TDengine-anode-3.3.6.0-Linux-x64.tar.gz
cd TDengine-anode-3.3.6.0
sudo ./install.sh
```
@ -80,7 +107,7 @@ app-log = /var/log/taos/taosanode/taosanode.app.log
model-dir = /usr/local/taos/taosanode/model/
# default log level
log-level = DEBUG
log-level = INFO
```

View File

@ -9,14 +9,14 @@ import wndata from './pic/white-noise-data.png'
### 分析流程
时序数据分析之前需要有预处理的过程为减轻分析算法的负担TDgpt 在将时序数据发给具体分析算法进行分析时,已经对数据做了预处理,整体的流程如下图所示。
<img src={activity} width="320" alt="预处理流程" />
<img src={activity} alt="预处理流程"/>
TDgpt 首先对输入数据进行白噪声检查White Noise Data check, 检查通过以后针对预测分析,还要进行输入(历史)数据的重采样和时间戳对齐处理(异常检测跳过数据重采样和时间戳对齐步骤)。
预处理完成以后,再进行预测或异常检测操作。预处理过程不属于预测或异常检测处理逻辑的一部分。
### 白噪声检查
<img src={wndata} width="344" alt="white-noise-data"/>
<img src={wndata} alt="white-noise-data"/>
白噪声时序数据可以简单地认为是随机数构成的时间数据序列(如上图所示的正态分布随机数序列),随机数构成的时间序列没有分析的价值,因此会直接返回。白噪声检查采用经典的 `Ljung-Box` 统计量检验,计算 `Ljung-Box` 统计量需遍历整个输入时间序列。如果用户能够明确输入序列一定不是白噪声序列,那么可以在参数列表中增加参数 `wncheck=0` 强制要求分析平台忽略白噪声检查,从而节省计算资源。
TDgpt 暂不提供独立的时间序列白噪声检测功能。

View File

@ -5,7 +5,7 @@ description: 预测算法
import fc_result from '../pic/fc-result.png';
时序数据预测处理以持续一个时间段的时序数据作为输入预测接下来一个连续时间区间内时间序列数据趋势。用户可以指定输出的预测时间序列数据点的数量因此其输出的结果行数不确定。为此TDengine 使用新 SQL 函数 `FORECAST` 提供时序数据预测服务。基础数据(用于预测的历史时间序列数据)是该函数的输入,预测结果是该函数的输出。用户可以通过 `FORECAST` 函数调用 Anode 提供的预测算法提供的服务。
时序数据预测处理以持续一个时间段的时序数据作为输入预测接下来一个连续时间区间内时间序列数据趋势。用户可以指定输出的预测时间序列数据点的数量因此其输出的结果行数不确定。为此TDengine 引入新 SQL 函数 `FORECAST` 提供预测分析功能。基础数据(用于预测的历史时间序列数据)是该函数的输入,预测结果是该函数的输出。用户可以通过 `FORECAST` 函数调用 Anode 提供的预测算法提供的服务。预测分析通常只能针对超级表的子表或者不同表中同一个时间序列。
在后续章节中,使用时序数据表 `foo` 作为示例,介绍预测和异常检测算法的使用方式,`foo` 表的模式如下:
@ -62,6 +62,9 @@ algo=expr1
2. 更改参数 `START`:返回预测结果的起始时间,改变起始时间不会影响返回的预测数值,只影响起始时间。
3. `EVERY`:可以与输入数据的采样频率不同。采样频率只能低于或等于输入数据采样频率,不能**高于**输入数据的采样频率。
4. 对于某些不需要计算置信区间的算法,即使指定了置信区间,返回的结果中其上下界退化成为一个点。
5. rows 的最大输出值是 1024即只能预测 1024 个值。超过输出范围的参数会被自动设置为 1024。
6. 预测分析的输入数据行数最大值是 40000 行,即用于预测分析的历史数据不能超过 40000 行。针对部分分析模型,输入限制更严格。
### 示例
@ -136,6 +139,9 @@ res_start_time = 1730000000000
gen_figure = true
```
对比程序执行完成以后,会自动生成名称为`fc_result.xlsx` 的文件,第一个卡片是算法运行结果(如下表所示),分别包含了算法名称、执行调用参数、均方误差、执行时间 4 个指标。
| algorithm | params | MSE | elapsed_time(ms.) |
| ----------- | ------------------------------------------------------------------------- | ------- | ----------------- |
| holtwinters | `{"trend":"add", "seasonal":"add"}` | 351.622 | 125.1721 |
@ -143,5 +149,5 @@ gen_figure = true
如果设置了 `gen_figure` 为 true分析结果中还会有绘制的分析预测结果图如下图所示
<img src={fc_result} width="360" alt="预测对比结果" />
<img src={fc_result} alt="预测对比结果"/>

View File

@ -17,7 +17,7 @@ ANOMALY_WINDOW(col_val, "algo=iqr");
如下图所示Anode 将返回时序数据异常窗口 $[10:51:30, 10:53:40]$
<img src={ad} width="760" alt="异常检测" />
<img src={ad} alt="异常检测"/>
在此基础上,用户可以针对异常窗口内的时序数据进行查询聚合、变换处理等操作。
@ -98,7 +98,8 @@ grubbs={}
lof={"algorithm":"auto", "n_neighbor": 3}
```
对比程序执行完成以后,会自动生成名称为`ad_result.xlsx` 的文件,第一个卡片是算法运行结果(如下图所示),分别包含了算法名称、执行调用参数、查全率、查准率、执行时间 5 个指标。
对比程序执行完成以后,会自动生成名称为`ad_result.xlsx` 的文件,第一个卡片是算法运行结果(如下表所示),分别包含了算法名称、执行调用参数、查全率、查准率、执行时间 5 个指标。
| algorithm | params | precision(%) | recall(%) | elapsed_time(ms.) |
@ -111,5 +112,6 @@ lof={"algorithm":"auto", "n_neighbor": 3}
如果设置了 `gen_figure``true`,比较程序会自动将每个参与比较的算法分析结果采用图片方式呈现出来(如下图所示为 ksigma 的异常检测结果标注)。
<img src={ad_result} width="540" alt="异常检测标注图" />
<img src={ad_result} alt="异常检测标注图"/>

View File

@ -8,6 +8,7 @@ sidebar_label: "预测算法"
### 输出约定及父类属性说明
`execute` 方法执行完成后的返回一个如下字典对象, 预测返回结果如下:
```python
return {
"mse": mse, # 预测算法的拟合数据最小均方误差(minimum squared error)

View File

@ -0,0 +1,6 @@
---
title: "缺失数据补值"
sidebar_label: "缺失数据补值"
---
近期发布

View File

@ -0,0 +1,6 @@
---
title: "时间序列分类"
sidebar_label: "时间序列分类"
---
近期发布

View File

@ -5,21 +5,94 @@ title: TDgpt
import TDgpt from './pic/data-analysis.png';
# 背景介绍
针对时间序列数据预测分析、异常检测、数据补全和数据分类的应用领域,相关领域的研究人员提出并开发出了众多不同技术特点、适用于不同场景的时序数据分析算法,广泛应用在时间序列数据预测、异常检测等领域。
TDgpt 是 TDengine Enterprise 中针对时序数据提供高级分析功能的企业级组件,通过内置接口向 TDengine 提供运行时动态扩展的时序数据分析服务。TDgpt 能够独立于 TDengine 主进程部署和运行,因此可避免消耗占用 TDengine 集群的主进程资源。
TDgpt 具有服务无状态、功能易扩展、快速弹性部署、应用轻量化、高安全性等优势。
TDgpt 运行在集群中的 AI Node (Anode)中,集群中可以部署若干个 Anode 节点,不同的 Anode 节点之间无同步依赖或协同的要求。Anode 注册到 TDengine 集群以后立即就可以提供服务。TDgpt 提供的高级时序数据分析服务可分为时序数据异常检测和时序数据预测分析两大类。
分析算法通常以高级编程语言Python语言或R语言工具包的形式存在并通过开源的方式广泛分发和使用这种应用模式极大地便利了软件开发人员在应用系统中调用复杂的分析算法极大地降低了使用高级算法的门槛。
下图是部署 TDgpt 的 TDengine 集群示意图。
<img src={TDgpt} width="560" alt="TDgpt架构图" />
另一方面数据库系统研发人员也尝试将数据分析算法模型整合到数据库系统中通过建立Machine Learning 库(例如 Spark 的机器学习库)充分利用成熟分析技术增强数据库或分析计算引擎的高级数据分析能力。
在查询处理过程中Vnode中运行的查询引擎会根据查询处理物理执行计划按需向 Anode 请求高级时序数据分析服务。因此用户可通过 SQL 语句与 Anode 节点交互并使用其提供的全部分析服务。需要注意的是 Anode 不直接接受用户的数据分析请求。同时 Anode 具备分析算法动态注册机制,其算法扩展过程完全不影响 TDengine 集群的服务,仅在非常小的(秒级)时间窗口内影响涉及高级分析的查询服务。
目前 TDgpt 提供如下的高级分析服务:
- 时序数据异常检测。TDengine 中定义了新的时间窗口——异常(状态)窗口——来提供异常检测服务。异常窗口可以视为一种特殊的**事件窗口Event Window**,即异常检测算法确定的连续异常时间序列数据所在的时间窗口。与普通事件窗口区别在于——时间窗口的起始时间和结束时间均是分析算法确定,不是用户指定的表达式判定。异常窗口使用方式与其他类型的时间窗口(例如状态窗口、会话窗口等)类似。因此时间窗口内可使用的查询操作均可应用在异常窗口上。
- 时序数据预测。定义了一个新函数`FORECAST`,基于输入的(历史)时间序列数据调用指定(或默认)预测算法给出输入时序数据后续时间序列的**预测**数据。
TDgpt 还为算法开发者提供了一 SDK。任何开发者只需要按照[算法开发者指南](./dev)的步骤,就可以将自己独有的时序数据预测或时序数据异常检测算法无缝集成到 TDgpt, 这样 TDengine 用户就可以通过一条 SQL 获得时序数据预测结果或是异常窗口了, 大幅降低了用户使用新的时序数据分析算法的门槛,而且让 TDengine 成为一开放的系统。
飞速发展的人工智能AI为时序数据分析应用带来的新机遇快速有效地将 AI 能力应用在时间序列数据分析领域也为数据库。为此,涛思数据创新性地提出了时序数据分析智能体 TDgpt使用 TDgpt将您能够通过SQL 语句,直接调用适配和整合驱动统计分析算法、机器学习算法模型、深度学习模型,时序数据基础模型以及大语言模型,并将这些分析能力转化为 SQL 语句的调用,通过异常检测窗口和预测函数的方式应用在时序数据上。
# 技术特点
TDgpt 是与 TDengine 主进程 taosd 适配的外置式时序数据分析智能体,能够将时序数据分析服务无缝集成在 TDengine 的查询执行流程中。
TDgpt 是一个无状态的平台,其内置了经典的统计分析模型库 Statsmodel内嵌了 torch/Keras 等机器/深度学习框架库,此外还通过请求转发和适配的方式直接调用涛思数据自研的时序数据基础大模型 TDtsfm (TDengine time series foundation model)。
作为一个分析智能体TDgpt 后续还将整合第三方时序数据 MaaS 大模型服务仅修改一个参数algo就能够调用最先进的时间序列模型服务。
TDgpt 是一个开放的系统,用户能够根据自己的需要,添加预测分析、异常检测、数据补全、数据分类算法,添加完成后,仅通过修改 SQL 语句中调用的算法参数就能够无缝使用新加入的算法。
无需应用修改一行代码。
# 系统架构
TDgpt 由若干个无状态的分析节点 anode 构成,可以按需在系统集群中部署 Anode 节点,也可以根据分析模型算法的特点,将 Anode 部署在合适的硬件环境中,例如带有 GPU 的计算节点。
TDgpt 针对不同的分析算法,提供统一的调用接口和调用方式,根据用户请求的参数,调用高级分析算法包及其他的分析工具,并将分析获得的结果按照约定的方式返回给 TDengine 的主进程 taosd。
TDgpt 的主要包含四个部分的内容。
- 第一部分是内置分析库包括statsmodels, pyculiarity, pmdarima 等,提供可以直接调用的预测分析和异常检测算法模型。
- 第二部分是内置的机器学习库包括torch,keras,scikit-learn等用于驱动预训练完成的机器深度学习模型在 TDgpt 的进程空间内运行。预训练的流程可以使用 Merlion/Kats 等 开源的端到端机器学习框架进行管理,并将完成训练的模型上传到 TDgpt 指定目录即可;
- 第三部分是通用大语言模型的请求适配模块。将时序数据预测请求转换后,基于 Prompt 向 DeepSeekLlaMa 等通用大语言模型 MaaS 请求服务(这部分功能暂未开源);
- 第四部分是通过 Adapter 直接向本地部署的 Time-MoE、TDtsfm 等时序数据模型请求服务。时序数据专用模型相对于通用语言大模型,无需 Prompt更加便捷轻量本地应用部署对硬件资源要求也较低除此之外Adapter 还可以直接请求 TimeGPT 这种类型的时序数据分析 MaaS 服务,调用云端的时序模型服务提供本地化时序数据分析能力。
<img src={TDgpt} alt="TDgpt架构图" />
查询过程中TDengine 中的Vnode 会将涉及时序数据高级分析的部分直接转发到 Anode并等待分析完成后将结果组装完成嵌入查询执行流程。
# 时序数据分析服务
使用TDgpt 提供的时序数据分析服务,包括:
- 时序数据异常检测TDengine 中定义了新的时间窗口——异常状态窗口——来提供异常检测服务。异常窗口可以视为一种特殊的事件窗口Event Window即异常检测算法确定的连续异常时间序列数据所在的时间窗口。与普通事件窗口区别在于——时间窗口的起始时间和结束时间均是分析算法确定不是用户指定的表达式判定。异常窗口使用方式与其他类型的时间窗口例如状态窗口、会话窗口等类似。因此时间窗口内可使用的查询操作均可应用在异常窗口上。
- 时序数据分析预测TDengine 中提供了一个新的函数FORECAST提供时序数据预测服务基于输入的历史时间序列数据调用指定或默认预测算法给出输入时序数据后续时间序列的预测数据。
- 时序数据补全研发测试中2025年7月发布
- 时序数据分类研发测试中2025年7月发布
# 自定义分析算法
TDgpt 是一个可扩展的时序数据高级分析智能体,用户遵循[算法开发者指南](./dev)中的简易步骤就能将自己开发的分析算法添加到系统中。之后应用可以通过 SQL语句直接调用, 让高级分析算法的使用门槛降到几乎为零。对于新引入的算法或模型,应用不用做任何调整。
TDpgt 只支持使用 Python 语言开发的分析算法。 Anode 采用 Python 类动态加载模式,在启动的时候扫描特定目录内满足约定条件的所有代码文件,并将其加载到系统中。因此,开发者只需要遵循以下几步就能完成新算法的添加工作:
1. 开发完成符合要求的分析算法类
2. 将代码文件放入对应目录,然后重启 Anode
3. 使用SQL命令更新算法缓存列表即可。
添加完成的算法在刷新算法列表后,立即使用 SQL 语句进行调用。
# 算法评估工具
在 TDgpt 企业版中,还提供针对多种算法模型有效性的综合评估工具。该工具可以针对 TDgpt 可调用所有时序数据分析(预测分析与异常检测)服务,包括内置数据分析算法模型,已部署的预训练机器学习模型、第三方时序数据(大)模型服务,基于 TDengine 中的时序数据进行预测分析对比和异常检测对比评估,并给出量化指标评估不同分析模型在给定数据集上准确度及性能。
# 模型管理
对于Torch/Tensorflow/Keras 等机器学习库框架驱动的预训练模型,需要首先将训练完成的数据模型添加到 Anode 的指定目录中Anode 可以自动调用该目录内的模型,驱动其运行并提供服务。
企业版本的 TDgpt 具备模型的管理能力能够与开源的端到端时序数据机器学习框架例如Merlion、Kats等无缝集成。
处理能力
通常意义上,时间序列数据分析主要是计算密集型任务。这种计算密集型任务,可以使用更高性能的 CPU 或 GPU 来提升处理性能。
如果是机器/深度学习模型,依赖于 torch 库驱动其运行,可以采用标准的提升分析处理能力的方案来提升 TDgpt 的服务能力,例如将 Anode 部署在内存更大,并具有 GPU 的服务器之上,使用可调用 GPU 的 torch 库驱动模型运行,以提升分析响应能力。
不同的模型、算法可以部署在不同的 Anode 上,增加并行的处理能力。
# 运营维护
开源版本不提供用户权限和资源控制机制。
TDgpt 默认使用 uWSGI 驱动的 flask 服务,可以通过打开 uwsgi 的端口监控服务的运行状态。
# 参考文献
[1] Merlionhttps://opensource.salesforce.com/Merlion/latest/index.html
[2] Kats:https://facebookresearch.github.io/Kats/
[3] StatsModels: https://www.statsmodels.org/stable/index.html
[4] Keras:https://keras.io/guides/
[5] Torch:https://pytorch.org/
[6] Scikit-learn:https://scikit-learn.org/stable/index.html
[7] Time-MoE:https://github.com/Time-MoE/Time-MoE
[8] TimeGPT:https://docs.nixtla.io/docs/getting-started-about_timegpt
[9] DeepSeek:https://www.deepseek.com/
[10] LlaMa:https://www.llama.com/docs/overview/
[11] Spark MLlib:https://spark.apache.org/docs/latest/ml-guide.html

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 29 KiB

BIN
docs/zh/06-advanced/06-TDgpt/pic/ad-result.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 KiB

After

Width:  |  Height:  |  Size: 40 KiB

BIN
docs/zh/06-advanced/06-TDgpt/pic/data-analysis.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 149 KiB

BIN
docs/zh/06-advanced/06-TDgpt/pic/fc-result.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 76 KiB

View File

@ -10784,6 +10784,18 @@ static const SSchema* getNormalColSchema(const STableMeta* pTableMeta, const cha
return NULL;
}
static const col_id_t getNormalColSchemaIndex(const STableMeta* pTableMeta, const char* pColName) {
int32_t numOfCols = getNumOfColumns(pTableMeta);
SSchema* pColsSchema = getTableColumnSchema(pTableMeta);
for (int32_t i = 0; i < numOfCols; ++i) {
const SSchema* pSchema = pColsSchema + i;
if (0 == strcmp(pColName, pSchema->name)) {
return (col_id_t)i;
}
}
return -1;
}
static SSchema* getTagSchema(const STableMeta* pTableMeta, const char* pTagName) {
int32_t numOfTags = getNumOfTags(pTableMeta);
SSchema* pTagsSchema = getTableTagSchema(pTableMeta);
@ -16065,11 +16077,12 @@ static int32_t buildVirtualSubTableBatchReq(const SCreateVSubTableStmt* pStmt, S
if (pStmt->pSpecificColRefs) {
FOREACH(pCol, pStmt->pSpecificColRefs) {
SColumnRefNode* pColRef = (SColumnRefNode*)pCol;
const SSchema* pSchema = getColSchema(pStbMeta, pColRef->colName);
if (pSchema == NULL) {
col_id_t schemaIdx = getNormalColSchemaIndex(pStbMeta, pColRef->colName);
if (schemaIdx == -1) {
PAR_ERR_JRET(TSDB_CODE_PAR_INVALID_COLUMN);
}
PAR_ERR_JRET(setColRef(&req.colRef.pColRef[pSchema->colId - 1], pSchema->colId, pColRef->refColName, pColRef->refTableName, pColRef->refDbName));
const SSchema* pSchema = getTableColumnSchema(pStbMeta) + schemaIdx;
PAR_ERR_JRET(setColRef(&req.colRef.pColRef[schemaIdx], pSchema->colId, pColRef->refColName, pColRef->refTableName, pColRef->refDbName));
}
} else if (pStmt->pColRefs){
col_id_t index = 1; // start from second column, don't set column ref for ts column

View File

@ -22,7 +22,10 @@ class TDTestCase(TBase):
def prepare_vtables(self):
tdSql.execute("drop table if exists vtb_virtual_stb;")
tdSql.execute("drop table if exists vtb_virtual_stb_1;")
tdSql.execute("drop table if exists vtb_virtual_ctb0;")
tdSql.execute("drop table if exists vtb_virtual_ctb_after_modified_1;")
tdSql.execute("drop table if exists vtb_virtual_ctb_after_modified_2;")
tdSql.execute("drop table if exists vtb_virtual_ntb0;")
tdLog.info(f"prepare virtual super tables.")
tdSql.execute(f"CREATE STABLE `vtb_virtual_stb` ("
@ -55,6 +58,36 @@ class TDTestCase(TBase):
"binary_32_tag binary(32))"
"VIRTUAL 1")
tdSql.execute(f"CREATE STABLE `vtb_virtual_stb_1` ("
"ts timestamp, "
"u_tinyint_col tinyint unsigned, "
"u_smallint_col smallint unsigned, "
"u_int_col int unsigned, "
"u_bigint_col bigint unsigned, "
"tinyint_col tinyint, "
"smallint_col smallint, "
"int_col int, "
"bigint_col bigint, "
"float_col float, "
"double_col double, "
"bool_col bool, "
"binary_16_col binary(16),"
"binary_32_col binary(32),"
"nchar_16_col nchar(16),"
"nchar_32_col nchar(32),"
"varbinary_16_col varbinary(16),"
"varbinary_32_col varbinary(32),"
"geo_16_col geometry(16),"
"geo_32_col geometry(32)"
") TAGS ("
"int_tag int,"
"bool_tag bool,"
"float_tag float,"
"double_tag double,"
"nchar_32_tag nchar(32),"
"binary_32_tag binary(32))"
"VIRTUAL 1")
tdLog.info(f"prepare virtual child tables.")
tdSql.execute("CREATE VTABLE `vtb_virtual_ctb0`("
"u_tinyint_col FROM vtb_org_child_0.u_tinyint_col, "
@ -301,6 +334,27 @@ class TDTestCase(TBase):
tdSql.query(f"select tag_type from information_schema.ins_tags where db_name='test_vtable_alter' and table_name='vtb_virtual_ctb0' and tag_name='nchar_32_tag'")
tdSql.checkData(0, 0, "NCHAR(64)")
def test_alter_virtual_super_table_and_create_child(self):
tdLog.info(f"test alter virtual super tables and create child.")
tdSql.execute("use test_vtable_alter;")
tdSql.execute("select database();")
# 1. add column
# 1.1. add column without column reference
tdSql.execute("alter stable vtb_virtual_stb_1 add column extra_boolcol bool")
# 1.2. create child table using modified super table
tdSql.execute("CREATE VTABLE `vtb_virtual_ctb_after_modified_1`(bool_col from vtb_org_child_18.bool_col, extra_boolcol from vtb_org_child_19.bool_col) USING vtb_virtual_stb_1 TAGS (0, false, 0, 0, 'vchild0', 'vchild0')")
tdSql.execute("select * from vtb_virtual_ctb_after_modified_1")
# 2. drop column
# 2.1. drop column from stb
tdSql.execute("alter stable vtb_virtual_stb_1 drop column bool_col;")
tdSql.execute("CREATE VTABLE `vtb_virtual_ctb_after_modified_2`(extra_boolcol from vtb_org_child_17.bool_col) USING vtb_virtual_stb_1 TAGS (0, false, 0, 0, 'vchild0', 'vchild0')")
tdSql.execute("select * from vtb_virtual_ctb_after_modified_2")
def test_error_cases(self):
tdLog.info(f"test alter virtual super tables.")
@ -360,6 +414,7 @@ class TDTestCase(TBase):
self.test_alter_virtual_normal_table()
self.test_alter_virtual_child_table()
self.test_alter_virtual_super_table()
self.test_alter_virtual_super_table_and_create_child()
self.test_error_cases()
tdLog.success(f"{__file__} successfully executed")