Unnest 和 totals.timeOnSite(BigQuery 和 Google Analytics 数据)

Posted

技术标签:

【中文标题】Unnest 和 totals.timeOnSite(BigQuery 和 Google Analytics 数据)【英文标题】:Unnest and totals.timeOnSite (BigQuery and Google Analytics data) 【发布时间】:2017-07-21 07:37:51 【问题描述】:

我想计算网站所有访问者的总 timeOnSite(并将其除以 3600,因为它在原始数据中存储为秒),然后我想将其分解为 content_group 和一个名为的自定义变量内容级别。

出现问题是因为 content_group 和 content_level 都嵌套在数组中,而 timeOnSite 是一个总计存储的变量,如果在包含和取消嵌套的查询中使用时会膨胀。 (content_group 是一个普通的 hits.-nested 变量,而 content_level 嵌套在 customDimensions 中,该 customDimensions 嵌套在 hits 中(第二级嵌套变量) (Will 和 Thomas C 很好地解释了为什么这个问题会出现在这个问题 Google Analytics Metrics are inflated when extracting hit level data using BigQuery 中,但我无法将他们的建议应用于 totals.timeOnSite 指标)

#StandardSQL
SELECT   
 date,   
 content_group,   
 content_level,  
 SUM(sessions) AS sessions,   
 SUM(sessions2) AS sessions2, 
 SUM(time_on_site) AS time_on_site   
FROM (   
     SELECT   
       date AS date,   
       hits.contentGroup.contentGroup1 AS content_group,   
       (SELECT MAX(IF(index=51, value, NULL)) FROM UNNEST(hits.customDimensions)) AS content_level,   
       SUM(totals.visits) AS sessions,   
       COUNT(DISTINCT CONCAT(cast(visitId AS STRING), fullVisitorId)) AS sessions2,   
       SUM(totals.timeOnSite)/3600 AS time_on_site   
     FROM `projectname.123456789.ga_sessions_20170101`,   
       unnest(hits) AS hits
     GROUP BY   
       iso_date, content_group, content_level
     ORDER BY 
       iso_date, content_group, content_level
    )   
GROUP BY iso_date, content_group, content_level
ORDER BY iso_date, content_group, content_level 

(我使用子查询是因为我计划使用 UNION_ALL 从多个表中提取数据,但我省略了该语法,因为我认为它与问题无关。)

问题:

*是否可以对两个命中进行“本地取消嵌套”。和 hits.customDimensions 以便可以在我的查询中使用 totals.timeOnSite 而不会被夸大?

*是否可以像我在会话和会话2中所做的那样为现场时间制定解决方法?

*这个问题是否有第三种隐藏的解决方案?

【问题讨论】:

【参考方案1】:

我无法完全测试这个,但它似乎对我的数据集起作用:

SELECT
  DATE,
  COUNT(DISTINCT CONCAT(fv, CAST(v AS STRING))) sessions,
  AVG(tos) avg_time_on_site,
  content_group,
  content_level
FROM(
  SELECT   
   date AS date,   
   fullvisitorid fv,
   visitid v,
   ARRAY(SELECT DISTINCT contentGroup.contentGroup1 FROM UNNEST(hits)) AS content_group,   
   ARRAY(SELECT DISTINCT value FROM UNNEST(hits) AS hits, UNNEST(hits.customDimensions) AS custd WHERE index = 51) AS content_level,   
   totals.timeOnSite / 3600 AS tos 
  FROM `dataset_id.ga_sessions_20170101`
  WHERE totals.timeOnSite IS NOT NULL
  )
CROSS JOIN UNNEST(content_group) content_group
LEFT JOIN UNNEST(content_level) content_level
GROUP BY
  DATE, content_group, content_level

我尝试做的是首先避免对整个数据集进行UNNEST(hits) 操作。因此,在第一个 SELECT 语句中,content_groupcontent_level 存储为 ARRAY。

在接下来的 SELECT 中,我取消了这两个 ARRAY 的嵌套,并在对所需字段进行分组时计算了总会话数和现场平均时间(我在这里使用了平均值,因为在处理现场时间,但如果您需要总和,您可以将AVG 更改为SUM)。

您不会在此查询中遇到重复timeOnSite 的问题,因为避免了外部UNNEST(hits)。当UNNEST(content_group)UNNEST(content_level) 发生时,这些ARRAY 中的每个值仅与其对应的time_on_site 关联一次,因此不会发生重复。

【讨论】:

此查询的输出与我尝试复制的 GA 中的报告不匹配。与 GA 相比,查询会话增加了三倍,SUM(time_on_site) 比 GA 大 12 倍(评估 SUM 时间比 AVG 时间更容易,但你说得对,AVG 时间更有用!)我明天再试一次,我现在已经很晚了,我可能没有想清楚。 您能否确认您的 GA 报告中应用的过滤器与此查询中应用的过滤器相同?因为在上面的查询中找不到任何错误。 又试了一次,结果还是一样。也检查了过滤器,它们只过滤掉内部流量和垃圾邮件域(例如 afora.ru、akuhni.by 等)。当我在没有自定义维度(即没有任何取消嵌套)的情况下运行查询时,总和结果是正确的,所以对我来说过滤器会干扰感觉有点奇怪(但我仍然是新手,所以我可能是错的! )【参考方案2】:

我这样回答自己的问题可能看起来很奇怪,但是我在 Stack Overflow 之外的一位联系人帮助我解决了这个问题,所以这实际上是他的答案,而不是我的。

session_duration 的问题可以通过使用窗口函数来解决(您可以在 BigQuery 文档中阅读有关窗口函数的更多信息:https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators#analytic-functions)

#StandardSQL
SELECT   
 iso_date,   
 content_group,   
 content_level,  
 COUNT(DISTINCT SessionId) AS sessions, 
 SUM(session_duration) AS session_duration 
FROM (   
     SELECT   
       date AS iso_date,   
       hits.contentGroup.contentGroup1 AS content_group,   
       (SELECT MAX(IF(index=51, value, NULL)) FROM UNNEST(hits.customDimensions)) AS content_level,  
       CONCAT(CAST(fullVisitorId AS STRING), CAST(visitId AS STRING)) AS SessionId, 
       (LEAD(hits.time, 1) OVER (PARTITION BY fullVisitorId, visitId ORDER BY hits.time ASC) - hits.time) / 3600000 AS session_duration 
     FROM `projectname.123456789.ga_sessions_20170101`,   
       unnest(hits) AS hits
     WHERE _TABLE_SUFFIX BETWEEN "20170101" AND "20170131" 
       AND (SELECT 
              MAX(IF(index=51, value, NULL)) 
            FROM 
              UNNEST(hits.customDimensions) 
            WHERE 
              value IN ("web", "phone", "tablet")
            ) IS NOT NULL 
     GROUP BY   
       iso_date, content_group, content_level
     ORDER BY 
       iso_date, content_group, content_level
    )   
GROUP BY iso_date, content_group, content_level
ORDER BY iso_date, content_group, content_level 

子选择中的 LEAD - OVER - PARTITION 和 WHERE 子句中的子子选择都是窗口函数正常工作所必需的。

还提供了一种更准确的会话计算方法。

【讨论】:

以上是关于Unnest 和 totals.timeOnSite(BigQuery 和 Google Analytics 数据)的主要内容,如果未能解决你的问题,请参考以下文章

使用 Psycopg2 和 unnest 时的“未知”数据类型

tidytext:unnest_tokens 和 token = 'ngrams' 的问题

Google BigQuery:UNNEST 结构数组和未嵌套项作为结构

Bigquery unnest 最小行数

Unnest 和 totals.timeOnSite(BigQuery 和 Google Analytics 数据)

查看 Google Analytics 时如何 UNNEST 和展平 BigQuery 中的所有记录