向量数据库实战:选型、调优与落地~系列文章20:向量数据库在推荐系统中的应用:从协同过滤到向量召回
向量数据库在推荐系统中的应用从协同过滤到向量召回 本文是《向量数据库实战选型、调优与落地》专栏第 20 篇⏱️阅读时间约 13 分钟 开篇推荐系统的召回革命传统推荐系统的核心流程 ┌─────────────────────────────────────────────────────────┐ │ 推荐系统经典架构 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 用户请求 │ │ │ │ │ ▼ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ 召回层 │ → │ 粗排层 │ → │ 精排层 │ │ │ │ (Recall) │ │ (Pre- │ │ (Rank) │ │ │ │ │ │ ranking) │ │ │ │ │ │ 百万→千 │ │ 千→百 │ │ 百→几十 │ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ │ │ │ ▼ │ │ ┌──────────┐ │ │ │ 重排层 │ │ │ │ (Re-rank)│ │ │ │ 几十→展示 │ │ │ └──────────┘ │ │ │ │ 召回层是核心它决定了推荐的天花板 │ │ → 向量数据库就是召回层的发动机 │ │ │ └─────────────────────────────────────────────────────────┘ 从协同过滤到向量召回传统协同过滤的问题用户 A 喜欢[商品1, 商品2, 商品3] 用户 B 喜欢[商品2, 商品3, 商品4] → A 和 B 有相似偏好 → 给用户 A 推荐商品4 问题 ❌ 只能发现显式相似的用户/物品 ❌ 稀疏性问题大部分用户-物品对没有交互 ❌ 无法理解为什么相似向量召回的优势商品1 的向量: [0.12, -0.34, ...] ← learned representation 商品2 的向量: [0.13, -0.33, ...] ← 语义相近 商品3 的向量: [0.89, 0.12, ...] ← 语义远 向量召回 ✅ 能发现隐式相似语义相近但没交互过的 ✅ 不受稀疏性影响 ✅ 能理解为什么相似向量空间中的距离 向量召回实战Step 1训练双塔模型importtorchimporttorch.nnasnnclassTwoTowerModel(nn.Module):双塔模型用户塔 物品塔def__init__(self,user_dim,item_dim,embedding_dim128):super().__init__()# 用户塔self.user_towernn.Sequential(nn.Linear(user_dim,256),nn.ReLU(),nn.Linear(256,128),nn.ReLU(),nn.Linear(128,embedding_dim),nn.LayerNorm(embedding_dim))# 物品塔self.item_towernn.Sequential(nn.Linear(item_dim,256),nn.ReLU(),nn.Linear(256,128),nn.ReLU(),nn.Linear(128,embedding_dim),nn.LayerNorm(embedding_dim))defforward(self,user_features,item_features):user_embself.user_tower(user_features)item_embself.item_tower(item_features)# 内积作为相似度return(user_emb*item_emb).sum(dim-1)defget_user_embedding(self,user_features):returnself.user_tower(user_features)defget_item_embedding(self,item_features):returnself.item_tower(item_features)Step 2生成物品向量并存入数据库frompymilvusimportCollection# 为所有物品生成向量item_embeddings[]foriteminall_items:item_featuresextract_features(item)# 类别、价格、标签等withtorch.no_grad():vecmodel.get_item_embedding(item_features)item_embeddings.append(vec.numpy()[0])# 存入向量数据库data[[item.idforiteminall_items],item_embeddings,[{category:item.category,price:item.price}foriteminall_items]]collection.insert(data)collection.flush()# 建索引collection.create_index(embedding,{index_type:HNSW,metric_type:IP,# 推荐系统用内积params:{M:32,efConstruction:256}})Step 3在线召回defrecall_for_user(user_id,user_features,collection,model,top_k100):为单个用户做向量召回# 1. 生成用户向量withtorch.no_grad():user_vecmodel.get_user_embedding(user_features).numpy()[0]# 2. 向量检索collection.load()resultscollection.search(data[user_vec.tolist()],anns_fieldembedding,param{metric_type:IP,params:{ef:128}},limittop_k,output_fields[category,price])# 3. 过滤已购买purchasedget_purchased_items(user_id)filtered[hitforhitinresults[0]ifhit.idnotinpurchased]returnfiltered[:top_k] 多路召回架构┌─────────────────────────────────────────────────────────┐ │ 多路召回架构 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 用户请求 │ │ │ │ │ ├──→ 向量召回语义相似→ 100 个候选 │ │ │ │ │ ├──→ 热门召回全局热门→ 50 个候选 │ │ │ │ │ ├──→ 协同过滤召回 → 50 个候选 │ │ │ │ │ ├──→ 标签召回同类目→ 50 个候选 │ │ │ │ │ └──→ 实时召回最近浏览的相似品→ 50 个候选 │ │ │ │ ↓ 合并去重 │ │ ~300 个候选 │ │ ↓ │ │ 粗排 → 精排 → 重排 → 展示 │ │ │ └─────────────────────────────────────────────────────────┘ 本篇核心要点回顾要点说明向量召回用双塔模型生成用户/物品向量向量数据库检索度量选择推荐系统用内积IP不是余弦多路召回向量召回只是其中一路需要多路融合性能要求召回层要求极低延迟 10ms下篇预告《向量数据库在图像搜索引擎中的应用以图搜图的完整实现 》有问题欢迎评论区讨论觉得有用请点赞收藏 作者高炉炼铁智能化技术研究者专注钢铁冶金与人工智能 交叉领域。 如果觉得有帮助请点赞、收藏、转发版权归作者所有未经许可请勿抄袭套用商用(或其它具有利益性行为)。 关注专栏不错过后续精彩内容