淘宝搜索每天承载数十亿次查询,搜索结果的前3个位置占据了超过60%的点击量。搜索算法团队的核心KPI是"让用户更快找到想要的商品",而位置CTR(Click Through Rate)衰减曲线是衡量搜索质量的关键指标——理想情况下CTR应该随位置平缓下降,如果前3位CTR断崖式下跌说明排序模型有严重问题。
业务场景:搜索产品经理每周看"各位置CTR衰减曲线",如果发现第1位CTR异常低(说明最匹配的商品没有被排到第1),或者第5位之后CTR几乎为0(说明用户只看前几个结果),就需要调整排序策略。
现有一张搜索点击日志表 t12_search_log,记录了每次搜索请求中各位置商品的曝光和点击情况。请统计各展示位置的点击率(CTR),分析CTR随位置的衰减趋势。
CTR = 该位置被点击的次数 / 该位置被曝光的次数
搜索点击日志表 t12_search_log:
+-----------+----------+----------+-----------+-----------+
| query_id | user_id | item_id | position | is_click |
+-----------+----------+----------+-----------+-----------+
| Q001 | u01 | I1001 | 1 | 1 |
| Q001 | u01 | I1002 | 2 | 0 |
| Q001 | u01 | I1003 | 3 | 1 |
| Q001 | u01 | I1004 | 4 | 0 |
| Q001 | u01 | I1005 | 5 | 0 |
| Q002 | u02 | I2001 | 1 | 1 |
| Q002 | u02 | I2002 | 2 | 1 |
| Q002 | u02 | I2003 | 3 | 0 |
| Q003 | u01 | I3001 | 1 | 0 |
| Q003 | u01 | I3002 | 2 | 1 |
| Q003 | u01 | I3003 | 3 | 0 |
| Q003 | u01 | I3004 | 4 | 0 |
+-----------+----------+----------+-----------+-----------+
is_click: 1-被点击, 0-未点击。 每条记录代表一次曝光(搜索结果展示),同一query_id下一次搜索有多个位置的曝光。
核心是按位置聚合 + CTR计算 + 衰减观察:
维度 | 评分 |
|---|---|
题目难度 | ⭐️⭐️ |
题目清晰度 | ⭐️⭐️⭐️⭐️⭐️ |
业务常见度 | ⭐️⭐️⭐️⭐️⭐️ |
select position,
count(1) as imp_cnt,
sum(is_click) as click_cnt
from t12_search_log
group by position
order by position
执行结果
+-----------+----------+------------+
| position | imp_cnt | click_cnt |
+-----------+----------+------------+
| 1 | 3 | 2 |
| 2 | 3 | 2 |
| 3 | 3 | 1 |
| 4 | 2 | 0 |
| 5 | 1 | 0 |
+-----------+----------+------------+
5 rows selected (1.439 seconds)(https://www.dwsql.com)
位置1被曝光3次(Q001/Q002/Q003各一次),被点击2次。位置5只曝光1次,样本太少CTR不稳定。
执行SQL
select position,
imp_cnt,
click_cnt,
round(click_cnt * 1.0 / imp_cnt, 4) as ctr,
round(1.0 * click_cnt / nullif(first_value(click_cnt) over (orderbyposition), 0), 4) as ctr_vs_pos1_ratio
from (
selectposition,
count(1) as imp_cnt,
sum(is_click) as click_cnt
from t12_search_log
groupbyposition
) t
orderbyposition
执行结果
+-----------+----------+------------+---------+--------------------+
| position | imp_cnt | click_cnt | ctr | ctr_vs_pos1_ratio |
+-----------+----------+------------+---------+--------------------+
| 1 | 3 | 2 | 0.6667 | 1.0000 |
| 2 | 3 | 2 | 0.6667 | 1.0000 |
| 3 | 3 | 1 | 0.3333 | 0.5000 |
| 4 | 2 | 0 | 0.0000 | 0.0000 |
| 5 | 1 | 0 | 0.0000 | 0.0000 |
+-----------+----------+------------+---------+--------------------+
5 rows selected (0.658 seconds)(https://www.dwsql.com)
位置1-2 CTR=66.7%,位置3降到33.3%,位置4-5 CTR=0。实际淘宝搜索的位置1 CTR通常在20%-40%,位置5之后在1%-3%。示例数据样本较小,趋势仅供参考。
坑1:曝光量太少的位置CTR不稳定
位置10可能只有几十次曝光,某一次偶然点击就让CTR从0%跳到10%。实际分析时需加最小曝光阈值(如 HAVING imp_cnt >= 100)过滤不可靠数据。
坑2:位置偏差(Position Bias)
高CTR不一定是商品好,可能只是因为排在前面。用户更信任前几个结果,天然会多点第1位。修正方法:用"位置1的CTR"做基准归一化,或使用IPW(逆概率加权)去偏。
坑3:不同query的搜索结果数不同
有些搜索词只有3个结果,有些有20个,导致后面位置的曝光量天然不同。分析时需要确认是按query去重(一个query下每个位置只算一次曝光)还是按用户去重。
LAG(ctr) OVER (ORDER BY position) 计算相邻位置CTR下降幅度,位置5之后CTR下降>50%说明"翻页率"有问题考点 | 说明 |
|---|---|
GROUP BY position | 按位置维度聚合曝光和点击 |
SUM(is_click) / COUNT(1) | CTR = 点击数 / 曝光数 |
FIRST_VALUE 窗口函数 | 以位置1的CTR为基准做归一化 |
HAVING 过滤小样本 | 曝光量不足的位置CTR不可靠 |
CREATE TABLE t12_search_log (
query_id stringCOMMENT'搜索请求ID',
user_id stringCOMMENT'用户ID',
item_id stringCOMMENT'商品ID',
positionintCOMMENT'展示位置(1-N)',
is_click intCOMMENT'是否点击: 1-是, 0-否'
) COMMENT'搜索点击日志表';
INSERTINTO t12_search_log VALUES
('Q001', 'u01', 'I1001', 1, 1),
('Q001', 'u01', 'I1002', 2, 0),
('Q001', 'u01', 'I1003', 3, 1),
('Q001', 'u01', 'I1004', 4, 0),
('Q001', 'u01', 'I1005', 5, 0),
('Q002', 'u02', 'I2001', 1, 1),
('Q002', 'u02', 'I2002', 2, 1),
('Q002', 'u02', 'I2003', 3, 0),
('Q003', 'u01', 'I3001', 1, 0),
('Q003', 'u01', 'I3002', 2, 1),
('Q003', 'u01', 'I3003', 3, 0),
('Q003', 'u01', 'I3004', 4, 0);