电商商品全网聚合平台 - 技术实现方案
搜索 + 比价 | 多平台数据聚合 | 混合检索
一、系统架构总览
二、技术栈选型
| 层级 | 技术组件 | 说明 |
|---|---|---|
| 后端框架 | Spring Boot 3.x | Java主服务 |
| 搜索引擎 | 阿里云 Elasticsearch 8.x | 倒排索引 + 向量索引 + 混合检索 |
| 关系型数据库 | MySQL 8.0 | 业务数据、任务调度、用户数据 |
| 缓存 | Redis 7.x | 热点数据缓存、分布式锁、限流 |
| 向量模型 | Qwen text-embedding-v3 | 商品文本向量化(1024维) |
| 稀疏向量模型 | SPLADE | 关键字扩展与词元权重 |
| 爬虫框架 | Selenium WebDriver (Java) | 动态页面采集 |
| 任务调度 | XXL-JOB | 定时采集任务管理 |
| 容器化 | Docker + Docker Compose | 服务部署 |
三、数据采集模块
3.1 数据源分类
| 数据源类型 | 平台 | 接入方式 | 优先级 |
|---|---|---|---|
| 官方开放平台 | 京东 | Open API (签名认证) | P0 |
| 官方开放平台 | 拼多多 | Open API (签名认证) | P0 |
| 官方开放平台 | 1688 | Open API (TOP协议) | P0 |
| 官方开放平台 | 抖音电商 | Open API (OAuth2.0) | P1 |
| 第三方聚合 | 万邦开放平台 | REST API | P1 |
| 第三方聚合 | 聚美数仓 | REST API | P1 |
| 自研爬虫 | 各平台 | Selenium WebDriver | P2 |
3.2 采集架构设计
3.3 各平台API接入说明
3.3.1 京东开放平台
| 项目 | 说明 |
|---|---|
| 认证方式 | AppKey + AppSecret |
| 签名算法 | MD5签名(secret + 排序参数 + secret) |
| 基础URL | https://api.jd.com/routerjson |
| 核心接口 | jingdong.ware.search(商品搜索) |
| 限流策略 | 单应用QPS限制,需控制请求频率 |
| 数据返回 | JSON格式,包含商品ID、标题、价格、图片等 |
接入要点:
- 请求参数按字母排序后拼接签名
- 时间戳使用毫秒级
- 需处理API限流,实现重试机制
- 商品数据需定时增量更新
3.3.2 拼多多开放平台
| 项目 | 说明 |
|---|---|
| 认证方式 | ClientID + ClientSecret |
| 签名算法 | MD5签名(secret + 排序参数 + secret) |
| 基础URL | https://gw-api.pinduoduo.com/api/router |
| 核心接口 | pdd.ddk.goods.search(多多进宝商品搜索) |
| 请求方式 | POST |
| 数据返回 | JSON格式,包含商品详情、优惠券信息等 |
接入要点:
- 时间戳使用秒级
- POST请求,参数放在body中
- 多多进宝接口可获取推广佣金信息
- 部分接口需要用户授权token
3.3.3 1688开放平台
| 项目 | 说明 |
|---|---|
| 认证方式 | AppKey + AppSecret |
| 签名算法 | MD5签名(排序参数拼接) |
| 基础URL | https://gw.open.1688.com/openapi/param2/1 |
| 核心接口 | alibaba.offer.search(商品搜索) |
| 协议 | TOP协议 |
| 数据返回 | JSON格式,包含批发价格、起订量等 |
接入要点:
- URL路径包含appKey和接口名称
- 批发商品有起订量、阶梯价格等特殊字段
- 部分数据需要企业账号权限
3.3.4 抖音电商开放平台
| 项目 | 说明 |
|---|---|
| 认证方式 | OAuth2.0 |
| Token获取 | AppID + AppSecret 换取 AccessToken |
| 基础URL | https://openapi-fxg.jinritemai.com |
| 核心接口 | 商品搜索、商品详情 |
| Token有效期 | 通常24小时,需定时刷新 |
| 数据返回 | JSON格式,包含商品、直播等信息 |
接入要点:
- AccessToken需缓存,提前5分钟刷新
- 部分接口需要用户授权
- 直播商品数据实时更新频率高
3.4 自研爬虫模块
技术选型: Selenium WebDriver (Java)
爬虫架构:
反爬策略:
- 无头浏览器模式运行
- 移除 webdriver 特征标识
- 设置合理的请求间隔(2-5秒)
- 使用代理IP池轮换
- Cookie池管理
数据采集流程:
- 创建WebDriver实例(配置反爬参数)
- 导航到搜索页面
- 等待页面加载完成(显式等待)
- 解析商品列表元素
- 提取商品标题、价格、销量等信息
- 翻页继续采集
- 关闭浏览器,释放资源
四、数据清洗与归一化模块
4.1 数据清洗流程总览
4.2 详细清洗步骤
4.2.1 第一步:格式校验与过滤
目标: 拦截无效数据,确保进入后续流程的数据结构正确
| 校验项 | 规则 | 处理方式 |
|---|---|---|
| JSON格式校验 | 必须是合法JSON | 解析失败直接丢弃,记录错误日志 |
| 必填字段检查 | product_id、title、price 不能为空 | 缺失则丢弃,记录缺失字段 |
| 数据类型校验 | 价格必须为数值型、销量必须为整型 | 类型错误尝试转换,转换失败则丢弃 |
| 数据范围校验 | 价格 > 0 且 < 999999、销量 >= 0 | 超出范围标记为异常,进入人工审核队列 |
| 平台标识校验 | 必须是预定义平台枚举值 | 未知平台直接丢弃 |
异常处理策略:
- 轻微异常(可修复):尝试自动修复后继续流程
- 严重异常(不可修复):丢弃数据,写入异常日志表
- 可疑异常(需人工判断):写入待审核队列
4.2.2 第二步:字段提取与转换
目标: 将各平台异构数据映射为统一数据模型
平台字段映射表:
| 统一字段 | 京东字段 | 拼多多字段 | 1688字段 | 抖音字段 |
|---|---|---|---|---|
| product_id | wareId | goodsId | offerId | productId |
| title | wareName | goodsName | subject | title |
| price | jdPrice | minGroupPrice | priceRange.min | price |
| original_price | marketPrice | marketPrice | originalPrice | originPrice |
| sales_count | commentCount | salesTip | amountOnSale | - |
| review_count | commentCount | - | - | - |
| rating | goodRate | - | - | rate |
| brand | brandName | brandName | brand | brandName |
| category | categoryId | categoryId | category | categoryId |
| main_image | imageInfo | goodsThumbnailUrl | imageUrls[0] | mainImg |
| images | imageInfoList | goodsGalleryUrls | imageUrls | detailImgList |
| shop_name | shopName | mallName | companyName | shopName |
| shop_id | shopId | mallId | memberId | shopId |
| product_url | wareUrl | goodsUrl | offerDetailUrl | productUrl |
类型转换规则:
| 源类型 | 目标类型 | 转换规则 |
|---|---|---|
| 字符串价格 “99.00” | Float 99.00 | 去除货币符号,解析为浮点数 |
| 价格区间 “50-100” | Float 50.00 | 取区间最小值 |
| 销量字符串 “1万+” | Integer 10000 | 解析中文数字,转换为整数 |
| 评分字符串 “4.8分” | Float 4.8 | 提取数值部分 |
| 时间戳(毫秒) | DateTime | 转换为标准日期时间格式 |
| HTML富文本 | 纯文本 | 去除HTML标签,保留文字内容 |
4.2.3 第三步:数据标准化与归一化
(1)价格标准化
| 标准化项 | 规则 | 示例 |
|---|---|---|
| 货币统一 | 所有价格转换为人民币(元) | $14.99 → ¥109.00(按汇率) |
| 精度统一 | 保留两位小数 | 99.999 → 100.00 |
| 促销价处理 | 优先取实际成交价,而非标价 | 原价199,促销价99 → 取99 |
| 券后价处理 | 记录券后价和原价两个字段 | price=89, original_price=119 |
| 阶梯价格 | 取最低起订量对应的价格 | 1件100元,10件90元 → 取100 |
| 异常价格过滤 | 价格<=0或>999999标记异常 | -1、0、9999999 → 标记异常 |
| 价格单位转换 | 部分平台以"分"为单位 | 9900分 → 99.00元 |
(2)文本清洗
| 清洗项 | 规则 | 示例 |
|---|---|---|
| HTML标签去除 | 移除所有 <tag> 标签 |
<b>手机</b> → 手机 |
| 特殊字符去除 | 移除不可见字符、emoji | 手机📱 → 手机 |
| 多余空格合并 | 连续空格合并为单个空格 | 苹果 手机 → 苹果手机 |
| 广告词过滤 | 移除营销类词汇 | 【包邮】正品手机 → 手机 |
| 全角转半角 | 全角数字/字母转半角 | 123 → 123 |
| 大小写统一 | 品牌名保留原样,其他转小写 | APPLE → apple |
广告词黑名单:
| 类别 | 词汇 |
|---|---|
| 物流类 | 包邮、顺丰、包邮到家、全国包邮 |
| 品质类 | 正品、原装、原厂、真品、正品保障 |
| 促销类 | 特价、限时、抢购、秒杀、清仓、打折 |
| 热度类 | 爆款、热卖、热销、畅销、网红 |
| 新品类 | 新品、新款、上新、最新 |
| 官方类 | 官方、旗舰店、官网、授权 |
| 符号类 | 【】、[]、★、◆、●、▲ |
(3)图片URL标准化
| 处理项 | 规则 |
|---|---|
| URL去重 | 同一商品多张图片去重 |
| 协议统一 | http 升级为 https |
| 尺寸参数去除 | 去除URL中的尺寸参数,获取原图 |
| 无效链接过滤 | 检测404/空图片,标记无效 |
(4)类目归一化
| 处理项 | 规则 |
|---|---|
| 平台类目映射 | 各平台类目映射到统一类目树 |
| 多级类目扁平化 | 保留最多3级类目 |
| 未知类目处理 | 映射到"其他"类目 |
(5)时间标准化
| 处理项 | 规则 |
|---|---|
| 时区统一 | 所有时间转换为北京时间(UTC+8) |
| 格式统一 | yyyy-MM-dd HH:mm:ss |
| 时间戳转换 | 毫秒/秒级时间戳转换为可读格式 |
4.2.4 第四步:去重与合并
(1)精确去重
| 去重维度 | 规则 | 说明 |
|---|---|---|
| 平台内去重 | platform + product_id 唯一 | 同一平台同一商品ID视为重复 |
| 跨平台去重 | 多维度相似度 >= 0.85 | 不同平台的同款商品,详见10.3节AI去重算法 |
(2)模糊去重算法
相似度计算 = 0.40 × 标题语义相似度
+ 0.25 × 品牌匹配度
+ 0.20 × 类目匹配度
+ 0.15 × 价格接近度
判定规则:
- 相似度 >= 0.85:视为同款商品,合并数据
- 0.70 <= 相似度 < 0.85:疑似同款,进入人工审核
- 相似度 < 0.70:视为不同商品
(3)数据合并策略
当识别为同款商品时:
| 字段 | 合并策略 |
|---|---|
| 价格 | 保留各平台价格,用于比价 |
| 标题 | 选择信息最完整的版本 |
| 图片 | 合并所有平台图片,去重后保留 |
| 销量 | 各平台销量独立保留 |
| 描述 | 合并多平台描述,去重 |
| 更新时间 | 取最新更新时间 |
(4)版本控制
| 策略 | 说明 |
|---|---|
| 数据版本 | 每次更新生成新版本号 |
| 历史保留 | 保留最近10个版本的价格历史 |
| 变更追踪 | 记录价格变动、标题变动等 |
4.2.5 第五步:质量评分与分级
质量评分维度:
| 评分项 | 权重 | 评分标准 |
|---|---|---|
| 字段完整度 | 30% | 必填字段齐全得满分,缺失扣分 |
| 数据准确性 | 25% | 通过校验规则的数量占比 |
| 图片质量 | 20% | 有主图且有效得满分 |
| 描述完整度 | 15% | 有详细描述得满分 |
| 时效性 | 10% | 数据更新时间距今越近得分越高 |
质量分级:
| 等级 | 分数 | 说明 | 处理方式 |
|---|---|---|---|
| A级(优质) | >= 90 | 字段完整、数据准确 | 直接入库,优先展示 |
| B级(良好) | 70-89 | 基本完整,少量缺失 | 直接入库,正常展示 |
| C级(一般) | 50-69 | 部分字段缺失 | 入库但降低搜索权重 |
| D级(较差) | < 50 | 大量字段缺失 | 标记异常,人工审核 |
4.3 统一商品数据模型
| 字段类别 | 字段名 | 类型 | 说明 |
|---|---|---|---|
| 基础信息 | product_id | String | 平台商品唯一ID |
| platform | Enum | 来源平台(jd/pdd/1688/douyin) | |
| title | String | 商品标题 | |
| subtitle | String | 副标题/卖点 | |
| description | String | 商品描述 | |
| 价格信息 | price | Float | 当前售价(元) |
| original_price | Float | 原价/划线价 | |
| currency | String | 货币单位(默认CNY) | |
| 销售信息 | sales_count | Integer | 销量 |
| review_count | Integer | 评论数 | |
| rating | Float | 评分(1-5) | |
| 分类信息 | category | String | 商品类目 |
| brand | String | 品牌 | |
| tags | List | 标签列表 | |
| 图片信息 | main_image | String | 主图URL |
| images | List | 图片URL列表 | |
| 商家信息 | shop_name | String | 店铺名称 |
| shop_id | String | 店铺ID | |
| shop_rating | Float | 店铺评分 | |
| 链接信息 | product_url | String | 商品详情页URL |
| affiliate_url | String | 推广链接 | |
| 时间信息 | crawl_time | DateTime | 爬取时间 |
| updated_at | DateTime | 更新时间 | |
| 质量信息 | quality_score | Float | 质量评分(0-100) |
| quality_level | Enum | 质量等级(A/B/C/D) | |
| 向量信息 | title_embedding | Float[] | 标题向量(1024维) |
| desc_embedding | Float[] | 描述向量(1024维) |
4.4 异常数据处理
异常类型与处理:
| 异常类型 | 示例 | 处理方式 |
|---|---|---|
| 解析异常 | JSON格式错误 | 丢弃,记录错误日志 |
| 字段缺失 | 缺少商品ID | 尝试从URL提取,失败则丢弃 |
| 类型错误 | 价格为字符串"免费" | 转换为0或标记异常 |
| 范围异常 | 价格99999999 | 标记异常,人工审核 |
| 链接失效 | 图片404 | 标记无效,使用备用图 |
| 重复数据 | 同一商品多次采集 | 更新时间戳,保留最新版本 |
异常数据流转:
4.5 清洗流程性能优化
| 优化点 | 方案 |
|---|---|
| 批量处理 | 每批100-500条数据并行清洗 |
| 同步管道 | 采集完直接清洗入库,简化架构 |
| 缓存复用 | 类目映射表、广告词黑名单加载到内存 |
| 并行计算 | 多平台数据并行清洗 |
| 失败重试 | 单次失败最多重试3次,间隔递增 |
| 监控告警 | 清洗失败率超过阈值触发告警 |
五、数据存储与索引构建
5.1 Elasticsearch 索引设计
5.1.1 索引配置
| 配置项 | 值 | 说明 |
|---|---|---|
| 分片数 | 3 | 根据数据量调整 |
| 副本数 | 1 | 保证高可用 |
| 中文分词 | ik_smart / ik_max_word | 标题用max_word,搜索用smart |
5.1.2 字段映射
| 字段 | 类型 | 分词器 | 说明 |
|---|---|---|---|
| product_id | keyword | - | 精确匹配 |
| platform | keyword | - | 精确匹配/过滤 |
| title | text | ik_max_word | 全文检索 |
| title.keyword | keyword | - | 精确匹配 |
| title.dense_vector | dense_vector | - | 稠密向量(1024维) |
| title.sparse_vector | sparse_vector | - | 稀疏向量 |
| description | text | ik_max_word | 全文检索 |
| price | float | - | 数值范围查询 |
| sales_count | integer | - | 数值排序 |
| category | keyword | - | 分类过滤 |
| brand | keyword | - | 品牌过滤 |
| tags | keyword | - | 标签过滤 |
| crawl_time | date | - | 时间范围查询 |
| desc.dense_vector | dense_vector | - | 描述稠密向量(1024维) |
5.2 向量化服务
向量模型选型:
| 模型 | 维度 | 特点 | 适用场景 |
|---|---|---|---|
| Qwen text-embedding-v3 | 1024 | 中文语义理解强、支持多语言 | 商品标题/描述语义检索 |
向量化流程:
商品入库时,对同一份商品数据同步执行向量化:
关键说明:
- 标题向量化:Qwen(清洗后标题+品牌+类目)+ SPLADE(原始标题文本)
- 描述向量化:Qwen(清洗后描述文本),仅生成稠密向量
- 所有向量化同步执行,互不依赖
- 最终同时写入ES对应字段
批量处理策略:
- 批量向量化(每批100条)
- 同步处理,采集完直接清洗入库
- 失败重试机制
- GPU加速(可选)
5.3 索引写入策略
写入流程:
- 采集Worker调用平台API获取原始数据
- 同步调用数据清洗服务,执行格式校验、字段映射、标准化
- 调用向量化服务生成标题稠密向量、标题稀疏向量、描述稠密向量
- 批量写入Elasticsearch
- 更新MySQL元数据(采集状态、时间等)
性能优化:
- 使用ES bulk API批量写入
- 每批100-500条记录
- 写入时关闭refresh_interval,完成后恢复
- 冷热数据分离(近期数据SSD,历史数据HDD)
六、数据检索服务
6.1 混合检索架构
6.2 三路检索说明
| 检索路 | 技术 | 权重 | 优势 | 劣势 |
|---|---|---|---|---|
| BM25关键字 | 倒排索引 + ik分词 | 0.3 | 精确匹配、可解释性强 | 无法理解语义 |
| 稠密向量语义 | 向量相似度(余弦) | 0.4 | 语义理解、同义词匹配 | 计算开销大 |
| 稀疏向量词元 | SPLADE词元权重 | 0.3 | 兼顾精确与语义 | 模型依赖 |
6.3 RRF融合排序
RRF(Reciprocal Rank Fusion)算法:
- 公式:
RRF(d) = Σ 1 / (k + rank(d)) - 参数 k 通常设为 60
- 将三路检索结果按排名倒数加权求和
- 最终按RRF得分降序排列
优势:
- 无需训练权重,简单有效
- 自动平衡不同检索路的结果
- 对排名靠前的结果给予更高权重
6.4 过滤与排序
支持的过滤条件:
- 平台过滤(京东/拼多多/1688/抖音)
- 价格区间过滤
- 品牌过滤
- 类目过滤
- 标签过滤
- 时间范围过滤
支持的排序方式:
- 相关度排序(默认,RRF得分)
- 价格升序/降序
- 销量排序
- 评分排序
- 上架时间排序
6.5 比价服务
比价逻辑:
- 根据搜索词检索商品
- 按平台分组
- 每个平台取最低价商品
- 按价格升序排列各平台结果
- 返回最优购买建议
比价结果包含:
- 各平台最低价
- 对应商品信息
- 平台商品数量
- 价格差异百分比
- 最优购买推荐
七、定时采集任务调度
7.1 任务调度架构
调度中心: XXL-JOB
7.2 采集任务配置
| 任务名称 | 执行频率 | Cron表达式 | 说明 |
|---|---|---|---|
| 全量商品同步 | 每日1次 | 0 0 2 * * ? |
每天凌晨2点全量更新 |
| 增量商品同步 | 每4小时 | 0 0 */4 * * ? |
价格变动、新增商品 |
| 热门商品监控 | 每小时 | 0 0 * * * ? |
热门商品价格追踪 |
| 向量索引重建 | 每周1次 | 0 0 3 ? * SUN |
重新生成向量 |
| 过期数据清理 | 每日1次 | 0 30 3 * * ? |
清理过期/无效数据 |
7.3 任务执行流程
全量同步流程:
- 触发全量同步任务
- 依次调用各平台API获取商品列表
- 同步执行数据清洗与归一化
- 调用向量化服务生成标题/描述向量
- 批量写入Elasticsearch
- 更新MySQL任务执行状态
- 发送执行报告
增量同步流程:
- 获取上次同步时间戳
- 查询各平台增量数据
- 仅处理新增和变更商品
- 更新ES索引
- 记录同步位点
八、API接口设计
8.1 RESTful API列表
| 接口路径 | 方法 | 说明 | 权限 |
|---|---|---|---|
/api/v1/products/search |
GET | 商品混合检索 | 公开 |
/api/v1/products/compare |
GET | 多平台比价 | 公开 |
/api/v1/products/{platform}/{id} |
GET | 商品详情 | 公开 |
/api/v1/products/hot |
GET | 热门商品 | 公开 |
/api/v1/categories |
GET | 类目列表 | 公开 |
/api/v1/price/history/{platform}/{id} |
GET | 价格历史 | 公开 |
8.2 搜索接口说明
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| query | String | 是 | 搜索关键词 |
| platforms | String | 否 | 平台过滤,逗号分隔 |
| min_price | Float | 否 | 最低价格 |
| max_price | Float | 否 | 最高价格 |
| brand | String | 否 | 品牌过滤 |
| category | String | 否 | 类目过滤 |
| sort_by | String | 否 | 排序方式 |
| page | Integer | 否 | 页码,默认1 |
| page_size | Integer | 否 | 每页数量,默认20 |
响应结构:
| 字段 | 类型 | 说明 |
|---|---|---|
| total | Integer | 总结果数 |
| page | Integer | 当前页码 |
| page_size | Integer | 每页数量 |
| results | Array | 商品列表 |
商品对象字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| product_id | String | 商品ID |
| platform | String | 来源平台 |
| title | String | 商品标题 |
| price | Float | 价格 |
| original_price | Float | 原价 |
| sales_count | Integer | 销量 |
| rating | Float | 评分 |
| brand | String | 品牌 |
| main_image | String | 主图 |
| product_url | String | 商品链接 |
| shop_name | String | 店铺名称 |
| score | Float | 相关度得分 |
8.3 比价接口说明
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| query | String | 是 | 商品搜索词 |
| platforms | String | 否 | 指定平台 |
响应结构:
| 字段 | 类型 | 说明 |
|---|---|---|
| query | String | 搜索词 |
| comparison | Array | 各平台比价结果 |
| best_deal | Object | 最优购买推荐 |
九、部署架构
9.1 服务组件
| 服务 | 端口 | 说明 |
|---|---|---|
| Elasticsearch | 9200 | 搜索引擎 |
| MySQL | 3306 | 关系型数据库 |
| Redis | 6379 | 缓存服务 |
| XXL-JOB Admin | 8081 | 任务调度中心 |
| 后端API服务 | 8080 | 主服务 |
| 数据采集服务 | - | 后台Worker |
| Nginx | 80/443 | 反向代理 |
9.3 资源配置建议
| 组件 | CPU | 内存 | 磁盘 |
|---|---|---|---|
| Elasticsearch | 4核+ | 8GB+ | SSD 100GB+ |
| MySQL | 2核+ | 4GB+ | SSD 50GB+ |
| Redis | 1核 | 2GB | - |
| 后端服务 | 2核+ | 4GB+ | - |
| 采集服务 | 2核+ | 4GB+ | - |
十、AI应用与核心算法
10.1 AI在系统中的角色
| AI能力 | 模型/技术 | 用途 |
|---|---|---|
| 稠密向量嵌入 | Qwen text-embedding-v3 | 商品标题/描述语义理解 |
| 稀疏向量生成 | SPLADE | 关键字扩展与词元权重 |
| 混合检索融合 | RRF算法 | 多路召回结果排序 |
| 语义去重 | 向量余弦相似度 | 跨平台同款商品识别 |
| 查询理解 | Query改写/纠错 | 搜索词优化 |
| 智能推荐 | 协同过滤+向量检索 | 相似商品推荐 |
| 价格预测 | 时序模型 | 价格趋势预测 |
10.2 混合检索详细实现
10.2.1 检索流程总览
10.2.2 第一路:BM25关键字检索
实现原理:
- 基于ES倒排索引,使用ik分词器对中文分词
- BM25算法根据词频(TF)和逆文档频率(IDF)计算相关性
分词策略:
| 场景 | 分词器 | 说明 |
|---|---|---|
| 索引时 | ik_max_word | 最大细粒度分词,提高召回率 |
| 搜索时 | ik_smart | 粗粒度分词,减少噪声 |
同义词扩展:
- 维护同义词词典:手机→移动电话、壳→保护套、iPhone→苹果手机
- 搜索时自动扩展同义词,提升召回
ES查询示例逻辑:
查询: "iPhone 15 手机壳"
分词: ["iPhone", "15", "手机壳", "手机", "壳"]
同义词扩展: ["iPhone", "苹果手机", "15", "手机壳", "保护套", "手机", "壳"]
BM25评分: 基于词频和逆文档频率计算相关性得分
优势与局限:
- 优势:精确匹配、可解释性强、速度快
- 局限:无法理解语义,“苹果手机壳"搜不到"iPhone保护套”
10.2.3 第二路:稠密向量语义检索
实现原理:
- 使用Qwen text-embedding-v3模型将查询和商品文本转为1024维向量
- 通过向量余弦相似度计算语义相关性
- ES使用HNSW近似最近邻索引加速检索
向量化流程:
相似度计算:
余弦相似度 = (A·B) / (||A|| × ||B||)
示例:
查询向量: "苹果手机保护套" → [0.11, -0.33, 0.55, ...]
商品向量: "iPhone 15 Pro Max手机壳" → [0.12, -0.34, 0.56, ...]
余弦相似度 = 0.92 (高度相似)
→ 即使字面不同,语义上匹配
HNSW索引参数:
| 参数 | 值 | 说明 |
|---|---|---|
| m | 16 | 每个节点的最大连接数 |
| ef_construction | 100 | 构建索引时的搜索深度 |
| ef_search | 50 | 查询时的搜索深度,越大越准越慢 |
优势与局限:
- 优势:语义理解强,能匹配字面不同但含义相同的商品
- 局限:计算开销大,对精确匹配不如BM25
10.2.4 第三路:稀疏向量词元检索(SPLADE)
实现原理:
- SPLADE模型将文本转为稀疏向量,每个维度对应词汇表中的一个词
- 向量值表示该词对文本的重要性权重
- 兼具BM25的精确性和向量的语义扩展能力
稀疏向量示例:
文本: "iPhone 15 手机壳"
SPLADE稀疏向量:
{
"iphone": 0.85,
"15": 0.72,
"手机": 0.68,
"手机壳": 0.91,
"保护套": 0.45, // 语义扩展
"苹果": 0.38, // 语义扩展
"配件": 0.25, // 语义扩展
...
}
与BM25的区别:
- BM25:基于统计,词权重由TF-IDF决定
- SPLADE:基于神经网络,自动学习词的重要性和扩展相关词
优势与局限:
- 优势:兼顾精确匹配和语义扩展,可解释性比稠密向量好
- 局限:依赖SPLADE模型质量,词汇表外词处理有限
10.2.5 RRF融合排序详解
RRF算法公式:
RRF_score(d) = Σ 1 / (k + rank_i(d))
其中:
- d: 文档(商品)
- k: 常数,通常设为60
- rank_i(d): 文档d在第i路检索中的排名
融合示例:
| 商品 | BM25排名 | 稠密向量排名 | 稀疏向量排名 | RRF得分 |
|---|---|---|---|---|
| 商品A | 1 | 3 | 2 | 1/61 + 1/63 + 1/62 = 0.0487 |
| 商品B | 2 | 1 | 5 | 1/62 + 1/61 + 1/65 = 0.0481 |
| 商品C | 5 | 2 | 1 | 1/65 + 1/62 + 1/61 = 0.0478 |
| 商品D | 3 | 8 | 4 | 1/63 + 1/68 + 1/64 = 0.0463 |
加权RRF(可选):
RRF_score(d) = Σ weight_i / (k + rank_i(d))
默认权重:
- BM25: 0.3
- 稠密向量: 0.4
- 稀疏向量: 0.3
为什么k=60?
- k值影响排名靠前结果的权重差异
- k=60是信息检索领域的经验值
- k越小,排名靠前的结果权重差异越大
- k越大,各排名结果权重差异越平滑
10.2.6 检索性能优化
| 优化点 | 方案 | 效果 |
|---|---|---|
| 查询缓存 | Redis缓存热门搜索Query结果 | 命中率>60%的查询直接返回 |
| 向量索引 | HNSW近似最近邻 | 检索速度提升10-100倍 |
| 分页优化 | search_after替代from/size | 深分页性能提升 |
| 字段裁剪 | 只返回必要字段 | 网络传输减少50% |
| 并发检索 | 三路检索并行执行 | 延迟降低至最慢的一路 |
| 预热机制 | 定时更新热门商品向量 | 冷启动延迟降低 |
10.3 AI商品去重详细实现
10.3.1 去重场景
| 场景 | 说明 | 示例 |
|---|---|---|
| 平台内去重 | 同一平台重复采集 | 京东同一商品被多次采集 |
| 跨平台同款 | 不同平台的同款商品 | 京东/拼多多都有iPhone 15 |
| SKU变体 | 同一商品不同规格 | iPhone 15 128G vs 256G |
| 套装组合 | 商品+配件组合 | 手机壳+钢化膜套装 |
10.3.2 精确去重
规则:
唯一标识 = platform + product_id
去重逻辑:
1. 新数据到来时,检查 (platform, product_id) 是否已存在
2. 已存在 → 比较更新时间
- 新数据更新 → 覆盖旧数据,记录变更历史
- 旧数据更新 → 丢弃新数据
3. 不存在 → 直接入库
10.3.3 跨平台模糊去重(AI核心)
多维度相似度计算:
综合相似度 = w1 × 标题语义相似度
+ w2 × 品牌匹配度
+ w3 × 类目匹配度
+ w4 × 价格接近度
权重配置:
w1 = 0.40 (标题语义)
w2 = 0.25 (品牌匹配)
w3 = 0.20 (类目匹配)
w4 = 0.15 (价格接近)
(1)标题语义相似度
方法:向量余弦相似度
步骤:
1. 将两个商品标题分别转为1024维向量
2. 计算余弦相似度
示例:
标题A: "Apple iPhone 15 Pro Max 256GB 原色钛金属"
标题B: "苹果15ProMax 256G 原色钛金属手机"
向量A: [0.12, -0.34, 0.56, ...]
向量B: [0.11, -0.33, 0.55, ...]
余弦相似度 = 0.94 (高度相似)
(2)品牌匹配度
| 匹配情况 | 得分 | 示例 |
|---|---|---|
| 完全相同 | 1.0 | Apple vs Apple |
| 别名匹配 | 0.9 | Apple vs 苹果 |
| 包含关系 | 0.7 | Apple vs Apple授权 |
| 不同 | 0.0 | Apple vs Samsung |
品牌别名映射表:
| 标准品牌 | 别名 |
|---|---|
| Apple | 苹果、iPhone、iPad |
| Huawei | 华为 |
| Xiaomi | 小米、MI |
| OPPO | OPPO、欧珀 |
| vivo | vivo、维沃 |
| Samsung | 三星、Galaxy |
(3)类目匹配度
方法:类目树路径匹配
示例:
类目A: 手机通讯 > 手机 > 智能手机
类目B: 数码 > 手机 > 智能手机
匹配逻辑:
1. 计算类目路径的Jaccard相似度
2. 检查末级类目是否相同
Jaccard = |A∩B| / |A∪B| = 2/4 = 0.5
末级相同 → 额外加分
最终类目匹配度 = 0.7
(4)价格接近度
方法:基于价格比率计算
公式:
price_ratio = min(priceA, priceB) / max(priceA, priceB)
price_score = price_ratio (范围0-1)
示例:
价格A: 8999元
价格B: 8799元
price_ratio = 8799 / 8999 = 0.978
price_score = 0.978 (价格非常接近)
阈值:
- price_score >= 0.8: 价格接近
- 0.5 <= price_score < 0.8: 价格有一定差异
- price_score < 0.5: 价格差异大,可能不是同款
10.3.4 去重判定与处理
判定阈值:
| 综合相似度 | 判定结果 | 处理方式 |
|---|---|---|
| >= 0.85 | 同款商品 | 自动合并,保留各平台价格用于比价 |
| 0.70 - 0.85 | 疑似同款 | 标记待审核,人工确认 |
| < 0.70 | 不同商品 | 独立保留 |
同款商品合并策略:
| 字段 | 合并策略 | 说明 |
|---|---|---|
| product_group_id | 生成统一ID | 同款商品共享一个group_id |
| 各平台价格 | 全部保留 | 用于比价展示 |
| 标题 | 选信息最完整版本 | 或拼接各平台标题 |
| 图片 | 合并去重 | 保留所有平台有效图片 |
| 描述 | 合并去重 | 补充各平台描述信息 |
| 销量 | 各平台独立 | 不合并,分别展示 |
| 更新时间 | 取最新 | 记录最后更新时间 |
10.3.5 去重性能优化
| 优化点 | 方案 | 说明 |
|---|---|---|
| 候选集缩小 | 先按类目/品牌过滤 | 减少需要比较的商品数量 |
| 向量索引加速 | ES向量检索找相似候选 | 避免全量两两比较 |
| 分层去重 | 粗筛→精筛两阶段 | 先用简单规则过滤,再AI精判 |
| 增量去重 | 只对新数据去重 | 已去重商品不再重复计算 |
| 缓存相似度 | Redis缓存已计算的相似度 | 避免重复计算 |
| 批量向量化 | 一次处理多条 | 提升向量化效率 |
分层去重流程:
10.4 混合检索调优
| 检索路 | 权重 | 调优方向 |
|---|---|---|
| BM25关键字 | 0.3 | 分词器优化、同义词扩展、停用词过滤 |
| 稠密向量语义 | 0.4 | 向量模型选择、Prompt优化、HNSW参数调整 |
| 稀疏向量词元 | 0.3 | SPLADE模型微调、词元权重校准 |
10.5 数据更新策略
| 策略 | 频率 | 说明 |
|---|---|---|
| 全量更新 | 每日1次 | 凌晨低峰期执行 |
| 增量更新 | 每4小时 | 价格变动、新增商品 |
| 实时监控 | 每小时 | 热门商品价格追踪 |
10.6 性能优化
| 优化点 | 方案 |
|---|---|
| 搜索响应时间 | Redis缓存热门搜索、ES查询优化、HNSW索引 |
| 向量化性能 | 批量向量化、GPU加速、向量缓存 |
| 采集效率 | 并发采集、代理池、限流控制 |
| 数据存储 | 冷热数据分离、索引分片 |
| 去重效率 | 分层去重、向量索引召回、相似度缓存 |
十一、风险与应对
| 风险 | 影响 | 应对措施 |
|---|---|---|
| 平台API限流 | 采集失败 | 多账号轮换、请求限流、重试机制 |
| 反爬封禁 | 数据缺失 | 代理池、请求间隔模拟、Cookie池 |
| 数据不一致 | 比价不准 | 数据校验、异常检测、人工审核 |
| ES性能瓶颈 | 搜索慢 | 分片优化、缓存、读写分离 |
文档版本: v1.0
创建日期: 2026-06-11
最后更新: 2026-06-11
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)