1. 项目背景与核心价值
去年在优化电商平台的商品搜索时,我发现传统的关键词匹配方式存在明显局限性。当用户搜索"适合夏天穿的轻薄外套"时,基于关键词的系统可能只匹配到标题含"夏天"和"外套"的商品,而忽略了那些描述中带有"透气"、"防晒"等特征的同类型商品。这种语义鸿沟使得我们错失了约30%的相关商品曝光机会。
DWS(Data Warehouse Service)的向量计算功能为解决这个问题提供了新思路。通过将商品特征向量化存储,我们能够实现基于语义相似度的商品搜索与推荐。实测表明,采用向量搜索后,相关商品召回率提升了47%,用户点击率增加了22%。更重要的是,这套方案可以直接在现有数据仓库上实现,不需要额外部署专门的向量数据库。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统架构设计
2.1 整体技术栈选择
我们采用以下技术组合构建系统:
- DWS:作为核心数据仓库,存储商品结构化数据和向量数据
- PGVector扩展:为DWS提供向量计算能力
- Flask:构建轻量级API服务
- Sentence-BERT:生成商品文本的特征向量
选择DWS而非专用向量数据库主要基于三点考虑:
- 避免数据在多个系统间同步带来的延迟和一致性问题
- 现有业务数据已存储在DWS中,减少ETL复杂度
- DWS的分布式计算能力足以支撑我们的查询量级(约500QPS)
2.2 数据流设计
系统数据处理流程分为离线计算和在线查询两个部分:
离线计算流程:
- 每日凌晨从商品库抽取新增/变更的商品数据
- 使用Sentence-BERT模型生成商品标题、描述的768维向量
- 将向量数据与商品基础信息一并存入DWS
在线查询流程:
- 接收用户搜索请求后,先进行传统关键词搜索作为初筛
- 对搜索词同样生成向量表示
- 在初筛结果集上执行向量相似度计算
- 融合两种搜索结果的评分进行最终排序
3. 核心实现细节
3.1 向量化建模方案
我们测试了多种文本向量化方案后选择了all-MiniLM-L6-v2模型,主要因为:
- 模型大小仅80MB,推理速度快(单商品处理约15ms)
- 在商品标题这种短文本上表现优异
- 支持输出归一化向量,省去后续计算中的归一化步骤
关键实现代码:
python复制from sentence_transformers import SentenceTransformer
model = SentenceTransformer('all-MiniLM-L6-v2')
product_vectors = model.encode(product_descriptions,
batch_size=128,
show_progress_bar=True)
3.2 DWS向量存储优化
在DWS中我们采用以下表设计:
sql复制CREATE TABLE product_vectors (
product_id BIGINT PRIMARY KEY,
title_vector VECTOR(768),
desc_vector VECTOR(768),
update_time TIMESTAMP
) DISTRIBUTE BY HASH(product_id);
CREATE INDEX idx_title_vector ON product_vectors
USING ivfflat (title_vector) WITH (lists = 100);
几个关键优化点:
- 将向量维度明确指定为768,避免动态维度带来的性能损耗
- 采用IVFFlat索引加速最近邻搜索,lists参数根据数据量调整
- 定期执行
VACUUM ANALYZE保持索引效率
3.3 混合搜索实现
融合搜索的核心SQL示例:
sql复制SELECT p.product_id, p.product_name,
(0.7 * (1 - (p.title_vector <=> '[0.1,0.2,...]'::vector)))
+ (0.3 * text_similarity(q.query, p.product_name)) AS combined_score
FROM products p, (SELECT '夏日轻薄外套' AS query) q
WHERE p.category = 'clothing'
ORDER BY combined_score DESC
LIMIT 50;
评分融合时需要注意:
- 向量相似度使用余弦距离(<=>操作符),结果在0-1之间
- 文本相似度函数需要提前归一化到相同范围
- 权重系数需要根据AB测试结果动态调整
4. 性能优化实践
4.1 查询加速技巧
我们发现以下配置能显著提升向量查询性能:
sql复制SET ivfflat.probes = 10; -- 控制在总lists的5-10%
SET work_mem = '256MB'; -- 避免磁盘临时文件
SET max_parallel_workers_per_gather = 4; -- 适当并行
在高峰期查询时,采用两级缓存策略:
- 使用Redis缓存热门搜索词的Top100结果(TTL 5分钟)
- 在应用层缓存向量化后的搜索词(TTL 1小时)
4.2 索引维护方案
随着商品数量增长,我们建立了以下维护机制:
- 每周重建一次IVFFlat索引,保持聚类中心点的准确性
- 每日更新统计信息:
ANALYZE product_vectors - 设置监控告警,当索引扫描效率低于70%时触发优化
重建索引的推荐做法:
sql复制BEGIN;
DROP INDEX idx_title_vector;
CREATE INDEX idx_title_vector ON product_vectors
USING ivfflat (title_vector) WITH (lists = 150);
COMMIT;
5. 典型问题与解决方案
5.1 向量维度不匹配
我们曾遇到从不同模型生成的向量混用导致查询失败的情况。现在的预防措施包括:
- 所有向量字段添加CHECK约束:
sql复制ALTER TABLE product_vectors ADD CONSTRAINT check_dim CHECK (vector_dims(title_vector) = 768); - 在应用层进行写入前的维度校验
- 建立数据质量监控任务,定期检查向量维度
5.2 新商品冷启动问题
对于新上架商品,采用以下解决方案:
- 基于类目均值向量:计算同类商品向量的均值作为初始值
- 关键词扩展法:提取商品关键词,组合已有关键词的向量均值
- 设置"新品"标记,在排序时给予适当加权
5.3 长尾查询优化
针对低频搜索词,我们发现:
- 当probes参数设置过高时,查询延迟明显增加
- 解决方案是动态调整probes值:
python复制if query_frequency < 10: # 低频查询 probes = min(5, total_lists//20) else: probes = total_lists//10
6. 效果评估与调优
我们建立了完整的评估体系:
-
离线评估:每周末计算以下指标
- 召回率@50:人工标注的相关商品在前50结果中的占比
- 多样性:推荐结果的类目分布熵值
-
在线评估:
- A/B测试对比点击率、转化率
- 实时监控第1页结果的平均点击位置
调优时发现几个关键规律:
- 标题向量权重在0.6-0.8时效果最佳
- 对高价商品适当提升文本匹配权重(用户更关注精确匹配)
- 促销商品需要单独处理,其点击行为会干扰模型学习
这套系统上线后,不仅提升了搜索质量,还衍生出新的应用场景:
- 商品去重:识别向量相似度>0.95的重复商品
- 智能补货:通过向量聚类发现潜在缺货品类
- 广告匹配:将广告与最相关商品页面关联
