假设我跟踪用户在网站上的"事件",事件可以是这样的:
- 已查看主页
- 已将商品添加到购物车
- 收款处
- 已支付订单
现在,这些事件中的每一个都存储在数据库中,如下所示:
session_id event_name created_date..
所以现在我想构建一个报告来显示我将定义的特定漏斗,如下所示:
Step#1 event_n
Step#2 event_n2
Step#3 event_n3
因此,这个特定的漏斗有 3 个步骤,每个步骤都与任何事件相关联。
鉴于我拥有的上述数据,我现在如何为此构建报告?
注意:只是想清楚一点,我希望能够创建我定义的任何漏斗,并能够为其创建报告。
我能想到的最基本的方法是:
- 获取数据库中每个步骤的所有事件
- 步骤#1将是,x%的人执行event_n
- 现在我将不得不查询步骤#2的数据,他也执行了步骤#1,并显示% 与#3
- 相同,但步骤#3的条件为步骤#2
我很好奇这些在线服务如何在托管的 Saas 环境中显示这些类型的报告。 map-reduce会以某种方式使这变得更容易吗?
首先,根据假设,使用标准SQL给出答案:有一个表
事件,布局简单:EVENTS
-----------------------------
SESION_ID , EVENT_NAME , TMST
要获取在某个时间执行步骤 #1 的会话,请执行以下操作:
-- QUERY 1
SELECT SESSION_ID,MIN(TMST) FROM EVENTS WHERE EVENT_NAME='event1' GROUP BY SESSION_ID;
在这里,我假设事件 1 在每个会话中可以发生一次以上。结果是某个时间演示 event1 的唯一会话列表。
为了获得步骤2和步骤3,我可以做同样的事情:
-- QUERY 2
SELECT SESSION_ID,MIN(TMST) FROM EVENTS WHERE EVENT_NAME='event2' GROUP BY SESSION_ID;
-- QUERY 3
SELECT SESSION_ID,MIN(TMST) FROM EVENTS WHERE EVENT_NAME='event3' GROUP BY SESSION_ID;
现在,您要按该顺序选择执行步骤 1、步骤 2 和步骤 3 的会话。更准确地说,您需要对执行步骤 1 的会话进行计数,然后对执行步骤 2 的会话进行计数,然后对执行步骤 3 的会话进行计数。基本上,我们只需要将上述 3 个查询与左联接相结合,即可列出进入漏斗的会话以及它们执行的步骤:
-- FUNNEL FOR S1/S2/S3
SELECT
SESSION_ID,
Q1.TMST IS NOT NULL AS PERFORMED_STEP1,
Q2.TMST IS NOT NULL AS PERFORMED_STEP2,
Q3.TMST IS NOT NULL AS PERFORMED_STEP3
FROM
-- QUERY 1
(SELECT SESSION_ID,MIN(TMST) FROM EVENTS WHERE EVENT_NAME='event1' GROUP BY SESSION_ID) AS Q1,
LEFT JOIN
-- QUERY 2
(SELECT SESSION_ID,MIN(TMST) FROM EVENTS WHERE EVENT_NAME='event2' GROUP BY SESSION_ID) AS Q2,
LEFT JOIN
-- QUERY 3
(SELECT SESSION_ID,MIN(TMST) FROM EVENTS WHERE EVENT_NAME='event2' GROUP BY SESSION_ID) AS Q3
-- Q2 & Q3
ON Q2.SESSION_ID=Q3.SESSION_ID AND Q2.TMST<Q3.TMST
-- Q1 & Q2
ON Q1.SESSION_ID=Q2.SESSION_ID AND Q1.TMST<Q2.TMST
结果是在步骤 1 进入漏斗的唯一会话列表,并且可能继续步骤 2 和步骤 3...例如:
SESSION_ID_1,TRUE,TRUE,TRUE
SESSION_ID_2,TRUE,TRUE,FALSE
SESSION_ID_3,TRUE,FALSE,FALSE
...
现在我们只需要计算一些统计数据,例如:
SELECT
STEP1_COUNT,
STEP1_COUNT-STEP2_COUNT AS EXIT_AFTER_STEP1,
STEP2_COUNT*100.0/STEP1_COUNT AS PERCENTAGE_TO_STEP2,
STEP2_COUNT-STEP3_COUNT AS EXIT_AFTER_STEP2,
STEP3_COUNT*100.0/STEP2_COUNT AS PERCENTAGE_TO_STEP3,
STEP3_COUNT*100.0/STEP1_COUNT AS COMPLETION_RATE
FROM
(-- QUERY TO COUNT session at each step
SELECT
SUM(CASE WHEN PERFORMED_STEP1 THEN 1 ELSE 0 END) AS STEP1_COUNT,
SUM(CASE WHEN PERFORMED_STEP2 THEN 1 ELSE 0 END) AS STEP2_COUNT,
SUM(CASE WHEN PERFORMED_STEP3 THEN 1 ELSE 0 END) AS STEP3_COUNT
FROM
[... insert the funnel query here ...]
) AS COMPUTE_STEPS
瞧!
现在进行讨论。第一点,结果非常简单,因为你采取"集合"(或功能(思维方式而不是"程序"方法。不要将数据库可视化为包含列和行的固定表的集合...这就是它的实现方式,但这不是您与之交互的方式。都是布景,你可以按照你需要的方式安排布景!
第二点,例如,如果您使用的是 MPP 数据库,则查询将自动优化为并行运行。您甚至不需要以不同的方式对查询进行编程,使用map-reduce或其他方法...我在测试数据集上运行了相同的查询,其中包含超过 1 亿个事件,并在几秒钟内获得结果。
最后但并非最不重要的一点是,查询开启了无限的可能性。例如,只需按推荐人、关键字、登陆页面、用户信息对结果进行分组,并分析哪个提供最佳转化率!
您思考这个问题的方式的核心问题是您在 SQL/表类型模型中思考。每个事件都是一条记录。NoSQL技术的一个好处(你觉得有点暗示(是,你可以自然地将记录存储为每个记录的一个会话。以基于会话的方式存储数据后,可以编写一个例程来检查该会话是否符合模式。无需执行联接或任何操作,只需循环访问会话中的事务列表即可。这就是半结构化数据的力量。
如果将会话存储在一起会怎样?然后,您所要做的就是遍历每个会话,看看它是否匹配。
在我看来,这是HBase的一个很棒的用例。
使用 HBase,可以将会话 ID 存储为行键,然后将每个事件存储为值,并将时间戳存储为列限定符。这留给您的是按会话 ID 分组在一起的数据,然后按时间排序。
好的,所以现在你想弄清楚有多少百分比的会话制定了行为 1,然后是 2,然后是 3。你对这些数据运行一个MapReduce作业。MapReduce作业将为每行键/值对提供一个会话。对数据进行循环,以检查它是否与模式匹配。如果它确实计数 + 1,如果不是,则不要。
无需全力以赴使用HBase,您可以使用MapReduce对静态无组织数据进行会话化。 按会话 ID 分组,然后在化简器中将与该会话关联的所有事件分组在一起。现在,您基本上处于HBase的位置,您可以在化简器中编写一个检查模式的方法。
如果您没有大量的数据,HBase 可能会矫枉过正。在这种情况下,任何类型的可以分层存储数据的数据库都是好的。MongoDB,Cassandra,Redis都会浮现在脑海中,并有其优点和缺点。
我最近发布了一个开源的Hive UDF来做到这一点:Hive-funnel-udf
用于这种漏斗分析任务非常简单,您只需编写Hive,而无需编写自定义Java MapReduce代码。
这只有在使用Hive/Hadoop来存储和查询数据时才有效。