在 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_AGGDISTINCT 一起不能保证正确的顺序:使用 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 中进行身份验证,而无需使用服务帐户进行用户输入

如何在 Google BigQuery 中设置用户的查询配额

Bigquery 和 Google Adwords(添加):国家/地区标签