Blame view

offline_tasks/scripts/ES_VECTOR_SIMILARITY.md 6.73 KB
b57c6eb4   tangwang   offline tasks: fi...
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
  # ES向量相似度索引生成
  
  ## 概述
  
  `i2i_content_similar.py` 脚本从Elasticsearch获取商品向量,计算并生成两种内容相似度索引:
  
  1. **基于名称文本向量的相似度** (`i2i_content_name`)
  2. **基于图片向量的相似度** (`i2i_content_pic`)
  
  ## 使用方法
  
  ### 运行脚本
  
  ```bash
  cd /home/tw/recommendation/offline_tasks
  python scripts/i2i_content_similar.py
  ```
  
  脚本无需任何参数,所有配置都在代码中设置好。
  
  ### 配置说明
  
  脚本内置配置(位于 `i2i_content_similar.py` 头部):
  
  ```python
  # ES配置
  ES_CONFIG = {
      'host': 'http://localhost:9200',
      'index_name': 'spu',
      'username': 'essa',
      'password': '4hOaLaf41y2VuI8y'
  }
  
  # 算法参数
  TOP_N = 50              # 每个商品返回的相似商品数量
  KNN_K = 100             # knn查询返回的候选数
  KNN_CANDIDATES = 200    # knn查询的候选池大小
  ```
  
  ## 工作流程
  
  ### 1. 获取活跃商品
  
  从数据库查询最近1年内有过行为的商品:
  
  ```sql
  SELECT DISTINCT item_id
  FROM sensors_events
  WHERE event IN ('click', 'contactFactory', 'addToPool', 'addToCart', 'purchase')
    AND create_time >= '1年前'
    AND item_id IS NOT NULL
  ```
  
  ### 2. 从ES获取向量
  
  对每个活跃商品,从Elasticsearch查询:
  
  ```json
  {
    "query": {
      "term": {
        "_id": "商品ID"
      }
    },
    "_source": {
fb8112e0   tangwang   offline tasks: me...
66
      "includes": ["_id", "name_zh", "embedding_name_zh", "embedding_pic_h14", "on_sell_days_boost"]
b57c6eb4   tangwang   offline tasks: fi...
67
68
69
70
71
72
73
74
75
76
77
    }
  }
  ```
  
  返回字段:
  - `_id`: 商品ID
  - `name_zh`: 中文名称(用于debug输出)
  - `embedding_name_zh`: 名称文本向量 (1024维)
  - `embedding_pic_h14`: 图片向量列表,每个元素包含:
    - `vector`: 向量 (1024维)
    - `url`: 图片URL
fb8112e0   tangwang   offline tasks: me...
78
  - `on_sell_days_boost`: 上架天数提权值 (0.9~1.1)
b57c6eb4   tangwang   offline tasks: fi...
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  
  ### 3. KNN向量相似度查询
  
  使用商品的向量查询相似商品:
  
  **名称向量查询:**
  ```json
  {
    "knn": {
      "field": "embedding_name_zh",
      "query_vector": [向量值],
      "k": 100,
      "num_candidates": 200
    },
fb8112e0   tangwang   offline tasks: me...
93
    "_source": ["_id", "name_zh", "on_sell_days_boost"],
b57c6eb4   tangwang   offline tasks: fi...
94
95
96
97
98
99
100
101
102
103
104
105
106
    "size": 100
  }
  ```
  
  **图片向量查询:**
  ```json
  {
    "knn": {
      "field": "embedding_pic_h14.vector",
      "query_vector": [向量值],
      "k": 100,
      "num_candidates": 200
    },
fb8112e0   tangwang   offline tasks: me...
107
    "_source": ["_id", "name_zh", "on_sell_days_boost"],
b57c6eb4   tangwang   offline tasks: fi...
108
109
110
111
    "size": 100
  }
  ```
  
fb8112e0   tangwang   offline tasks: me...
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
  ### 4. 应用上架天数提权
  
  对每个查询结果,应用 `on_sell_days_boost` 提权:
  
  ```python
  base_score = knn_result['_score']  # KNN基础分数
  boost = knn_result['_source']['on_sell_days_boost']  # 提权值 (0.9~1.1)
  final_score = base_score * boost  # 最终分数
  ```
  
  **提权说明:**
  - `on_sell_days_boost` 是基于商品上架天数计算的提权因子
  - 取值范围: 0.9 ~ 1.1
  - > 1.0: 提权(新品或热门商品)
  - = 1.0: 不提权(正常商品)
  - < 1.0: 降权(长尾商品)
  - 如果字段缺失或异常,默认使用 1.0(不提权)
  
  ### 5. 生成索引文件
b57c6eb4   tangwang   offline tasks: fi...
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
  
  输出两个文件到 `output/` 目录:
  
  - `i2i_content_name_YYYYMMDD.txt`: 基于名称向量的相似索引
  - `i2i_content_pic_YYYYMMDD.txt`: 基于图片向量的相似索引
  
  **文件格式:**
  ```
  item_id\titem_name\tsimilar_id1:score1,similar_id2:score2,...
  ```
  
  **示例:**
  ```
  123456  香蕉干  234567:0.9234,345678:0.8756,456789:0.8432
  ```
  
  ## 输出说明
  
  ### Redis Key 格式
  
  #### 名称向量相似
  - **Key**: `item:similar:content_name:{item_id}`
  - **Value**: `[[similar_id1,score1],[similar_id2,score2],...]`
  - **TTL**: 30天
  
  #### 图片向量相似
  - **Key**: `item:similar:content_pic:{item_id}`
  - **Value**: `[[similar_id1,score1],[similar_id2,score2],...]`
  - **TTL**: 30天
  
  ### 使用示例
  
  ```python
  import redis
  import json
  
  r = redis.Redis(host='localhost', port=6379, db=0)
  
  # 获取基于名称向量的相似商品
  similar_items = json.loads(r.get('item:similar:content_name:123456'))
  # 返回: [[234567, 0.9234], [345678, 0.8756], ...]
  
  # 获取基于图片向量的相似商品
  similar_items = json.loads(r.get('item:similar:content_pic:123456'))
  # 返回: [[567890, 0.8123], [678901, 0.7856], ...]
  ```
  
  ## 性能说明
  
  ### 运行时间估算
  
  假设有 50,000 个活跃商品:
  
  - ES查询获取向量: ~50,000次,每次约10ms = 8-10分钟
  - KNN相似度查询: ~50,000次,每次约50ms = 40-50分钟
  - 总计: 约50-60分钟
  
  ### 优化建议
  
  如果性能不够:
  
  1. **批量处理**: 使用ES的 `_mget` 批量获取向量
  2. **并发查询**: 使用多线程/异步IO提高查询并发
  3. **增量更新**: 只处理新增/更新的商品
  4. **缓存结果**: 将ES向量缓存到本地,避免重复查询
  
  ## ES向量字段说明
  
  ### embedding_name_zh
  
  - **类型**: `dense_vector`
  - **维度**: 1024
  - **相似度**: `dot_product`
  - **用途**: 基于商品名称的语义向量
  
  ### embedding_pic_h14
  
  - **类型**: `nested`
  - **结构**:
    ```json
    [
      {
        "vector": [1024维向量],
        "url": "图片URL"
      }
    ]
    ```
  - **相似度**: `dot_product`
  - **用途**: 基于商品图片的视觉向量
  
fb8112e0   tangwang   offline tasks: me...
221
222
223
224
225
226
227
228
  ### on_sell_days_boost
  
  - **类型**: `float`
  - **取值范围**: 0.9 ~ 1.1
  - **默认值**: 1.0
  - **用途**: 基于上架天数的提权因子
  - **计算逻辑**: 最终分数 = KNN分数 × on_sell_days_boost
  
b57c6eb4   tangwang   offline tasks: fi...
229
230
231
232
233
234
235
  ## 注意事项
  
  1. **网络连接**: 确保能访问ES服务器
  2. **权限**: 确保ES用户有查询权限
  3. **向量缺失**: 部分商品可能没有向量,会被跳过
  4. **向量格式**: 图片向量是嵌套结构,取第一个图片的向量
  5. **自我排除**: KNN结果会排除商品自己
fb8112e0   tangwang   offline tasks: me...
236
237
  6. **提权应用**: 所有相似度分数都已应用 `on_sell_days_boost` 提权
  7. **提权范围**: boost值会被限制在0.9~1.1范围内,异常值使用1.0
b57c6eb4   tangwang   offline tasks: fi...
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
  
  ## 故障排查
  
  ### 连接ES失败
  
  ```python
  # 检查ES配置
  curl -u essa:4hOaLaf41y2VuI8y http://localhost:9200/_cat/indices
  ```
  
  ### 查询超时
  
  调整超时参数:
  ```python
  es = Elasticsearch(
      [ES_CONFIG['host']],
      basic_auth=(ES_CONFIG['username'], ES_CONFIG['password']),
      request_timeout=60  # 增加到60秒
  )
  ```
  
  ### 向量字段不存在
  
  检查ES mapping:
  ```bash
  curl -u essa:4hOaLaf41y2VuI8y http://localhost:9200/spu/_mapping
  ```
  
  ## 与其他相似度算法的对比
  
  | 算法 | 数据源 | 优势 | 适用场景 |
  |------|--------|------|---------|
  | **Swing** | 用户行为 | 捕获真实交互关系 | 行为相似推荐 |
  | **W2V** | 用户会话 | 捕获序列关系 | 下一个商品推荐 |
  | **DeepWalk** | 行为图 | 发现深层关联 | 潜在兴趣挖掘 |
  | **名称向量** | ES语义向量 | 语义理解强 | 文本相似推荐 |
  | **图片向量** | ES视觉向量 | 视觉相似性强 | 外观相似推荐 |
  
  ## 更新频率建议
  
  - **名称向量相似**: 每周更新(商品名称变化少)
  - **图片向量相似**: 每周更新(商品图片变化少)
  - **Redis TTL**: 30天(内容相似度变化慢)