GFI 示例

此主题介绍了可以使用常数和线性插值方案编写的部分查询。

常数插值

第一个查询使用 TS_FIRST_VALUE()TIMESERIES 子句将输入记录放入时长为 3 秒的时间片中,然后返回每个符号/时间片组合的第一个出价值(时间片开始时的值)。

=> SELECT slice_time, symbol, TS_FIRST_VALUE(bid) AS first_bid FROM TickStore
   TIMESERIES slice_time AS '3 seconds' OVER (PARTITION BY symbol ORDER BY ts);

因为股票 XYZ 的出价在 3:00:03 时为 10.0,即第二个时间片的 first_bid 值。此值从 3:00:03 开始时一直为 10.0,因为 10.5 的输入值直到 3:00:05 时才产生。在这种情况下,根据在股票 XYZ 中见到的最后一个值为时间 3:00:03 推断了内插值:

     slice_time      | symbol | first_bid
---------------------+--------+-----------
 2009-01-01 03:00:00 | XYZ    |        10
 2009-01-01 03:00:03 | XYZ    |        10
(2 rows)

下一个示例将输入记录放入 2 秒时间片以返回每个股票代码/时间片组合的第一个出价值:

=> SELECT slice_time, symbol, TS_FIRST_VALUE(bid) AS first_bid FROM TickStore
   TIMESERIES slice_time AS '2 seconds' OVER (PARTITION BY symbol ORDER BY ts);

此时结果包含 2 秒时间片中的三个记录,所有这些出现在 03:00:00 时的第一个输入行和在 3:00:05 时的第二个输入行之间。请注意,第二个和第三个输出记录与不存在输入记录的时间片对应。

     slice_time      | symbol | first_bid
---------------------+--------+-----------
 2009-01-01 03:00:00 | XYZ    |        10
2009-01-01 03:00:02 | XYZ    |        10
2009-01-01 03:00:04 | XYZ    |        10
(3 rows)

使用同一个表架构时,下一个查询将 TS_LAST_VALUE() 与 TIMESERIES 结合使用以返回每个时间片最后的值(时间片结束时的值)。

=> SELECT slice_time, symbol, TS_LAST_VALUE(bid) AS last_bid FROM TickStore
   TIMESERIES slice_time AS '2 seconds' OVER (PARTITION BY symbol ORDER BY ts);

请注意,最后一个值输出行为 10.5,因为在时间 3:00:05 时的值 10.5 是从 3:00:04 开始的 2 秒时间片中的最后一个点。

     slice_time      | symbol | last_bid
---------------------+--------+----------
 2009-01-01 03:00:00 | XYZ    |       10
 2009-01-01 03:00:02 | XYZ    |       10
 2009-01-01 03:00:04 | XYZ    |     10.5
(3 rows)

请记住,因为常数插值为默认方案,如果按下述方式使用 CONST 参数编写查询,则会返回相同的结果:

=> SELECT slice_time, symbol, TS_LAST_VALUE(bid, 'CONST') AS last_bid FROM TickStore
   TIMESERIES slice_time AS '2 seconds' OVER (PARTITION BY symbol ORDER BY ts);

线性插值

根据常数插值示例(指定了 2 秒时间片)中所列的上述输入记录,通过线性插值得出的 TS_LAST_VALUE 结果如下:

=> SELECT slice_time, symbol, TS_LAST_VALUE(bid, 'linear') AS last_bid   FROM TickStore
   TIMESERIES slice_time AS '2 seconds' OVER (PARTITION BY symbol ORDER BY ts);

在结果中,没有返回最后一行的 last_bid 值,因为查询指定了 TS_LAST_VALUE,并且在 3:00:04 时间片之后没有要插值的任何数据点。

     slice_time      | symbol | last_bid
---------------------+--------+----------
 2009-01-01 03:00:00 | XYZ    |     10.2
 2009-01-01 03:00:02 | XYZ    |     10.4
 2009-01-01 03:00:04 | XYZ    |
(3 rows)

使用多个时序聚合函数

同一个查询中可以使用多个时序聚合函数。按照 TIMESERIES 子句中的定义,它们共享同一个空白填充策略;然而,每个时序聚合函数可以指定自己的插值策略。在以下示例中,有两个常数插值和一个线性插值方案,但这三个函数全部使用三秒时间片。

=> SELECT slice_time, symbol,
       TS_FIRST_VALUE(bid, 'const') fv_c,
       TS_FIRST_VALUE(bid, 'linear') fv_l,
       TS_LAST_VALUE(bid, 'const') lv_c
   FROM TickStore
   TIMESERIES slice_time AS '3 seconds' OVER(PARTITION BY symbol ORDER BY ts);

在以下输出中,比较了原始输出与多个时序聚合函数返回的输出。

使用分析 LAST_VALUE 函数

以下是使用 LAST_VALUE() 的示例,这样您可以了解此函数与 GFI 语法之间的区别。

=> SELECT *, LAST_VALUE(bid) OVER(PARTITION by symbol ORDER BY ts)
   AS "last bid" FROM TickStore;

对于输出值,没有执行任何空白填充和内插。

         ts          | symbol | bid  | last bid
---------------------+--------+------+----------
 2009-01-01 03:00:00 | XYZ    |   10 |       10
 2009-01-01 03:00:05 | XYZ    | 10.5 |     10.5
(2 rows)

使用 slice_time

在 TIMESERIES 查询中,您无法在 WHERE 子句中使用 slice_time 列,因为 WHERE 子句的评估先于 TIMESERIES 子句,并且直到评估 TIMESERIES 之后才会生成 slice_time 列。例如,Vertica 不支持以下查询:

=> SELECT symbol, slice_time, TS_FIRST_VALUE(bid IGNORE NULLS) AS fv
   FROM TickStore
   WHERE slice_time = '2009-01-01 03:00:00'
   TIMESERIES slice_time as '2 seconds' OVER (PARTITION BY symbol ORDER BY ts);
ERROR:  Time Series timestamp alias/Time Series Aggregate Functions not allowed in WHERE clause

但是,您可以编写子查询,将 slice_time 中的谓词放在外部查询中:

=> SELECT * FROM (
      SELECT symbol, slice_time,
        TS_FIRST_VALUE(bid IGNORE NULLS) AS fv
      FROM TickStore
      TIMESERIES slice_time AS '2 seconds'
      OVER (PARTITION BY symbol ORDER BY ts) ) sq
   WHERE slice_time = '2009-01-01 03:00:00';
 symbol |     slice_time      | fv
--------+---------------------+----
 XYZ    | 2009-01-01 03:00:00 | 10
(1 row)

创建稠密时间序列

借助 TIMESERIES 子句,您可以方便地创建稠密时间序列,以便与实际数据一起用于外部联接。结果将表示所有时间点,而不只是存在数据的时间点。

随后的示例将使用空白填充和插值 (GFI)中所述的相同 TickStore 架构,并添加一个新内部表以用于创建联接:

=> CREATE TABLE inner_table (
       ts TIMESTAMP,
       bid FLOAT
   );
=> CREATE PROJECTION inner_p (ts, bid) as SELECT * FROM inner_table
   ORDER BY ts, bid UNSEGMENTED ALL NODES;
=> INSERT INTO inner_table VALUES ('2009-01-01 03:00:02', 1);
=> INSERT INTO inner_table VALUES ('2009-01-01 03:00:04', 2);
=> COMMIT;

为了返回所有时间点,可以在相关时间帧的开始和结束范围之间创建一个简单的并集。在本例中以 1 秒为时间段:

=> SELECT ts FROM (
     SELECT '2009-01-01 03:00:00'::TIMESTAMP AS time FROM TickStore
     UNION
     SELECT '2009-01-01 03:00:05'::TIMESTAMP FROM TickStore) t
   TIMESERIES ts AS '1 seconds' OVER(ORDER BY time);
         ts
---------------------
 2009-01-01 03:00:00
 2009-01-01 03:00:01
 2009-01-01 03:00:02
 2009-01-01 03:00:03
 2009-01-01 03:00:04
 2009-01-01 03:00:05
(6 rows)

下一个查询将以 500 毫秒为时间段在时间帧的开始和结束范围之间创建一个并集:

=> SELECT ts FROM (
     SELECT '2009-01-01 03:00:00'::TIMESTAMP AS time
     FROM TickStore
     UNION
     SELECT '2009-01-01 03:00:05'::TIMESTAMP FROM TickStore) t
   TIMESERIES ts AS '500 milliseconds' OVER(ORDER BY time);
          ts
-----------------------
 2009-01-01 03:00:00
 2009-01-01 03:00:00.5
 2009-01-01 03:00:01
 2009-01-01 03:00:01.5
 2009-01-01 03:00:02
 2009-01-01 03:00:02.5
 2009-01-01 03:00:03
 2009-01-01 03:00:03.5
 2009-01-01 03:00:04
 2009-01-01 03:00:04.5
 2009-01-01 03:00:05
(11 rows)

以下查询以 1 秒为时间段在相关时间帧的开始和结束范围之间创建一个并集:

=> SELECT * FROM (
     SELECT ts FROM (
       SELECT '2009-01-01 03:00:00'::timestamp AS time FROM TickStore
       UNION
       SELECT '2009-01-01 03:00:05'::timestamp FROM TickStore) t
       TIMESERIES ts AS '1 seconds' OVER(ORDER BY time) ) AS outer_table
   LEFT OUTER JOIN inner_table ON outer_table.ts = inner_table.ts;

此并集将从左联接表返回一组与右联接表中记录相匹配的完整记录。如果查询没有找到任何匹配项,它会使用 NULL 值扩展右侧列:

         ts          |         ts          | bid
---------------------+---------------------+-----
 2009-01-01 03:00:00 |                     |
 2009-01-01 03:00:01 |                     |
 2009-01-01 03:00:02 | 2009-01-01 03:00:02 |   1
 2009-01-01 03:00:03 |                     |
 2009-01-01 03:00:04 | 2009-01-01 03:00:04 |   2
 2009-01-01 03:00:05 |                     |
(6 rows)