BIG QUERY SQL:使用移动引用在滑动时间窗口上标记日期

时间:2016-07-21 06:33:01

标签: sql google-bigquery

这个帖子是什么?

作为一个团队,我们希望根据以下内容将每个日期标记为TRUE或FALSE;

1)访问者的visit_date为第一次访问,然后为TRUE

2)对于第一次访问日期之后的所有visit_date

a)与最后一次为TRUE的visit_date(特此 LAST TRUE )相比,如果visit_date位于 LAST TRUE 的30天前视窗口内;然后FALSE

Visitor A Visitor B

我使用的是什么数据?

访问者和visit_date的网站数据。

为访问者创建的每个新会话记录visit_date。我们操纵数据,每个访问者每个日期只能获得一条记录。

ISSUE:

简单的LAG功能和LEAD功能没有用,因为;

1)在给出新的TRUE标签后 LAST TRUE 的参考位置不断变化

a)访问者必须检查最后一次的记录数量。下一个TRUE可以是2行或15行;这取决于访客。

实际上,我们无法在BigQuery中创建循环

  1. 检查visit_date是否符合条件

  2. 如果确实如此,则将其标记为TRUE,同时更改 LAST TRUE 对此visit_date的引用

  3. 重复此过程,直至访客的最后一条记录

  4. 使用的查询:

    First Table(table_id)只是为了得到以下计算

    访问者唯一标识符

    visit_date 访问日

    plus_30_days 30天+访问日

    lag_value 上面一行的visit_date值

    lead_value 以下一行的visit_date值

    为了便于使用,所有值都转换为DAYOFYEAR()

    基于上表,我使用了以下查询

     SELECT    *
     , CASE WHEN lag_value IS NULL THEN 1 
            WHEN visit_date - lag_value > 30 THEN 1 
            WHEN lead_value IS NULL THEN 1 
            ELSE 0 END AS true_false
     FROM [project_id:dataset.table_id] 
     ORDER BY visitor, visit_date
    

    输出:

    绿色框应为TRUE OUTPUT

    由于

    visitor C

    采取的行动:

    1)我尝试过LEAD和LAG功能

    2)检查网络,可以翻译成BIGQUERY的正常SQL函数>>找不到循环函数

    3)询问我的团队负责人>>同样的问题

    4)最多3小时的实验>>相同的输出

    供参考的表格(未格式化)

    visitor_id  file_date   plus_30_days    lag_value   lead_value  true_false
    A   1   31  null    38  1
    A   38  68  1   41  1
    A   41  71  38  65  0
    A   65  95  41  76  0
    A   76  106 65  null    1
    B   90  120 null    122 1
    B   122 152 90  null    1
    C   123 153 null    134 1
    C   134 164 123 163 0
    C   163 193 134 183 0
    C   183 213 163 217 0
    C   217 247 183 null    1
    D   245 275 null    256 1
    D   256 286 245 262 0
    D   262 292 256 275 0
    D   275 305 262 279 0
    D   279 309 275 null    1
    E   279 309 null    310 1
    E   310 340 279 341 1
    E   341 5   310 null    1
    

1 个答案:

答案 0 :(得分:2)

请尝试以下操作。

SELECT visitor_id, file_date, true_false FROM JS(    // input table
( SELECT visitor_id, GROUP_CONCAT(STRING(100000 + file_date), ';') AS visits FROM
    (SELECT 'A' AS visitor_id, 1 AS file_date), (SELECT 'A' AS visitor_id, 38 AS file_date), (SELECT 'A' AS visitor_id, 41 AS file_date), (SELECT 'A' AS visitor_id, 65 AS file_date),
    (SELECT 'A' AS visitor_id, 76 AS file_date), (SELECT 'B' AS visitor_id, 90 AS file_date), (SELECT 'B' AS visitor_id, 122 AS file_date), (SELECT 'C' AS visitor_id, 123 AS file_date),
    (SELECT 'C' AS visitor_id, 134 AS file_date), (SELECT 'C' AS visitor_id, 163 AS file_date), (SELECT 'C' AS visitor_id, 183 AS file_date), (SELECT 'C' AS visitor_id, 217 AS file_date),
    (SELECT 'D' AS visitor_id, 245 AS file_date), (SELECT 'D' AS visitor_id, 256 AS file_date), (SELECT 'D' AS visitor_id, 262 AS file_date), (SELECT 'D' AS visitor_id, 275 AS file_date),
    (SELECT 'D' AS visitor_id, 279 AS file_date), (SELECT 'E' AS visitor_id, 279 AS file_date), (SELECT 'E' AS visitor_id, 310 AS file_date), (SELECT 'E' AS visitor_id, 341 AS file_date)  
  GROUP BY visitor_id
) ,
// input columns
visitor_id, visits,
// output schema
"[{name: 'visitor_id', type: 'string'},
{name: 'file_date', type: 'integer'},
{name: 'true_false', type: 'integer'}]",
// function
"function(r, emit){
  var visits = r.visits.split(';');
  visits.sort();
  plus_30_days = 0;
  for (var i = 0; i < visits.length; i++) { 
    file_date = parseInt(visits[i]) - 100000;
    true_false = 0;
    if (file_date > plus_30_days) {
      plus_30_days = file_date + 30;
      true_false = 1;
    }
      emit({
        visitor_id: r.visitor_id,
        file_date: file_date,
        true_false: true_false
      });      
  }
 }")

希望这能给你带来良好的开端 请注意:上面的示例使用了未记录的JavaScript UDF内联版本,这对于快速演示/共享/尝试代码非常有用,但是......没有记录,因此不受支持
要在生产中使用上述示例,您最好对其进行修改以符合BigQuery User-Defined Functions文档(很少进行非常简单的调整)。