Commit 001b488959c30296277dd112463ad004d81d4e3d

Authored by tangwang
1 parent b1bafbbc

1. docs

2. 设置sku_filter_dimension参数的默认值为option1
api/models.py
... ... @@ -154,7 +154,7 @@ class SearchRequest(BaseModel):
154 154  
155 155 # SKU筛选参数
156 156 sku_filter_dimension: Optional[List[str]] = Field(
157   - None,
  157 + ["option1"],
158 158 description=(
159 159 "子SKU筛选维度(店铺配置),为字符串列表。"
160 160 "指定后,每个SPU下的SKU将按这些维度的组合进行分组,每个维度组合只保留一个SKU返回。"
... ...
docs/UA-站内全站埋点数据结构定义.md deleted
... ... @@ -1,105 +0,0 @@
1   -# UA 站内全站埋点数据结构定义(推荐/搜索/画像统一口径)
2   -
3   -本文档用于定义站内全量行为采集(基于“全站埋点采集”,可落地到神策 JS SDK 二次开发),覆盖推荐、搜索、画像、转化分析等核心场景。
4   -
5   -## 1. 目标与约束
6   -
7   -- **目标**:用一套统一事件模型覆盖全站行为(Pageview / Exposure / Click / View Product / Add to Cart / Purchase / Search&Filtering / Cart&Checkout)。
8   -- **约束**:事件需要能在“推荐/搜索请求”与“曝光-点击-加购”等链路上串联;同时需要能表达购物车/结账阶段的状态快照,用于搭配、互补、凑单、替代品推荐。
9   -
10   -## 2. 关键设计原则
11   -
12   -- **统一事件骨架**:所有事件共享同一套顶层字段(用户标识、时间、页面、trace、设备、扩展字段),业务差异放到 `event`(oneof)里。
13   -- **可串联**:用 `trace_id` 串联一次搜索/推荐请求与后续点击、加购、详情浏览等行为;用 `session_id` 串联同一次访问会话。
14   -- **可回放/可训练**:曝光事件尽量携带曝光商品列表、位置、模块;购物车/结账事件携带快照(items + 国家/币种/价格等)。
15   -- **停留时长口径一致**:对 `page_view`/`view_item` 统一给出 `dwell_time_ms` 的采集口径与上报方式。
16   -
17   -## 3. 顶层事件模型(概念)
18   -
19   -每条 UA 事件为一个 `UserActionEvent`,包含:
20   -
21   -- **identity**:tenant / user / anonymous / device / cookie
22   -- **time**:事件发生时间(毫秒时间戳)
23   -- **page**:页面类型、URL、来源、模块位置信息
24   -- **trace**:`trace_id`、`session_id`、实验信息
25   -- **device**:OS / UA / viewport 等
26   -- **event**:具体业务事件(page_view、exposure、click、view_item、search、filter、cart、checkout、purchase…)
27   -- **extra**:业务扩展 KV
28   -
29   -> proto 草案见 `docs/proto/user_action.proto`(本次补充文件)。
30   -
31   -## 4. 核心字段说明
32   -
33   -### 4.1 标识体系(强烈建议)
34   -
35   -- **tenant_id**:租户/店铺/商家维度的隔离主键。
36   -- **user_id**:登录用户 ID(未登录可为空)。
37   -- **anonymous_id**:匿名用户 ID(建议 Cookie 级别稳定,登录后可与 user_id 做归因合并)。
38   -- **device_id**:设备指纹(可选;Web 端更推荐 anonymous_id + cookie_id)。
39   -- **cookie_id**:首次访问生成的持久化 Cookie ID(与 anonymous_id 可以一致,也可分开)。
40   -
41   -### 4.2 trace_id(最重要)
42   -
43   -**定义**:串联一次“搜索/推荐请求(曝光)”与后续点击、详情、加购等行为的请求级会话 ID,同时用于串联内部技术模块(召回/排序/重排等子模块日志)。
44   -
45   -**规则建议**:
46   -
47   -- **新搜索/新推荐刷新**:生成新的 `trace_id`。
48   -- **搜索翻页**:沿用原 `trace_id`,用 `page_number` 区分页(见 `SearchEvent`)。
49   -- **曝光 → 点击/详情/加购**:沿用产生曝光的 `trace_id`,用于表达“该转化源自哪一次曝光/哪一次请求”。
50   -- **购买/支付**:如果链路被购物车长时间阻隔,串联成本高,可不强制要求延续 `trace_id`;但建议在 `PurchaseEvent.attribution_trace_id` 上尽力保留“主要来源”的 trace(若可得)。
51   -
52   -### 4.3 停留时长(dwell_time_ms)
53   -
54   -**适用事件**:
55   -
56   -- `PageViewEvent`:用户在该页面的停留时长
57   -- `ViewItemEvent`:用户在详情页/商品内容上的停留时长(可与 pageview 相同,也可更精细)
58   -
59   -**采集口径建议(Web)**:
60   -
61   -- 在 `pagehide` / `beforeunload` / SPA 路由切换时计算当前页面停留:`now - enter_time`。
62   -- 若页面进入后立即产生 `page_view`,则可在离开页面时补发一条 `page_view_end`(或在同一条事件里填充 `dwell_time_ms`,需要延迟上报)。
63   -- 对详情页:可按“进入详情页到离开详情页”计算;若停留时长无法计算,允许不上报或置 0,但需要在文档/ETL 中区分“缺失 vs 真实 0”。
64   -
65   -## 5. 必须覆盖的事件清单(推荐)
66   -
67   -- **Pageview**
68   - - 分类页、活动页、列表页、首页、店铺页、购物车页、结账页等
69   - - *最好携带该页面曝光的商品列表*(见 `ExposureEvent`,或在 `PageViewEvent.exposed_items` 携带“本页首屏/本次渲染”曝光)
70   -- **Exposure / Click**
71   - - 列表/推荐位曝光与点击(必须包含 position / module_id / item)
72   -- **View product(详情页浏览)**
73   - - 包含 `dwell_time_ms`
74   -- **Add to cart**
75   - - 商品信息 + 数量 + 价格(若可得)+ 当前 cart 快照(若可得)
76   -- **Purchase**
77   - - 订单信息(order_id / currency / total)+ 购买 items
78   -- **On-site Search & Filtering**
79   - - 搜索词、建议词、排序、筛选条件(结构化,避免仅 JSON 字符串)
80   - - 搜索结果曝光/点击建议归入 Exposure/Click,但必须携带 `search_context`
81   -- **Cart Logic / Checkout 状态**
82   - - `cart_snapshot`:购物车当前 items 及属性(qty、price、category、brand…)
83   - - `checkout`:shipping_country、step、payment_method(如可得)
84   -
85   -## 6. 落地建议(神策 JS SDK 二次开发)
86   -
87   -- **事件名**:建议统一用一个事件名(如 `ua_event`),将 `action_type`(主类型)+ `event_id`(子类型,可选)作为属性;或按神策习惯拆分事件名,但必须保证字段一致。
88   -- **批量上报**:曝光事件可批量(一屏/一次渲染一次上报)以降低量级;点击/加购/购买等强转化事件单条实时上报。
89   -- **字段扩展**:放入 `extra.debug_info`,严禁在顶层无限加字段造成版本失控。
90   -
91   -## 7. proto 草案
92   -
93   -见 `docs/proto/user_action.proto`。
94   -
95   -### 7.1 枚举命名说明(避免 proto 枚举值冲突)
96   -
97   -为兼容较旧版本 `protoc`(枚举值采用 package 级作用域),本 proto 中枚举值都带前缀:
98   -
99   -- **ActionType**:`ACTION_TYPE_*`(如 `ACTION_TYPE_PAGEVIEW`)
100   -- **EventId**:`EVENT_ID_*`(如 `EVENT_ID_ADD_TO_CART`)
101   -- **PageType**:`PAGE_TYPE_*`
102   -- **SortType**:`SORT_TYPE_*`
103   -- **CheckoutStep**:`CHECKOUT_STEP_*`
104   -
105   -
docs/blog/语义搜索.md
... ... @@ -41,7 +41,7 @@
41 41 搜索“sports shoes”时,系统自动识别并强化关键购买决策维度:“运动类型(跑步/篮球)”、“适用场地(户外/室内)”、“减震技术”等,使结果更聚焦于用户真实意图。
42 42  
43 43 3. **跨语言自适应能力**
44   - 采用先进的跨语言对齐模型,基于英语训练的系统无需重新训练即可理解泰语、越南语、西班牙语等查询,实测跨语言召回率提升40%,真正实现“一次训练,全球适用”
  44 + 商家上传的商品可以是任何一种语言,用户可以用英语、中文、法语、意大利语、波兰语、西班牙语等30多种语言进行查询
45 45  
46 46 **阶段二:语义重排——让业务目标融入排序决策**
47 47  
... ... @@ -69,16 +69,3 @@
69 69  
70 70 ### 3. 混合查询精准解析:拥抱语言多样性
71 71 针对东南亚、拉美等市场的混合语言查询,系统不再依赖简单的词典翻译,而是理解语言混合背后的完整意图。搜索“裙 kasual wanita”能够准确理解这是“女士休闲裙”的需求,即使查询中包含本地语言词汇。
72   -
73   -## 实测效果:数据驱动的价值证明
74   -
75   -采用语义搜索技术的独立站客户已观察到显著改善:
76   -
77   -- **搜索转化率提升**:平均提升35%,长尾查询提升尤为明显
78   -- **零结果率下降**:从行业平均12%降至2%以下
79   -- **运营效率飞跃**:同义词维护工作量减少80%,可专注于更高价值的优化
80   -- **跨语言覆盖扩展**:支持语言从5种扩展到30+种,无需为每种语言单独训练模型
81   -- **新品曝光加速**:新上架商品在首周获得搜索曝光的概率提升3倍
82   -
83   ----
84   -
... ...
docs/对话式智能导购设计.md 0 → 100644
... ... @@ -0,0 +1,464 @@
  1 +# 对话式智能导购设计(服饰鞋帽独立站)
  2 +
  3 +## 1. 核心场景与用户旅程
  4 +
  5 +### 1.1 典型对话流程示例
  6 +
  7 +**场景 A:新用户首次咨询(需要完善档案)**
  8 +```
  9 +用户: "我想买一件适合夏天的T恤"
  10 +导购: "好的,我来帮您找。请问您平时穿什么尺码?"
  11 +用户: "M码"
  12 +导购: "好的。您比较喜欢什么颜色?我们这里有白色、黑色、蓝色、灰色等"
  13 +用户: "白色或浅色都可以"
  14 +导购: "了解。您希望是休闲款还是运动款?"
  15 +用户: "休闲的"
  16 +导购: "好的,我为您找到了几款,价格在50-150元之间,您看看..."
  17 +[展示结果]
  18 +```
  19 +
  20 +**场景 B:老用户(已有档案,快速推荐)**
  21 +```
  22 +用户: "帮我找一条牛仔裤"
  23 +导购: "好的,根据您的尺码偏好(30码),我为您推荐..."
  24 +[直接展示结果,如不满意再细化]
  25 +```
  26 +
  27 +**场景 C:模糊需求逐步明确**
  28 +```
  29 +用户: "我想买件外套"
  30 +导购: "好的,请问是用于什么场合?日常通勤、运动、还是正式场合?"
  31 +用户: "日常通勤"
  32 +导购: "了解。您希望是薄款还是厚款?现在这个季节..."
  33 +用户: "薄款就行"
  34 +导购: "好的,我为您推荐几款适合通勤的薄外套..."
  35 +```
  36 +
  37 +### 1.2 核心价值点
  38 +
  39 +- **降低搜索门槛**:用户用自然语言表达,无需熟悉筛选器
  40 +- **个性化合身推荐**:通过尺码/合身偏好,减少退货率
  41 +- **提升转化**:多轮对话收集偏好,推荐更精准
  42 +- **完善用户档案**:每次对话积累偏好,后续推荐更准
  43 +
  44 +---
  45 +
  46 +## 2. 技术架构
  47 +
  48 +### 2.1 整体架构(LLM + 商品检索 + 推荐引擎 + 用户档案)
  49 +
  50 +```
  51 +┌─────────────────────────────────────────────────────────┐
  52 +│ 前端对话界面 │
  53 +│ (Web Chat Widget / 小程序 / H5) │
  54 +└────────────────────┬────────────────────────────────────┘
  55 + │
  56 + ▼
  57 +┌─────────────────────────────────────────────────────────┐
  58 +│ 对话式导购服务层 (Conversational Service) │
  59 +│ ┌──────────────────────────────────────────────────┐ │
  60 +│ │ 对话状态管理 (Dialogue State Tracker, DST) │ │
  61 +│ │ - 当前意图 (intent) │ │
  62 +│ │ - 已收集的偏好 (collected_preferences) │ │
  63 +│ │ - 待确认信息 (pending_confirmation) │ │
  64 +│ │ - 对话历史 (dialogue_history) │ │
  65 +│ └──────────────────────────────────────────────────┘ │
  66 +│ ┌──────────────────────────────────────────────────┐ │
  67 +│ │ LLM 对话引擎 (核心) │ │
  68 +│ │ - 意图理解 (NLU) │ │
  69 +│ │ - 实体抽取 (NER: 类目/颜色/尺码/价格/风格...) │ │
  70 +│ │ - 回复生成 (NLG) │ │
  71 +│ │ - 策略决策 (何时问问题/何时展示结果) │ │
  72 +│ └──────────────────────────────────────────────────┘ │
  73 +│ ┌──────────────────────────────────────────────────┐ │
  74 +│ │ 商品检索与推荐引擎 │ │
  75 +│ │ - 基于偏好生成 filters/range_filters │ │
  76 +│ │ - 调用搜索 API (复用现有 /search/) │ │
  77 +│ │ - 结果排序与多样性控制 │ │
  78 +│ └──────────────────────────────────────────────────┘ │
  79 +│ ┌──────────────────────────────────────────────────┐ │
  80 +│ │ 用户档案管理 (User Profile) │ │
  81 +│ │ - 尺码偏好 (size_preferences) │ │
  82 +│ │ - 风格偏好 (style_preferences) │ │
  83 +│ │ - 价格偏好 (price_range) │ │
  84 +│ │ - 历史购买/浏览 │ │
  85 +│ └──────────────────────────────────────────────────┘ │
  86 +└────────────────────┬────────────────────────────────────┘
  87 + │
  88 + ┌────────────┼────────────┐
  89 + ▼ ▼ ▼
  90 +┌─────────────┐ ┌──────────┐ ┌──────────────┐
  91 +│ 搜索 API │ │ 商品库 │ │ 用户行为库 │
  92 +│ (现有) │ │ (ES/DB) │ │ (埋点数据) │
  93 +└─────────────┘ └──────────┘ └──────────────┘
  94 +```
  95 +
  96 +### 2.2 核心组件说明
  97 +
  98 +#### 2.2.1 对话状态管理 (DST)
  99 +- **存储位置**:Redis(key: `dialogue:{tenant_id}:{user_key}:{session_id}`)
  100 +- **状态结构**:
  101 + ```json
  102 + {
  103 + "intent": "find_product|refine_search|ask_question|...",
  104 + "collected_preferences": {
  105 + "category": "T恤",
  106 + "size": "M",
  107 + "color": ["白色", "浅色"],
  108 + "style": "休闲",
  109 + "price_range": {"min": 50, "max": 150},
  110 + "occasion": "日常",
  111 + "season": "夏季"
  112 + },
  113 + "pending_confirmation": ["size", "color"],
  114 + "dialogue_history": [
  115 + {"role": "user", "content": "..."},
  116 + {"role": "assistant", "content": "..."}
  117 + ],
  118 + "current_results": [...], // 当前推荐结果(如有)
  119 + "turn_count": 3
  120 + }
  121 + ```
  122 +
  123 +#### 2.2.2 LLM 对话引擎
  124 +- **输入**:用户消息 + 对话状态 + 商品库元信息(可选:类目列表、颜色列表、尺码列表)
  125 +- **输出**:
  126 + - **结构化输出**(必须):`intent`、`extracted_entities`、`action`(ask_question|show_results|clarify)
  127 + - **自然语言回复**(用于前端展示)
  128 +- **LLM 选择**:
  129 + - **推荐**:GPT-4o / Claude 3.5 Sonnet(强推理、结构化输出)
  130 + - **成本优化**:GPT-4o-mini / Claude Haiku(简单场景)
  131 + - **私有化**:Qwen2.5 / GLM-4(如需要)
  132 +
  133 +#### 2.2.3 商品检索与推荐引擎
  134 +- **输入**:对话状态中的 `collected_preferences`
  135 +- **处理**:
  136 + 1. 将偏好转换为搜索 API 的 `filters` / `range_filters`
  137 + 2. 调用现有 `/search/` API
  138 + 3. 结果排序(可结合用户历史、商品热度、多样性)
  139 +- **输出**:商品列表(含图片/标题/价格/链接)
  140 +
  141 +#### 2.2.4 用户档案管理
  142 +- **存储位置**:MySQL/Redis(key: `user_profile:{tenant_id}:{user_key}`)
  143 +- **字段结构**:
  144 + ```json
  145 + {
  146 + "size_preferences": {
  147 + "tops": "M",
  148 + "bottoms": "30",
  149 + "shoes": "42"
  150 + },
  151 + "style_preferences": ["休闲", "简约"],
  152 + "color_preferences": ["白色", "黑色", "灰色"],
  153 + "price_range": {"min": 50, "max": 300},
  154 + "brand_preferences": ["品牌A", "品牌B"],
  155 + "last_updated": "2026-01-21T10:00:00Z"
  156 + }
  157 + ```
  158 +
  159 +---
  160 +
  161 +## 3. 主要能力清单
  162 +
  163 +### 3.1 核心能力(MVP 必须)
  164 +
  165 +#### A. 意图理解与实体抽取 (NLU)
  166 +- **能力**:从用户自然语言中提取:
  167 + - **类目**:T恤、牛仔裤、运动鞋、外套...
  168 + - **属性**:颜色、尺码、材质、风格(休闲/正式/运动)
  169 + - **价格**:价格区间、预算
  170 + - **场合**:日常、通勤、运动、正式
  171 + - **季节**:春夏秋冬
  172 + - **其他**:品牌、折扣、新品等
  173 +- **实现**:LLM 做 NER(命名实体识别)+ 规则后处理(映射到商品库的 specifications)
  174 +
  175 +#### B. 偏好收集与确认
  176 +- **能力**:
  177 + - 识别用户已表达的偏好
  178 + - 判断哪些关键信息缺失(如尺码、颜色)
  179 + - 生成追问问题(基于店铺商品库的可用选项)
  180 +- **实现**:
  181 + - LLM 判断缺失项
  182 + - 从商品库分面(facets)获取可用选项(如"我们这里有白色、黑色、蓝色...")
  183 + - 生成自然语言问题
  184 +
  185 +#### C. 商品检索与筛选
  186 +- **能力**:
  187 + - 将对话偏好转换为搜索 API 的 `filters` / `range_filters`
  188 + - 调用搜索 API 获取候选
  189 + - 结果排序(相关性 + 个性化 + 多样性)
  190 +- **实现**:
  191 + - 偏好 → filters 映射规则(可配置)
  192 + - 复用现有 `/search/` API
  193 + - 排序可结合用户档案(如优先推荐用户偏好的品牌/价格带)
  194 +
  195 +#### D. 结果展示与解释
  196 +- **能力**:
  197 + - 生成推荐理由("根据您的尺码偏好和风格,我为您推荐...")
  198 + - 展示商品卡片(图片/标题/价格/链接)
  199 + - 支持继续对话("不满意?告诉我您想要什么样的")
  200 +- **实现**:LLM 生成回复 + 前端渲染商品卡片
  201 +
  202 +#### E. 用户档案管理
  203 +- **能力**:
  204 + - 从对话中提取并持久化偏好(尺码/风格/价格/品牌)
  205 + - 后续对话自动使用档案(减少重复询问)
  206 + - 档案更新(用户纠正/新偏好)
  207 +- **实现**:
  208 + - 对话结束后更新 `user_profile`
  209 + - 下次对话时作为上下文输入 LLM
  210 +
  211 +### 3.2 进阶能力(后续迭代)
  212 +
  213 +#### F. 合身推荐(Size Fit)
  214 +- **能力**:
  215 + - 基于用户历史购买/浏览,学习"合身偏好"(如"这个品牌M码偏大,建议选S")
  216 + - 跨品牌尺码映射(如"您平时穿Nike 42码,这个品牌建议选41码")
  217 +- **实现**:
  218 + - 需要用户历史数据(购买/退货/评价)
  219 + - 可做简单的"品牌-尺码映射表"(运营配置)
  220 + - 或训练轻量模型(用户尺码偏好 → 商品推荐尺码)
  221 +
  222 +#### G. 搭配推荐(Outfit Recommendation)
  223 +- **能力**:
  224 + - 用户选中一件商品后,推荐搭配(如"这件T恤可以搭配这条牛仔裤")
  225 + - 基于商品属性相似度 + 历史共购数据
  226 +- **实现**:
  227 + - 商品 embedding(文本/图片)
  228 + - 共购规则(FBT)
  229 + - LLM 生成搭配理由
  230 +
  231 +#### H. 多轮对话策略优化
  232 +- **能力**:
  233 + - 智能判断"何时该问问题" vs "何时该展示结果"
  234 + - 避免过度询问(用户流失)
  235 +- **实现**:
  236 + - 规则:关键信息(尺码/类目)缺失时必问;可选信息(颜色/风格)有足够候选时可不问
  237 + - 或训练策略模型(RL/bandit)
  238 +
  239 +#### I. 上下文记忆与纠错
  240 +- **能力**:
  241 + - 记住对话中提到的商品("刚才那件白色的")
  242 + - 支持用户纠正("不对,我要的是黑色")
  243 +- **实现**:
  244 + - 对话状态中维护 `mentioned_items`
  245 + - LLM 理解指代消解(coreference resolution)
  246 +
  247 +---
  248 +
  249 +## 4. 数据层需求
  250 +
  251 +### 4.1 对话事件表(DWD 层)
  252 +
  253 +- `dwd_conversation_turn`:每次对话轮次
  254 + - `tenant_id`, `user_key`, `session_id`, `conversation_id`
  255 + - `turn_number`, `role` (user/assistant), `content`
  256 + - `intent`, `extracted_entities_json`
  257 + - `action` (ask_question|show_results|clarify)
  258 + - `created_at`
  259 +
  260 +- `dwd_conversation_result`:对话产生的推荐结果
  261 + - `tenant_id`, `conversation_id`, `turn_number`
  262 + - `item_id`, `position`, `clicked` (是否被点击)
  263 + - `exposed_at`
  264 +
  265 +### 4.2 用户档案表(DIM 层)
  266 +
  267 +- `dim_user_profile`:用户偏好档案
  268 + - `tenant_id`, `user_key`
  269 + - `size_preferences_json`
  270 + - `style_preferences_json`
  271 + - `color_preferences_json`
  272 + - `price_range_json`
  273 + - `brand_preferences_json`
  274 + - `last_updated`, `created_at`
  275 +
  276 +### 4.3 商品库元信息(用于 LLM 上下文)
  277 +
  278 +- **类目列表**:从商品库聚合 `category1_name`, `category2_name`, `category3_name`
  279 +- **颜色列表**:从 `specifications` 聚合 `name="color"` 的所有 `value`
  280 +- **尺码列表**:从 `specifications` 聚合 `name="size"` 的所有 `value`
  281 +- **风格标签**:从 `tags` 或自定义字段聚合
  282 +
  283 +> **注意**:这些元信息需要定期更新(如每天),作为 LLM 的"知识库"输入,确保推荐的商品确实存在。
  284 +
  285 +---
  286 +
  287 +## 5. 技术实现要点
  288 +
  289 +### 5.1 LLM Prompt 设计(关键)
  290 +
  291 +**系统提示词模板**:
  292 +```
  293 +你是一个专业的服饰导购助手,帮助用户在店铺中找到合适的商品。
  294 +
  295 +店铺信息:
  296 +- 类目:{category_list}
  297 +- 颜色:{color_list}
  298 +- 尺码:{size_list}
  299 +- 风格:{style_list}
  300 +
  301 +用户档案(如有):
  302 +{user_profile_json}
  303 +
  304 +当前对话状态:
  305 +{conversation_state_json}
  306 +
  307 +任务:
  308 +1. 理解用户意图
  309 +2. 提取商品偏好(类目/颜色/尺码/价格/风格/场合等)
  310 +3. 判断缺失的关键信息
  311 +4. 生成自然语言回复
  312 +
  313 +输出格式(JSON):
  314 +{
  315 + "intent": "find_product|refine_search|ask_question|...",
  316 + "extracted_entities": {
  317 + "category": "...",
  318 + "color": [...],
  319 + "size": "...",
  320 + "price_range": {"min": ..., "max": ...},
  321 + "style": "...",
  322 + "occasion": "..."
  323 + },
  324 + "action": "ask_question|show_results|clarify",
  325 + "missing_info": ["size", "color"], // 缺失的关键信息
  326 + "reply": "自然语言回复"
  327 +}
  328 +```
  329 +
  330 +### 5.2 偏好 → 搜索 Filters 映射规则
  331 +
  332 +```python
  333 +def preferences_to_filters(collected_preferences, user_profile):
  334 + filters = {}
  335 + range_filters = {}
  336 +
  337 + # 类目
  338 + if collected_preferences.get("category"):
  339 + filters["category_name"] = collected_preferences["category"]
  340 +
  341 + # 颜色(specifications)
  342 + if collected_preferences.get("color"):
  343 + filters["specifications"] = [
  344 + {"name": "color", "value": c}
  345 + for c in collected_preferences["color"]
  346 + ]
  347 +
  348 + # 尺码(specifications)
  349 + if collected_preferences.get("size"):
  350 + # 优先用对话中的,否则用用户档案
  351 + size = collected_preferences.get("size") or user_profile.get("size_preferences", {}).get("tops")
  352 + if size:
  353 + filters.setdefault("specifications", []).append({"name": "size", "value": size})
  354 +
  355 + # 价格区间
  356 + if collected_preferences.get("price_range"):
  357 + pr = collected_preferences["price_range"]
  358 + range_filters["min_price"] = {"gte": pr.get("min", 0), "lte": pr.get("max", 9999)}
  359 +
  360 + # 风格(tags 或自定义字段)
  361 + if collected_preferences.get("style"):
  362 + filters["tags"] = collected_preferences["style"]
  363 +
  364 + return filters, range_filters
  365 +```
  366 +
  367 +### 5.3 对话流程控制(状态机)
  368 +
  369 +```
  370 +初始状态: waiting_for_intent
  371 + ↓ 用户输入
  372 +意图理解: extract_intent_and_entities
  373 + ↓
  374 +判断缺失信息:
  375 + - 关键信息缺失(如尺码)→ ask_question
  376 + - 有足够信息 → show_results
  377 + ↓
  378 +展示结果后:
  379 + - 用户满意 → end_conversation
  380 + - 用户不满意/继续提问 → refine_search (更新偏好,重新检索)
  381 +```
  382 +
  383 +---
  384 +
  385 +## 6. 产品形态建议
  386 +
  387 +### 6.1 前端交互方式
  388 +
  389 +- **Web Chat Widget**:右下角悬浮聊天框(类似客服)
  390 +- **全屏对话页**:独立页面,适合移动端
  391 +- **搜索结果页集成**:在搜索结果页提供"智能导购"入口
  392 +
  393 +### 6.2 回复展示格式
  394 +
  395 +- **纯文本回复**:LLM 生成的自然语言
  396 +- **商品卡片**:展示推荐结果(图片/标题/价格/加购按钮)
  397 +- **选项按钮**:快速选择(如"白色"、"黑色"、"蓝色")
  398 +- **追问输入框**:用户继续输入
  399 +
  400 +---
  401 +
  402 +## 7. 评估指标
  403 +
  404 +### 7.1 对话质量
  405 +- **平均对话轮次**:完成一次推荐的平均轮次(越少越好,但需平衡信息收集)
  406 +- **用户满意度**:对话结束后的反馈(如"有用"/"无用")
  407 +- **推荐点击率**:对话推荐的商品被点击的比例
  408 +
  409 +### 7.2 业务指标
  410 +- **转化率**:对话用户 → 加购/购买的转化
  411 +- **AOV 提升**:对话用户的平均订单价值 vs 非对话用户
  412 +- **档案完善率**:用户档案被更新的比例
  413 +
  414 +---
  415 +
  416 +## 8. 实施优先级
  417 +
  418 +### Phase 1 (MVP - 2-3个月)
  419 +- ✅ 基础对话能力(LLM + 意图理解 + 实体抽取)
  420 +- ✅ 偏好收集(尺码/颜色/类目/价格)
  421 +- ✅ 商品检索(偏好 → filters → 搜索 API)
  422 +- ✅ 结果展示(商品卡片)
  423 +- ✅ 用户档案(基础字段:尺码/颜色/价格)
  424 +
  425 +### Phase 2 (增强 - 3-4个月)
  426 +- ✅ 合身推荐(尺码映射)
  427 +- ✅ 搭配推荐
  428 +- ✅ 多轮对话策略优化
  429 +- ✅ 上下文记忆
  430 +
  431 +### Phase 3 (优化 - 持续)
  432 +- ✅ 个性化排序(结合用户历史)
  433 +- ✅ A/B 测试(不同 prompt/策略)
  434 +- ✅ 跨租户知识共享(可选)
  435 +
  436 +---
  437 +
  438 +## 9. 技术栈建议
  439 +
  440 +- **LLM 服务**:OpenAI API / Anthropic API / 私有化部署(Qwen/GLM)
  441 +- **对话状态存储**:Redis
  442 +- **用户档案存储**:MySQL + Redis(缓存)
  443 +- **商品检索**:复用现有搜索 API
  444 +- **后端框架**:Python FastAPI(与现有 API 保持一致)
  445 +- **前端**:React/Vue + WebSocket(实时对话)
  446 +
  447 +---
  448 +
  449 +## 10. 注意事项
  450 +
  451 +1. **成本控制**:LLM API 调用成本(每次对话可能 3-10 轮),建议:
  452 + - 简单场景用轻量模型(GPT-4o-mini)
  453 + - 复杂场景用强模型(GPT-4o)
  454 + - 缓存常见问题回复
  455 +
  456 +2. **延迟**:LLM 生成回复通常 1-3 秒,需要:
  457 + - 前端显示"正在思考..."
  458 + - 考虑流式输出(streaming)
  459 +
  460 +3. **商品库同步**:确保 LLM 的"知识库"(类目/颜色/尺码列表)与商品库实时同步
  461 +
  462 +4. **多语言**:如店铺支持多语言,LLM 需要支持对应语言
  463 +
  464 +5. **隐私合规**:用户档案数据需符合 GDPR/CCPA 等要求
... ...
docs/搜索推荐数据.md 0 → 100644
... ... @@ -0,0 +1,353 @@
  1 +
  2 +## 1)BI 怎么设计(对标 Shopify/独立站“搜索/推荐”常见报表)
  3 +Shopify 的 Search & Discovery/行为报表里,搜索常看的就是 **query、no results、no clicks、click rate、purchase rate**(会话口径漏斗)。推荐系统的看板更强调 **曝光→点击→加购→购买→收入**,并按**推荐位/算法/实验**拆解。
  4 +
  5 +### 1.1 搜索 BI(核心看板)
  6 +- **搜索总览(KPI + 漏斗)**
  7 + - **搜索 PV/UV**:search request 次数 / 搜索用户数
  8 + - **Click rate(会话口径,Shopify 常用)**:有点击的搜索会话 / 搜索会话
  9 + - **ATC rate**:有加购的搜索会话 / 搜索会话
  10 + - **Purchase rate(会话口径,Shopify 常用)**:有购买的搜索会话 / 搜索会话
  11 + - **结果曝光 CTR(结果口径)**:点击次数 / 结果曝光次数(更适合诊断排序/样式)
  12 + - **延迟&稳定性**:P50/P95 搜索耗时、错误率、空响应率
  13 +
  14 +- **Query 分析(运营/选品/词库最常用)**
  15 + - **高热搜索词**:按搜索 UV、曝光 UV、点击 UV、购买 UV 排序
  16 + - **飙升词/新词**:与过去 \(7/14/28\) 天对比的增速
  17 + - **无结果 query**(no results)
  18 + - **有结果但无点击 query**(no clicks)——强信号:相关性差/图片价位不吸引/首屏无货等
  19 + - **建议词(suggestion)**:suggest 点击发起的搜索占比、suggest→点击/购买转化
  20 +
  21 +- **结果质量诊断(给算法/工程用)**
  22 + - **点击位置分布**:position=1/2/3… 的点击占比(反推排序质量)
  23 + - **类目/品牌/价格带分布**:哪些 query 对哪些类目贡献转化
  24 + - **筛选/排序使用率**:filter 使用率、排序切换率、filter 后的 CTR/CVR 变化
  25 +
  26 +- **用户与渠道拆解(增长/产品用)**
  27 + - **新/老客**、地域、语言、设备、来源(自然/广告/社媒)
  28 + - **页面维度**:首页搜索框 / 搜索页 / 分类页搜索 / 详情页内搜索等
  29 +
  30 +- **Session/链路回放(你提到的 track_id/trace_id)**
  31 + - 单用户或单 trace:**搜索→换词→曝光→点击→详情→加购→支付**
  32 + - 支持按 **trace_id** 串联一次“搜索请求”与后续行为(你们文档也强调这一点)
  33 +
  34 +> 参考: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))。
  35 +
  36 +### 1.2 推荐 BI(核心看板)
  37 +- **推荐位总览(按 placement/module)**
  38 + - **Impressions/Clicks/CTR**
  39 + - **ATC、Purchase、Revenue**
  40 + - **Revenue per impression / per click**
  41 + - **AOV(推荐归因订单)**
  42 + - **覆盖与多样性**:覆盖商品数、长尾曝光占比、重复率(避免“只推爆款”)
  43 +
  44 +- **按算法/实验拆解**
  45 + - 算法版本(model_version/strategy_id)
  46 + - 实验(experiment_id/variant_id)
  47 + - **Lift(增量)**:相对对照组的 CTR/CVR/Revenue uplift(最好有 holdout)
  48 +
  49 +- **健康度与风控**
  50 + - 缺货/下架命中率、被过滤原因分布(无库存/不可售/地域不发货)
  51 + - 冷启动占比(新用户/新商品)与表现
  52 +
  53 +---
  54 +
  55 +## 2)数据层面的设计(埋点→数仓→指标→推荐特征)
  56 +你们已有统一事件骨架的方向(`tenant_id / session_id / trace_id / event(oneof)`)。建议在数据层分成 **ODS(原始)→DWD(清洗明细)→DWS(汇总)→ADS(看板语义层)**,同时给推荐做 **离线+在线特征库**。
  57 +
  58 +### 2.1 关键 ID 设计(决定 BI/推荐能否串起来)
  59 +- **tenant_id**:多租户隔离必备(所有表分区/主键都带)
  60 +- **user_key**:归一后的用户主键(优先 login/user_id;否则 anonymous_id/cookie_id)
  61 +- **session_id**:会话(SDK 产生或用 30min inactivity 规则补齐)
  62 +- **trace_id(最重要)**:一次搜索/一次推荐刷新生成一个,后续点击/详情/加购尽量继承
  63 +- **request_id**:后端请求日志关联(用于延迟、错误、召回/排序 debug)
  64 +- **order_id/cart_id/item_id(sku/spu)**:交易与商品归因
  65 +
  66 +### 2.2 ODS:原始事件(“可回放、可重放”)
  67 +- `ods_ua_event_raw`
  68 + - tenant_id, event_time, received_time
  69 + - identities(原始字段:distinct_id/login_id/anonymous_id/cookie_id…)
  70 + - page/device/geo/referrer
  71 + - trace_id, session_id, experiment 信息
  72 + - event_name + properties(原始 JSON,保留全量)
  73 +
  74 +> 你现在的 `$pageview/$WebClick` 自动采集能覆盖点击和页面,但 **推荐/搜索“曝光”必须补埋点**(否则 CTR、归因、训练样本都会缺)。
  75 +
  76 +### 2.3 DWD:清洗后的事实表(BI/训练统一口径)
  77 +建议把“强分析对象”拆成事实表(便于 join、去重、做漏斗):
  78 +
  79 +- **搜索域**
  80 + - `dwd_search_request`:一次“搜索结果刷新/请求”的主表(强烈建议:**每次请求一个 request_id,同时每次请求一个 trace_id**)
  81 + - **用途**:search PV/UV、零结果、延迟、query 聚合、会话口径漏斗分母(search_session)
  82 + - **主键建议**:`(tenant_id, request_id)`
  83 + - **核心索引建议**:
  84 + - `(tenant_id, created_at)`
  85 + - `(tenant_id, user_key, created_at)`
  86 + - `(tenant_id, query_normalized, created_at)`
  87 + - `(tenant_id, trace_id)`(用于 join 曝光/点击)
  88 + - `(tenant_id, search_session_id, created_at)`
  89 + - **字段建议(MySQL 参考类型,可按你们存储调整)**
  90 + - `tenant_id` VARCHAR(64) NOT NULL:店铺/租户
  91 + - `request_id` VARCHAR(64) NOT NULL:该次搜索请求唯一 ID(前端生成或后端返回)
  92 + - `trace_id` VARCHAR(64) NOT NULL:该次搜索链路 ID(一次结果集 = 一个 trace)
  93 + - `session_id` VARCHAR(64) NULL:访问会话(30min inactivity)
  94 + - `search_session_id` VARCHAR(64) NULL:搜索会话(一次“找东西”的连续过程)
  95 + - `user_id` VARCHAR(64) NULL:登录用户 ID
  96 + - `anonymous_id` VARCHAR(64) NULL:匿名用户(cookie 级稳定)
  97 + - `user_key` VARCHAR(64) NOT NULL:归一用户主键(ETL 生成)
  98 + - `query` TEXT NOT NULL:原始 query
  99 + - `query_normalized` VARCHAR(512) NOT NULL:归一化 query(聚合用)
  100 + - `is_suggestion` TINYINT NOT NULL DEFAULT 0:是否由 suggestion 触发
  101 + - `suggestion_text` VARCHAR(512) NULL:命中的 suggestion(如有)
  102 + - `page_number` INT NOT NULL DEFAULT 1:翻页页码(1-based)
  103 + - `sort` VARCHAR(64) NULL:排序方式(如 relevance/price_asc/…)
  104 + - `filters_json` JSON NULL:结构化筛选条件(原子字段更好;JSON 为起步方案)
  105 + - `filters_hash` CHAR(32) NULL:filters 归一化后的 hash(便于聚合/去重)
  106 + - `results_count` INT NOT NULL DEFAULT 0:总命中数
  107 + - `returned_count` INT NULL:本页返回数量(page size)
  108 + - `latency_ms` INT NULL:搜索耗时
  109 + - `is_zero_result` TINYINT NOT NULL DEFAULT 0:是否零结果(可由 results_count=0 派生)
  110 + - `is_error` TINYINT NOT NULL DEFAULT 0:是否错误
  111 + - `error_code` VARCHAR(64) NULL:错误码(如超时/限流等)
  112 + - `page_type` VARCHAR(64) NULL:发生搜索的页面(home/search/pdp/collection…)
  113 + - `referrer` TEXT NULL:来源页
  114 + - `device_type` VARCHAR(32) NULL:pc/mobile(可从 UA 解析)
  115 + - `country` VARCHAR(8) NULL:国家(建议由 IP->Geo 派生;避免落全量 IP)
  116 + - `created_at` DATETIME(3) NOT NULL:事件时间(毫秒级可选)
  117 +
  118 + - `dwd_search_impression_item`:搜索结果“曝光明细”(**必须补**,否则无法算 position CTR、训练负样本)
  119 + - **用途**:曝光 PV/UV、位置 CTR、召回/排序诊断、训练样本(曝光未点为负样本)
  120 + - **主键建议**:`(tenant_id, trace_id, item_id, position)`(或 `(tenant_id, request_id, item_id, position)`,二选一但全局统一)
  121 + - **核心索引建议**:
  122 + - `(tenant_id, trace_id)`
  123 + - `(tenant_id, request_id)`
  124 + - `(tenant_id, item_id, exposed_at)`
  125 + - **字段建议**
  126 + - `tenant_id` VARCHAR(64) NOT NULL
  127 + - `request_id` VARCHAR(64) NOT NULL
  128 + - `trace_id` VARCHAR(64) NOT NULL
  129 + - `search_session_id` VARCHAR(64) NULL
  130 + - `user_key` VARCHAR(64) NOT NULL
  131 + - `query_normalized` VARCHAR(512) NOT NULL
  132 + - `item_id` VARCHAR(64) NOT NULL:spu 或 sku,需统一
  133 + - `position` INT NOT NULL:在搜索结果中的排名(1-based)
  134 + - `score` DOUBLE NULL:排序分(如 ES score/learning-to-rank score)
  135 + - `price` DECIMAL(18,2) NULL:曝光时价格快照(可选但强烈建议)
  136 + - `currency` VARCHAR(8) NULL
  137 + - `in_stock` TINYINT NULL:曝光时库存可售快照(可选但强烈建议)
  138 + - `exposed_at` DATETIME(3) NOT NULL:曝光时间
  139 +
  140 + - `dwd_search_click_item`:搜索结果点击明细(点击必须能回链到曝光/请求)
  141 + - **用途**:click UV、CTR(曝光口径/会话口径)、位置点击分布、归因触点
  142 + - **主键建议**:`(tenant_id, click_id)`(若无 click_id,可用 `(tenant_id, trace_id, item_id, clicked_at)` 近似)
  143 + - **核心索引建议**:
  144 + - `(tenant_id, trace_id)`
  145 + - `(tenant_id, request_id)`
  146 + - `(tenant_id, item_id, clicked_at)`
  147 + - **字段建议**
  148 + - `tenant_id` VARCHAR(64) NOT NULL
  149 + - `click_id` VARCHAR(64) NULL:点击事件唯一 ID(推荐补)
  150 + - `request_id` VARCHAR(64) NOT NULL
  151 + - `trace_id` VARCHAR(64) NOT NULL
  152 + - `search_session_id` VARCHAR(64) NULL
  153 + - `user_key` VARCHAR(64) NOT NULL
  154 + - `query_normalized` VARCHAR(512) NOT NULL
  155 + - `item_id` VARCHAR(64) NOT NULL
  156 + - `position` INT NULL:点击时该商品所在排名(无法取到则置空)
  157 + - `clicked_at` DATETIME(3) NOT NULL
  158 + - `target_url` TEXT NULL:点击跳转 URL(可选)
  159 +
  160 +- **推荐域**
  161 + - `dwd_rec_request`:一次推荐请求/刷新主表(一次刷新 = 一个 trace_id)
  162 + - **用途**:推荐 PV/UV、分推荐位指标、实验/版本拆解、延迟与稳定性
  163 + - **主键建议**:`(tenant_id, request_id)`
  164 + - **核心索引建议**:
  165 + - `(tenant_id, created_at)`
  166 + - `(tenant_id, placement, created_at)`
  167 + - `(tenant_id, trace_id)`
  168 + - `(tenant_id, algo_id, model_version, created_at)`
  169 + - **字段建议**
  170 + - `tenant_id` VARCHAR(64) NOT NULL
  171 + - `request_id` VARCHAR(64) NOT NULL
  172 + - `trace_id` VARCHAR(64) NOT NULL
  173 + - `session_id` VARCHAR(64) NULL
  174 + - `user_key` VARCHAR(64) NOT NULL
  175 + - `placement` VARCHAR(64) NOT NULL:推荐位(home/pdp/cart/checkout/search…)
  176 + - `module_id` VARCHAR(128) NULL:页面内模块标识(一个页面多个推荐模块)
  177 + - `trigger_item_id` VARCHAR(64) NULL:触发商品(PDP/Cart 场景常用)
  178 + - `candidates_count` INT NULL:候选数量
  179 + - `returned_count` INT NULL:返回条数
  180 + - `algo_id` VARCHAR(64) NULL:策略/算法标识(rule/i2i/embedding/…)
  181 + - `model_version` VARCHAR(64) NULL:模型版本
  182 + - `experiment_id` VARCHAR(64) NULL:实验 ID(如有)
  183 + - `variant_id` VARCHAR(64) NULL:分桶/分组(如有)
  184 + - `latency_ms` INT NULL
  185 + - `is_error` TINYINT NOT NULL DEFAULT 0
  186 + - `error_code` VARCHAR(64) NULL
  187 + - `created_at` DATETIME(3) NOT NULL
  188 +
  189 + - `dwd_rec_impression_item`:推荐曝光明细
  190 + - **主键建议**:`(tenant_id, trace_id, item_id, position)`
  191 + - **核心索引建议**:`(tenant_id, trace_id)`、`(tenant_id, item_id, exposed_at)`
  192 + - **字段建议**
  193 + - `tenant_id` VARCHAR(64) NOT NULL
  194 + - `request_id` VARCHAR(64) NOT NULL
  195 + - `trace_id` VARCHAR(64) NOT NULL
  196 + - `user_key` VARCHAR(64) NOT NULL
  197 + - `placement` VARCHAR(64) NOT NULL
  198 + - `module_id` VARCHAR(128) NULL
  199 + - `trigger_item_id` VARCHAR(64) NULL
  200 + - `item_id` VARCHAR(64) NOT NULL
  201 + - `position` INT NOT NULL
  202 + - `score` DOUBLE NULL
  203 + - `price` DECIMAL(18,2) NULL
  204 + - `currency` VARCHAR(8) NULL
  205 + - `in_stock` TINYINT NULL
  206 + - `exposed_at` DATETIME(3) NOT NULL
  207 +
  208 + - `dwd_rec_click_item`:推荐点击明细
  209 + - **主键建议**:`(tenant_id, click_id)`(或 `(tenant_id, trace_id, item_id, clicked_at)`)
  210 + - **核心索引建议**:`(tenant_id, trace_id)`、`(tenant_id, item_id, clicked_at)`
  211 + - **字段建议**
  212 + - `tenant_id` VARCHAR(64) NOT NULL
  213 + - `click_id` VARCHAR(64) NULL
  214 + - `request_id` VARCHAR(64) NOT NULL
  215 + - `trace_id` VARCHAR(64) NOT NULL
  216 + - `user_key` VARCHAR(64) NOT NULL
  217 + - `placement` VARCHAR(64) NOT NULL
  218 + - `module_id` VARCHAR(128) NULL
  219 + - `trigger_item_id` VARCHAR(64) NULL
  220 + - `item_id` VARCHAR(64) NOT NULL
  221 + - `position` INT NULL
  222 + - `clicked_at` DATETIME(3) NOT NULL
  223 +
  224 +- **转化域(全站通用)**
  225 + - `dwd_view_item`:商品详情页浏览(可承接 search/rec 的 trace,用于链路与兴趣序列)
  226 + - **主键建议**:`(tenant_id, view_id)`(或 `(tenant_id, user_key, item_id, viewed_at)`)
  227 + - **核心索引建议**:`(tenant_id, user_key, viewed_at)`、`(tenant_id, item_id, viewed_at)`
  228 + - **字段建议**
  229 + - `tenant_id` VARCHAR(64) NOT NULL
  230 + - `view_id` VARCHAR(64) NULL
  231 + - `session_id` VARCHAR(64) NULL
  232 + - `user_key` VARCHAR(64) NOT NULL
  233 + - `item_id` VARCHAR(64) NOT NULL
  234 + - `source_type` VARCHAR(32) NULL:来源(search/rec/direct/ads/…)
  235 + - `source_trace_id` VARCHAR(64) NULL:来源 trace(若来自 search/rec)
  236 + - `dwell_time_ms` INT NULL
  237 + - `viewed_at` DATETIME(3) NOT NULL
  238 +
  239 + - `dwd_add_to_cart`:加购事实表(全站统一)
  240 + - **主键建议**:`(tenant_id, atc_id)`(或 `(tenant_id, user_key, item_id, added_at)`)
  241 + - **核心索引建议**:`(tenant_id, user_key, added_at)`、`(tenant_id, item_id, added_at)`
  242 + - **字段建议**
  243 + - `tenant_id` VARCHAR(64) NOT NULL
  244 + - `atc_id` VARCHAR(64) NULL
  245 + - `session_id` VARCHAR(64) NULL
  246 + - `cart_id` VARCHAR(64) NULL
  247 + - `user_key` VARCHAR(64) NOT NULL
  248 + - `item_id` VARCHAR(64) NOT NULL
  249 + - `quantity` INT NOT NULL DEFAULT 1
  250 + - `price` DECIMAL(18,2) NULL
  251 + - `currency` VARCHAR(8) NULL
  252 + - `source_type` VARCHAR(32) NULL:来源(search/rec/direct/…)
  253 + - `source_trace_id` VARCHAR(64) NULL:来源 trace(若来自 search/rec)
  254 + - `added_at` DATETIME(3) NOT NULL
  255 + - `cart_snapshot_json` JSON NULL:购物车快照(可选,体积大时可下沉到独立表)
  256 +
  257 + - `dwd_purchase`:订单事实表(全站统一)
  258 + - **主键建议**:`(tenant_id, order_id)`
  259 + - **核心索引建议**:`(tenant_id, user_key, paid_at)`、`(tenant_id, paid_at)`
  260 + - **字段建议**
  261 + - `tenant_id` VARCHAR(64) NOT NULL
  262 + - `order_id` VARCHAR(64) NOT NULL
  263 + - `user_key` VARCHAR(64) NOT NULL
  264 + - `currency` VARCHAR(8) NULL
  265 + - `total_amount` DECIMAL(18,2) NULL
  266 + - `paid_at` DATETIME(3) NOT NULL
  267 +
  268 + - `dwd_purchase_item`:订单明细事实表(全站统一)
  269 + - **主键建议**:`(tenant_id, order_id, item_id)`(若一单同商品可多行,则增加 `line_id`)
  270 + - **核心索引建议**:`(tenant_id, item_id, paid_at)`、`(tenant_id, order_id)`
  271 + - **字段建议**
  272 + - `tenant_id` VARCHAR(64) NOT NULL
  273 + - `order_id` VARCHAR(64) NOT NULL
  274 + - `line_id` VARCHAR(64) NULL
  275 + - `user_key` VARCHAR(64) NOT NULL
  276 + - `item_id` VARCHAR(64) NOT NULL
  277 + - `quantity` INT NOT NULL DEFAULT 1
  278 + - `price` DECIMAL(18,2) NULL
  279 + - `paid_at` DATETIME(3) NOT NULL
  280 +
  281 + - **落库/分区建议(MySQL)**
  282 + - 量小:按 `tenant_id` + `created_at` 索引即可
  283 + - 量大:建议按月分表/分区(`*_202601`),或落到 ClickHouse/ES/湖仓;DWD 保持明细可追溯,DWS/ADS 做聚合提速
  284 +
  285 +- **归因桥(可选但强烈建议)**
  286 + - `dwd_attribution_touch`
  287 + - order_id, item_id, last_touch_trace_id, touch_type(search/rec), touch_time, window(如 7d click/1d view)
  288 + - 这样 BI 里的“搜索带来收入/推荐带来收入”不会口径混乱。
  289 +
  290 +### 2.4 DWS/ADS:面向看板的汇总层(高性能)
  291 +- `dws_search_kpi_daily`(tenant_id, date, page_type/device/geo/new_vs_returning…)
  292 + - search_pv, search_uv, sessions_with_click, sessions_with_atc, sessions_with_purchase
  293 + - click_rate_session, purchase_rate_session, zero_result_rate, no_click_rate, p95_latency
  294 +- `dws_query_daily`(tenant_id, date, normalized_query)
  295 + - searches, exposure_uv, click_uv, purchase_uv, zero_cnt, no_click_cnt
  296 +- `dws_rec_kpi_daily`(tenant_id, date, placement, algo_id/model_version)
  297 + - impressions, clicks, ctr, atc, purchases, revenue, rpi(revenue per impression)
  298 +- `dws_item_daily`(tenant_id, date, item_id)
  299 + - search_impr/click/atc/purchase、rec_impr/click/…(用于“商品天级统计特征”与运营)
  300 +
  301 +---
  302 +
  303 +## 3)推荐系统依赖的数据(“能训练、能实时、能解释”)
  304 +把特征分成 **用户/商品/上下文**,再分 **静态/快照/统计/序列(实时)**。
  305 +
  306 +### 3.1 用户基础信息(dim)
  307 +- `dim_user`:user_key、注册时间、是否会员、国家/语言、获客渠道(如可得)、新老客标签
  308 +- 合规:只存业务需要的最小信息,敏感字段做脱敏/哈希
  309 +
  310 +### 3.2 用户实时特征(在线序列 + 聚合)
  311 +在线(Redis/Key-Value)建议保留:
  312 +- **最近 N 次行为序列**(按时间衰减)
  313 + - view_item_seq(最近浏览商品)
  314 + - search_query_seq(最近搜索词/类目)
  315 + - click_seq(点击的商品,区分来自 search/rec)
  316 + - cart_seq、purchase_seq
  317 +- **实时聚合**
  318 + - 最近 1h/24h 搜索次数、点击次数、加购次数
  319 + - 最近一次偏好类目/品牌/价格带(从序列实时计算)
  320 +
  321 +离线(天/小时级)输出:
  322 +- RFM、长期偏好向量(类目/品牌 embedding)、价格敏感度、复购周期等
  323 +
  324 +### 3.3 商品基础特征(静态)
  325 +- `dim_item`(sku/spu)
  326 + - 类目、品牌、属性(颜色/尺码/材质…)、标题/描述、价格、币种、图片
  327 + - 文本/图片 embedding(你们已有 embeddings 模块可复用)
  328 +
  329 +### 3.4 商品快照(强业务约束,必须可回溯)
  330 +- `item_snapshot`(tenant_id, item_id, snapshot_time)
  331 + - 库存/可售、折扣、上新、发货国家限制、活动标签
  332 +- 推荐/搜索曝光明细里最好**写入当时的关键快照字段**(至少 in_stock、price),避免事后回算失真。
  333 +
  334 +### 3.5 商品天级统计特征(训练/排序最常用)
  335 +- 由 `dws_item_daily` 派生:
  336 + - 1d/7d/28d:search_ctr、search_cvr、rec_ctr、rec_cvr、atc_rate、purchase_rate
  337 + - 热度、趋势(环比/同比)、退货/取消(如可得)
  338 + - 分 placement 的表现(同一商品在“购物车推荐”与“首页推荐”差异巨大)
  339 +
  340 +### 3.6 标签(Label)与训练样本(建议一开始就定口径)
  341 +- **曝光→点击**(CTR)标签:以 `impression_item` 为样本
  342 +- **点击→加购/购买**(CVR/GMV)标签:以 click 或 impression 为样本,设定归因窗口
  343 +- 负样本:同一 trace_id 下未被点击的曝光 item(更稳定)
  344 +
  345 +---
  346 +
  347 +## 4)你提到的两项“未完成工作”,数据层如何补齐
  348 +- **商品曝光(搜索/推荐)**:必须新增 `ExposureEvent`(建议一屏/一次渲染批量上报 item 列表 + position + module/placement + trace_id)
  349 +- **链路跟踪**:以 `trace_id` 为主串联;若购买跨会话严重,可在 purchase 上补 `attribution_trace_id` 或单独落 `attribution_touch` 表做归因
  350 +
  351 +---
  352 +
  353 +如果你愿意,我可以基于你们现有 `proto`/事件骨架,把“搜索请求/曝光/点击/加购/购买/推荐请求”这几类事件的**最小必填字段清单**列成一张表(直接给前端埋点和后端 ETL 用),并给出每个指标(CTR/CVR/zero/no-click)的**精确定义与 SQL 计算口径**。
0 354 \ No newline at end of file
... ...
frontend/static/js/tenant_facets_config.js
... ... @@ -33,32 +33,53 @@ const TENANT_FACETS_CONFIG = {
33 33 // tenant_id=170: 使用首字母大写的规格名称(Color, Size),没有material
34 34 "170": {
35 35 specificationFields: [
36   - {
37   - field: "specifications.Color",
  36 + {
  37 + field: "specifications.Color",
38 38 label: "Color",
39 39 containerId: "colorTags",
40   - size: 20,
41   - type: "terms",
42   - disjunctive: true
  40 + size: 20,
  41 + type: "terms",
  42 + disjunctive: true
43 43 },
44   - {
45   - field: "specifications.Size",
  44 + {
  45 + field: "specifications.Size",
46 46 label: "Size",
47 47 containerId: "sizeTags",
48   - size: 15,
49   - type: "terms",
50   - disjunctive: true
  48 + size: 15,
  49 + type: "terms",
  50 + disjunctive: true
51 51 }
52 52 // 示例:如果170还有其他规格,可以这样添加:
53   - // {
54   - // field: "specifications.Weight",
  53 + // {
  54 + // field: "specifications.Weight",
55 55 // label: "Weight",
56 56 // containerId: "weightTags",
57   - // size: 15,
58   - // type: "terms",
59   - // disjunctive: true
  57 + // size: 15,
  58 + // type: "terms",
  59 + // disjunctive: true
60 60 // }
61 61 ]
  62 + },
  63 + // tenant_id=171: 与170配置相同
  64 + "171": {
  65 + specificationFields: [
  66 + {
  67 + field: "specifications.Color",
  68 + label: "Color",
  69 + containerId: "colorTags",
  70 + size: 20,
  71 + type: "terms",
  72 + disjunctive: true
  73 + },
  74 + {
  75 + field: "specifications.Size",
  76 + label: "Size",
  77 + containerId: "sizeTags",
  78 + size: 15,
  79 + type: "terms",
  80 + disjunctive: true
  81 + }
  82 + ]
62 83 }
63 84 };
64 85  
... ...