计算BigQuery中的移动最大值

Ben*_*aft 5 google-bigquery

给定一个带有一些排序的BigQuery表和一些数字,我想计算数字的"移动最大值" - 类似于移动平均线,但是最大值.从尝试使用BigQuery计算EMA(指数移动平均值)看来,最好的方法是使用LEAD()然后自己进行聚合.(Bigquery移动平均线表明基本上是一个CROSS JOIN,但考虑到数据的大小,这看起来似乎很慢.)

理想情况下,我也许能够只返回一个单一的重复场,而不是20个个人领域,从内部查询,然后使用普通聚集在重复场,但我还没有想出一个办法做到这一点,所以我我坚持滚动自己的聚合.虽然这对于求和或平均来说很容易,但计算最大内联是非常棘手的,我还没有想出一个好方法.

(下面的例子当然是为了使用公共数据集有点做作.他们还做滚动最大超过300元,而我想这样做对周围20我已经生成的查询程序,因此使得它简短不是一个大问题.)

一种方法是执行以下操作:

SELECT word,
  (CASE
    WHEN word_count >= word_count_1 AND word_count >= word_count_2 THEN word_count
    WHEN word_count_1 >= word_count AND word_count_1 >= word_count_2 THEN word_count_1
    ELSE word_count_2 END
    ) AS max_count
FROM (
  SELECT word, word_count,
    LEAD(word_count, 1) OVER (ORDER BY word) AS word_count_1,
    LEAD(word_count, 2) OVER (ORDER BY word) AS word_count_2,
  FROM [publicdata:samples.shakespeare]
  WHERE corpus = 'macbeth'
)
Run Code Online (Sandbox Code Playgroud)

这是O(n ^ 2),但它至少有效.我也可以做一个嵌套的IFs 链,像这样:

SELECT word,
  IF(word_count >= word_count_1,
    IF(word_count >= word_count_2, word_count, word_count_2),
    IF(word_count_1 >= word_count_2, word_count_1, word_count_2)) AS max_count
FROM ...
Run Code Online (Sandbox Code Playgroud)

这是O(n)来评估,但查询大小在n中是指数的,所以我认为这不是一个好的选择; 当然它会超过n = 20的BigQuery查询大小限制.我也可以做嵌套查询:

SELECT word,
  IF(word_count_2 >= max_count, word_count_2, max_count) AS max_count
FROM (
  SELECT word,
    IF(word_count_1 >= word_count, word_count_1, word_count) AS max_count
  FROM ...
)
Run Code Online (Sandbox Code Playgroud)

但是,似乎做20个嵌套查询在性能方面可能不是一个好主意.

有没有办法做这种查询?如果没有,我是否正确,对于20左右的n,第一个是最不好的?

Fel*_*ffa 7

我用来滚动窗口的技巧:CROSS JOIN和一个数字表.在这种情况下,要有一个3年的移动窗口,我用数字0,1,2交叉连接.然后,您可以为每个组创建一个id(ending_at_year== year-i)并按此组进行分组.

SELECT ending_at_year, MAX(mean_temp) max_temp, COUNT(DISTINCT year) c
FROM 
(
 SELECT mean_temp, year-i ending_at_year, year
 FROM [publicdata:samples.gsod] a
 CROSS JOIN 
  (SELECT i FROM [fh-bigquery:public_dump.numbers_255] WHERE i<3) b
 WHERE station_number=722860
)
GROUP BY ending_at_year
HAVING c=3
ORDER BY ending_at_year;
Run Code Online (Sandbox Code Playgroud)