You need to enable JavaScript to run this app.
导航
路径分析函数
最近更新时间:2025.06.06 15:23:30首次发布时间:2025.06.06 15:23:30
我的收藏
有用
有用
无用
无用

本文介绍路径分析函数的基础概念和函数的基本用法。

功能概述

业务场景

路径分析函数适用于选定一段时间范围,分析此时间范围内用户行为路径,在前端展示效果大致如下:
Image
路径分析计算逻辑简介:

  • 先使用 pathSplit 生成每个用户所有的路径组合成的数组。
  • 再使用 **array join **将单个用户单行包含所有路径的二维数组展开成多行单个路径。
  • 再使用 pathCount 统计所有用户的路径转化情况。

基础概念

  • 事件(event):发生的事件,在此语境下,也指在路径分析图中展示的页面访问节点。
  • 属性(prop):相当于给对应事件打上 tag。
  • 层级(level):也可理解为图中的路径深度,超过 x 个节点截断路径。
  • 节点(node):在路径分析的语境下,每个节点即为一个页面。
  • 边(edge):页面 1 到页面 2 的访问路径。

函数释义

pathSplit()

使用 pathSplit 生成每个用户所有的路径组合成的数组。

pathSplit(session_time, level)(timestamp, event, prop)

Image
输入参数:

  • session_time:路径分析的时间窗口,单位和timestamp 保持一致,下例中为 600 秒,也即只计算首个event 发生后 10 分钟内形成的路径。
  • level:路径深度,超过 x 个节点截断路径。
  • timestamp:**时间戳 **所在列,需要先转换成时间戳,再转换成 Uint64 格式。
  • event:事件列,仅支持数值类型,需要通过 multiIf 显式指定。如下例中的:multiIf(EventName = 'E0001', 1, EventName = 'E0002', 2, EventName = 'E0003', 3, 0) AS e
  • prop:属性列,没有时传 '' 占位。

输出参数(中间结果):
返回二维数组:[(e1, p1), (e2, p2), (e1, p2)]

  • (ex,px):对应事件流,即此条path上发生的事件。
  • e:事件,对应event 列中 multiif定义的事件编号。
  • p:事件对应属性,对应prop

pathCount()

使用 **arrayjoin **将单个用户单行包含所有路径的二维数组展开成多行单个路径,然后再使用 pathCount 统计所有用户的路径转化情况。示例如下:

pathCount(y, x)(path, cnt1, cnt2)
SELECT pathCount(3, 3)(path, 1, cnt)
FROM
(
 SELECT
 path AS path, count() AS cnt
 FROM
 (
 SELECT arrayJoin(pathSplit(600, 3)(toUInt64(toUnixTimestamp(LOG.EventTime)), multiIf(EventName = 'E0001', 1, EventName = 'E0002', 2, EventName = 'E0004', 3, 0) AS e, '')) AS path
 FROM LOG
 WHERE (EventTime >= '2022-06-01 00:00:00') AND (EventTime < '2022-06-02 00:00:00') AND (EventName IN ('E0001', 'E0002', 'E0004')) AND (Visitor = 964049)
 GROUP BY Visitor
 )
 GROUP BY path
)

pathCount 返回界面展示需要的数据,x 表示横向的路径深度(如下图为 4 列),前端展示需要的数据是每个浅蓝色方块代表的 node 和浅蓝色方块之间的边 edge,二者均由 pathCount 输出。
Image

  • y纵向单层展示深度,如上图中黄色圈的部分,即 y = 5;
  • x横向路径深度,超过 x 个节点截断路径,如上图中 x = 4;
  • pathpathSplit的返回 path 列(需通过 arrayJoin 展开);
  • cnt1:路径权重 1,通常直接传 1 就行,用于计算路径去重后的次数;
  • cnt2:路径权重 2,通常传pathSplit子查询里的 count()求出的 cnt ,用来求路径不去重的总次数。

返回格式

  • 返回格式为 3 元组 ([node_index],[nodes], [edges]),通过此结果集组成一张页面路径转化的流图。
  • node_index:格式为:(event, prop) ,事件节点展示。
    • event 为事件的下标编号,若 之前 pathSplitevent写 multiIf(EventName = 'E0001', 1, EventName = 'E0002', 2, EventName = 'E0004', 3, 0),则此时返回 1 对应 'E0001' ,2对应 'E0002',3对应 'E0004';
    • prop为 pathSplit 传入的 prop。
  • nodes:二维数组。表示每个节点在各层级(level,下标从 0 开始)出现的去重次数、次数,格式为:(level, node_index, cnt1, cnt2)
    • level:当前节点所处的层级 ;
    • node_index:事件的 index,参考 node_index 数组中和事件的映射关系;
    • cnt1:节点访问的去重次数;
    • cnt2:节点访问的次数。
  • edge:二维数组,每条在各层级出现的去重次数、次数,格式为:(level, from_node_index, to_node_index, cnt1, cnt2)
    • level:层级,即输入的 x;
    • from_node_index:来源节点,参考 node_index 数组中和事件的映射关系;
    • to_node_index:目标节点,参考 node_index 数组中和事件的映射关系;to_node_index 用 65535 标记 from_node_index 已经是终点的情况,即用户进行到这个事件之后流失的情况;
    • cnt1:节点访问的去重次数;
    • cnt2:节点访问的次数。

使用示例

示例模型

如下示例用表是由用户行为事实表 Log 和用户维度表 User 组成常用的星型模型,后文将基于此表演示留存分析函数的具体用法。

CREATE TABLE -- 事件日志表
  default.LOG (
    `Visitor` UInt32,
    `EventName` String,
    `EventTime` DateTime,
    `Province` String,
    `City` String
  ) ENGINE = CnchMergeTree
  ORDER BY Visitor;
  
  CREATE TABLE -- 用户表
  default.User (
    `Visitor` UInt32,
    `Fvisit_Time` DateTime,
    `Fvisit_Province` String,
    `Fvisit_City` String
  ) ENGINE = CnchMergeTree
  ORDER BY Visitor;

页面路径分析

该示例指定一个用户 Visitor = 964049 来说明。
该示例为 2022/6/1-2022/6/2 中,发生 'E0001', 'E0002', 'E0004' 事件的路径数据,展示发生事件后 10 分钟内的页面信息,展示的页面路径深度为 3 层。
首先通过 pathSplit 计算中间结果:

SELECT Visitor,pathSplit(600, 3) (toUInt64(toUnixTimestamp(LOG.EventTime)), multiIf(EventName = 'E0001', 1, EventName = 'E0002', 2, EventName = 'E0004', 3, 0) AS e, '') AS path
FROM LOG
WHERE (EventTime >= '2022-06-01 00:00:00')
  AND (EventTime < '2022-06-02 00:00:00')
  AND (EventName IN ('E0001', 'E0002', 'E0004'))
  and Visitor = 964049
GROUP BY Visitor

--返回:
┌─Visitor─┬─path────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│  964049 │ [[(1,''),(2,''),(3,'')],[(1,'')],[(1,''),(2,''),(3,'')],[(1,''),(2,''),(2,'')],[(1,'')],[(1,'')],[(1,'')],[(1,''),(3,''),(3,'')],[(1,''),(2,''),(3,'')],[(1,''),(1,''),(3,'')],[(1,'')],[(1,''),(2,''),(3,'')],[(1,'')],[(1,''),(2,''),(2,'')]] │
└─────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

再通过 arrayJoin 把单行的 path 返回的二维数组表示的多条 path 展开成多行单条 path,计算每一条 path 出现的次数。

SELECT path    AS path,
             count() AS cnt
      FROM (SELECT arrayJoin(pathSplit(600, 3)(toUInt64(toUnixTimestamp(LOG.EventTime)), multiIf(EventName = 'E0001', 1, EventName = 'E0002', 2, EventName = 'E0004', 3, 0) AS e, '')) AS path
            FROM LOG
            WHERE (EventTime >= '2022-06-01 00:00:00')
              AND (EventTime < '2022-06-02 00:00:00')
              AND (EventName IN ('E0001', 'E0002', 'E0004'))
              and Visitor = 964049
            GROUP BY Visitor)
      GROUP BY path
 --返回
┌─path───────────────────┬─cnt─┐
│ [(1,'')]               │   6 │
│ [(1,''),(1,''),(3,'')] │   1 │
│ [(1,''),(2,''),(3,'')] │   4 │
│ [(1,''),(2,''),(2,'')] │   2 │
│ [(1,''),(3,''),(3,'')] │   1 │
└────────────────────────┴─────┘

再通过 pathCount 计算出最终的 3*3 结果(路径深度为 3,同时每层至多展示的节点为 3 个):

SELECT pathCount(3, 3) (path, 1, cnt)
FROM (SELECT path    AS path,
             count() AS cnt
      FROM (SELECT arrayJoin(pathSplit(600, 3)(toUInt64(toUnixTimestamp(LOG.EventTime)), multiIf(EventName = 'E0001', 1, EventName = 'E0002', 2, EventName = 'E0004', 3, 0) AS e, '')) AS path
            FROM LOG
            WHERE (EventTime >= '2022-06-01 00:00:00')
              AND (EventTime < '2022-06-02 00:00:00')
              AND (EventName IN ('E0001', 'E0002', 'E0004'))
              and Visitor = 964049
            GROUP BY Visitor)
      GROUP BY path )
--返回
┌─pathCount(5, 3)(path, 1, cnt)─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ([(1,''),(3,''),(2,'')],
[[0,0,5,14],[1,0,1,1],[1,1,1,1],[1,2,2,6],[2,1,3,6],[2,2,1,2]],
[[0,0,0,1,1],[0,0,1,1,1],[0,0,65535,1,6],[0,0,2,2,6],[1,2,2,1,2],[1,1,1,1,1],[1,0,1,1,1],[1,2,1,1,4]]) │
└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

结果为:

  • node_index:[(1,''),(3,''),(2,'')],表示事件编号映射为 0->1(E0001),1->3(E0004),2->2(E0002)

  • nodes:[[0,0,5,14],[1,0,1,1],[1,1,1,1],[1,2,2,6],[2,1,3,6],[2,2,1,2]]

    • 第 1 层,[0,0,5,14]
      • 仅一个节点“事件 1”,即 E0001;
      • 该节点的去重访问次数为 5,总访问次数为 14。
    • 第 2 层,[1,0,1,1],[1,1,1,1],[1,2,2,6]
      • 发生了三个事件:E0001,E0004,E0002
      • 3个节点的去重访问次数为 1,1,2;总访问次数为 1,1,6
    • ....
  • edge:[0,0,0,1,1],[0,0,1,1,1],[0,0,65535,1,6],[0,0,2,2,6],[1,2,2,1,2],[1,1,1,1,1],[1,0,1,1,1],[1,2,1,1,4]

    • 第一层,存在以下几条边:
      • 0->0:即 'E0001'->'E0001',1 个访问;
      • 0->1:1 个访问;
      • 0->65535(即已经是终点),1个去重访问;
      • 0->2,2个去重访问。
    • 第二层,存在以下几条边:
      • 2->2,1 个去重访问;
      • 1->1,1 个去重访问;
      • 0->1,1 个去重访问;
      • 2->1,1 个去重访问。

    可以将结果信息补充为页面路径分析,如
    Image