快速实验篇(B07 )Session 会话化与序列

小肥柴的Hadoop之旅 快速实验篇(B07 )Session 会话化与序列

电商用户行为分析实战 · B 组 · 第七阶段

数据源:b_group.dwd_user_behavior

技术栈:Hive on MR(窗口函数 LAG + COLLECT_LIST)


前言

B07 是 B 组第七个业务分析项目,也是第一个出现强区分度业务发现的阶段 。原设计的问题是:用户在 session 内的行为轨迹是什么?有哪些常见的路径模式?

B03--B06 一路建立"均匀认知":品类均匀、加权无区分度、头部集中、页面满矩阵。B07 一开始也被预期为"均匀认知第 7 条证据"。但 B07 实测结果首次打破这一预期:

  • session 长度是长尾分布:p50=13,max=203,差 15.6 倍。
  • 深层 session(≥100 行为)100% 转化:39/39,无一例外。
  • 极短 session(<5 行为)仅 25.8% 转化:423/1640。
  • 全量基准 56.9%:4977/8744。

100% vs 25.8%,4 倍差,这是 B 组首个强业务信号。

同时,B07 也发现一个深层的分布悖论 :n-gram 频次是长尾的(click>click 占 44.6%),但 n-gram 的条件转化率是均匀的(53%~57%)。频次长尾 + 条件概率均匀,两者同时成立。

B07 的真正产出,因此是:

  • ads_session_sequence(8744 行):session 完整行为序列 + 摘要统计,B11/B12 可直接复用。
  • ads_session_ngram(80 行):2-gram + 3-gram 频次与条件转化率。
  • "均匀 vs 长尾"的维度澄清:B03--B06 的"均匀"和 B07 的"长尾"不矛盾,是不同维度。
  • 首个强区分度发现:深层 session 100% 转化。

0. 实验全景

text 复制代码
b_group.dwd_user_behavior
   │  排除 07-27:dt BETWEEN '2019-07-17' AND '2019-07-26'
   │
   │  ① session 序列构建(脚本 01,COLLECT_LIST)
   ▼
ads_session_sequence       8744 行(每 session 一行,含完整序列 + 摘要)
   │
   │  ② n-gram 频次(脚本 02,LAG 构造 2-gram / 3-gram)
   ▼
ads_session_ngram          80 行(16 个 2-gram + 64 个 3-gram)
   │
   │  ③ 统一验证(脚本 03)
   ▼
15 项全部通过
   │
   ▼
质量报告:output/b07_quality_report.csv
  • 小结:B06 说"页面跳转完全稠密",B07 说"session 长度长尾,深层 session 100% 转化";两者不矛盾,一个描述聚合边缘,一个描述个体结构。

1. Why:为什么做 B07

1.1 如果不做这一步,后面哪些项目会受影响

B11(用户 RFM 分层)会受影响 :B11 需要 session 级的 F(Frequency)和 M(Monetary)输入。B07 的 ads_session_sequence 已经包含 seq_len 和 has_order / has_pay,可直接作为 F 维基础。

B12(异常流量与刷单识别)会受影响 :B07 发现 39 个"深层 session"全部转化,这是 B12 排查异常行为的反向基线(正常深度用户 vs 刷单机器人)。同时极短 session 的 25.8% 转化率也是重要对照。

B13(ADS 主题宽表)会受影响 :ads_session_sequence 是 ADS 层"session 主题表"的核心输入。

B14(可视化)会受影响:session 长度分布图、n-gram 热力图,都依赖 B07 的输出。

B15(总结与工程复盘)会受影响 :B07 是 B 组故事线的转折点,从"均匀"到"长尾+强区分度",是复盘的核心素材。

1.2 这一步具体做什么

用 Hive 计算两张表:

表 粒度 核心问题 行数
ads_session_sequence session 完整行为序列 + 摘要 8744
ads_session_ngram (n, ngram) 2-gram / 3-gram 频次 80

排序 / 拼接规则:

text 复制代码
序列顺序:PARTITION BY session_id ORDER BY ts
序列拼接:COLLECT_LIST(behavior_type) + CONCAT_WS('>', ...)
序列分隔符:> (避免与行为名冲突)
n-gram 提取:LAG(behavior_type, 1/2)
  • 用 ts 排序:B02 timestamp 才是正确时间序。
  • 用 DISTRIBUTE BY ... SORT BY :保证同一 session 行为按 ts 有序进入 reducer,COLLECT_LIST 才能保序。
  • 保留三个子计数 :seq_len、has_order、has_pay 全部保留。

1.3 做完怎么验证

15 项统一验证,覆盖:

类别 验证项
序列表规模 session_rows = 8744, total_behavior = 166770
长度极值 seq_len_max = 203, seq_len_min = 1
转化标记 order_sessions = 4977, pay_sessions = 4111(与 B03 一致)
n-gram 守恒 ngram_2_freq = 158026(与 B06 一致), ngram_3_freq = 149734
n-gram 种类 ngram_2_kinds = 16, ngram_3_kinds = 64
深层 session long_sessions_100 = 39, long_all_converted = 39
极短 session short_sessions_lt5 = 1640, short_converted = 423
中位数 median_seq_len = 13

1.4 与下游什么关系

下游 本步给了什么 不用会怎样
B11 session 级 F 维基础 RFM 要重算
B12 深层 vs 极短 session 对照 无正常/异常基线
B13 session 主题表 ADS 层缺 session 主题
B14 长度分布图、n-gram 热力图 无法可视化
B15 "转折点"素材 故事线缺高潮

2. 业务价值声明

2.1 在真实电商里,这一步解决什么业务问题

Session 序列分析是"用户路径挖掘"的基础。真实电商用它做四件事:

  1. 黄金路径识别:找到"高转化 session 的共同路径",用于优化关键页面。
  2. 用户深度分层:按 session 长度和转化行为分层,做差异化运营。
  3. 异常路径识别:发现"非人类路径",用于风控和刷单识别。
  4. 路径聚类:把 session 按模式分组,做差异化推荐。

2.2 本实验的产出,哪些可以直接用

产出 可直接用 说明
ads_session_sequence 表结构 ✅ 任何真实数据都可复用
序列拼接方法(COLLECT_LIST + CONCAT_WS) ✅ 代码模板可直接复用
深层 session 100% 转化 ✅ 在 B 组数据上已成立
极短 session 25.8% 转化 ✅ 在 B 组数据上已成立
n-gram 提取方法(LAG + CONCAT) ✅ 代码模板可直接复用
内存控制参数(继承 B06) ✅ 2GB 集群必备

2.3 哪些必须用真实数据重新验证

结论 为什么受限
"黄金路径"排名 条件转化率均匀(53%~57%),TopN 无意义
路径聚类簇数 条件概率均匀,聚类可能退化为随机分组
"深层 session 100% 转化"的阈值 100 这个阈值是 B 组数据标定的,真实数据可能要调整
品类/页面偏好的路径差异 继承 B03/B04/B06 的均匀约束

报告必须标注:

B07 的"深层 session 100% 转化"和"极短 session 25.8% 转化"在 B 组数据上成立。但阈值(100 / 5)需要真实数据重新标定。同时,n-gram 条件转化率均匀(53%~57%)意味着**"路径本身"没有预测力**,路径推荐的业务价值需真实数据重新评估。

2.4 如果数据正常,这一步的理想产出是什么

真实电商的 session 序列分析,应该呈现以下形态:

  1. 长度长尾:B07 已呈现(p50=13, max=203)✅
  2. 黄金路径头部集中:Top10 路径覆盖 30%~50% 的高转化 session(B07 未呈现)
  3. 条件转化率有梯度:不同路径的后续转化率应有 2~3 倍差(B07 未呈现,仅 4.1pp 差)
  4. 异常路径可分离:机器路径的 n-gram 分布与人类路径显著不同(B07 未分析)

B07 已经实现了"长度长尾"和"深层 100% 转化"两个理想形态,剩下的两个需要真实数据或 B12 补充。


3. B06 的硬约束:页面满矩阵

3.1 B06 实测数据

B06 已实测确认:

  • 50 个页面,2500 条跳转路径全部出现(满矩阵)。
  • 每条路径的 transition_count 在 40~91 之间,仅 2.3 倍差。
  • order 转化率范围 62.5%~98.3%,但 Top10 内部仅 5pp 差。

3.2 B07 的预期与反转

B07 原设计预期是"均匀认知第 7 条证据"。但实测首次打破:

  • session 长度不是均匀,是长尾(p50=13,max=203,差 15.6 倍)。
  • 深层 session 100% 转化,与极短 session 的 25.8% 形成 4 倍差。

这不是推翻 B06,而是揭示 B06 的"均匀"只适用于"聚合边缘分布",不适用于"个体结构分布"。

3.3 B07 的应对:全量 + 分层

B07 采用三个应对措施:

  • 不做 TopN,输出全量:8744 个 session 全量输出,80 个 n-gram 全量输出。

  • 分层标注:把 session 分为"极短(<5)/ 正常(5~99)/ 深层(≥100)"三层,分别统计。

  • 量化维度差异 :专门增加 V11~V14 四项,量化"深层 vs 极短"的转化率差异。


4. 脚本逐个讲

4.0 三个脚本的依赖链

text 复制代码
前置:目录 + 基线 + B02 表检查 + session 长度分布探测
   │
   ▼
脚本 01:session 序列构建(COLLECT_LIST,8744 行)
   │  唯一的"事实源"
   ▼
脚本 02:n-gram 频次(LAG 构造 2-gram / 3-gram,80 行)
   │
   ▼
脚本 03:统一验证(15 项)
   │
   ▼
质量报告 b07_quality_report.csv

设计原则:

  • 01 是唯一事实源 :02 从 dwd_user_behavior 重新读,不从 01 读。因为 01 已经把序列拼成字符串,02 需要原始行来构造 n-gram。
  • 02 用 UNION ALL :2-gram 和 3-gram 合成一张表,通过 n 列区分。
  • 03 依赖 01/02 全部完成,做统一验收。

为什么用 COLLECT_LIST 而不是 GROUP_CONCAT?

  • Hive 的 GROUP_CONCAT 只支持单列,且不保序。
  • COLLECT_LIST + DISTRIBUTE BY ... SORT BY 保证顺序。
  • COLLECT_LIST 返回数组,可以用 behavior_list[0] 取首元素,比字符串解析更高效。

为什么用 LAG 构造 n-gram,而不是从序列字符串解析?

  • LAG 是 O(N log N) 一次扫描,字符串解析是 O(N × 序列长度)。
  • LAG 可以同时算 has_later_order 等窗口聚合,字符串解析做不到。
  • LAG 是 B06 已经验证过的模式,复用成本低。

4.1 前置:目录、基线、表检查

这一步具体做什么?

bash 复制代码
mkdir -p /home/hadoop/b07/sql /home/hadoop/b07/output
cd /home/hadoop/b07

# 检查 B02 底座
hive -e "USE b_group; DESCRIBE dwd_user_behavior;" 2>&1 | grep -E 'session_id|behavior_type|page_id|ts|dt'

# 总量检查
hive -e "USE b_group;
SELECT COUNT(DISTINCT session_id) AS session_cnt, COUNT(*) AS behavior_cnt
FROM dwd_user_behavior
WHERE dt BETWEEN '2019-07-17' AND '2019-07-26';" 2>&1 | tail -5

# session 长度分布探测(关键)
hive -e "USE b_group;
SELECT
  MIN(seq_len) AS min_len, MAX(seq_len) AS max_len, ROUND(AVG(seq_len), 2) AS avg_len,
  PERCENTILE(seq_len, 0.5) AS p50, PERCENTILE(seq_len, 0.9) AS p90, PERCENTILE(seq_len, 0.99) AS p99
FROM (SELECT session_id, COUNT(*) AS seq_len FROM dwd_user_behavior
      WHERE dt BETWEEN '2019-07-17' AND '2019-07-26' GROUP BY session_id) t;" 2>&1 | tail -5

# 记录基线
cat > output/b07_baseline.txt << 'EOF'
source_table,dwd_user_behavior
dt_range,2019-07-17_to_2019-07-26
expected_session_rows,8744
expected_ngram_2_rows,16
expected_ngram_3_rows,64
sequence_separator,>
sequence_order,ts
n_gram_range,2_to_3
EOF

实测结果:

  • B02 底座完整,含 session_id、behavior_type、page_id、ts、dt 五列。
  • session_cnt = 8744,behavior_cnt = 166770。
  • session 长度分位数:
text 复制代码
min    max    avg    p50   p90   p99
1      203    19.07  13.0  43.0  83.0
  • 这是 B 组第一个非均匀信号。

4.2 脚本 01:session 序列构建

这一步具体做什么?

  • 从 dwd_user_behavior 读全量行为。
  • 按 session_id 分组,COLLECT_LIST 收集 behavior_type 和 page_id。
  • 用 DISTRIBUTE BY session_id SORT BY session_id, ts 保证顺序。
  • 输出 session_id, user_id, seq_len, behavior_seq, page_seq, first_behavior, last_behavior, has_order, has_pay, start_ts, end_ts, duration_sec。
  • 关键细节 :behavior_list[CAST(seq_len - 1 AS INT)] 取尾元素。Hive 数组下标只支持 int,seq_len 是 bigint,必须 CAST。

完整脚本 sql/01_create_session_sequence.hql:

sql 复制代码
USE b_group;

SET hive.exec.mode.local.auto=false;
SET mapreduce.map.memory.mb=512;
SET mapreduce.map.java.opts=-Xmx384m;
SET mapreduce.reduce.memory.mb=768;
SET mapreduce.reduce.java.opts=-Xmx512m;
SET mapreduce.task.io.sort.mb=32;
SET mapreduce.task.io.sort.factor=10;
SET hive.exec.reducers.max=1;
SET hive.exec.compress.intermediate=true;
SET hive.exec.compress.output=true;

DROP TABLE IF EXISTS ads_session_sequence;

CREATE TABLE ads_session_sequence (
  session_id        string,
  user_id           bigint,
  seq_len           bigint,
  behavior_seq      string,
  page_seq          string,
  first_behavior    string,
  last_behavior     string,
  has_order         int,
  has_pay           int,
  start_ts          timestamp,
  end_ts            timestamp,
  duration_sec      bigint
)
STORED AS ORC
TBLPROPERTIES ("orc.compress"="SNAPPY");

INSERT OVERWRITE TABLE ads_session_sequence
SELECT
  session_id,
  user_id,
  seq_len,
  CONCAT_WS('>', behavior_list) AS behavior_seq,
  CONCAT_WS('>', page_list)     AS page_seq,
  behavior_list[0]                                    AS first_behavior,
  behavior_list[CAST(seq_len - 1 AS INT)]             AS last_behavior,
  has_order,
  has_pay,
  start_ts,
  end_ts,
  UNIX_TIMESTAMP(end_ts) - UNIX_TIMESTAMP(start_ts) AS duration_sec
FROM (
  SELECT
    session_id,
    MAX(user_id) AS user_id,
    COUNT(*) AS seq_len,
    COLLECT_LIST(behavior_type) AS behavior_list,
    COLLECT_LIST(CAST(page_id AS STRING)) AS page_list,
    MAX(CASE WHEN behavior_type = 'order' THEN 1 ELSE 0 END) AS has_order,
    MAX(CASE WHEN behavior_type = 'pay'   THEN 1 ELSE 0 END) AS has_pay,
    MIN(ts) AS start_ts,
    MAX(ts) AS end_ts
  FROM (
    SELECT session_id, user_id, behavior_type, page_id, ts
    FROM dwd_user_behavior
    WHERE dt BETWEEN '2019-07-17' AND '2019-07-26'
    DISTRIBUTE BY session_id
    SORT BY session_id, ts
  ) sorted
  GROUP BY session_id
) t;

执行:耗时 84.5 秒,2 个 MR Stage 全部 SUCCESS。

验证:

text 复制代码
8744    8744    166770  1       203     19.07   4977    4111

八项全部符合预期:

指标 实际 判定
rows_cnt 8744 ✅
session_cnt 8744 ✅
total_behavior 166770 ✅
min_len 1 ✅
max_len 203 ✅
avg_len 19.07 ✅
order_sessions 4977 ✅ 与 B03 一致
pay_sessions 4111 ✅ 与 B03 一致

Top10 最长 session:

text 复制代码
329b966c-d61b-46ad-949a-7e37142d384a    203     click   search  1       1       1039
66c96daa-0525-4e1b-ba55-d38a4b462b97    163     order   pay     1       1       768
5e3545a0-1521-4ad6-91fe-e792c20c46da    161     click   click   1       1       770
4509c42c-3aa3-4d28-84c6-5ed27bbf2444    156     click   click   1       1       835
fde62452-7c09-4733-9655-5bd3fb705813    149     search  search  1       1       795
71f1c966-11e4-450f-81d2-c0b334710ccc    137     click   click   1       1       689
b4589b16-fb45-4241-a576-28f77c6e4b96    133     click   click   1       1       674
1b5ac69b-5e00-4ff3-8a5c-6822e92ecc0c    127     click   click   1       1       641
1b5e5ce7-cd04-4e78-9a6f-1c3dbb29ce39    126     click   click   1       1       595
213bc2d5-be6b-49a3-9cb6-f9afc5b69b3d    125     click   click   1       1       610

关键观察:

  • Top10 最长 session 全部 has_order=1, has_pay=1,这是 B07 首个强信号。
  • duration_sec 在 595~1039 秒(10~17 分钟),人类深度浏览节奏,不是机器行为。
  • 与 B05 的 Top1 session 交叉验证:329b966c、66c96daa、4509c42c、fde62452 都是 B05 的 Top1 session。

4.3 脚本 02:n-gram 频次

这一步具体做什么?

  • 用 LAG 构造 2-gram 和 3-gram。
  • UNION ALL 合并成一张表,用 n 列区分。
  • 按 (n, ngram) 分组,统计 freq、session_cnt、order_sessions、pay_sessions。
  • 行为空间只有 4 种(click/search/order/pay),2-gram 最多 16 种,3-gram 最多 64 种。

完整脚本 sql/02_create_session_ngram.hql:

sql 复制代码
USE b_group;

SET hive.exec.mode.local.auto=false;
SET mapreduce.map.memory.mb=512;
SET mapreduce.map.java.opts=-Xmx384m;
SET mapreduce.reduce.memory.mb=768;
SET mapreduce.reduce.java.opts=-Xmx512m;
SET mapreduce.task.io.sort.mb=32;
SET mapreduce.task.io.sort.factor=10;
SET hive.exec.reducers.max=1;
SET hive.exec.compress.intermediate=true;
SET hive.exec.compress.output=true;

DROP TABLE IF EXISTS ads_session_ngram;

CREATE TABLE ads_session_ngram (
  n               int,
  ngram           string,
  freq            bigint,
  session_cnt     bigint,
  order_sessions  bigint,
  pay_sessions    bigint
)
STORED AS ORC
TBLPROPERTIES ("orc.compress"="SNAPPY");

INSERT OVERWRITE TABLE ads_session_ngram
SELECT
  n,
  ngram,
  SUM(freq)             AS freq,
  COUNT(DISTINCT session_id) AS session_cnt,
  COUNT(DISTINCT CASE WHEN has_order = 1 THEN session_id END) AS order_sessions,
  COUNT(DISTINCT CASE WHEN has_pay   = 1 THEN session_id END) AS pay_sessions
FROM (
  -- 2-gram
  SELECT
    2 AS n,
    CONCAT(b1, '>', b2) AS ngram,
    session_id,
    1 AS freq,
    has_order,
    has_pay
  FROM (
    SELECT
      session_id,
      behavior_type AS b2,
      LAG(behavior_type) OVER (PARTITION BY session_id ORDER BY ts) AS b1,
      MAX(CASE WHEN behavior_type = 'order' THEN 1 ELSE 0 END) OVER (PARTITION BY session_id) AS has_order,
      MAX(CASE WHEN behavior_type = 'pay'   THEN 1 ELSE 0 END) OVER (PARTITION BY session_id) AS has_pay
    FROM dwd_user_behavior
    WHERE dt BETWEEN '2019-07-17' AND '2019-07-26'
  ) t2
  WHERE b1 IS NOT NULL

  UNION ALL

  -- 3-gram
  SELECT
    3 AS n,
    CONCAT(b1, '>', b2, '>', b3) AS ngram,
    session_id,
    1 AS freq,
    has_order,
    has_pay
  FROM (
    SELECT
      session_id,
      behavior_type AS b3,
      LAG(behavior_type, 1) OVER (PARTITION BY session_id ORDER BY ts) AS b2,
      LAG(behavior_type, 2) OVER (PARTITION BY session_id ORDER BY ts) AS b1,
      MAX(CASE WHEN behavior_type = 'order' THEN 1 ELSE 0 END) OVER (PARTITION BY session_id) AS has_order,
      MAX(CASE WHEN behavior_type = 'pay'   THEN 1 ELSE 0 END) OVER (PARTITION BY session_id) AS has_pay
    FROM dwd_user_behavior
    WHERE dt BETWEEN '2019-07-17' AND '2019-07-26'
  ) t3
  WHERE b1 IS NOT NULL AND b2 IS NOT NULL
) all_ngrams
GROUP BY n, ngram;

执行:耗时约 2 分钟,多个 MR Stage,SUCCESS。

验证 V1:n-gram 种类与总频次

text 复制代码
n   ngram_cnt   total_freq   distinct_ngram
2   16          158026       16
3   64          149734       64

n=2 的 total_freq = 158026 ,与 B06 完全一致 (B06 的 ads_page_transition 也是 158026 行)。这是硬约束。

验证 V2:Top10 2-gram

text 复制代码
2       click>click     70517   7641    4709    3924
2       click>search    23503   6698    4306    3639
2       search>click    23273   6615    4289    3620
2       search>search   7881    3880    2787    2390
2       order>click     6913    3921    3921    2436
2       click>order     6885    3949    3949    2458
2       click>pay       4679    3102    2301    3102
2       pay>click       4678    3098    2304    3098
2       search>order    2354    1872    1872    1247
2       order>search    2260    1817    1817    1232

关键观察:

  • click>click 一个占 44.6%(70517 / 158026)。
  • 前三个(click>click、click>search、search>click)合计占 74.2%。
  • 说明用户大量行为是连续点击或点击-搜索交替。

验证 V3:Top10 3-gram

text 复制代码
3       click>click>click       44819   6537    4276    3561
3       click>click>search      14817   5784    3877    3302
3       click>search>click      14666   5428    3713    3152
3       search>click>click      14640   5678    3831    3270
3       search>search>click     5034    3284    2397    2061
3       click>search>search     4986    3265    2357    2042
3       search>click>search     4966    2973    2193    1887
3       click>order>click       4379    2868    2868    1838
3       order>click>click       4373    2950    2950    1892
3       click>click>order       4332    2936    2936    1912

关键观察:

  • click>click>click 占 29.9%(44819 / 149734)。
  • 与 B06 的"页面满矩阵"完全一致:用户在两两页面间随机跳转。

验证 V4 修正:条件转化率(后续行为)

原 V4 查询有逻辑陷阱 :has_order 是从整个 session 聚合来的,任何含 order 的 n-gram 必然 order_rate = 1.0,这不是业务发现。

修正后,查询"走了这条 n-gram 之后,会话是否继续下单/支付":

text 复制代码
2       click>click     7641    4134    3378    0.541   0.4421
2       click>search    6698    3599    2967    0.5373  0.443
2       search>click    6615    3564    2954    0.5388  0.4466
2       click>order     3949    2119    1751    0.5366  0.4434
2       order>click     3921    2119    1721    0.5404  0.4389
2       search>search   3880    2050    1682    0.5284  0.4335
2       click>pay       3102    1692    1389    0.5455  0.4478
2       pay>click       3098    1701    1390    0.5491  0.4487
2       search>order    1872    1030    819     0.5502  0.4375
2       order>search    1817    993     830     0.5465  0.4568
2       search>pay      1350    745     600     0.5519  0.4444
2       pay>search      1343    716     616     0.5331  0.4587
2       order>order     595     319     276     0.5361  0.4639
2       order>pay       451     238     195     0.5277  0.4324
2       pay>order       448     255     204     0.5692  0.4554
2       pay>pay         298     162     128     0.5436  0.4295

关键观察:

  • order_after_rate 范围 52.8%~56.9%,差 4.1pp。
  • pay_after_rate 范围 43.0%~46.4%,差 3.4pp。
  • 全量基准 order 率 = 4977/8744 = 56.9% ,pay 率 = 4111/8744 = 47.0%。
  • 所有 2-gram 的后续转化率都贴近基准,没有一条路径显著高或低。

这是"频次长尾 + 条件概率均匀"的强证据:哪些路径更常见有规律(长尾),但走哪条路径不影响最终转化(均匀)。


4.4 脚本 03:统一验证

完整脚本 sql/03_verify_b07.hql:

sql 复制代码
USE b_group;

SET hive.exec.mode.local.auto=false;
SET mapreduce.task.io.sort.mb=32;

SELECT 'V01_session_rows'       AS check_name, CAST(COUNT(*) AS STRING) AS check_value FROM ads_session_sequence
UNION ALL
SELECT 'V02_total_behavior',    CAST(SUM(seq_len) AS STRING) FROM ads_session_sequence
UNION ALL
SELECT 'V03_seq_len_max',       CAST(MAX(seq_len) AS STRING) FROM ads_session_sequence
UNION ALL
SELECT 'V04_seq_len_min',       CAST(MIN(seq_len) AS STRING) FROM ads_session_sequence
UNION ALL
SELECT 'V05_order_sessions',    CAST(SUM(has_order) AS STRING) FROM ads_session_sequence
UNION ALL
SELECT 'V06_pay_sessions',      CAST(SUM(has_pay) AS STRING) FROM ads_session_sequence
UNION ALL
SELECT 'V07_ngram_2_freq',      CAST(SUM(freq) AS STRING) FROM ads_session_ngram WHERE n = 2
UNION ALL
SELECT 'V08_ngram_3_freq',      CAST(SUM(freq) AS STRING) FROM ads_session_ngram WHERE n = 3
UNION ALL
SELECT 'V09_ngram_2_kinds',     CAST(COUNT(*) AS STRING) FROM ads_session_ngram WHERE n = 2
UNION ALL
SELECT 'V10_ngram_3_kinds',     CAST(COUNT(*) AS STRING) FROM ads_session_ngram WHERE n = 3
UNION ALL
SELECT 'V11_long_sessions_100', CAST(COUNT(*) AS STRING) FROM ads_session_sequence WHERE seq_len >= 100
UNION ALL
SELECT 'V12_long_all_converted',CAST(SUM(CASE WHEN has_order = 1 AND has_pay = 1 THEN 1 ELSE 0 END) AS STRING)
  FROM ads_session_sequence WHERE seq_len >= 100
UNION ALL
SELECT 'V13_short_sessions_lt5',CAST(COUNT(*) AS STRING) FROM ads_session_sequence WHERE seq_len < 5
UNION ALL
SELECT 'V14_short_converted',   CAST(SUM(CASE WHEN has_order = 1 OR has_pay = 1 THEN 1 ELSE 0 END) AS STRING)
  FROM ads_session_sequence WHERE seq_len < 5
UNION ALL
SELECT 'V15_median_seq_len',    CAST(PERCENTILE(seq_len, 0.5) AS STRING) FROM ads_session_sequence;

15 项实测结果:

text 复制代码
V01_session_rows        8744
V02_total_behavior      166770
V03_seq_len_max         203
V04_seq_len_min         1
V05_order_sessions      4977
V06_pay_sessions        4111
V07_ngram_2_freq        158026
V08_ngram_3_freq        149734
V09_ngram_2_kinds       16
V10_ngram_3_kinds       64
V11_long_sessions_100   39
V12_long_all_converted  39
V13_short_sessions_lt5  1640
V14_short_converted     423
V15_median_seq_len      13.0

15 项全部与预期一致。

V05/V06 与 B03 完全一致 ,V07 与 B06 完全一致 ,B07 与 B03/B06 交叉验证通过。


5. 核心发现

5.1 发现 1:session 长度是长尾分布

指标 值 含义
min_len 1 只做一次行为就离开
p50 13 一半 session ≤ 13 次行为
p90 43 90% session ≤ 43 次行为
p99 83 99% session ≤ 83 次行为
max_len 203 最长 session
avg_len 19.07 平均值
max / p50 15.6 长尾强度

关键观察:

  • p50=13,max=203,差 15.6 倍。
  • 对比 B06 的 2.3 倍差,量级完全不同。
  • 前 10 个长度(1~10)的 session 数从 452 递减到 281,短 session 数量占优。
  • 30 以内长度的 session 约 7355 个,占全量 8744 的 84%。

这是 B 组第一次出现真正的长尾信号。

5.2 发现 2:深层 session(≥100)100% 转化

指标 值
V11_long_sessions_100 39
V12_long_all_converted 39
转化率 100%

39 个 seq_len ≥ 100 的深层 session,全部 has_order=1 且 has_pay=1,无例外。

业务解释:

  • 深度浏览的用户几乎必然下单和支付。
  • 这与"浏览越深越可能转化"的常识一致,但100% 是极强的信号。
  • Top10 最长 session 的 duration_sec 在 595~1039 秒(10~17 分钟),是人类深度浏览节奏,不是机器行为。

5.3 发现 3:极短 session(<5)仅 25.8% 转化

指标 值
V13_short_sessions_lt5 1640
V14_short_converted 423
转化率 25.8%

对比:

session 长度分层 session 数 转化率
极短(<5) 1640 25.8%
深层(≥100) 39 100%
全量基准 8744 56.9%

100% vs 25.8%,4 倍差,这是 B 组首个强区分度发现。

5.4 发现 4:n-gram 频次长尾 + 条件转化率均匀

频次长尾:

  • click>click 占 2-gram 总量 44.6%。
  • click>click>click 占 3-gram 总量 29.9%。
  • 前三个 2-gram 合计占 74.2%。

条件转化率均匀:

  • 16 种 2-gram 的 order_after_rate 范围 52.8%~56.9%,差 4.1pp。
  • pay_after_rate 范围 43.0%~46.4%,差 3.4pp。
  • 全量基准 order 率 = 56.9%,pay 率 = 47.0%。
  • 所有 2-gram 的后续转化率都贴近基准。

这是"频次长尾 + 条件概率均匀"的强证据:

哪些路径更常见有规律(长尾),但走哪条路径不影响最终转化(均匀)。


6. "均匀 vs 长尾"的维度澄清

6.1 B03--B06 说的"均匀"和 B07 说的"长尾"是不同维度

阶段 描述的是哪个维度 实测
B03/B04 品类边缘分布(20 个品类的总量) click 全部 5438~5687
B05 session 对品类的贡献集中度 65 session 撑 100 席
B06 页面跳转对的边缘分布(2500 条边) 每条边 40~91 次
B07 单个 session 的长度 1~203,p50=13,p99=83

这些是不同维度的分布,可以同时成立。

6.2 用统计语言重述

"品类/页面/跳转对是聚合后的边缘分布均匀,但 session 内部结构(长度、路径)也有自己的分布。"

举个例子(假想):

text 复制代码
1000 个 session,每个 session 都访问所有 20 个品类
→ 品类边缘分布:每个品类 click 数接近(均匀)✓
→ 但 session 长度从 20 到 2000 不等(长尾)✓

两者不矛盾。聚合后的边缘分布均匀,不代表个体分布均匀。

6.3 B05 其实已经暗示了长尾

B05 的核心发现:

  • 100 个 Top10 席位只来自 65 个 session(集中)
  • 15 个 session 跨 2+ 品类进入 Top10(少数 session 多品类活跃)

这就是长尾在 session 维度的表现!只是 B05 用了"头部集中"这个词,没有把它归到"长尾"框架下。

B07 的发现,不是推翻 B05,而是给 B05 的"头部集中"提供了更完整的分布证据。

6.4 为什么 B06 的页面跳转是均匀的,但 session 长度是长尾的?

这个组合乍看矛盾,其实很自然:

  • 长尾 session(少数几百次行为):贡献大量跳转,覆盖面广。
  • 短 session(大多数十几次行为):跳转少,但数量多。

结果是:

  • 每条边(页面跳转对)被所有 session 累计起来,边缘分布趋于均匀(B06)。
  • 但单个 session 的长度保持长尾(B07)。

聚合抵消了个体差异,这是统计学的经典现象。

6.5 方法论含义

以后遇到"均匀"结论,必须问一句"哪个维度的均匀?"

  • 不能笼统地说"数据均匀"。
  • 必须明确:是边缘分布均匀 ,还是个体分布均匀 ,还是条件概率均匀。
  • 不同维度的结论可以同时成立,而且往往必须同时成立才能解释完整现象。

7. 对下游的影响

下游 影响
B11 ads_session_sequence 提供 session 级 F 维基础
B12 39 个深层 session 是"正常深度用户"基线,1640 个极短 session 是"浅层用户"基线
B13 ads_session_sequence 是 ADS session 主题表候选输入
B14 session 长度分布图、n-gram 热力图数据
B15 "均匀 vs 长尾"是 B 组故事线的转折点

8. 工程收获

8.1 Hive 数组下标的类型陷阱

behavior_list[seq_len - 1] 报错:

复制代码
SemanticException 11:15 Not proper type for index of ARRAY.
Currently, only integer type is supported.

原因:Hive 数组下标只支持 int,seq_len 是 bigint,seq_len - 1 也是 bigint。

修复 :behavior_list[CAST(seq_len - 1 AS INT)]。

8.2 COLLECT_LIST 保序必须配合 DISTRIBUTE BY + SORT BY

COLLECT_LIST 不保证顺序。必须:

sql 复制代码
SELECT ... FROM (
  SELECT ... FROM dwd_user_behavior
  DISTRIBUTE BY session_id
  SORT BY session_id, ts
) sorted
GROUP BY session_id

DISTRIBUTE BY 保证同一 session 进入同一 reducer,SORT BY 保证进入 reducer 时已按 ts 有序。

8.3 窗口函数加内存控制(继承 B06)

sql 复制代码
SET mapreduce.map.memory.mb=512;
SET mapreduce.map.java.opts=-Xmx384m;
SET mapreduce.reduce.memory.mb=768;
SET mapreduce.reduce.java.opts=-Xmx512m;
SET mapreduce.task.io.sort.mb=32;
SET hive.exec.reducers.max=1;

8.4 V4 逻辑陷阱记录

原 V4 查询用 session 级 has_order 标记算 n-gram 转化率,导致所有含 order 的 n-gram 的 order_rate = 1.0。这不是业务发现,是逻辑必然。

修正 :用窗口函数 ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING 算"n-gram 之后是否还有 order"。

工程教训 :任何"条件转化率"都要明确"条件"是什么、"转化"发生在条件之前还是之后。


9. 方法收获

  • "均匀"是有维度的:B03--B06 的均匀是"聚合边缘均匀",B07 的长尾是"个体结构长尾",两者不矛盾。
  • 长尾和均匀可以共存 :click>click 占 44.6%(长尾),但所有 2-gram 的后续转化率都是 53%~57%(均匀)。
  • 长尾不代表强区分度 :session 长度是长尾,但长度与转化的关系才是关键(深层 100% vs 极短 25.8%)。
  • 交叉验证是硬约束:V05/V06 与 B03 一致,V07 与 B06 一致,是 B07 正确性的基础。
  • 逻辑陷阱要显式记录 :V4 的错误不是 bug,而是方法设计问题,必须在报告中明确记录,供后续复用。

10. 遗留问题

  • 39 个深层 session 的业务解释:为什么它们 100% 转化?是真实业务特征(深度用户必然下单)还是数据生成方式?B12 需进一步分析。
  • 极短 session 的 25.8% 转化:1640 个短 session 中有 423 个转化,这些转化发生在 <5 次行为内,是否有异常?
  • n-gram 条件概率均匀的原因:为什么路径不影响转化?是数据集生成方式,还是真的业务特征?待 B12 分析。
  • page_id 50 种的业务含义:B06 遗留问题,B09 需自建小维表。
  • 07-27 疑截断:B07 全部排除。
  • OOM 风险:B07 之后的窗口函数脚本,必须继承内存控制参数。
  • 阈值(100 / 5)需要真实数据重新标定:B 组的 39 个深层 session 和 1640 个极短 session 是按 100/5 分的,真实数据可能要调整。

11. 结语

B07 是 B 组第七个业务分析项目,也是第一个出现强区分度业务发现的阶段。

原来的问题是"用户在 session 内的行为轨迹是什么"。实测发现:

  • session 长度是长尾分布(p50=13,max=203,差 15.6 倍)。
  • 深层 session(≥100)100% 转化(39/39)。
  • 极短 session(<5)仅 25.8% 转化(423/1640)。
  • n-gram 频次长尾 + 条件转化率均匀 :click>click 占 44.6%,但所有 2-gram 的后续转化率都是 53%~57%。

B07 对后续 B08--B15 的真正贡献:

  1. ads_session_sequence(8744 行):session 完整行为序列,B11/B12 可直接复用。
  2. ads_session_ngram(80 行):n-gram 频次与条件转化率。
  3. 首个强区分度发现:深层 session 100% 转化 vs 极短 session 25.8%。
  4. "均匀 vs 长尾"的维度澄清:B 组故事线的转折点。

B01 建立了"数据认知",B02 建立了"结构认知",B03 建立了"业务认知",B04 建立了"均匀认知",B05 建立了"头部结构认知",B06 建立了"页面稠密认知",B07 建立了"长尾 + 强区分度认知"。

这七层认知,是 B08--B15 的共同底座。


附录 A:质量报告

output/b07_quality_report.csv:

text 复制代码
check_name,check_value
V01_session_rows,8744
V02_total_behavior,166770
V03_seq_len_max,203
V04_seq_len_min,1
V05_order_sessions,4977
V06_pay_sessions,4111
V07_ngram_2_freq,158026
V08_ngram_3_freq,149734
V09_ngram_2_kinds,16
V10_ngram_3_kinds,64
V11_long_sessions_100,39
V12_long_all_converted,39
V13_short_sessions_lt5,1640
V14_short_converted,423
V15_median_seq_len,13.0

附录 B:执行环境

项 版本
Hadoop 3.3.6
Hive 3.1.3 (on MR)
集群 1 master + 3 worker,每节点 2GB
Java 8
工作目录 /home/hadoop/b07
Metastore 全局固定 /home/hadoop/hive_metastore/metastore_db
Hive CLI 堆 HADOOP_CLIENT_OPTS="-Xmx512m -Xms256m"
运行日期 2026-10-03

附录 C:B07 与 B03/B06 的交叉验证

B07 验证项 值 上游对照 判定
V05_order_sessions 4977 B03 的 4977 ✅
V06_pay_sessions 4111 B03 的 4111 ✅
V07_ngram_2_freq 158026 B06 的 158026 ✅
V02_total_behavior 166770 B03/B06 的 166770 ✅

本文是 B07 阶段完整复盘,也是 B08--B15 的 session 级分析底座说明。

B01 是"数据认知",B02 是"结构认知",B03 是"业务认知",B04 是"均匀认知",B05 是"头部结构认知",B06 是"页面稠密认知",B07 是"长尾 + 强区分度认知"。七者共同构成 B 组的分析底座。

相关推荐
卷毛迷你猪1 小时前
快速实验篇(B08)搜索词分析实战
大数据·hive·hadoop
IT研究室2 小时前
最新大数据毕业设计选题推荐-基于大数据的考研相关视频数据可视化分析-大数据-Spark-Hadoop-Bigdata
大数据·考研·课程设计
johnsong3 小时前
幽灵协议:当AI推荐死去的SaaS,编码Agent控制层正在形成
大数据·人工智能
蝶依斓(湖南)全案整装3 小时前
旧房改造整装内容写作框架:用户痛点与叙述结构
大数据
蝶依斓(湖南)全案整装3 小时前
整装行业长尾需求内容矩阵搭建方法:从五个维度拆解用户需求
大数据·人工智能·矩阵
回眸&啤酒鸭4 小时前
GLM 5.3 Flash 批量处理实战指南
大数据·人工智能
躺柒4 小时前
读数据架构知识体系指南13现代数据仓库
大数据·数据分析·数据湖·mdm·rdm
科技研学社4 小时前
外贸订单回流与关税新规下,服装工厂技改如何突围
大数据·人工智能
liulilittle4 小时前
短期内不存在通用 AI 工作流魔法
大数据·开发语言·c++·人工智能·llm·agent·tools