在 Google BigQuery 中查找用户的旅程
Posted
技术标签:
【中文标题】在 Google BigQuery 中查找用户的旅程【英文标题】:Finding the journey made by users in Google BigQuery 【发布时间】:2018-08-03 08:58:59 【问题描述】:我正在寻找用户在特定网站上的旅程。我的数据集的架构与 Google Merchandise Store 相同,可以在这里找到:https://support.google.com/analytics/answer/3437719?hl=en
根据 Google BigQuery 食谱,我实施并修改了提供的 SQL 代码,以获取每位客户的点击序列。
SELECT
fullVisitorId AS id,
visitId AS visitid,
visitNumber AS visitnumber,
h.hitNumber AS hitNumber,
CASE
WHEN h.eventInfo.eventAction = "Lead" THEN "Lead"
WHEN h.eventInfo.eventAction = "Homepage" THEN "Homepage"
WHEN h.eventInfo.eventAction = "Search" THEN "Search"
WHEN h.eventInfo.eventAction = "High Intent Use" THEN "High Intent Use"
WHEN h.eventInfo.eventAction = "Listing Page" THEN "Listing Page"
END AS journey
FROM
`dataset`,
UNNEST(hits) AS h
WHERE
h.type="PAGE"
OR h.type="EVENT"
ORDER BY
fullVisitorId,
visitId,
visitNumber,
hitNumber
我得到的一个sn-p结果如下:
fullVisitorId visitId visitNumber hitnumber journey
001 1001 1 1 Homepage
001 1001 1 2 Search
001 1001 1 3 null
001 1001 1 4 Search
001 1001 1 5 Listing Page
001 1001 1 6 Lead
001 1001 1 2 Search
001 1001 1 7 Lead
002 1002 1 1 Search
...
我需要的是另一列显示每个访问者在第一个“Lead”之前所经历的旅程,同时忽略重复项(例如,如果访问者连续搜索 5 页,则旅程应该只显示“搜索”一次) IE。对于访问 1001 的访问者 001,该列将显示:
Homepage -> Search -> Listing Page -> Lead
我希望问题很清楚。感谢提供的任何帮助! :)
【问题讨论】:
这是一个类似的问题:***.com/questions/54196418/… 【参考方案1】:以下适用于 BigQuery 标准 SQL,并将额外逻辑应用于您现有/当前的查询
#standardSQL
SELECT
fullVisitorId, visitId,
STRING_AGG(journey, ' -> ' ORDER BY visitNumber, hitnumber) journey_path
FROM (
SELECT
fullVisitorId, visitId,
MIN(visitNumber) visitNumber, MIN(hitnumber) hitnumber, journey
FROM (
SELECT *, COUNTIF(journey = 'Lead') OVER(win) grp
FROM `your_current_query`
WINDOW win AS (
PARTITION BY fullVisitorId, visitId
ORDER BY visitNumber, hitnumber
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
)
)
WHERE grp = 0
GROUP BY fullVisitorId, visitId, journey
)
GROUP BY fullVisitorId, visitId
所以你可以使用你现有的查询如下
#standardSQL
WITH `your_current_query` AS (
SELECT
fullVisitorId AS id,
visitId AS visitid,
visitNumber AS visitnumber,
h.hitNumber AS hitNumber,
CASE
WHEN h.eventInfo.eventAction = "Lead" THEN "Lead"
WHEN h.eventInfo.eventAction = "Homepage" THEN "Homepage"
WHEN h.eventInfo.eventAction = "Search" THEN "Search"
WHEN h.eventInfo.eventAction = "High Intent Use" THEN "High Intent Use"
WHEN h.eventInfo.eventAction = "Listing Page" THEN "Listing Page"
END AS journey
FROM
`dataset`,
UNNEST(hits) AS h
WHERE
h.type="PAGE"
OR h.type="EVENT"
)
SELECT
fullVisitorId, visitId,
STRING_AGG(journey, ' -> ' ORDER BY visitNumber, hitnumber) journey_path
FROM (
SELECT
fullVisitorId, visitId,
MIN(visitNumber) visitNumber, MIN(hitnumber) hitnumber, journey
FROM (
SELECT *, COUNTIF(journey = 'Lead') OVER(win) grp
FROM `your_current_query`
WINDOW win AS (
PARTITION BY fullVisitorId, visitId
ORDER BY visitNumber, hitnumber
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
)
)
WHERE grp = 0
GROUP BY fullVisitorId, visitId, journey
)
GROUP BY fullVisitorId, visitId
--- ORDER BY fullVisitorId, visitId
如果按照你的结果示例 - 上面应该产生下面的结果
Row fullVisitorId visitId journey_path
1 001 1001 Homepage -> Search -> Listing Page -> Lead
2 002 1002 Search
【讨论】:
嗨@mikhail,谢谢你的回答!你能解释一下 'COUNTIF(journey = 'Lead') OVER(win) grp' 的作用以及为什么要过滤 'grp = 0' 吗? 啊,好吧,我玩弄了这个查询,发现 'grp = 0' 捕获了第一个领先之前的所有命中。总是从你那里学到新东西@Mikhail!谢谢你:) 当然。正确的。这是在每个“线索”之前对所有事件进行分组。因为您只想在第一次领先之前有事件 - 'grp = 0' 正是这样做的。很高兴你自己得到了这个:o)【参考方案2】:我建议使用STRING_AGG 来制作一系列旅程步骤,将 DISTINCT 添加到您的选择中只会为每个用户显示一次单独的旅程步骤。
类似:
STRING_AGG(DISTINCT(journey), '->') as propensity_banding_subset
然后您可以使用一些正则表达式在第一个“引导”之后进行剪辑,除非有人可以建议在原始字符串聚合中执行此操作的更好方法?
【讨论】:
啊啊啊谢谢@Ben,这帮助我进入了下一步! :) 我正在考虑将 strpos() 与其他函数(可能是 substr())结合起来进行剪辑。如果我设法得到结果,将再次在这里更新。STRING_AGG
与 DISTINCT
一起不能保证正确的顺序:使用 DISTINCT
您只能使用 ORDER BY journey
- 不能使用 hitNumber
- 但如果没有 ORDER BY
则无法保证顺序.【参考方案3】:
我采用了 Mikhails 的出色方法,并为拥有大量数据的用户提供了更具可扩展性的版本。这个想法是一样的,但应用于 hits 数组的子查询。
SELECT
fullVisitorId AS id,
visitId AS visitid,
visitNumber AS visitnumber,
ARRAY(
(SELECT AS STRUCT *
FROM
(SELECT AS STRUCT
hitNumber,
page.pagePath, -- pagePath instead of CASE-WHEN with events
count(page.pagePath) over (win) elNumber
FROM t.hits
WHERE type IN ('PAGE', 'EVENT')
WINDOW win AS (
PARTITION BY page.pagePath
ORDER BY hitnumber
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
)
ORDER BY hitNumber)
WHERE elNumber=0
-- instead of 'Lead' I used '/signin.html'
AND hitNumber < (SELECT MIN(hitNumber) FROM t.hits WHERE page.pagePath='/signin.html')
)
) AS journey
FROM
`bigquery-public-data.google_analytics_sample.ga_sessions_20170801` t
limit 1000
我使用了实际的示例数据,但在该示例中找不到事件,因此我只使用了页面路径。但它应该很容易被采用。
同样,这个返回嵌套数据,而不是平面表,这在将结果保存为表时再次节省空间,并且在对其执行查询时更快。
也没有涉及分组 - 子查询中的所有事情都只发生在数组上,由于并行化允许非常快速的处理。
【讨论】:
以上是关于在 Google BigQuery 中查找用户的旅程的主要内容,如果未能解决你的问题,请参考以下文章
如何优化 google-bigquery 以从大数据表中查找最常见的类别?
NOT IN 不能在 google BigQuery 标准 sql 中工作
在 Google 表格中使用 BigQuery,如何授予其他用户按“刷新”的权限?
如何使用 Bigquery 在 Google Bigquery 中进行身份验证,而无需使用服务帐户进行用户输入