-
时间序列聚合引擎
关于聚合引擎,参见《DolphinDB基础概念理解:流数据聚合引擎》
-
createTimeSeriesAggregator()
createTimeSeriesAggregator(name, windowSize, step, metrics, dummyTable, outputTable, timeColumn, [useSystemTime=false], [keyColumn], [garbageSize])
参数 意义 备注 name 表示时间序列聚合引擎的名称,是时间序列聚合引擎的唯一标识 可以包含字母、数字、下划线,但必须以字母开头 windowSize 表示数据窗口的长度,是一个正整数 windowSize必须是step的整数倍,否则会抛出异常;
对流数据进行聚合计算,每次要截取一段静态数据集用于计算,这个截取出来的静态数据集我们也称为数据窗口step 表示计算的时间间隔,是一个正整数 windowSize和step的精度取决于useSystemTime参数 metrics 是元代码,详情可参考元编程。 可以是系统内置或用户自定义的聚合函数(使用defg关键字定义),如 <[sum(qty), avg(price)]>
;
可以对聚合结果使用表达式,如<[avg(price1)-avg(price2)]>
;
也可以对计算列进行聚合运算,如<[std(price1-price2)]>
。dummyTable 表对象 提供一个样本表对象,它可以不包含数据,但它的结构必须与订阅的流数据表结构相同;
系统利用dummyTable的schema来决定信息每一列的数据类型outputTable 表对象,用于保存计算结果。 它的第一列必须是时间类型,用于存放发生计算的时间戳(此处是发布表时间序列中的时间,并非本地系统时间),并且该列的数据类型要与dummyTable的时间列一致;
如果keyColumn参数不为空,那么outputTable的第二列为keyColumn;
如果keyColumn参数为空,那么从第二列开始,每列用于保存聚合结果。timeColumn 表示输入流数据表的时间列名称,是字符串标量 [useSystemTime] 表示聚合引擎的驱动方式 useSystemTime = true:表示时间驱动方式,windowSize和step的单位是毫秒。每当到达一个预定的时间点,聚合引擎就会激活并以设定的窗口截取流数据进行计算。在此模式下,系统内部会给每一个进入的数据添加一个毫秒精度的系统时间戳作为数据窗口截取的依据;
useSystemTime = false(默认):表示数据驱动方式,windowSize和step的单位与timeColumn的时间精度一样。只有当数据进入系统时,聚合引擎才会被激活,此时窗口的截取依据是timeColumn列内容,时间的精度也取决于timeColumn列的时间精度。[keyColumn] 表示分组列,是字符串标量 聚合引擎会按照keyColumn对输入数据分组,并在每组中进行聚合计算;
指定分组计算的组别,以对流数据分组进行聚合计算。比如以股市报价数据中的每支股票为一组进行聚合计算[garbageSize] 正整数 默认值是50,000;
如果没有指定keyColumn,当内存中历史数据的数量超过garbageSize时,系统会清理本次计算不需要的历史数据;
如果指定了keyColumn,意味着需要分组计算时,内存清理是各分组独立进行的。当一个组的历史数据记录数超出garbageSize时,会清理该组不再需要的历史数据。若一个组的历史数据记录数未超出garbageSize,则该组数据不会被清理。 -
规整尺度alignmentSize
为了便于观察和对比计算结果,系统会对第一个数据窗口的起始时间进行规整。系统会根据step参数和数据的时间精度来确定整数类型的规整尺度
alignmentSize
。假设第一条数据的时间的最小精度(
ss
,mmm
)为X
,那么第一个数据窗口的左边界的最小精度为
X / a l i g n m e n t S i z e ∗ a l i g n m e n t S i z e X/alignmentSize*alignmentSize X/alignmentSize∗alignmentSize
其中, / / /表示整除。例如,第一条数据的时间为
2018.10.08T01:01:01.365
,step=100
,那么X=365
,第一个数据窗口的左边界的最小精度为 365 / 100 ∗ 100 = 300 365/100*100=300 365/100∗100=300,第一个数据窗口的起始时间为2018.10.08T01:01.300
。官方文档的这段描述有歧义,补充说明:
第一个数据窗口的起始时间为
2018.10.08T01:01.300
。即第一个数据窗口WindowSize坐落在时间间隔[2018.10.08T01:01:01.300, 2018.10.08T01:01:01.400)
,依据step以此累加,得到每次进行计算的时间点,准确来讲此处是不存在时间区间的,在时间这一列上,有价值的是隐居step得到的一个个点。数据窗口一般不是针对时间列而言,只是通过时间节点给出了数据窗口的结束位置,再通过
windowSize
大小向前推,一直到alignmentSize
给出了规整的起始时间。
-
数据精度为秒
当数据的时间精度为秒时,如
DATETIME(yyyy-MM-dd HH:mm:ss)
、SECOND(HH:mm:ss)
类型,alignmentSize
的取值如下:step alignmentSize 0~2 2 3~5 5 6~10 10 11~15 15 16~20 20 21~30 30 31~60 60 -
数据精度为毫秒
当数据的时间精度为毫秒时,如
TIMESTAMP(yyyy-MM-dd HH:mm:ss.mmm)
、TIME(HH:mm:ss.mmm)
类型,alignmentSize
的取值如下:step alignmentSize 0~2 2 3~5 5 6~10 10 11~20 20 21~25 25 26~50 50 51~100 100 101~200 200 201~250 250 251~500 500 501~1000 1000
-
函数作用
返回一个表对象,向该表写入数据意味着这些数据进入时间序列聚合引擎进行计算。
通常***createTimeSeriesAggregator***与subscribeTable函数一起使用。
***createTimeSeriesAggregator***返回的==时间序列聚合引擎(name)==可以跨会话调用。
-
使用示例
-
函数及变量准备
# 创建流数据表 share streamTable(1000:0, `time`qty, [TIMESTAMP, INT]) as trades # 创建输出表 outputTable = table(10000:0, `time`sumQty, [TIMESTAMP, INT]) # 实例化聚合计算表 tradesAggregator = createTimeSeriesAggregator("streamAggr1", 5, 5, <[sum(qty)]>, trades, outputTable, `time ) # 订阅,从发布表trades订阅到聚合计算表tradesAggregator subscribeTable(, "trades", "tradesAggregator", 0, append!{tradesAggregator}, true) # 定义函数 def writeData(n){ timev = 2018.10.08T01:01:01.001 + timestamp(1..n) qtyv = take(1, n) insert into trades values(timev, qtyv) }
-
第一次操作:向发布表写入5行数据
发布表,是一种流数据表,当向其写入数据,即意味着发布数据,因为需要被不同会话访问,因此需要将其共享。
流 数 据 表 + 共 享 表 + 写 入 数 据 = 自 动 将 数 据 导 入 订 阅 表 , 实 现 发 布 功 能 流数据表 + 共享表 + 写入数据 = 自动将数据导入订阅表,实现发布功能 流数据表+共享表+写入数据=自动将数据导入订阅表,实现发布功能# 向发布表trades中写入5条数据 writeData(5)
writeData(5)
这个函数实现了三部分动作:- 插入n=5个数据对(timev, qtyv)到发布表;
- 因为订阅的原理,向发布表trades写入数据,自动传入订阅表;
- 因为聚合引擎的原理,向聚合计算表tradesAggregator(也即订阅表)写入数据意味着这些数据进入(时间序列)聚合引擎进行计算
这三个动作的后两个,各自还包含了一个消费过程,即接受到数据的同时,还对数据做了实时处理。三个动作详解:
-
插入n=5个数据对(
timev
,qtyv
)到发布表;这个动作是单向一次完成
-
因为订阅的原理,向发布表
trades
写入数据,自动传入订阅表;关于subscribeTable函数的详解,参见:
《DolphinDB使用案例16:Python实现流数据订阅》
subscribeTable(, "trades", "tradesAggregator", 0, append!{tradesAggregator}, true) # 解析 subscribeTable(server为空表示本地节点, tableName="trades"表示发布表, actionName="tradesAggregator"表示对此订阅的描述标记, offset=0表示从发布表的第0行开始订阅, handler=append!{tradesAggregator}表示处理(消费)订阅数据的是一个函数,原本两个参数的append!通过部分应用固定被追加数据的表对象, msgAsTable=true表示订阅的数据是表)
关于部分应用(
append!{tradesAggregator}
)参见《DolphinDB基础概念理解:部分应用partial application》。此订阅环节中,有对数据进行处理(
append!{tradesAggregator}
)的环节,这个环节就是把数据追加到tradesAggregator
表中。 -
因为聚合引擎的原理,向聚合计算表
tradesAggregator
(也即订阅表)写入数据意味着这些数据进入(时间序列)聚合引擎进行计算tradesAggregator = createTimeSeriesAggregator("streamAggr1", 5, 5, <[sum(qty)]>, trades, outputTable, `time ) # 解析 tradesAggregator = createTimeSeriesAggregator(name="streamAggr1"表示时间序列聚合引擎的名称, windowSize=5表示数据窗口的长度, step=5表示计算的时间间隔, metrics=<[sum(qty)]>是表示聚合函数的元代码, dummyTable=trades, outputTable=outputTable用于保存计算结果, timeColumn=`time表示输入流数据表的时间列 )
与上述订阅环节有些类似,当(通过订阅的方式)向
tradesAggregator
表写入数据,就意味着这些数据进入聚合引擎streamAggr1
进行计算(sum(qty)
)。经过上述分析,向发布表
trades
中写入5条数据writeData(5)
这个函数,在DolphinDB
中真正的过程是:values()
函数生成5对数据;insert
将5个数据对插入发布表trades
;发布表trades
接收到数据就启动了订阅功能
,自动推送给handler=append!{tradesAggregator}
进行数据消费
,保存到tradesAggregator表
中聚合引擎表tradesAggregator
收到数据,就启动了时间序列聚合引擎
,通过metrics=<[sum(qty)]>
对数据进行聚合计算,并将计算后的结果保存到outputTable=outputTable
表中。
-
查看第一次操作计算结果
根据上述分析,此时
发布表trades
中应该有5条记录:>> select * from trades time qty 2018.10.08T01:01:01.002 1 2018.10.08T01:01:01.003 1 2018.10.08T01:01:01.004 1 2018.10.08T01:01:01.005 1 2018.10.08T01:01:01.006 1
outputTable表
中应该有一次计算结果:>> select * from outputTable time sumQty 2018.10.08T01:01:01.005 3
trades
中有5条记录,qty的和
应该是5,但outputTable
中sumQty
的结果却是3。这里就是时间序列聚合函数
createTimeSeriesAggregator()
通过step
的值确定的整型的规整尺寸alignmentSize
在起作用:此时
trades
表中time列
的数据类型是TIMESTAMP
,精度是毫秒
,alignmentSize
的取值规则如下:step alignmentSize 0~2 2 3~5 5 6~10 10 11~20 20 21~25 25 26~50 50 51~100 100 101~200 200 201~250 250 251~500 500 501~1000 1000 根据规则,此时
step=5
,则alignmentSize=5
,计算第一个数据窗口的左边界最小精度:
( x a l i g n m e n t S i z e ) 取 整 ∗ a l i g n m e n t S i z e = ( 2 5 ) 取 整 ∗ 5 = 0 (\frac{x}{alignmentSize})_{取整}*alignmentSize=(\frac{2}{5})_{取整}*5=0 (alignmentSizex)取整∗alignmentSize=(52)取整∗5=0
得到第一个计算窗口的左边界为2018.10.08T01:01:01.000
,即第一个数据窗口为[2018.10.08T01:01:01.000, 2018.10.08T01:01:01.005)
,其中包含[2018.10.08T01:01:01.002, 2018.10.08T01:01:01.003, 2018.10.08T01:01:01.004]
,因此结果sumQty
为3
.根据
outputTable参数
的定义,输出表的第一列
必须是时间类型,用于存放计算发生的时间戳
,这个列的数据类型要和流数据表中的时间列类型一致。 -
第二次操作:向发布表写入10行数据
首先清空发布表trades;
重新设置windowSize=6,step=3;
最后模拟写入10条数据。
writeData(10)
写入完成后,select * from trades
应该有10条记录,这些都未改变。由于alignmentSize
机理的存在,sumQty
的结果有所不同。根据
alignmentSize
规则,此时step=3
,则alignmentSize=5
,计算第一窗口的左边界最小精度:
( x a l i g n m e n t S i z e ) 取 整 ∗ a l i g n m e n t S i z e = ( 2 5 ) 取 整 ∗ 5 = 0 (\frac{x}{alignmentSize})_{取整}*alignmentSize=(\frac{2}{5})_{取整}*5=0 (alignmentSizex)取整∗alignmentSize=(52)取整∗5=0
根据时间间隔step=3
确定计算区间为:time 2018.10.08T01:01:01.000 第一个窗口的左边界 2018.10.08T01:01:01.003 第一次发生计算的时间戳 2018.10.08T01:01:01.006 第二次发生计算的时间戳=第一次 + step 2018.10.08T01:01:01.009 第三次发生计算的时间戳 第一次发生计算的时间戳
2018.10.08T01:01:01.003
之前取windowSize=6
,从000
开始只有002
一条,因此sumQty=1
;第二次发生计算的时间戳
2018.10.08T01:01:01.006
之前取windowSize=6
,从000
开始只有005、004、003、002
四条,因此sumQty=4
;第三次发生计算的时间戳
2018.10.08T01:01:01.009
之前取windowSize=6
,从000
开始有008、007、006、005、004、003
六条,因此sumQty=6
;
-
Github >> Tutorials_CN >> DolphinDB流数据聚合引擎