Blame view

docs/搜索推荐数据.md 19.5 KB
001b4889   tangwang   1. docs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
  
  ## 1)BI 怎么设计(对标 Shopify/独立站“搜索/推荐”常见报表)
  Shopify 的 Search & Discovery/行为报表里,搜索常看的就是 **query、no results、no clicks、click rate、purchase rate**(会话口径漏斗)。推荐系统的看板更强调 **曝光→点击→加购→购买→收入**,并按**推荐位/算法/实验**拆解。
  
  ### 1.1 搜索 BI(核心看板)
  - **搜索总览(KPI + 漏斗)**
    - **搜索 PV/UV**:search request 次数 / 搜索用户数
    - **Click rate(会话口径,Shopify 常用)**:有点击的搜索会话 / 搜索会话
    - **ATC rate**:有加购的搜索会话 / 搜索会话
    - **Purchase rate(会话口径,Shopify 常用)**:有购买的搜索会话 / 搜索会话
    - **结果曝光 CTR(结果口径)**:点击次数 / 结果曝光次数(更适合诊断排序/样式)
    - **延迟&稳定性**:P50/P95 搜索耗时、错误率、空响应率
  
  - **Query 分析(运营/选品/词库最常用)**
    - **高热搜索词**:按搜索 UV、曝光 UV、点击 UV、购买 UV 排序
    - **飙升词/新词**:与过去 \(7/14/28\) 天对比的增速
    - **无结果 query**(no results)
    - **有结果但无点击 query**(no clicks)——强信号:相关性差/图片价位不吸引/首屏无货等
    - **建议词(suggestion)**:suggest 点击发起的搜索占比、suggest→点击/购买转化
  
  - **结果质量诊断(给算法/工程用)**
    - **点击位置分布**:position=1/2/3… 的点击占比(反推排序质量)
    - **类目/品牌/价格带分布**:哪些 query 对哪些类目贡献转化
    - **筛选/排序使用率**:filter 使用率、排序切换率、filter 后的 CTR/CVR 变化
  
  - **用户与渠道拆解(增长/产品用)**
    - **新/老客**、地域、语言、设备、来源(自然/广告/社媒)
    - **页面维度**:首页搜索框 / 搜索页 / 分类页搜索 / 详情页内搜索等
  
  - **Session/链路回放(你提到的 track_id/trace_id)**
    - 单用户或单 trace:**搜索→换词→曝光→点击→详情→加购→支付**
    - 支持按 **trace_id** 串联一次“搜索请求”与后续行为(你们文档也强调这一点)
  
  > 参考:Shopify 官方对搜索分析的核心指标包括 click rate、purchase rate、queries、no results、no clicks(见 [Shopify Search & Discovery analytics](https://help.shopify.com/en/manual/online-store/storefront-search/search-and-discovery-analytics))。
  
  ### 1.2 推荐 BI(核心看板)
  - **推荐位总览(按 placement/module)**
    - **Impressions/Clicks/CTR**
    - **ATC、Purchase、Revenue**
    - **Revenue per impression / per click**
    - **AOV(推荐归因订单)**
    - **覆盖与多样性**:覆盖商品数、长尾曝光占比、重复率(避免“只推爆款”)
  
  - **按算法/实验拆解**
    - 算法版本(model_version/strategy_id)
    - 实验(experiment_id/variant_id)
    - **Lift(增量)**:相对对照组的 CTR/CVR/Revenue uplift(最好有 holdout)
  
  - **健康度与风控**
    - 缺货/下架命中率、被过滤原因分布(无库存/不可售/地域不发货)
    - 冷启动占比(新用户/新商品)与表现
  
  ---
  
  ## 2)数据层面的设计(埋点→数仓→指标→推荐特征)
  你们已有统一事件骨架的方向(`tenant_id / session_id / trace_id / event(oneof)`)。建议在数据层分成 **ODS(原始)→DWD(清洗明细)→DWS(汇总)→ADS(看板语义层)**,同时给推荐做 **离线+在线特征库**
  
  ### 2.1 关键 ID 设计(决定 BI/推荐能否串起来)
  - **tenant_id**:多租户隔离必备(所有表分区/主键都带)
  - **user_key**:归一后的用户主键(优先 login/user_id;否则 anonymous_id/cookie_id)
  - **session_id**:会话(SDK 产生或用 30min inactivity 规则补齐)
  - **trace_id(最重要)**:一次搜索/一次推荐刷新生成一个,后续点击/详情/加购尽量继承
  - **request_id**:后端请求日志关联(用于延迟、错误、召回/排序 debug)
  - **order_id/cart_id/item_id(sku/spu)**:交易与商品归因
  
  ### 2.2 ODS:原始事件(“可回放、可重放”)
  - `ods_ua_event_raw`
    - tenant_id, event_time, received_time
    - identities(原始字段:distinct_id/login_id/anonymous_id/cookie_id…)
    - page/device/geo/referrer
    - trace_id, session_id, experiment 信息
    - event_name + properties(原始 JSON,保留全量)
  
  > 你现在的 `$pageview/$WebClick` 自动采集能覆盖点击和页面,但 **推荐/搜索“曝光”必须补埋点**(否则 CTR、归因、训练样本都会缺)。
  
  ### 2.3 DWD:清洗后的事实表(BI/训练统一口径)
  建议把“强分析对象”拆成事实表(便于 join、去重、做漏斗):
  
  - **搜索域**
    - `dwd_search_request`:一次“搜索结果刷新/请求”的主表(强烈建议:**每次请求一个 request_id,同时每次请求一个 trace_id**
      - **用途**:search PV/UV、零结果、延迟、query 聚合、会话口径漏斗分母(search_session)
      - **主键建议**`(tenant_id, request_id)`
      - **核心索引建议**
        - `(tenant_id, created_at)`
        - `(tenant_id, user_key, created_at)`
        - `(tenant_id, query_normalized, created_at)`
        - `(tenant_id, trace_id)`(用于 join 曝光/点击)
        - `(tenant_id, search_session_id, created_at)`
      - **字段建议(MySQL 参考类型,可按你们存储调整)**
        - `tenant_id` VARCHAR(64) NOT NULL:店铺/租户
        - `request_id` VARCHAR(64) NOT NULL:该次搜索请求唯一 ID(前端生成或后端返回)
        - `trace_id` VARCHAR(64) NOT NULL:该次搜索链路 ID(一次结果集 = 一个 trace)
        - `session_id` VARCHAR(64) NULL:访问会话(30min inactivity)
        - `search_session_id` VARCHAR(64) NULL:搜索会话(一次“找东西”的连续过程)
        - `user_id` VARCHAR(64) NULL:登录用户 ID
        - `anonymous_id` VARCHAR(64) NULL:匿名用户(cookie 级稳定)
        - `user_key` VARCHAR(64) NOT NULL:归一用户主键(ETL 生成)
        - `query` TEXT NOT NULL:原始 query
        - `query_normalized` VARCHAR(512) NOT NULL:归一化 query(聚合用)
        - `is_suggestion` TINYINT NOT NULL DEFAULT 0:是否由 suggestion 触发
        - `suggestion_text` VARCHAR(512) NULL:命中的 suggestion(如有)
        - `page_number` INT NOT NULL DEFAULT 1:翻页页码(1-based)
        - `sort` VARCHAR(64) NULL:排序方式(如 relevance/price_asc/…)
        - `filters_json` JSON NULL:结构化筛选条件(原子字段更好;JSON 为起步方案)
        - `filters_hash` CHAR(32) NULL:filters 归一化后的 hash(便于聚合/去重)
        - `results_count` INT NOT NULL DEFAULT 0:总命中数
        - `returned_count` INT NULL:本页返回数量(page size)
        - `latency_ms` INT NULL:搜索耗时
        - `is_zero_result` TINYINT NOT NULL DEFAULT 0:是否零结果(可由 results_count=0 派生)
        - `is_error` TINYINT NOT NULL DEFAULT 0:是否错误
        - `error_code` VARCHAR(64) NULL:错误码(如超时/限流等)
        - `page_type` VARCHAR(64) NULL:发生搜索的页面(home/search/pdp/collection…)
        - `referrer` TEXT NULL:来源页
        - `device_type` VARCHAR(32) NULL:pc/mobile(可从 UA 解析)
        - `country` VARCHAR(8) NULL:国家(建议由 IP->Geo 派生;避免落全量 IP)
        - `created_at` DATETIME(3) NOT NULL:事件时间(毫秒级可选)
  
    - `dwd_search_impression_item`:搜索结果“曝光明细”(**必须补**,否则无法算 position CTR、训练负样本)
      - **用途**:曝光 PV/UV、位置 CTR、召回/排序诊断、训练样本(曝光未点为负样本)
      - **主键建议**`(tenant_id, trace_id, item_id, position)`(或 `(tenant_id, request_id, item_id, position)`,二选一但全局统一)
      - **核心索引建议**
        - `(tenant_id, trace_id)`
        - `(tenant_id, request_id)`
        - `(tenant_id, item_id, exposed_at)`
      - **字段建议**
        - `tenant_id` VARCHAR(64) NOT NULL
        - `request_id` VARCHAR(64) NOT NULL
        - `trace_id` VARCHAR(64) NOT NULL
        - `search_session_id` VARCHAR(64) NULL
        - `user_key` VARCHAR(64) NOT NULL
        - `query_normalized` VARCHAR(512) NOT NULL
        - `item_id` VARCHAR(64) NOT NULL:spu 或 sku,需统一
        - `position` INT NOT NULL:在搜索结果中的排名(1-based)
        - `score` DOUBLE NULL:排序分(如 ES score/learning-to-rank score)
        - `price` DECIMAL(18,2) NULL:曝光时价格快照(可选但强烈建议)
        - `currency` VARCHAR(8) NULL
        - `in_stock` TINYINT NULL:曝光时库存可售快照(可选但强烈建议)
        - `exposed_at` DATETIME(3) NOT NULL:曝光时间
  
    - `dwd_search_click_item`:搜索结果点击明细(点击必须能回链到曝光/请求)
      - **用途**:click UV、CTR(曝光口径/会话口径)、位置点击分布、归因触点
      - **主键建议**`(tenant_id, click_id)`(若无 click_id,可用 `(tenant_id, trace_id, item_id, clicked_at)` 近似)
      - **核心索引建议**
        - `(tenant_id, trace_id)`
        - `(tenant_id, request_id)`
        - `(tenant_id, item_id, clicked_at)`
      - **字段建议**
        - `tenant_id` VARCHAR(64) NOT NULL
        - `click_id` VARCHAR(64) NULL:点击事件唯一 ID(推荐补)
        - `request_id` VARCHAR(64) NOT NULL
        - `trace_id` VARCHAR(64) NOT NULL
        - `search_session_id` VARCHAR(64) NULL
        - `user_key` VARCHAR(64) NOT NULL
        - `query_normalized` VARCHAR(512) NOT NULL
        - `item_id` VARCHAR(64) NOT NULL
        - `position` INT NULL:点击时该商品所在排名(无法取到则置空)
        - `clicked_at` DATETIME(3) NOT NULL
        - `target_url` TEXT NULL:点击跳转 URL(可选)
  
  - **推荐域**
    - `dwd_rec_request`:一次推荐请求/刷新主表(一次刷新 = 一个 trace_id)
      - **用途**:推荐 PV/UV、分推荐位指标、实验/版本拆解、延迟与稳定性
      - **主键建议**`(tenant_id, request_id)`
      - **核心索引建议**
        - `(tenant_id, created_at)`
        - `(tenant_id, placement, created_at)`
        - `(tenant_id, trace_id)`
        - `(tenant_id, algo_id, model_version, created_at)`
      - **字段建议**
        - `tenant_id` VARCHAR(64) NOT NULL
        - `request_id` VARCHAR(64) NOT NULL
        - `trace_id` VARCHAR(64) NOT NULL
        - `session_id` VARCHAR(64) NULL
        - `user_key` VARCHAR(64) NOT NULL
        - `placement` VARCHAR(64) NOT NULL:推荐位(home/pdp/cart/checkout/search…)
        - `module_id` VARCHAR(128) NULL:页面内模块标识(一个页面多个推荐模块)
        - `trigger_item_id` VARCHAR(64) NULL:触发商品(PDP/Cart 场景常用)
        - `candidates_count` INT NULL:候选数量
        - `returned_count` INT NULL:返回条数
        - `algo_id` VARCHAR(64) NULL:策略/算法标识(rule/i2i/embedding/…)
        - `model_version` VARCHAR(64) NULL:模型版本
        - `experiment_id` VARCHAR(64) NULL:实验 ID(如有)
        - `variant_id` VARCHAR(64) NULL:分桶/分组(如有)
        - `latency_ms` INT NULL
        - `is_error` TINYINT NOT NULL DEFAULT 0
        - `error_code` VARCHAR(64) NULL
        - `created_at` DATETIME(3) NOT NULL
  
    - `dwd_rec_impression_item`:推荐曝光明细
      - **主键建议**`(tenant_id, trace_id, item_id, position)`
      - **核心索引建议**`(tenant_id, trace_id)`、`(tenant_id, item_id, exposed_at)`
      - **字段建议**
        - `tenant_id` VARCHAR(64) NOT NULL
        - `request_id` VARCHAR(64) NOT NULL
        - `trace_id` VARCHAR(64) NOT NULL
        - `user_key` VARCHAR(64) NOT NULL
        - `placement` VARCHAR(64) NOT NULL
        - `module_id` VARCHAR(128) NULL
        - `trigger_item_id` VARCHAR(64) NULL
        - `item_id` VARCHAR(64) NOT NULL
        - `position` INT NOT NULL
        - `score` DOUBLE NULL
        - `price` DECIMAL(18,2) NULL
        - `currency` VARCHAR(8) NULL
        - `in_stock` TINYINT NULL
        - `exposed_at` DATETIME(3) NOT NULL
  
    - `dwd_rec_click_item`:推荐点击明细
      - **主键建议**`(tenant_id, click_id)`(或 `(tenant_id, trace_id, item_id, clicked_at)`
      - **核心索引建议**`(tenant_id, trace_id)`、`(tenant_id, item_id, clicked_at)`
      - **字段建议**
        - `tenant_id` VARCHAR(64) NOT NULL
        - `click_id` VARCHAR(64) NULL
        - `request_id` VARCHAR(64) NOT NULL
        - `trace_id` VARCHAR(64) NOT NULL
        - `user_key` VARCHAR(64) NOT NULL
        - `placement` VARCHAR(64) NOT NULL
        - `module_id` VARCHAR(128) NULL
        - `trigger_item_id` VARCHAR(64) NULL
        - `item_id` VARCHAR(64) NOT NULL
        - `position` INT NULL
        - `clicked_at` DATETIME(3) NOT NULL
  
  - **转化域(全站通用)**
    - `dwd_view_item`:商品详情页浏览(可承接 search/rec 的 trace,用于链路与兴趣序列)
      - **主键建议**`(tenant_id, view_id)`(或 `(tenant_id, user_key, item_id, viewed_at)`
      - **核心索引建议**`(tenant_id, user_key, viewed_at)`、`(tenant_id, item_id, viewed_at)`
      - **字段建议**
        - `tenant_id` VARCHAR(64) NOT NULL
        - `view_id` VARCHAR(64) NULL
        - `session_id` VARCHAR(64) NULL
        - `user_key` VARCHAR(64) NOT NULL
        - `item_id` VARCHAR(64) NOT NULL
        - `source_type` VARCHAR(32) NULL:来源(search/rec/direct/ads/…)
        - `source_trace_id` VARCHAR(64) NULL:来源 trace(若来自 search/rec)
        - `dwell_time_ms` INT NULL
        - `viewed_at` DATETIME(3) NOT NULL
  
    - `dwd_add_to_cart`:加购事实表(全站统一)
      - **主键建议**`(tenant_id, atc_id)`(或 `(tenant_id, user_key, item_id, added_at)`
      - **核心索引建议**`(tenant_id, user_key, added_at)`、`(tenant_id, item_id, added_at)`
      - **字段建议**
        - `tenant_id` VARCHAR(64) NOT NULL
        - `atc_id` VARCHAR(64) NULL
        - `session_id` VARCHAR(64) NULL
        - `cart_id` VARCHAR(64) NULL
        - `user_key` VARCHAR(64) NOT NULL
        - `item_id` VARCHAR(64) NOT NULL
        - `quantity` INT NOT NULL DEFAULT 1
        - `price` DECIMAL(18,2) NULL
        - `currency` VARCHAR(8) NULL
        - `source_type` VARCHAR(32) NULL:来源(search/rec/direct/…)
        - `source_trace_id` VARCHAR(64) NULL:来源 trace(若来自 search/rec)
        - `added_at` DATETIME(3) NOT NULL
        - `cart_snapshot_json` JSON NULL:购物车快照(可选,体积大时可下沉到独立表)
  
    - `dwd_purchase`:订单事实表(全站统一)
      - **主键建议**`(tenant_id, order_id)`
      - **核心索引建议**`(tenant_id, user_key, paid_at)`、`(tenant_id, paid_at)`
      - **字段建议**
        - `tenant_id` VARCHAR(64) NOT NULL
        - `order_id` VARCHAR(64) NOT NULL
        - `user_key` VARCHAR(64) NOT NULL
        - `currency` VARCHAR(8) NULL
        - `total_amount` DECIMAL(18,2) NULL
        - `paid_at` DATETIME(3) NOT NULL
  
    - `dwd_purchase_item`:订单明细事实表(全站统一)
      - **主键建议**`(tenant_id, order_id, item_id)`(若一单同商品可多行,则增加 `line_id`
      - **核心索引建议**`(tenant_id, item_id, paid_at)`、`(tenant_id, order_id)`
      - **字段建议**
        - `tenant_id` VARCHAR(64) NOT NULL
        - `order_id` VARCHAR(64) NOT NULL
        - `line_id` VARCHAR(64) NULL
        - `user_key` VARCHAR(64) NOT NULL
        - `item_id` VARCHAR(64) NOT NULL
        - `quantity` INT NOT NULL DEFAULT 1
        - `price` DECIMAL(18,2) NULL
        - `paid_at` DATETIME(3) NOT NULL
  
    - **落库/分区建议(MySQL)**
      - 量小:按 `tenant_id` + `created_at` 索引即可
      - 量大:建议按月分表/分区(`*_202601`),或落到 ClickHouse/ES/湖仓;DWD 保持明细可追溯,DWS/ADS 做聚合提速
  
  - **归因桥(可选但强烈建议)**
    - `dwd_attribution_touch`
      - order_id, item_id, last_touch_trace_id, touch_type(search/rec), touch_time, window(如 7d click/1d view)
    - 这样 BI 里的“搜索带来收入/推荐带来收入”不会口径混乱。
  
  ### 2.4 DWS/ADS:面向看板的汇总层(高性能)
  - `dws_search_kpi_daily`(tenant_id, date, page_type/device/geo/new_vs_returning…)
    - search_pv, search_uv, sessions_with_click, sessions_with_atc, sessions_with_purchase
    - click_rate_session, purchase_rate_session, zero_result_rate, no_click_rate, p95_latency
3a5fda00   tangwang   1. ES字段 skus的 ima...
294
  - `dws_query_daily`(tenant_id, date, query_normalized)
001b4889   tangwang   1. docs
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
    - searches, exposure_uv, click_uv, purchase_uv, zero_cnt, no_click_cnt
  - `dws_rec_kpi_daily`(tenant_id, date, placement, algo_id/model_version)
    - impressions, clicks, ctr, atc, purchases, revenue, rpi(revenue per impression)
  - `dws_item_daily`(tenant_id, date, item_id)
    - search_impr/click/atc/purchase、rec_impr/click/…(用于“商品天级统计特征”与运营)
  
  ---
  
  ## 3)推荐系统依赖的数据(“能训练、能实时、能解释”)
  把特征分成 **用户/商品/上下文**,再分 **静态/快照/统计/序列(实时)**
  
  ### 3.1 用户基础信息(dim)
  - `dim_user`:user_key、注册时间、是否会员、国家/语言、获客渠道(如可得)、新老客标签
  - 合规:只存业务需要的最小信息,敏感字段做脱敏/哈希
  
  ### 3.2 用户实时特征(在线序列 + 聚合)
  在线(Redis/Key-Value)建议保留:
  - **最近 N 次行为序列**(按时间衰减)
    - view_item_seq(最近浏览商品)
    - search_query_seq(最近搜索词/类目)
    - click_seq(点击的商品,区分来自 search/rec)
    - cart_seq、purchase_seq
  - **实时聚合**
    - 最近 1h/24h 搜索次数、点击次数、加购次数
    - 最近一次偏好类目/品牌/价格带(从序列实时计算)
  
  离线(天/小时级)输出:
  - RFM、长期偏好向量(类目/品牌 embedding)、价格敏感度、复购周期等
  
  ### 3.3 商品基础特征(静态)
  - `dim_item`(sku/spu)
    - 类目、品牌、属性(颜色/尺码/材质…)、标题/描述、价格、币种、图片
    - 文本/图片 embedding(你们已有 embeddings 模块可复用)
  
  ### 3.4 商品快照(强业务约束,必须可回溯)
  - `item_snapshot`(tenant_id, item_id, snapshot_time)
    - 库存/可售、折扣、上新、发货国家限制、活动标签
  - 推荐/搜索曝光明细里最好**写入当时的关键快照字段**(至少 in_stock、price),避免事后回算失真。
  
  ### 3.5 商品天级统计特征(训练/排序最常用)
  -`dws_item_daily` 派生:
    - 1d/7d/28d:search_ctr、search_cvr、rec_ctr、rec_cvr、atc_rate、purchase_rate
    - 热度、趋势(环比/同比)、退货/取消(如可得)
    - 分 placement 的表现(同一商品在“购物车推荐”与“首页推荐”差异巨大)
  
  ### 3.6 标签(Label)与训练样本(建议一开始就定口径)
  - **曝光→点击**(CTR)标签:以 `impression_item` 为样本
  - **点击→加购/购买**(CVR/GMV)标签:以 click 或 impression 为样本,设定归因窗口
  - 负样本:同一 trace_id 下未被点击的曝光 item(更稳定)
  
  ---
  
  ## 4)你提到的两项“未完成工作”,数据层如何补齐
  - **商品曝光(搜索/推荐)**:必须新增 `ExposureEvent`(建议一屏/一次渲染批量上报 item 列表 + position + module/placement + trace_id)
  - **链路跟踪**:以 `trace_id` 为主串联;若购买跨会话严重,可在 purchase 上补 `attribution_trace_id` 或单独落 `attribution_touch` 表做归因
  
  ---
  
  如果你愿意,我可以基于你们现有 `proto`/事件骨架,把“搜索请求/曝光/点击/加购/购买/推荐请求”这几类事件的**最小必填字段清单**列成一张表(直接给前端埋点和后端 ETL 用),并给出每个指标(CTR/CVR/zero/no-click)的**精确定义与 SQL 计算口径**