提取session内有效访问路径

背景

用户访问APP内页面的顺序是不固定的,为了专注于研究用户转化,只需要研究符合正常产品流程的用户行为即可,则需要对用户的操作日志记录做清洗,只保留符合产品使用流程的访问记录。

规定用户的访问1->2->3->4->5是有效的,则实际记录1->2->3->3->2中1->2->3->3是有效的,最后的2则剔除,只保留1->2->3->3。
问题一:得到规定的访问序列
问题二:根据规定的访问序列提取有效访问记录
实际业务中,页面不只是一级页面,还有二级页面,同时二级页面还有顺序,相当于是一个树的结构

问题一:得到规定的访问序列

原始数据配置如下

WITH event_road AS (
    /* 模拟步骤mapping数据 */
    SELECT 'page1' AS event_key, 1 AS event_id, 0 AS p_event_id, 0 AS group_id
    UNION ALL
    SELECT 'page2' AS event_key, 2 AS event_id, 0 AS p_event_id, 0 AS group_id
    UNION ALL
    SELECT 'page2-1-1' AS event_key, 3 AS event_id, 2 AS p_event_id, 1 AS group_id
    UNION ALL
    SELECT 'page2-1-2' AS event_key, 4 AS event_id, 2 AS p_event_id, 1 AS group_id
    UNION ALL
    SELECT 'page2-2-1' AS event_key, 5 AS event_id, 2 AS p_event_id, 2 AS group_id
    UNION ALL
    SELECT 'page2-2-2' AS event_key, 6 AS event_id, 2 AS p_event_id, 2 AS group_id
    UNION ALL
    SELECT 'page3' AS event_key, 7 AS event_id, 0 AS p_event_id, 0 AS group_id
    UNION ALL
    SELECT 'page4' AS event_key, 8 AS event_id, 0 AS p_event_id, 0 AS group_id
    UNION ALL
    SELECT 'page5' AS event_key, 9 AS event_id, 0 AS p_event_id, 0 AS group_id
)
SELECT * FROM event_road

图一

event_id有顺序的含义,p_event_id为二级页面独有,值为上一级页面的event_id,group_id为二级页面的组号,此表规定的正确路径有3条,分别两个二级的1->2->3->41->2->5->6和一个一级的1->2->7->8->9

SELECT
    string_to_array(
        CASE
            WHEN p1.event_id_str IS NOT NULL THEN p1.event_id_str || ',' || p0.event_id_str
        ELSE
            p0.event_id_str
        END,',') AS event_id_seq
FROM
    (
        SELECT
            p_event_id,
            event_id_str
        FROM
            (
                SELECT
                    p_event_id,
                    group_id,
                    string_agg (event_id, ',' ORDER BY event_id) AS event_id_str
                FROM
                    event_road
                GROUP BY
                    p_event_id,
                    group_id
            ) m0
        GROUP BY
            p_event_id,
            event_id_str
    ) p0
LEFT JOIN 
(
    /* 找到一级步骤到二级步骤的分叉点 */
    SELECT
        t1.p_event_id,
        string_agg (
            t0.event_id,
            ','
        ORDER BY
            t0.event_id
        ) AS event_id_str
    FROM
        (
            /* 一级步骤 */
            SELECT
                *
            FROM
                event_road
            WHERE
                p_event_id = 0
        ) t0
    JOIN 
    (
        /* 二级步骤 */
        SELECT
            p_event_id,
            MIN (event_id) AS min_event_id
        FROM
            event_road
        WHERE
            p_event_id != 0
        GROUP BY
            p_event_id
    ) t1 ON t0.event_id <= t1.min_event_id
    GROUP BY
        t1.p_event_id
) p1 ON p0.p_event_id = p1.p_event_id
图二

问题二:根据规定的访问序列提取有效访问记录

用户的访问记录如下:

/*
session_id
访问序号:session_action_seq
页面:event_key
*/
WITH event_data AS (
    /* 模拟访问数据 */
    SELECT '123' AS session_id, '1' AS session_action_seq, 'page1' AS event_key, 1 AS event_id
    UNION ALL
    SELECT '123' AS session_id, '2' AS session_action_seq, 'page3' AS event_key, 3 AS event_id
    UNION ALL
    SELECT '123' AS session_id, '3' AS session_action_seq, 'page2' AS event_key, 2 AS event_id
    UNION ALL
    SELECT '123' AS session_id, '4' AS session_action_seq, 'page2-1-1' AS event_key, 3 AS event_id
    UNION ALL
    SELECT '123' AS session_id, '5' AS session_action_seq, 'page2-1-2' AS event_key, 4 AS event_id
    UNION ALL
    SELECT '123' AS session_id, '6' AS session_action_seq, 'page3' AS event_key, 7 AS event_id
    UNION ALL
    SELECT '123' AS session_id, '7' AS session_action_seq, 'page5' AS event_key, 9 AS event_id
    UNION ALL
    SELECT '123' AS session_id, '8' AS session_action_seq, 'page4' AS event_key, 8 AS event_id
    UNION ALL
    SELECT '123' AS session_id, '9' AS session_action_seq, 'page6' AS event_key, 10 AS event_id
)
SELECT * FROM event_data
图三

按照规定的访问顺序,提取有效的路径应为(event_id):1->2->3->4和1->2->7->8,其中 session_action_seq 为2、7、9的记录无效,应剔除
由于用sql实现这个逻辑太复杂,需要定义一个函数

DECLARE
    /* 在arr中查找arr_rn中出现的元素,arr_rn中的元素第一次在arr中出现顺序递增 */
    arr_len int:=array_upper(arr,1);
    val INT[];
    val_empty INT[];
    idx INT:=1;
    idx_max INT:=idx;
    item INT;
BEGIN
        FOR item IN SELECT UNNEST(arr_rn)
        LOOP
            FOR idx in idx_max..arr_len
            LOOP
                IF item = arr[idx] THEN
                    IF arr[idx] != arr[idx_max] THEN
                        idx_max = idx;
                    END IF;
                    val:=array_append(val,idx);
                ELSE
                    CONTINUE;
                END IF;
            END LOOP;
            IF item != arr[idx_max] THEN
                EXIT;
            END IF;
        END LOOP;
    IF arr[val[1]] != arr_rn[1] THEN
            RETURN NEXT val_empty;
        ELSE
            RETURN NEXT val;
        END IF;
END;

问题转化为,从[1,3,2,3,4,7,9,8,10]中找出符合[1,2,3,4],[1,2,5,6],[1,2,7,8,9]三种顺序的序列,结果为[1,2,3,4],[1,2],[1,2,7,8],去重之后的有效访问为[1,2,3,4,7,8]

SELECT
    session_id,
    /* 剔除不合法记录 */
    unnest(public.get_inter_arr(event_id_arr,event_id_seq::INT[]))::BIGINT AS session_action_rank
FROM
    (
        SELECT
            session_id,
            ARRAY_AGG (event_id) AS event_id_arr
        FROM
            event_data
        GROUP BY
            session_id
    )t1
    LEFT JOIN
    (/* 通过配置表生成合法路径 */
    SELECT
        string_to_array(
            CASE
                WHEN p1.event_id_str IS NOT NULL THEN p1.event_id_str || ',' || p0.event_id_str
            ELSE
                p0.event_id_str
            END,',') AS event_id_seq
    FROM
        (
            SELECT
                p_event_id,
                event_id_str
            FROM
                (
                    SELECT
                        p_event_id,
                        group_id,
                        string_agg (event_id, ',' ORDER BY event_id) AS event_id_str
                    FROM
                        event_road
                    GROUP BY
                        p_event_id,
                        group_id
                ) m0
            GROUP BY
                p_event_id,
                event_id_str
        ) p0
    LEFT JOIN 
    (
        /* 找到一级步骤到二级步骤的分叉点 */
        SELECT
            t1.p_event_id,
            string_agg (
                t0.event_id,
                ','
            ORDER BY
                t0.event_id
            ) AS event_id_str
        FROM
            (
                /* 一级步骤 */
                SELECT
                    *
                FROM
                    event_road
                WHERE
                    p_event_id = 0
            ) t0
        JOIN 
        (
            /* 二级步骤 */
            SELECT
                p_event_id,
                MIN (event_id) AS min_event_id
            FROM
                event_road
            WHERE
                p_event_id != 0
            GROUP BY
                p_event_id
        ) t1 ON t0.event_id <= t1.min_event_id
        GROUP BY
            t1.p_event_id
    ) p1 ON p0.p_event_id = p1.p_event_id
)t2 ON 1=1
图四

图四中的session_action_rank就是[1,3,2,3,4,7,9,8,10]的下标(从1开始),对应有效访问为[1,2,3,4,7,8]。至此,得到了所有用户的有效访问记录,经过一系列的整理之后,再通过简单的统计就可以得到每一个步骤的UV转化数据。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容