Clickhouse(流量分析(一).漏斗分析案例)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Clickhouse(流量分析(一).漏斗分析案例)相关的知识,希望对你有一定的参考价值。

参考技术A 神策用户分析模型——漏斗分析的使用方法

Clickhouse数据模型之有序漏斗分析

Hologres漏斗分析函数

Java UDF StarRocks Docs

window — 滑动窗户的大小,单位是秒。
mode - 这是一个可选的参数。
‘strict’ - 当 ‘strict’ 设置时,windowFunnel()仅对唯一值应用匹配条件。
timestamp — 包含时间的列。 数据类型支持: 日期, 日期时间 和其他无符号整数类型(请注意,即使时间戳支持 UInt64 类型,它的值不能超过Int64最大值,即2^63-1)。
cond — 事件链的约束条件。 UInt8 类型。

如果数据在不同的完成点具有多个事件链,则该函数将仅输出最长链的大小

ClickHouse数组函数

漏斗分析模型

分析"2022-01-02"这天 路径为“浏览->点击->下单->支付”的转化情况

这个函数看起来很强大,但是少了点什么,我理解的流量分析滑动窗口不太一样

痛点:很显然,如果数据量超过100亿往上,clickhouse大概就拉了,比较好的方法还是结合bitmap进行编码,这里有篇文章可以参考一下的

每天数百亿用户行为数据,美团点评怎么实现秒级转化分析?

neighbor
uniqCombined | ClickHouse Docs
housepower/olap2018: 易观第二届OLAP漏斗算法大赛

上面这种是这样的,如果一个uid路径是4层,那么他可能走了第一层,着看产品的口径了,如果只算走了第一步的是1,走了四步的只算作4,那么就是上面这种口径

groupArray | ClickHouse Docs
Array Functions | ClickHouse Docs
Clickhouse中的Array类型

ClickHouse中如何实现漏斗分析

【中文标题】ClickHouse中如何实现漏斗分析【英文标题】:How to realize funnel analysis in ClickHouse 【发布时间】:2021-03-17 06:19:36 【问题描述】:

我想根据存储在 ClickHouse 中的埋点数据进行漏斗分析。让我们为漏斗分析定义一些元素:

    一系列事件:A (event_id = 1) -> B (event_id = 2) -> C (event_id = 3)

    时间段:0 (event_ms) ~ 500 (event_ms)

    时间窗口:100 (event_ms)

我想知道,对于每个用户,在时间段内是否发生了一系列事件(A->B->C),并且A和C之间的间隔在时间窗口内。

这是我的测试数据集:

CREATE TABLE test_dataset
(
    `event_id` UInt64,
    `event_ms` UInt64,
    `uid` UInt64 // user_id
)
ENGINE = AggregatingMergeTree
PARTITION BY toYYYYMMDD(toDate(event_ms))
ORDER BY (event_id, event_ms,uid)
SETTINGS index_granularity = 8192;

INSERT INTO TABLE test_dataset VALUES 
      (1, 100, 123), 
      (1, 120, 123), 
      (1, 130, 123), 
      (1, 150, 345), 
      (1, 180, 345), 
      (2, 150, 123), 
      (2, 200, 234), 
      (2, 140, 345),
      (2, 210, 345),
      (2, 300, 345),
      (3, 180, 123),
      (3, 250, 123),
      (3, 290, 234),
      (3, 270, 345);

我使用join 查找所有符合条件的事件系列:

SELECT
    t1.event_ms, t2.event_ms, t3.event_ms, t4.event_ms,
    t1.uid, t2.uid, t3.uid, t4.uid
FROM
(SELECT 
    uid, event_ms 
FROM funnel_join_test_1
WHERE
    event_id = 1 AND event_ms >= 0 AND event_ms <= 500) as t1
ASOF left join
(SELECT 
    uid, event_ms 
FROM funnel_join_test_1
WHERE
    event_id = 2 AND event_ms >= 0 AND event_ms <= 500) as t2
ON t1.uid = t2.uid AND t1.event_ms  < t2.event_ms
ASOF left join
(SELECT 
    uid, event_ms 
FROM funnel_join_test_1
WHERE
    event_id = 3 AND event_ms >= 0 and event_ms <= 500) as t3
ON t2.uid = t3.uid and t2.event_ms < t3.event_ms
ASOF left join
(SELECT 
    uid, event_ms 
FROM funnel_join_test_1
WHERE
    event_id = 3 AND event_ms >= 0 and event_ms <= 500) as t4
ON t3.uid = t4.uid and t4.event_ms < t1.event_ms + 100
WHERE t4.event_ms > 0;

以下是所有合格的系列活动:

┌─t1.event_ms─┬─t2.event_ms─┬─t3.event_ms─┬─t4.event_ms─┬─t1.uid─┬─t2.uid─┬─t3.uid─┬─t4.uid─┐
│         180 │         210 │         270 │         270 │    345 │    345 │    345 │    345 │
└─────────────┴─────────────┴─────────────┴─────────────┴────────┴────────┴────────┴────────┘
┌─t1.event_ms─┬─t2.event_ms─┬─t3.event_ms─┬─t4.event_ms─┬─t1.uid─┬─t2.uid─┬─t3.uid─┬─t4.uid─┐
│         120 │         150 │         180 │         180 │    123 │    123 │    123 │    123 │
└─────────────┴─────────────┴─────────────┴─────────────┴────────┴────────┴────────┴────────┘
┌─t1.event_ms─┬─t2.event_ms─┬─t3.event_ms─┬─t4.event_ms─┬─t1.uid─┬─t2.uid─┬─t3.uid─┬─t4.uid─┐
│         130 │         150 │         180 │         180 │    123 │    123 │    123 │    123 │
└─────────────┴─────────────┴─────────────┴─────────────┴────────┴────────┴────────┴────────┘
┌─t1.event_ms─┬─t2.event_ms─┬─t3.event_ms─┬─t4.event_ms─┬─t1.uid─┬─t2.uid─┬─t3.uid─┬─t4.uid─┐
│         100 │         150 │         180 │         180 │    123 │    123 │    123 │    123 │
└─────────────┴─────────────┴─────────────┴─────────────┴────────┴────────┴────────┴────────┘

然后我知道用户 123 和 345 在该时间段内有这样的事件系列。在 ClickHouse 中使用 join 很慢,有没有其他方法可以解决这个问题?

顺便说一句,我不需要知道所有合格的系列,我只想知道每个用户是否有一个这样的事件系列。

【问题讨论】:

【参考方案1】:

有函数windowFunnel在滑动窗口中搜索事件链。

SELECT
    uid,
    windowFunnel(100)(event_ms, event_id = 1, event_id = 2, event_id = 3) AS chain_len
FROM test_dataset
WHERE (event_ms > 0) AND (event_ms < 500)
GROUP BY uid;

结果:

┌─uid─┬─chain_len─┐
│ 234 │         0 │
│ 345 │         3 │
│ 123 │         3 │
└─────┴───────────┘

它返回匹配的链长度,因此对于用户345123,我们有3,这意味着整个链都匹配。

如果我们将window 减少到10,它将仅找到链的开头并且由于条件timestamp of event 2 &lt;= timestamp of event 1 + window 不成立而与其他事件不匹配。

SELECT
    uid,
    windowFunnel(10)(event_ms, event_id = 1, event_id = 2, event_id = 3) AS chain_len
FROM test_dataset
WHERE (event_ms > 0) AND (event_ms < 500)
GROUP BY uid

结果:

┌─uid─┬─chain_len─┐
│ 234 │         0 │
│ 345 │         1 │
│ 123 │         1 │
└─────┴───────────┘

因此,要检查用户是否存在这样的链,您可以检查 windowFunnel 是否匹配适当数量的事件。

时间间隔限制(时间段:0(event_ms)~500(event_ms)),在WHERE子句中简单处理。

添加更多非周期事件:

INSERT INTO TABLE test_dataset VALUES (1, 600, 234), (2, 601, 234), (3, 602, 234);

然后检查:

SELECT
    uid,
    windowFunnel(100)(event_ms, event_id = 1, event_id = 2, event_id = 3) AS chain_len
FROM test_dataset
WHERE (event_ms > 0) AND (event_ms < 500)
GROUP BY uid

结果:

┌─uid─┬─chain_len─┐
│ 234 │         0 │
│ 345 │         3 │
│ 123 │         3 │
└─────┴───────────┘

没有WHERE

SELECT
    uid,
    windowFunnel(100)(event_ms, event_id = 1, event_id = 2, event_id = 3) AS chain_len
FROM test_dataset
GROUP BY uid

结果:

┌─uid─┬─chain_len─┐
│ 234 │         3 │
│ 345 │         3 │
│ 123 │         3 │
└─────┴───────────┘

【讨论】:

嗨@vdimir,感谢您的建议!我也发现了这个函数,但似乎它有一个关于重复时间戳的错误,请参阅更详细的描述here,您对此有什么想法吗?

以上是关于Clickhouse(流量分析(一).漏斗分析案例)的主要内容,如果未能解决你的问题,请参考以下文章

ClickHouse中如何实现漏斗分析

Clickhouse(流量分析(二).留存分析案例)

用户行为分析模型实践—— 漏斗分析模型

十大互联网数据分析方法之-漏斗分析

漏斗思维

2.3.7Google Analytics高级应用——漏斗转化