股票学习网

股票行情网,股票入门,和讯股票,股票查询 - - 股票学习网!

Td指标看什么书(td指标源码大全)

2023-05-05 22:15分类:波段操作 阅读:

作者:大数据模型

本篇文章出自 2022 年“用 TDengine,写 TDengine”征文投稿活动。


因为工作的关系,最近几年我接触到过各种国产数据库,唯独对 TDengine 念念不忘。在众多数据库中,TiDB 一枝独秀,OceanBase 出身名门世家,openGauss 有华为撑腰,只有 TDengine 给人有一种草莽出英雄的感觉;在开发上,TiDB 借用了 rocksDB 的性能,openGauss 是基于 postgreSQL9.2.4 开发的,即使 OceanBase 也是基于内部应用需求开始打造的,只有 TDengine 不依赖任何开源或第三方软件自研而成。而且它不是一款通用型的数据库,剑走偏锋,它有自己独特的社会应用场景,主要为工业网服务。

基于对 TDengine 的定义和理解,笔者将会在本篇文章中从 TDengine 能解决什么问题、它的优势与亮点、它与其它数据库的区别等维度展开详述,希望能帮助到对 TDengine 感兴趣的小伙伴。

“区别于通用数据库,TDengine 抛掉无用包袱”

数据库想要完成出色的的读写,最核心的能力就是索引,一般数据库产品都具备正向索引能力。所谓正向索引就是通过文档记录里面的标识符为关键字,通过关键标识符不再需要进行全盘扫描。虽然 B树索引、哈希索引、位图索引有区别,但是大方向都属于正向索引。

除了正向索引,还有反向索引【也称倒排索引】,反向索引主要用于全文检索,例如 ElasticSearch,大多数据库都是正向索引。TDengine 也是使用正向索引,它的特别之处是标识符肯定包含时间戳,再加上一个维度指标数据,构成一个对数据值明确的描述——某个时间某个指标对象的数据值是多少。

从数据组织的存储引擎来看,数据库底层可以分为 B树机制、LSM 机制,两种机制没有最好,各有各的优点和缺点:

B树最大好处在于它对数据持续高涨读性能的处理,即使数据量级增大,它的读也没有放大。 奥秘在于对数据进行终极持久存储时,B树是以有序有规律的数据结构保存在硬盘上的。这样随着数据越来越大,它依然保持有序有规律的特性,面对成千上万的读操作,都可以遵循条件运行,减少或避免读放大的行为。

与 B树机制截然相反,LSM 机制则是减少避免了写放大。LSM 机制充分利用了内存,在内存里面开辟了一个空间,写数据优先往内存里放,写进去直接返回用户成功,而不是像 B树那样写一个,我要找出谁比我大谁比我小,只要内存有够,就直接往内存里面填就好,当内存达到一定的阈值,将内存中的数据以批量、顺序的方式一次写入硬盘上,内存则重置清零再服务新的写要求

传统数据库 MySQL、Oracle 使用的是 B树机制,而 TiDB、OceanBae 使用的是优化后的 LSM 机制,而 TDengine 使用的是 B树 + LSM 机制的方式,其中 B树存储的是元数据【主要是时间戳+指标数据】,LSM 机制存储的是具体的数据,元数据以有序表结构方式进行存储,而具体数据则是以追加的方式写入,这样即避免了读话大和写放大。

一般来说,OLTP 产品为了提升并发控制的性能,必定会有写时复制或者 MVCC 的功能选项,写时复制与 MVCC 虽然保障了数据的一致性,但是带来更多的 IO 负担。TDengine 不需要对数据进行修改,所以不需要考虑数据一致性的问题,数据是以有序的规律并追加的形式写进去的,因为只有读和写,所以也不需要锁保护,抛掉一些无用的包袱,可以集中优化其它地方,例如列式表。

业界通用数据库针对各种业务都会有行式表、列式表甚至完全的内存库,对于具体的数据存储 TDengine 使用完全列式存储在硬盘,而维度指标则行式保存在内存中。因为 TDengine 面对的是机器的数据,机器 24 小时工作精确到每个毫秒都在产生数据,为了存储更多的数据,所以 TDengine 用上行列并存、用途分离的方式。

一般来说,数据库里面每一行的文档记录都是非常重要的,即使这行记录信息无关交易,只是一个用户的基本信息,那它的价值密度也十分高。但时序数据库(Time Series Database)不同,单行文档记录价值密度低,因为 1 秒可以产生 1 万条记录,必须要把数据聚合汇总起来才能体现数据的价值。快速并有效聚合普通数据使之变成价值密度高的数据,这个也是时序数据库区别于其它数据库的一个重要的特征。

TDengine目前提供了三个版本的产品:社区版,企业版以及云版本, 以满足市场的需求和个人开发者的需求。

“拆解时序数据库,几大产品特点分析”

从技术上区分定位,TDengine 是专注时间序列领域的一个分布式的海量数据分析平台。它的竞争对手可以分为直接竞争对手和间接竞争对手,间接竞争对手有国内的 TiDB、OceanBase、GaussDB 以及国外的 Oracle、MySQL 等等,虽然它们在综合技术维度上与 TDengine 没有对标,但是分析上只要是使用时间戳,与时间序列有关系,这里就有 TDengine 的用武之地。与 TDengine 构成直接竞争的对手有 Druid、OpenTSDB、InfluxDB,他们都是时间序列分析的前辈。

Druid 是一个分布式系统,采用 Lambda 架构,有利于充分利用内存,也会把历史数据保存到硬盘上,按一定的时间粒度对数据进行聚合,实时处理和批处理数据解耦分开。实时处理面向写多读少的场景,主要是以流方式处理增量数据,批处理面向读多写少的场景,主要是以此方式处理离线数据。Druid 依赖 Hadoop,集群中采用 share nothing 的架构,各个节点都有自己的计算和存储能力,整个系统通过 Zookeeper 进行协调。为了提高计算性能,其会采用近似计算方法包括 HyperLoglog、DataSketches 的一些基数计算。

OpenTSDB 是一个开源的时序数据库,支持存储数千亿的数据点,并提供精确的查询,采用 Java 语言编写,通过基于 HBase 的存储实现横向扩展,OpenTSDB 广泛用于服务器的监控和度量,包括网络和服务器、传感器、IoT、金融数据的实时监控领域。OpenTSDB 在设计思路上是利用 HBase 的 key 去存储一些 tag 信息,将同一个小时数据放在一行存储,以此提高查询速度。OpenTSDB 通过预先定义好维度 tag 等,采用精巧的数据组织形式放在 HBase 里面,通过 HBase 的 keyRange 可以进行快速查询,但是在任意维度的组织查询下,OpenTSDB的效率会降低。

InfluxDB 是一款非常流行的时序数据库,采用 Go 语言开发,社区非常活跃,技术特点支持任意数量的列,去模式化,集成了数据采集、存储和可视化存储,使用高压缩比的算法支持高效存储,采用 TIME SERIES MERGE TREE 的内部存储引擎,支持与 SQL 类似的语言(2.0 版本不再支持)

时间序列的业务背景,在 OLAP 场景中一般会进行预聚合来减少数据量,影响预聚合主要因素可以汇总如下:

  • 维度指标的个数
  • 维度指标的基数
  • 维度指标组合程度
  • 时间维度指标的粗粒度和细粒度

为了实现高效的预聚合,TDengine 的秘诀是超级表,Druid 会提前定义预计算,InfluxDB 也有自己的连续查询方法,只有 HBase 使用时才进行拼接,所以涉及不同的维度指标查询,HBase 会慢一些。

据了解,TDengine 基于 TSBS 的测试报告将于近日出炉,第一期报告针对 InfluxDB 和 TimeScaleDB 进行了详细的性能层面的对比分析,感兴趣的小伙伴最近可以多多关注下公众号的内容。

“放到今天,TDengine 一定是首选”

我对 TDengine 的认识和了解要从过去的项目经验说起,以 2018 年为背景,我给大家讲述一个工业界坏件故障件预测的故事。

某知名集团随着公司业务的快速增长、新工厂的不断增加,各种有价值的数据不能很好的整合、分析与挖掘出它应有的价值。此时公司发展已经进入下一轮“拼”的战略,快速响应与准确预测是业务发展的关键,大数据在其中起到举足轻重的作用,以科学的分析手法整合各系统数据、推动工厂制造智能化发展,成为一件迫在眉睫的工作。

当前工厂生产过程中出现了同一种特殊问题的 glass id,glass 的品质由于各种原因是参差不齐的,甚至会有品质异常的 glass。这些异常 glass 在检测过程中,是无法检测出异常原因的,如果无法快速定位出异常原因,就会造成更多的异常 glass,严重影响生产。应对的具体手段包括:

  1. 通过品质异常的 glass,找到产生此异常的相关性因子。如:机台、物料、载具、参数等。
  2. 异常 glass 侦测预警,通过对产生品质异常的因子进行数学建模,预测出偏离正常范围的异常玻璃,提前预警。
  3. 分析 glass 的特征值与特征值之间的关联关系,并建立预测模型,提前预测出 glass 的特征值。
  4. 分析 glass 相关的电压、电阻、电流、温度、湿度影响。

很明显这是数据挖掘的项目,要分析以上 glass 在生产过程中的环境信息、检测机台资料、量测机台资料、制程参数信息,以及 FDC、OEE 系统的数据,才能找出产生这种问题的原因。第一步是数据收集整合,第二步是数据探索,第三步是模型调校——找出可能性、影响最大的因素的特征因素,第四步是投入生产验证,通过 spark ml 提供预测动力。

当时的技术栈用的是 CDH,首先要通过 Kafka 采集数据,Spark对接 Kafka 进行初步计算去噪并汇总到 Hadoop 里面,以 parquet 的格式保存,如果需要进一步的加工,就通过 impala 进行。这样每天挂起 N 个任务,不停的调度计算。

CDH Hadoop 虽然无法做到实时数据分析,但是也还能做些事,聊胜于无,就继续用着。当时这个坏件故障件预测项目有以下痛点,主要是及时性、有效性、准确性的问题:

  • 难以满足用户需求,某些机器数据的聚合计算需要第二天才能出结果,甚至更多的时间才能出来。
  • 经济成本的费用较高,CPU、磁盘、网络都在一个高段的使用状态,针对越来越多的数据需要投入新机器。
  • 维护成本高,你需要维护 Hadoop 所有的机器,各种 HBase、Spark、Zookeeper、HDFS 之类,不但对工程师要求高,而且工作量巨大。
  • 低质量数据,因为数据流程或者错误的逻辑整合,导致机器传感器聚合后数据模型无法正常使用。
  • 无法做到实时监测,机器数据作为宝贵的自变量因素无法及时传输并进行计算,自然会影响因变量。

笔者经历了这个项目,知道这个坏件故障预测与时间序列有紧密的关系。时至今日,时间序列分析也是重要的数据分析技术,尤其面对季节性、周期性变化数据时,传统的回归拟合技术难以奏效,这时就需要复杂的时间序列模型,以时间为特征作为抓手点。这样即使你不太懂业务的前提下,也可以进行数据挖掘的工作。

那这个项目与 TDengine 有什么关系呢? 实际上,这个项目并没有用上 TDengine,后来集团搭建了一个 Hadoop集群试点,这次居然用了 HDP,理由很简单,因为 HDP 默认搭载了时序数据库 Druid

当时技术负责人认为坏件故障预测模型的数据库基座应该是时序数据库,而不是 Hadoop 不停的进行数据采集、数据转换以及各种批计算,通过时序数据库不但可以实时计算,而且输出的数据质量高。至于选择哪个时序数据库,彼时考虑平稳过渡替换以及学习成本综合因素后他们选择了 Druid。

但当时是 2017 年,TDengine 也还没有面世,如果放到今天,TDengine 必定是选型考虑的首选。

要知道,TDengine 的优势相对 Druid 要多了去了,首先 Druid 不是一个经过开源版本 1.00 正式发布的软件,虽然发展多年,直至 HDP 与 CDH 两家公司融合,HDP 搭配的 Druid 也不是 1.00 版;其次 Druid 依赖 Hadoop,动辄就使用大量的资源以及各种复杂的 Hadoop 组件,最后 Druid 只提供 json 的方式,对传统的 DBA 使用十分不友好。

TDengine 有一个我认为很秀的功能,就是它的超级表的跨指标维度建模思想,目前它仅用于自由组合维度指标,拼接不同的时间粒度进行聚合。在我看来,将来应用于时间序列机器学习模型也会是它的一个亮点,在数据建模方面,针对工厂的设施、设备、机床、机房、车间、测台等必须要做高效准确的定义。我们进行项目规划建设时,都会做大量的数据治理工作,但是在具体实施工作上,还是要使用这些传统工具和技术。TDengine 可以有效汇集各种机器数据源,并且能够高质量的提炼,这个是过去的时序数据产品所不具备的。

“是提速,更是赋能”

中国有句话叫做“长江后浪推前浪,一代新人胜旧人”,IT 世界千变万化,如果你和我一样,一直在关注着 TDengine,就会发现,它这几年崛起的非常迅速。去年 TDengine 推出 3.0 版本,新版本升级成为了一款真正的云原生时序数据库,优化了流计算功能,而且还重新设计了计算引擎,优化工程师对 SQL 的使用,另外增加了 taosX,利用自己的数据订阅功能来解决增量备份、异地容灾,更加方便了企业应用。我对 TDengine 未来的期望是,希望它增加库内机器学习函数,增加 ARIMA 模型、MA 模型等时间相关功能,TDengine 的未来是一个智能学习时间序列数据库,对工业 4. 0 来说不仅是提速,更是赋能。


点击了解更多 TDengine Database 的具体细节。

(本文由公众号越声投顾(yslcw927))整理,仅供参考,不构成操作建议。如自行操作,注意仓位控制和风险自负。)

成交量是反映股市人气聚散的一面镜子,是投资市场的“粮草”,是价格变化的原动力。而价格则是因为成交量之后的体现,量价是技术面的根本。可见它在实战中技术分析的地位,因此不少散户通过观察个股成交量的变化来操作股票取得收益。所以在分析识别股票的好与坏,成交量的配合是必不可少的。

一、如何利用成交量来选股?

1、股价启动初期,单日成交量大于该股的前五日移动平均成交量2.5倍,大于前10日移动平均成交量3倍。

2、股价启动初期的单日盘中量比至少要达到10以上,收盘时量比至少要达到2.5以上。

3、股价启动初期成交量保持温和放大状态,量能乖离率指标VBIAS能够保持3至5天的快速持续上涨,并且在股价启动后的一段时间内,24日VBIAS能多次穿越0轴线。

4、移动平均成交量VOSC指标大于0轴线,并且逐渐缓慢上移,即使偶遇调整,VOSC指标为正值的时间远多于为负值的时间。

5、成交量标准差指标VSTD快速上升到该股历史上罕见的极高位置时,表示该股成交量过度放大。这种极高位置由于各种股票的流通盘大小不同和成交活跃度不同而有所不同,所以没有一定的量化标准,投资者可以根据个股的VSTD指标历史表现进行比较。

二、成交量选股技巧

第一种量价选股法无量涨停

在涨跌停板制度下,股票的第一个无量跌停,后市仍将继续跌停,直到有大量出现才能反弹或反转;同理,股票的第一个无量涨停,后市仍将继续涨停,直到有大量出现才能回档或反转。

第二种量价选股法低位放量涨停

放 量总是有原因的:在高价区有些主力往往对敲放量,常在一些价位上放上大卖单,然后将其吃掉,以显示其魄力吸引市场跟风眼球,或是在某些关键点位放上大笔买 盘,以显示其护盘决心大,凡此种种现象皆为假,重心真实的升降即可辨别。若是在低位出现的对敲放量,说明机构在换庄或是在准备拉高起一波行情,可以择机跟进。

三、成交量最佳买点

1、成交量最佳买点:缓慢攀升后开始放量上涨—第一根放量大阳线处买入

2、成交量最佳买点:股价跌至某个重要支撑位—缩量企稳时买入

3、成交量最佳买点:放量突破重要阻力位—突破日买入

4、成交量最佳买点:低位的第一根放量大阳线—大阳线处买入

四、使用成交量应注意以下4点

1、任何进出,均以大盘为观察点,大盘不好时不要做,更不要被逆市上涨股迷惑。

2、在多数情况下,当量缩后价不再跌,一旦量逐步放大,这是好事。

3、在下跌过程中,若成交量不断萎缩,在某天量缩到“不可思意”的程度,而股价跌势又趋缓时,就是买入的时机。

4、成交量萎缩后,新底点连续2天不再出现时,量的打底已可确认,可考虑介入。

如果您喜欢以上文章,想了解更多股市投资经验及技巧,关注公众号越声投顾(yslcw927),干货很多!

作者 | 刘垚

编辑 | 尔悦

小 T 导读:在使用或者实现分布式数据库(Distributed Database)时,会面临把一个表的数据按照一定的策略分散到各个数据库节点上的情况,随之而来的是多节点数据查询复杂性的问题,例如 Join 和子查询。本文将会为你解读分布式数据库下子查询和 Join 等复杂 SQL 如何实现,来帮助你更好地解决上述问题。

首先简单讲一下 SQL 的执行过程:

SQL ==> Parser ==> Translate & Semantic Check ==> Optimizer ==> Coordinator ==> Executer

  • Parser 产生的是语法树,即 Abstract Syntax Tree;
  • Translate & Semantic Check,这一步会从 Catalog 读取元数据,用元数据完善语法树,便于 Optimizer 使用。例如:常见的 select * from tableA,一般会在这一步把“*”换成 tableA 的列;
  • Optimizer 产生的是优化之后的逻辑执行计划,即 Optimized Logical Plan,执行计划是个有向无环图,即 DAG;
  • Coordinator 负责分发逻辑执行计划给各个节点去计算;
  • Executer 会把逻辑执行计划转成物理执行计划,即 Physical Plan。

开源的数据库有很多,我们可以结合一些主流数据库的源代码来理解子查询和 Join 的实现方式,比如关系型数据库 :Impala、Presto、ClickHouse,时序数据库(Time- Series Database): TDengine 等。下面从子查询和 Join 两部分进行分析。

子查询部分

逻辑执行计划有多种 Node,分别对应着 SQL 中的各种计算,包括 Scan Node、Join Node、Aggregate Node、Sort Node、Project Node 等等,相应的物理执行计划的算子为 Scan Operator 、Join Operator、Aggregate Operator、Sort Operator、Project Operator 等等。而数据库一般没有计算子查询的算子,这是因为将抽象语法树转成逻辑执行计划之后,就已经没有子查询的概念了,其运行逻辑是数据算子之间自下而上逐层传递,并逐层计算,并不特别计算子查询。下面讲一下分布式数据库针对子查询的一些相关处理。

首先,分布式数据库的优化器会将子查询扁平化处理,这种方式一般分为两种,一种是直接在语法树(AST)上做子查询扁平化(Subquery Flatten),另外一种是在生成逻辑执行计划时进行扁平化。这两种方式本质上大同小异,都要保证语义的等价性。但也并不是所有的子查询都能扁平化,有如下几种特殊情况:

  • 子查询和父查询都有聚集函数
  • 子查询有聚集函数,并且父查询有分组计算(Group By)
  • 子查询有聚集函数,并且用子查询聚集函数的结果关联(Join)父查询的表
  • 父查询有聚集函数,并且子查询有分组计算(Group By)
  • 子查询有 Limit(限制返回结果的行数),并且父查询有过滤条件(Where)或者分组计算、排序(Order By)
  • 其他

基于 AST 进行子查询扁平化时,需要先遍历语法数据,并按规则进行判断,进而去除不必要的子查询。对于生成逻辑执行计划时的子查询扁平化,在生成 Plan Node 时需要先去除冗余的 Node,举个例子,SQL:select colA from (select * from tA) group by colA;

一般来说,逻辑执行计划会有多个子计划,通常在需要网络传输时才会产生子计划,需要注意的是子计划和子查询之间并没有必然的联系,即有子查询不一定对应一个子计划。

Join 部分

首先,分布式数据库会对 Join 进行优化,包括 Join 消除(例如基于主键外键去除不必要的 Join)、外连接消除(Outer Join 转成 Inner Join)、Join Order 优化(基于数据的统计信息,用动态规划算法、贪心算法或遗传算法等优化 Table 的 Join 顺序)等等。

再讲一下 Join 的三种基本算法:Hash Join(必须要有等值连接条件,例如 t1.colA = t2.colB)、Merge Join(左表和右表的数据都是有序的,按连接条件中的列有序)、Nestloop Join(含有非等值连接条件并且数据无序)。在实际当中,会把三种算法进行混合使用,这是因为 Join 条件可以同时包含等值连接和非等值连接,例如 t1.colA = t2.colB AND t1.colC > t2.colC

Hash Join

在进行 Join Order 优化时,优化器会调整左表和右表的顺序,一般把小表放右边,大表放左边,并且选择 Join 模式:Shuffle Join(按照关联条件,同时 shuffle 左表和右表,然后再计算 Join) 或 Boradcast Join(把右表广播到左表所在的节点,注意左表不动,然后再计算 Join)。一般是基于代价去选择 Join Order 优化,但考虑到统计信息可能会存在误差,因此很多数据库可以通过 Hint、Query Option 等方式,由用户来指定 Join 顺序、Join 模式等。

Hash Join 是目前最常用的 Join 算法,大部分数据库都实现了 Hash Join。这种算法会先读取右表,并把右表的数据放入 Hash Map 里,如果存不下就会放入外存。通常情况下,各个数据库都会实现自己的 Hash Map,很少直接使用 STL 或 Boost 等第三方库中的 Hash Map,原因主要有两点:

  • 定制化 Hash Map 会提升 Join 计算速度。
  • 定制化 Hash Map 能更准确地控制内存使用,当内存不足时,会使用外存,定制化 Hash Map 可以根据 Join 算法,优化 Swap 机制,减少 Swap 的数据量。Hash Map 的结构如下:

右表可能含有重复的数据,所以会有 Duplicate Node。这里的重复数据是指 Join Key(Join 条件对应的列)的数据重复,并且其他列不重复,所以要分别缓存。注意上述图中,是通过 Hash 算法解决 Hash 冲突的问题,即不会把不同的 Join Key 放在同一个桶中。当然,现实操作中也有把不同的 Join Key 放在同一个桶中的情况,那需要遍历 List 才能确定查找的 Join Key 是否存在。

Merge Join

Merge Join 一般是在左表和右表的数据是有序的情况下使用。例如时序数据库 TDengine,数据按时间戳列有序,那么用时间戳列做 Join 时,TDengine database 会用 Merge Join 来计算,这样的一个好处是处理速度非常快,并且占用内存非常小。

Nestloop Join

这种 Join 算法速度非常慢,但对于全功能数据库而言是不可缺少的。使用这种算法时,可以结合索引来提速。

总结而言,Hash Join 使用最广,适用于很多数据分析的场景,并且大部分数据库都支持;Merge Join 一般是在左右表数据有序时才会使用,不需要缓存数据,所以使用内存非常少,计算速度是三种 Join 算法中最快的;Nestloop Join 性能很差,分布式数据库一般很少使用,有些分布式数据库就不支持,可以通过索引来加速 Nestloop Join。

写在最后

上面我们对子查询和 Join 两种复杂 SQL 的实现方式做了具体解读,大家可以结合一些开源数据库的源代码来理解,像 TDengine 的源代码都可以在 GitHub 上看到,如果你对时序数据库的复杂 SQL 实现有兴趣,这就是一个不错的观摩对象。也欢迎大家在下方评论区进行交流。


点击了解更多 TDengine Database 的具体细节。

小 T 导读:虽然 TDengine 已经提供了非常多的常用计算函数,但是在具体实践中,企业的开发团队往往会因为自己特殊的业务需求,需要特有的计算函数,这时候,支持自定义函数功能就特别重要了。本文将介绍 TDengine 3.0 支持的 UDF 机制。

在使用 TDengine 这款时序数据库(Time Series Database, TSDB)的时候,我们经常会用到各种内置函数,通过在数据库中完成很多计算,可以大大简化数据库应用层的开发工作。

TDengine 提供了大量的内置函数,可以分为几个大类:

  • 单行函数:单行函数为查询结果中的每一行返回一个结果行
  • 数学函数:如 ABS、SIN、COS、LOG、POW 等
  • 字符串函数:如 CHAR_LENGTH、CONCAT、LOWER、SUBSTR、UPPER 等
  • 转换函数:如 CAST、TO_JSON、TO_UNIXTIMESTAMP 等
  • 时间和日期函数:NOW、TIMEDIFF、TIMEZONE、TODAY 等
  • 聚合函数:聚合函数为查询结果集的每一个分组返回单个结果行
  • 如 AVG、COUNT、STDDEV、SUM 等
  • 选择函数
  • 时序数据特有函数
  • 系统信息函数

虽然 TDengine 已经提供了这么多常用的计算函数,但是在具体实践中,企业的开发团队往往会因为自己特殊的业务需求,需要特有的计算函数,这时候,支持自定义函数功能就特别重要了。

本文将具体介绍如何在 TDengine 中定义并使用自定义函数。

利用 UDF(User Defined Function) 功能,TDengine 可以插入用户编写的处理代码并在查询中使用它们,这样就能很方便地解决特殊应用场景中的使用需求。 UDF 通常以数据表中的一列数据做为输入,同时支持以嵌套子查询的结果作为输入。

TDengine 支持通过 C/C++ 语言来定义 UDF。TDengine 3.0 优化了相关机制,所以本文描述的特性适用于 3.0 及以上版本。

基本概念

用户可以通过 UDF 实现两类函数:标量函数和聚合函数。标量函数对每行数据输出一个值,如求绝对值 abs,正弦函数 sin,字符串拼接函数 concat 等。聚合函数对多行数据进行输出一个值,如求平均数 avg,最大值 max 等。

实现 UDF 时,需要实现规定的接口函数

  • 标量函数需要实现标量接口函数 scalarfn
  • 聚合函数需要实现聚合接口函数 aggfn_start、aggfn、aggfn_finish
  • 如果需要初始化,实现 udf_init;如果需要清理工作,实现 udf_destroy

接口函数的名称是 UDF 名称,或者是 UDF 名称和特定后缀(_start, _finish, _init, _destroy)的连接。列表中的scalarfn、aggfn、udf需要替换成udf函数名。

标量接口函数

int32_t scalarfn(SUdfDataBlock* inputDataBlock, SUdfColumn *resultColumn)

其中 scalarFn 是函数名的占位符。这个函数对数据块进行标量计算,通过设置resultColumn结构体中的变量设置值。

参数的具体含义是:

  • inputDataBlock: 输入的数据块
  • resultColumn: 输出列

聚合接口函数

int32_t aggfn_start(SUdfInterBuf *interBuf)

int32_t aggfn(SUdfDataBlock* inputBlock, SUdfInterBuf *interBuf, SUdfInterBuf *newInterBuf)

int32_t aggfn_finish(SUdfInterBuf* interBuf, SUdfInterBuf *result)

其中 aggfn 是函数名的占位符。首先调用aggfn_start生成结果buffer,然后相关的数据会被分为多个行数据块,对每个数据块调用 aggfn 用数据块更新中间结果,最后再调用 aggfn_finish 从中间结果产生最终结果,最终结果只能含 0 或 1 条结果数据。

参数的具体含义是:

  • interBuf:中间结果 buffer。
  • inputBlock:输入的数据块。
  • newInterBuf:新的中间结果buffer。
  • result:最终结果。

UDF 初始化和销毁

int32_t udf_init()

int32_t udf_destroy()

其中 udf 是函数名的占位符。udf_init 完成初始化工作。 udf_destroy 完成清理工作。如果没有初始化工作,无需定义udf_init函数。

如果没有清理工作,无需定义udf_destroy函数。 篇幅所限,相关数据结构的定义可以参考 UDF 文档。

编译 UDF

用户定义函数的 C 语言源代码无法直接被 TDengine 系统所使用,而是需要先编译为 动态链接库,之后才能载入 TDengine 系统。

假设我们编写了自定义函数,保存在 add_one.c 文件中,在 Linux 上可以这样编译:

gcc -g -O0 -fPIC -shared add_one.c -o add_one.so

创建 UDF

用户可以通过 SQL 指令在系统中加载客户端所在主机上的 UDF 函数库。一旦创建成功,则当前 TDengine 集群的所有用户都可以在 SQL 指令中使用这些函数。UDF 存储在系统的 MNode 节点上,因此即使重启 TDengine 系统,已经创建的 UDF 也仍然可用。

在创建 UDF 时,需要区分标量函数和聚合函数。

  • 创建标量函数

CREATE FUNCTION function_name AS library_path OUTPUTTYPE output_type;

例如,如下语句可以把 libbitand.so 创建为系统中可用的 UDF:

CREATE FUNCTION bit_and AS "/home/taos/udf_example/libbitand.so" OUTPUTTYPE INT;

  • 创建聚合函数:

CREATE AGGREGATE FUNCTION function_name AS library_path OUTPUTTYPE output_type [ BUFSIZE buffer_size ];

例如,如下语句可以把 libl2norm.so 创建为系统中可用的 UDF:

CREATE AGGREGATE FUNCTION l2norm AS "/home/taos/udf_example/libl2norm.so" OUTPUTTYPE DOUBLE bufsize 8;

如果不再需要,可以通过 DROP 指令删除所创建的 UDF。

DROP FUNCTION function_name;

使用 UDF

在 SQL 指令中,可以直接以在系统中创建 UDF 时赋予的函数名来调用用户定义函数。例如:

SELECT X(c1,c2) FROM table/stable;

表示对名为 c1、c2 的数据列调用名为 X 的用户定义函数。SQL 指令中用户定义函数可以配合 WHERE 等查询特性来使用。

欢迎下载试用 TDengine 3.0,并尝试编写一个自定义函数。

欢迎添加小T的VX:tdengine,加入物联网技术讨论群,第一时间了解 TDengine 官方信息,与关注前沿技术的同学们共同探讨新技术、新玩法。

https://www.xusbuy.com

上一篇:买涨卖跌汇盈(买涨买跌一分钟一交易)

下一篇:福晶公司怎么样(福建福晶公司)

相关推荐

返回顶部