【问题标题】:How to use SQL to attribute events to visit source in traffic logs?如何在流量日志中使用 SQL 将事件归因于访问源?
【发布时间】:2015-09-25 17:17:05
【问题描述】:

我正在尝试将事件归因于流量日志中的来源。对于任何半精明的技术营销人员或网站管理员来说,这似乎是相当基本的领域,但我已经在 Google 上搜索了一下,令人惊讶的是,似乎没有人涉及到这一点。

背景:我正在使用 T-SQL,我们在 SQL Server 2016 上运行。我的事件日志(HAProxy)看起来像这样,其中RefererHost'%mysite%' 用于内部推荐,但可以是其他任何外部推荐(入口)。

User Agent ||     IP     ||  RefererHost ||     Event     ||   CreationDate
------------------------------------------------------------------------------
qwertyuiop || 99.99.99.9 ||   google.com ||   Home/View   || 2015-05-29 00:00:25
------------------------------------------------------------------------------
qwertyuiop || 99.99.99.9 ||   mysite/x   ||   Home/View   || 2015-05-29 00:00:27
------------------------------------------------------------------------------
abcdefghij || 11.11.11.1 ||   yahoo.com  ||   Home/View   || 2015-05-29 00:00:49
------------------------------------------------------------------------------
qwertyuiop || 99.99.99.9 ||   mysite/y   ||     Submit    || 2015-05-29 00:01:28
------------------------------------------------------------------------------
abcdefghij || 11.11.11.1 ||   mysite/p   ||   Photo/View  || 2015-05-29 00:02:04
------------------------------------------------------------------------------
abcdefghij || 11.11.11.1 ||   mysite/n   ||     Submit    || 2015-05-29 00:02:09

目标:我试图将所有Submit 事件与其入口相关联。汇总后,结果将如下所示:

RefererHost || SubmitCount  ||
------------------------------
google.com  ||      1       || 
yahoo.com   ||      1       || 

复杂因素:但这是一个非常简单的例子。事实上,单个用户每个周期可以访问多次,并且每次访问(会话)可以多次Submit。此外,用户可能会在进入后长时间处于空闲状态:Submit 可能会在进入后数小时出现。

所以我认为我想要做的是选择所有CreationDates,其中Event = Submit,以及用户(IP + UA 校验和),然后找到最近的先前事件其中 = RefererHost 不是'%mysite%',并将其存储在与Submit 事件相关的某个位置。然后我可以对Submit 事件进行计数,按RefererHost 分组,以获得我要查找的内容。

这种方法对我来说有点意义,但我不知道如何编写一个“回溯”以查找最近的先前引用者的查询。另外,我不确定单独的 SQL 是否可以在操作超时的情况下处理这个问题。而且我不确定我是否缺少边缘案例。以前有人做过这样的事吗?

【问题讨论】:

  • 使用您的样本数据的预期结果是什么
  • @wewestthemenace 添加。感谢您的关注。
  • 在 SQL 2012 或更高版本中,您需要 LAG 函数。

标签: sql tsql haproxy referer sql-server-2016


【解决方案1】:

如果您使用的是具有窗口函数的数据库,则可以通过相当短的查询来完成此操作。如果您想对实时数据进行修改,您还可以查看此查询的工作示例(带有一些虚拟数据):https://modeanalytics.com/benn/reports/9f72b24dce58/query

其中的每个步骤都被分解为一个公用表表达式。虽然这样更容易描述,但如果您更喜欢这种风格,则可以将查询编写为一系列子查询。

第 1 步:我做了你的桌子。

WITH event_table AS (
    SELECT user_id AS dummy_ip,
           occurred_at,
           location AS dummy_referer,
           event_name
      FROM tutorial.playbook_events 
)

我的示例数据并未完全映射到您的示例,但这会创建一个大致相同的表。我将user_id 映射到ip_address,因为这两个字段在概念上是相同的。 locationreferer 彼此完全没有关系,但它们都是与每个事件相关的事件属性。我的数据中有一个location 字段,所以我选择了它。我猜,可以把它想象成物理引用或其他东西。

第 2 步:确定自上次事件以来的时间。

with_last_event AS (
    SELECT *,
           LAG(occurred_at,1) OVER (PARTITION BY dummy_ip ORDER BY occurred_at) AS last_event
      FROM event_table
)

此处的 LAG 函数查找该 IP 上最后一个事件的时间。如果没有最后一个事件,则为空。

第 3 步:找出哪些事件标志着新会话的开始。

with_new_session_flag AS (
    SELECT *,
           CASE WHEN EXTRACT('EPOCH' FROM occurred_at) - EXTRACT('EPOCH' FROM last_event) >= (60 * 10) OR last_event IS NULL 
                THEN 1 ELSE 0 END AS is_new_session,
           CASE WHEN EXTRACT('EPOCH' FROM occurred_at) - EXTRACT('EPOCH' FROM last_event) >= (60 * 10) OR last_event IS NULL 
                THEN dummy_referer ELSE NULL END AS first_referer
      FROM with_last_event
)

大多数平台将新会话定义为一段时间不活动后的操作。第一个 case 语句通过查找距离上一个事件已经过去了多长时间来做到这一点。如果它长于您选择的时间(在本例中为 60 秒 * 10,即 10 分钟),那么该事件将被标记为新会话中的第一个事件。它用 1 标记;非第一个事件用 0 标记。

第二个 case 语句找到相同的事件,但不是用 1 标记该事件以将其标记为新会话,而是返回引用者。如果不是新会话,则返回null

第 4 步:创建会话 ID。

with_session_ids AS (
    SELECT *,
           SUM(is_new_session) OVER (ORDER BY dummy_ip, occurred_at) AS global_session_id,
           SUM(is_new_session) OVER (PARTITION BY dummy_ip ORDER BY occurred_at) AS user_session_id
      FROM with_new_session_flag
)

这些窗口函数生成会话标志的运行总数(当它是新会话时该列为 1,当它不是新会话时为 0)。结果是一列在会话未更改时保持不变,并在每次新会话开始时递增 1。根据您对该窗口函数的分区和排序方式,您可以创建对该用户唯一且全局唯一的会话 ID。

第 5 步:查找原始会话引用者。

with_session_referer AS (
    SELECT *,
           MAX(first_referer) OVER (PARTITION BY global_session_id) AS session_referer
      FROM with_session_ids
)

这个最终的窗口函数为global_session_id 查找first_refererMAX 值。由于对于该会话的第一个事件以外的每个值,该列都设置为 null,因此这将为该会话中的每个事件返回该会话的 first_referer

第 6 步:数一些东西。

SELECT session_referer,
       COUNT(1) AS total_events,
       COUNT(DISTINCT global_session_id) AS distinct_sessions,
       COUNT(DISTINCT dummy_ip) AS distinct_ips
  FROM with_session_referer
 WHERE event_name = 'send_message'
 GROUP BY 1

最后一步很简单 - 将您的事件过滤为仅您关心的事件(Submit,在您的示例中)。然后按session_referer 计算事件数,这是发生该事件的会话的第一个引用者。通过计算global_session_iddummy_ip,您还可以了解会话是如何发生该事件的,以及有多少不同的 IP 记录了该事件。

【讨论】:

  • 执行此操作的过程主要遵循 blog post 关于使用 SQL 定义用户会话的过程,尽管针对此特定情况进行了一些修改。
猜你喜欢
  • 2014-12-25
  • 2010-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-08
  • 1970-01-01
相关资源
最近更新 更多