欢迎光临
我们一直在努力

电商商品全网聚合平台 - 技术实现方案

搜索 + 比价 | 多平台数据聚合 | 混合检索


一、系统架构总览

#mermaid-svg-h2652FpwyP0a8N0g{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-h2652FpwyP0a8N0g .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-h2652FpwyP0a8N0g .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-h2652FpwyP0a8N0g .error-icon{fill:#552222;}#mermaid-svg-h2652FpwyP0a8N0g .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-h2652FpwyP0a8N0g .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-h2652FpwyP0a8N0g .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-h2652FpwyP0a8N0g .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-h2652FpwyP0a8N0g .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-h2652FpwyP0a8N0g .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-h2652FpwyP0a8N0g .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-h2652FpwyP0a8N0g .marker{fill:#333333;stroke:#333333;}#mermaid-svg-h2652FpwyP0a8N0g .marker.cross{stroke:#333333;}#mermaid-svg-h2652FpwyP0a8N0g svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-h2652FpwyP0a8N0g p{margin:0;}#mermaid-svg-h2652FpwyP0a8N0g .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-h2652FpwyP0a8N0g .cluster-label text{fill:#333;}#mermaid-svg-h2652FpwyP0a8N0g .cluster-label span{color:#333;}#mermaid-svg-h2652FpwyP0a8N0g .cluster-label span p{background-color:transparent;}#mermaid-svg-h2652FpwyP0a8N0g .label text,#mermaid-svg-h2652FpwyP0a8N0g span{fill:#333;color:#333;}#mermaid-svg-h2652FpwyP0a8N0g .node rect,#mermaid-svg-h2652FpwyP0a8N0g .node circle,#mermaid-svg-h2652FpwyP0a8N0g .node ellipse,#mermaid-svg-h2652FpwyP0a8N0g .node polygon,#mermaid-svg-h2652FpwyP0a8N0g .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-h2652FpwyP0a8N0g .rough-node .label text,#mermaid-svg-h2652FpwyP0a8N0g .node .label text,#mermaid-svg-h2652FpwyP0a8N0g .image-shape .label,#mermaid-svg-h2652FpwyP0a8N0g .icon-shape .label{text-anchor:middle;}#mermaid-svg-h2652FpwyP0a8N0g .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-h2652FpwyP0a8N0g .rough-node .label,#mermaid-svg-h2652FpwyP0a8N0g .node .label,#mermaid-svg-h2652FpwyP0a8N0g .image-shape .label,#mermaid-svg-h2652FpwyP0a8N0g .icon-shape .label{text-align:center;}#mermaid-svg-h2652FpwyP0a8N0g .node.clickable{cursor:pointer;}#mermaid-svg-h2652FpwyP0a8N0g .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-h2652FpwyP0a8N0g .arrowheadPath{fill:#333333;}#mermaid-svg-h2652FpwyP0a8N0g .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-h2652FpwyP0a8N0g .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-h2652FpwyP0a8N0g .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-h2652FpwyP0a8N0g .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-h2652FpwyP0a8N0g .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-h2652FpwyP0a8N0g .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-h2652FpwyP0a8N0g .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-h2652FpwyP0a8N0g .cluster text{fill:#333;}#mermaid-svg-h2652FpwyP0a8N0g .cluster span{color:#333;}#mermaid-svg-h2652FpwyP0a8N0g div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-h2652FpwyP0a8N0g .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-h2652FpwyP0a8N0g rect.text{fill:none;stroke-width:0;}#mermaid-svg-h2652FpwyP0a8N0g .icon-shape,#mermaid-svg-h2652FpwyP0a8N0g .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-h2652FpwyP0a8N0g .icon-shape p,#mermaid-svg-h2652FpwyP0a8N0g .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-h2652FpwyP0a8N0g .icon-shape .label rect,#mermaid-svg-h2652FpwyP0a8N0g .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-h2652FpwyP0a8N0g .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-h2652FpwyP0a8N0g .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-h2652FpwyP0a8N0g :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

数据存储层

Elasticsearch搜索+向量索引

MySQL业务数据/元数据

Redis缓存/分布式锁/限流

数据处理层

数据采集Scheduler

数据清洗ETL管道

向量化Embedding

索引构建ES写入

服务层

搜索服务

比价服务

商品服务

前端应用层

Web搜索界面 / API接口 / 数据可视化面板


二、技术栈选型

层级技术组件说明
后端框架 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 采集架构设计

#mermaid-svg-rAv7BrurnQqTMwzl{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-rAv7BrurnQqTMwzl .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-rAv7BrurnQqTMwzl .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-rAv7BrurnQqTMwzl .error-icon{fill:#552222;}#mermaid-svg-rAv7BrurnQqTMwzl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rAv7BrurnQqTMwzl .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-rAv7BrurnQqTMwzl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rAv7BrurnQqTMwzl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rAv7BrurnQqTMwzl .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-rAv7BrurnQqTMwzl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rAv7BrurnQqTMwzl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rAv7BrurnQqTMwzl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rAv7BrurnQqTMwzl .marker.cross{stroke:#333333;}#mermaid-svg-rAv7BrurnQqTMwzl svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rAv7BrurnQqTMwzl p{margin:0;}#mermaid-svg-rAv7BrurnQqTMwzl .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-rAv7BrurnQqTMwzl .cluster-label text{fill:#333;}#mermaid-svg-rAv7BrurnQqTMwzl .cluster-label span{color:#333;}#mermaid-svg-rAv7BrurnQqTMwzl .cluster-label span p{background-color:transparent;}#mermaid-svg-rAv7BrurnQqTMwzl .label text,#mermaid-svg-rAv7BrurnQqTMwzl span{fill:#333;color:#333;}#mermaid-svg-rAv7BrurnQqTMwzl .node rect,#mermaid-svg-rAv7BrurnQqTMwzl .node circle,#mermaid-svg-rAv7BrurnQqTMwzl .node ellipse,#mermaid-svg-rAv7BrurnQqTMwzl .node polygon,#mermaid-svg-rAv7BrurnQqTMwzl .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rAv7BrurnQqTMwzl .rough-node .label text,#mermaid-svg-rAv7BrurnQqTMwzl .node .label text,#mermaid-svg-rAv7BrurnQqTMwzl .image-shape .label,#mermaid-svg-rAv7BrurnQqTMwzl .icon-shape .label{text-anchor:middle;}#mermaid-svg-rAv7BrurnQqTMwzl .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-rAv7BrurnQqTMwzl .rough-node .label,#mermaid-svg-rAv7BrurnQqTMwzl .node .label,#mermaid-svg-rAv7BrurnQqTMwzl .image-shape .label,#mermaid-svg-rAv7BrurnQqTMwzl .icon-shape .label{text-align:center;}#mermaid-svg-rAv7BrurnQqTMwzl .node.clickable{cursor:pointer;}#mermaid-svg-rAv7BrurnQqTMwzl .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-rAv7BrurnQqTMwzl .arrowheadPath{fill:#333333;}#mermaid-svg-rAv7BrurnQqTMwzl .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-rAv7BrurnQqTMwzl .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-rAv7BrurnQqTMwzl .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rAv7BrurnQqTMwzl .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-rAv7BrurnQqTMwzl .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rAv7BrurnQqTMwzl .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-rAv7BrurnQqTMwzl .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-rAv7BrurnQqTMwzl .cluster text{fill:#333;}#mermaid-svg-rAv7BrurnQqTMwzl .cluster span{color:#333;}#mermaid-svg-rAv7BrurnQqTMwzl div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-rAv7BrurnQqTMwzl .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-rAv7BrurnQqTMwzl rect.text{fill:none;stroke-width:0;}#mermaid-svg-rAv7BrurnQqTMwzl .icon-shape,#mermaid-svg-rAv7BrurnQqTMwzl .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rAv7BrurnQqTMwzl .icon-shape p,#mermaid-svg-rAv7BrurnQqTMwzl .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-rAv7BrurnQqTMwzl .icon-shape .label rect,#mermaid-svg-rAv7BrurnQqTMwzl .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rAv7BrurnQqTMwzl .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-rAv7BrurnQqTMwzl .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-rAv7BrurnQqTMwzl :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

采集调度中心 (XXL-JOB)

京东采集 Worker

拼多多 Worker

1688采集 Worker

抖音采集 Worker

同步处理管道

1. 数据采集

2. 数据清洗

3. 向量化

4. 写入 ES

5. 更新 MySQL

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)

爬虫架构:

#mermaid-svg-dle9eDZz06FwIuv3{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-dle9eDZz06FwIuv3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-dle9eDZz06FwIuv3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-dle9eDZz06FwIuv3 .error-icon{fill:#552222;}#mermaid-svg-dle9eDZz06FwIuv3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dle9eDZz06FwIuv3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-dle9eDZz06FwIuv3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dle9eDZz06FwIuv3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dle9eDZz06FwIuv3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-dle9eDZz06FwIuv3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dle9eDZz06FwIuv3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dle9eDZz06FwIuv3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dle9eDZz06FwIuv3 .marker.cross{stroke:#333333;}#mermaid-svg-dle9eDZz06FwIuv3 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dle9eDZz06FwIuv3 p{margin:0;}#mermaid-svg-dle9eDZz06FwIuv3 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-dle9eDZz06FwIuv3 .cluster-label text{fill:#333;}#mermaid-svg-dle9eDZz06FwIuv3 .cluster-label span{color:#333;}#mermaid-svg-dle9eDZz06FwIuv3 .cluster-label span p{background-color:transparent;}#mermaid-svg-dle9eDZz06FwIuv3 .label text,#mermaid-svg-dle9eDZz06FwIuv3 span{fill:#333;color:#333;}#mermaid-svg-dle9eDZz06FwIuv3 .node rect,#mermaid-svg-dle9eDZz06FwIuv3 .node circle,#mermaid-svg-dle9eDZz06FwIuv3 .node ellipse,#mermaid-svg-dle9eDZz06FwIuv3 .node polygon,#mermaid-svg-dle9eDZz06FwIuv3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-dle9eDZz06FwIuv3 .rough-node .label text,#mermaid-svg-dle9eDZz06FwIuv3 .node .label text,#mermaid-svg-dle9eDZz06FwIuv3 .image-shape .label,#mermaid-svg-dle9eDZz06FwIuv3 .icon-shape .label{text-anchor:middle;}#mermaid-svg-dle9eDZz06FwIuv3 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-dle9eDZz06FwIuv3 .rough-node .label,#mermaid-svg-dle9eDZz06FwIuv3 .node .label,#mermaid-svg-dle9eDZz06FwIuv3 .image-shape .label,#mermaid-svg-dle9eDZz06FwIuv3 .icon-shape .label{text-align:center;}#mermaid-svg-dle9eDZz06FwIuv3 .node.clickable{cursor:pointer;}#mermaid-svg-dle9eDZz06FwIuv3 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-dle9eDZz06FwIuv3 .arrowheadPath{fill:#333333;}#mermaid-svg-dle9eDZz06FwIuv3 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-dle9eDZz06FwIuv3 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-dle9eDZz06FwIuv3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dle9eDZz06FwIuv3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-dle9eDZz06FwIuv3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dle9eDZz06FwIuv3 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-dle9eDZz06FwIuv3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-dle9eDZz06FwIuv3 .cluster text{fill:#333;}#mermaid-svg-dle9eDZz06FwIuv3 .cluster span{color:#333;}#mermaid-svg-dle9eDZz06FwIuv3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-dle9eDZz06FwIuv3 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-dle9eDZz06FwIuv3 rect.text{fill:none;stroke-width:0;}#mermaid-svg-dle9eDZz06FwIuv3 .icon-shape,#mermaid-svg-dle9eDZz06FwIuv3 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dle9eDZz06FwIuv3 .icon-shape p,#mermaid-svg-dle9eDZz06FwIuv3 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-dle9eDZz06FwIuv3 .icon-shape .label rect,#mermaid-svg-dle9eDZz06FwIuv3 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dle9eDZz06FwIuv3 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-dle9eDZz06FwIuv3 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-dle9eDZz06FwIuv3 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

爬虫调度器

BaseCrawler 抽象基类createDriver() 创建浏览器驱动crawl() 执行爬取流程search() 搜索商品(抽象)parseProduct() 解析商品(抽象)

TBCrawler(淘宝/天猫)

其他爬虫(扩展)

反爬策略:

  • 无头浏览器模式运行
  • 移除 webdriver 特征标识
  • 设置合理的请求间隔(2-5秒)
  • 使用代理IP池轮换
  • Cookie池管理

数据采集流程:

  • 创建WebDriver实例(配置反爬参数)
  • 导航到搜索页面
  • 等待页面加载完成(显式等待)
  • 解析商品列表元素
  • 提取商品标题、价格、销量等信息
  • 翻页继续采集
  • 关闭浏览器,释放资源

  • 四、数据清洗与归一化模块

    4.1 数据清洗流程总览

    #mermaid-svg-lsX8MIh14qSbwx7Z{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-lsX8MIh14qSbwx7Z .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-lsX8MIh14qSbwx7Z .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-lsX8MIh14qSbwx7Z .error-icon{fill:#552222;}#mermaid-svg-lsX8MIh14qSbwx7Z .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-lsX8MIh14qSbwx7Z .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-lsX8MIh14qSbwx7Z .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-lsX8MIh14qSbwx7Z .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-lsX8MIh14qSbwx7Z .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-lsX8MIh14qSbwx7Z .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-lsX8MIh14qSbwx7Z .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-lsX8MIh14qSbwx7Z .marker{fill:#333333;stroke:#333333;}#mermaid-svg-lsX8MIh14qSbwx7Z .marker.cross{stroke:#333333;}#mermaid-svg-lsX8MIh14qSbwx7Z svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-lsX8MIh14qSbwx7Z p{margin:0;}#mermaid-svg-lsX8MIh14qSbwx7Z .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-lsX8MIh14qSbwx7Z .cluster-label text{fill:#333;}#mermaid-svg-lsX8MIh14qSbwx7Z .cluster-label span{color:#333;}#mermaid-svg-lsX8MIh14qSbwx7Z .cluster-label span p{background-color:transparent;}#mermaid-svg-lsX8MIh14qSbwx7Z .label text,#mermaid-svg-lsX8MIh14qSbwx7Z span{fill:#333;color:#333;}#mermaid-svg-lsX8MIh14qSbwx7Z .node rect,#mermaid-svg-lsX8MIh14qSbwx7Z .node circle,#mermaid-svg-lsX8MIh14qSbwx7Z .node ellipse,#mermaid-svg-lsX8MIh14qSbwx7Z .node polygon,#mermaid-svg-lsX8MIh14qSbwx7Z .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-lsX8MIh14qSbwx7Z .rough-node .label text,#mermaid-svg-lsX8MIh14qSbwx7Z .node .label text,#mermaid-svg-lsX8MIh14qSbwx7Z .image-shape .label,#mermaid-svg-lsX8MIh14qSbwx7Z .icon-shape .label{text-anchor:middle;}#mermaid-svg-lsX8MIh14qSbwx7Z .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-lsX8MIh14qSbwx7Z .rough-node .label,#mermaid-svg-lsX8MIh14qSbwx7Z .node .label,#mermaid-svg-lsX8MIh14qSbwx7Z .image-shape .label,#mermaid-svg-lsX8MIh14qSbwx7Z .icon-shape .label{text-align:center;}#mermaid-svg-lsX8MIh14qSbwx7Z .node.clickable{cursor:pointer;}#mermaid-svg-lsX8MIh14qSbwx7Z .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-lsX8MIh14qSbwx7Z .arrowheadPath{fill:#333333;}#mermaid-svg-lsX8MIh14qSbwx7Z .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-lsX8MIh14qSbwx7Z .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-lsX8MIh14qSbwx7Z .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lsX8MIh14qSbwx7Z .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-lsX8MIh14qSbwx7Z .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lsX8MIh14qSbwx7Z .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-lsX8MIh14qSbwx7Z .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-lsX8MIh14qSbwx7Z .cluster text{fill:#333;}#mermaid-svg-lsX8MIh14qSbwx7Z .cluster span{color:#333;}#mermaid-svg-lsX8MIh14qSbwx7Z div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-lsX8MIh14qSbwx7Z .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-lsX8MIh14qSbwx7Z rect.text{fill:none;stroke-width:0;}#mermaid-svg-lsX8MIh14qSbwx7Z .icon-shape,#mermaid-svg-lsX8MIh14qSbwx7Z .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lsX8MIh14qSbwx7Z .icon-shape p,#mermaid-svg-lsX8MIh14qSbwx7Z .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-lsX8MIh14qSbwx7Z .icon-shape .label rect,#mermaid-svg-lsX8MIh14qSbwx7Z .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lsX8MIh14qSbwx7Z .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-lsX8MIh14qSbwx7Z .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-lsX8MIh14qSbwx7Z :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    原始数据(Raw JSON)

    格式校验 & 过滤结构校验 / 空值检查异常拦截 / 类型转换

    字段提取 & 转换平台映射 / 字段转换

    数据标准化 & 归一化价格/文本/图片时间/类目归一化

    去重过滤 & 合并唯一标识 / 模糊匹配版本控制

    质量评分 & 入库质量打分 / 分级入库异常标记

    多平台原始JSON

    校验规则

    字段映射表

    标准化规则

    去重算法

    质量等级 A/B/C/D

    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 标记无效,使用备用图
    重复数据 同一商品多次采集 更新时间戳,保留最新版本

    异常数据流转:

    #mermaid-svg-F8gSjGIoSqF40OrM{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-F8gSjGIoSqF40OrM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-F8gSjGIoSqF40OrM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-F8gSjGIoSqF40OrM .error-icon{fill:#552222;}#mermaid-svg-F8gSjGIoSqF40OrM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-F8gSjGIoSqF40OrM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-F8gSjGIoSqF40OrM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-F8gSjGIoSqF40OrM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-F8gSjGIoSqF40OrM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-F8gSjGIoSqF40OrM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-F8gSjGIoSqF40OrM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-F8gSjGIoSqF40OrM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-F8gSjGIoSqF40OrM .marker.cross{stroke:#333333;}#mermaid-svg-F8gSjGIoSqF40OrM svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-F8gSjGIoSqF40OrM p{margin:0;}#mermaid-svg-F8gSjGIoSqF40OrM .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-F8gSjGIoSqF40OrM .cluster-label text{fill:#333;}#mermaid-svg-F8gSjGIoSqF40OrM .cluster-label span{color:#333;}#mermaid-svg-F8gSjGIoSqF40OrM .cluster-label span p{background-color:transparent;}#mermaid-svg-F8gSjGIoSqF40OrM .label text,#mermaid-svg-F8gSjGIoSqF40OrM span{fill:#333;color:#333;}#mermaid-svg-F8gSjGIoSqF40OrM .node rect,#mermaid-svg-F8gSjGIoSqF40OrM .node circle,#mermaid-svg-F8gSjGIoSqF40OrM .node ellipse,#mermaid-svg-F8gSjGIoSqF40OrM .node polygon,#mermaid-svg-F8gSjGIoSqF40OrM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-F8gSjGIoSqF40OrM .rough-node .label text,#mermaid-svg-F8gSjGIoSqF40OrM .node .label text,#mermaid-svg-F8gSjGIoSqF40OrM .image-shape .label,#mermaid-svg-F8gSjGIoSqF40OrM .icon-shape .label{text-anchor:middle;}#mermaid-svg-F8gSjGIoSqF40OrM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-F8gSjGIoSqF40OrM .rough-node .label,#mermaid-svg-F8gSjGIoSqF40OrM .node .label,#mermaid-svg-F8gSjGIoSqF40OrM .image-shape .label,#mermaid-svg-F8gSjGIoSqF40OrM .icon-shape .label{text-align:center;}#mermaid-svg-F8gSjGIoSqF40OrM .node.clickable{cursor:pointer;}#mermaid-svg-F8gSjGIoSqF40OrM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-F8gSjGIoSqF40OrM .arrowheadPath{fill:#333333;}#mermaid-svg-F8gSjGIoSqF40OrM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-F8gSjGIoSqF40OrM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-F8gSjGIoSqF40OrM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-F8gSjGIoSqF40OrM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-F8gSjGIoSqF40OrM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-F8gSjGIoSqF40OrM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-F8gSjGIoSqF40OrM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-F8gSjGIoSqF40OrM .cluster text{fill:#333;}#mermaid-svg-F8gSjGIoSqF40OrM .cluster span{color:#333;}#mermaid-svg-F8gSjGIoSqF40OrM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-F8gSjGIoSqF40OrM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-F8gSjGIoSqF40OrM rect.text{fill:none;stroke-width:0;}#mermaid-svg-F8gSjGIoSqF40OrM .icon-shape,#mermaid-svg-F8gSjGIoSqF40OrM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-F8gSjGIoSqF40OrM .icon-shape p,#mermaid-svg-F8gSjGIoSqF40OrM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-F8gSjGIoSqF40OrM .icon-shape .label rect,#mermaid-svg-F8gSjGIoSqF40OrM .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-F8gSjGIoSqF40OrM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-F8gSjGIoSqF40OrM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-F8gSjGIoSqF40OrM :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    异常数据

    异常分类

    自动修复

    修复成功?

    正常流程

    修复失败

    人工审核

    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 中文语义理解强、支持多语言 商品标题/描述语义检索

    向量化流程:

    商品入库时,对同一份商品数据同步执行向量化:

    #mermaid-svg-HDEMOtho4VEVW5cF{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HDEMOtho4VEVW5cF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HDEMOtho4VEVW5cF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HDEMOtho4VEVW5cF .error-icon{fill:#552222;}#mermaid-svg-HDEMOtho4VEVW5cF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HDEMOtho4VEVW5cF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HDEMOtho4VEVW5cF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HDEMOtho4VEVW5cF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HDEMOtho4VEVW5cF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HDEMOtho4VEVW5cF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HDEMOtho4VEVW5cF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HDEMOtho4VEVW5cF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HDEMOtho4VEVW5cF .marker.cross{stroke:#333333;}#mermaid-svg-HDEMOtho4VEVW5cF svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HDEMOtho4VEVW5cF p{margin:0;}#mermaid-svg-HDEMOtho4VEVW5cF .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-HDEMOtho4VEVW5cF .cluster-label text{fill:#333;}#mermaid-svg-HDEMOtho4VEVW5cF .cluster-label span{color:#333;}#mermaid-svg-HDEMOtho4VEVW5cF .cluster-label span p{background-color:transparent;}#mermaid-svg-HDEMOtho4VEVW5cF .label text,#mermaid-svg-HDEMOtho4VEVW5cF span{fill:#333;color:#333;}#mermaid-svg-HDEMOtho4VEVW5cF .node rect,#mermaid-svg-HDEMOtho4VEVW5cF .node circle,#mermaid-svg-HDEMOtho4VEVW5cF .node ellipse,#mermaid-svg-HDEMOtho4VEVW5cF .node polygon,#mermaid-svg-HDEMOtho4VEVW5cF .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HDEMOtho4VEVW5cF .rough-node .label text,#mermaid-svg-HDEMOtho4VEVW5cF .node .label text,#mermaid-svg-HDEMOtho4VEVW5cF .image-shape .label,#mermaid-svg-HDEMOtho4VEVW5cF .icon-shape .label{text-anchor:middle;}#mermaid-svg-HDEMOtho4VEVW5cF .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-HDEMOtho4VEVW5cF .rough-node .label,#mermaid-svg-HDEMOtho4VEVW5cF .node .label,#mermaid-svg-HDEMOtho4VEVW5cF .image-shape .label,#mermaid-svg-HDEMOtho4VEVW5cF .icon-shape .label{text-align:center;}#mermaid-svg-HDEMOtho4VEVW5cF .node.clickable{cursor:pointer;}#mermaid-svg-HDEMOtho4VEVW5cF .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-HDEMOtho4VEVW5cF .arrowheadPath{fill:#333333;}#mermaid-svg-HDEMOtho4VEVW5cF .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HDEMOtho4VEVW5cF .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HDEMOtho4VEVW5cF .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HDEMOtho4VEVW5cF .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-HDEMOtho4VEVW5cF .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HDEMOtho4VEVW5cF .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-HDEMOtho4VEVW5cF .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HDEMOtho4VEVW5cF .cluster text{fill:#333;}#mermaid-svg-HDEMOtho4VEVW5cF .cluster span{color:#333;}#mermaid-svg-HDEMOtho4VEVW5cF div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HDEMOtho4VEVW5cF .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-HDEMOtho4VEVW5cF rect.text{fill:none;stroke-width:0;}#mermaid-svg-HDEMOtho4VEVW5cF .icon-shape,#mermaid-svg-HDEMOtho4VEVW5cF .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HDEMOtho4VEVW5cF .icon-shape p,#mermaid-svg-HDEMOtho4VEVW5cF .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-HDEMOtho4VEVW5cF .icon-shape .label rect,#mermaid-svg-HDEMOtho4VEVW5cF .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HDEMOtho4VEVW5cF .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-HDEMOtho4VEVW5cF .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-HDEMOtho4VEVW5cF :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    文本预处理

    【输入】商品数据标题 / 描述 / 品牌 / 类目

    标题清洗后文本标题+品牌+类目

    原始标题文本

    描述清洗后文本

    【Qwen】标题稠密向量1024维

    【SPLADE】标题稀疏向量

    【Qwen】描述稠密向量1024维

    写入 EStitle.dense_vector

    写入 EStitle.sparse_vector

    写入 ESdesc.dense_vector

    向量化完成

    关键说明:

    • 标题向量化:Qwen(清洗后标题+品牌+类目)+ SPLADE(原始标题文本)
    • 描述向量化:Qwen(清洗后描述文本),仅生成稠密向量
    • 所有向量化同步执行,互不依赖
    • 最终同时写入ES对应字段

    批量处理策略:

    • 批量向量化(每批100条)
    • 同步处理,采集完直接清洗入库
    • 失败重试机制
    • GPU加速(可选)

    5.3 索引写入策略

    写入流程:

  • 采集Worker调用平台API获取原始数据
  • 同步调用数据清洗服务,执行格式校验、字段映射、标准化
  • 调用向量化服务生成标题稠密向量、标题稀疏向量、描述稠密向量
  • 批量写入Elasticsearch
  • 更新MySQL元数据(采集状态、时间等)
  • 性能优化:

    • 使用ES bulk API批量写入
    • 每批100-500条记录
    • 写入时关闭refresh_interval,完成后恢复
    • 冷热数据分离(近期数据SSD,历史数据HDD)

    六、数据检索服务

    6.1 混合检索架构

    #mermaid-svg-BOsuy2snRx3e0WyW{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-BOsuy2snRx3e0WyW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BOsuy2snRx3e0WyW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BOsuy2snRx3e0WyW .error-icon{fill:#552222;}#mermaid-svg-BOsuy2snRx3e0WyW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BOsuy2snRx3e0WyW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BOsuy2snRx3e0WyW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BOsuy2snRx3e0WyW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BOsuy2snRx3e0WyW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BOsuy2snRx3e0WyW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BOsuy2snRx3e0WyW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BOsuy2snRx3e0WyW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BOsuy2snRx3e0WyW .marker.cross{stroke:#333333;}#mermaid-svg-BOsuy2snRx3e0WyW svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BOsuy2snRx3e0WyW p{margin:0;}#mermaid-svg-BOsuy2snRx3e0WyW .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-BOsuy2snRx3e0WyW .cluster-label text{fill:#333;}#mermaid-svg-BOsuy2snRx3e0WyW .cluster-label span{color:#333;}#mermaid-svg-BOsuy2snRx3e0WyW .cluster-label span p{background-color:transparent;}#mermaid-svg-BOsuy2snRx3e0WyW .label text,#mermaid-svg-BOsuy2snRx3e0WyW span{fill:#333;color:#333;}#mermaid-svg-BOsuy2snRx3e0WyW .node rect,#mermaid-svg-BOsuy2snRx3e0WyW .node circle,#mermaid-svg-BOsuy2snRx3e0WyW .node ellipse,#mermaid-svg-BOsuy2snRx3e0WyW .node polygon,#mermaid-svg-BOsuy2snRx3e0WyW .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-BOsuy2snRx3e0WyW .rough-node .label text,#mermaid-svg-BOsuy2snRx3e0WyW .node .label text,#mermaid-svg-BOsuy2snRx3e0WyW .image-shape .label,#mermaid-svg-BOsuy2snRx3e0WyW .icon-shape .label{text-anchor:middle;}#mermaid-svg-BOsuy2snRx3e0WyW .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-BOsuy2snRx3e0WyW .rough-node .label,#mermaid-svg-BOsuy2snRx3e0WyW .node .label,#mermaid-svg-BOsuy2snRx3e0WyW .image-shape .label,#mermaid-svg-BOsuy2snRx3e0WyW .icon-shape .label{text-align:center;}#mermaid-svg-BOsuy2snRx3e0WyW .node.clickable{cursor:pointer;}#mermaid-svg-BOsuy2snRx3e0WyW .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-BOsuy2snRx3e0WyW .arrowheadPath{fill:#333333;}#mermaid-svg-BOsuy2snRx3e0WyW .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-BOsuy2snRx3e0WyW .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-BOsuy2snRx3e0WyW .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BOsuy2snRx3e0WyW .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-BOsuy2snRx3e0WyW .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BOsuy2snRx3e0WyW .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-BOsuy2snRx3e0WyW .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-BOsuy2snRx3e0WyW .cluster text{fill:#333;}#mermaid-svg-BOsuy2snRx3e0WyW .cluster span{color:#333;}#mermaid-svg-BOsuy2snRx3e0WyW div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-BOsuy2snRx3e0WyW .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-BOsuy2snRx3e0WyW rect.text{fill:none;stroke-width:0;}#mermaid-svg-BOsuy2snRx3e0WyW .icon-shape,#mermaid-svg-BOsuy2snRx3e0WyW .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BOsuy2snRx3e0WyW .icon-shape p,#mermaid-svg-BOsuy2snRx3e0WyW .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-BOsuy2snRx3e0WyW .icon-shape .label rect,#mermaid-svg-BOsuy2snRx3e0WyW .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BOsuy2snRx3e0WyW .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-BOsuy2snRx3e0WyW .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-BOsuy2snRx3e0WyW :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    用户查询: iPhone 15 手机壳

    关键字检索 (BM25)

    稠密向量语义检索(Qwen 1024维)

    稀疏向量词元检索(SPLADE)

    RRF 融合排序Reciprocal Rank Fusion

    最终结果排序(价格/销量/品牌等)

    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

    #mermaid-svg-D46sPV5ltEBx4S1f{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-D46sPV5ltEBx4S1f .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-D46sPV5ltEBx4S1f .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-D46sPV5ltEBx4S1f .error-icon{fill:#552222;}#mermaid-svg-D46sPV5ltEBx4S1f .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-D46sPV5ltEBx4S1f .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-D46sPV5ltEBx4S1f .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-D46sPV5ltEBx4S1f .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-D46sPV5ltEBx4S1f .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-D46sPV5ltEBx4S1f .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-D46sPV5ltEBx4S1f .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-D46sPV5ltEBx4S1f .marker{fill:#333333;stroke:#333333;}#mermaid-svg-D46sPV5ltEBx4S1f .marker.cross{stroke:#333333;}#mermaid-svg-D46sPV5ltEBx4S1f svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-D46sPV5ltEBx4S1f p{margin:0;}#mermaid-svg-D46sPV5ltEBx4S1f .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-D46sPV5ltEBx4S1f .cluster-label text{fill:#333;}#mermaid-svg-D46sPV5ltEBx4S1f .cluster-label span{color:#333;}#mermaid-svg-D46sPV5ltEBx4S1f .cluster-label span p{background-color:transparent;}#mermaid-svg-D46sPV5ltEBx4S1f .label text,#mermaid-svg-D46sPV5ltEBx4S1f span{fill:#333;color:#333;}#mermaid-svg-D46sPV5ltEBx4S1f .node rect,#mermaid-svg-D46sPV5ltEBx4S1f .node circle,#mermaid-svg-D46sPV5ltEBx4S1f .node ellipse,#mermaid-svg-D46sPV5ltEBx4S1f .node polygon,#mermaid-svg-D46sPV5ltEBx4S1f .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-D46sPV5ltEBx4S1f .rough-node .label text,#mermaid-svg-D46sPV5ltEBx4S1f .node .label text,#mermaid-svg-D46sPV5ltEBx4S1f .image-shape .label,#mermaid-svg-D46sPV5ltEBx4S1f .icon-shape .label{text-anchor:middle;}#mermaid-svg-D46sPV5ltEBx4S1f .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-D46sPV5ltEBx4S1f .rough-node .label,#mermaid-svg-D46sPV5ltEBx4S1f .node .label,#mermaid-svg-D46sPV5ltEBx4S1f .image-shape .label,#mermaid-svg-D46sPV5ltEBx4S1f .icon-shape .label{text-align:center;}#mermaid-svg-D46sPV5ltEBx4S1f .node.clickable{cursor:pointer;}#mermaid-svg-D46sPV5ltEBx4S1f .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-D46sPV5ltEBx4S1f .arrowheadPath{fill:#333333;}#mermaid-svg-D46sPV5ltEBx4S1f .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-D46sPV5ltEBx4S1f .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-D46sPV5ltEBx4S1f .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-D46sPV5ltEBx4S1f .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-D46sPV5ltEBx4S1f .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-D46sPV5ltEBx4S1f .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-D46sPV5ltEBx4S1f .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-D46sPV5ltEBx4S1f .cluster text{fill:#333;}#mermaid-svg-D46sPV5ltEBx4S1f .cluster span{color:#333;}#mermaid-svg-D46sPV5ltEBx4S1f div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-D46sPV5ltEBx4S1f .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-D46sPV5ltEBx4S1f rect.text{fill:none;stroke-width:0;}#mermaid-svg-D46sPV5ltEBx4S1f .icon-shape,#mermaid-svg-D46sPV5ltEBx4S1f .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-D46sPV5ltEBx4S1f .icon-shape p,#mermaid-svg-D46sPV5ltEBx4S1f .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-D46sPV5ltEBx4S1f .icon-shape .label rect,#mermaid-svg-D46sPV5ltEBx4S1f .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-D46sPV5ltEBx4S1f .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-D46sPV5ltEBx4S1f .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-D46sPV5ltEBx4S1f :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    XXL-JOB 调度中心

    任务管理界面- 任务配置/启停- 执行日志查看- 告警配置

    执行器A(采集服务)

    执行器B(清洗服务)

    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 检索流程总览

    #mermaid-svg-vad6qgRX5MaZzPE2{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-vad6qgRX5MaZzPE2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-vad6qgRX5MaZzPE2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-vad6qgRX5MaZzPE2 .error-icon{fill:#552222;}#mermaid-svg-vad6qgRX5MaZzPE2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-vad6qgRX5MaZzPE2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-vad6qgRX5MaZzPE2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vad6qgRX5MaZzPE2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vad6qgRX5MaZzPE2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-vad6qgRX5MaZzPE2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vad6qgRX5MaZzPE2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vad6qgRX5MaZzPE2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-vad6qgRX5MaZzPE2 .marker.cross{stroke:#333333;}#mermaid-svg-vad6qgRX5MaZzPE2 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vad6qgRX5MaZzPE2 p{margin:0;}#mermaid-svg-vad6qgRX5MaZzPE2 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-vad6qgRX5MaZzPE2 .cluster-label text{fill:#333;}#mermaid-svg-vad6qgRX5MaZzPE2 .cluster-label span{color:#333;}#mermaid-svg-vad6qgRX5MaZzPE2 .cluster-label span p{background-color:transparent;}#mermaid-svg-vad6qgRX5MaZzPE2 .label text,#mermaid-svg-vad6qgRX5MaZzPE2 span{fill:#333;color:#333;}#mermaid-svg-vad6qgRX5MaZzPE2 .node rect,#mermaid-svg-vad6qgRX5MaZzPE2 .node circle,#mermaid-svg-vad6qgRX5MaZzPE2 .node ellipse,#mermaid-svg-vad6qgRX5MaZzPE2 .node polygon,#mermaid-svg-vad6qgRX5MaZzPE2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-vad6qgRX5MaZzPE2 .rough-node .label text,#mermaid-svg-vad6qgRX5MaZzPE2 .node .label text,#mermaid-svg-vad6qgRX5MaZzPE2 .image-shape .label,#mermaid-svg-vad6qgRX5MaZzPE2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-vad6qgRX5MaZzPE2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-vad6qgRX5MaZzPE2 .rough-node .label,#mermaid-svg-vad6qgRX5MaZzPE2 .node .label,#mermaid-svg-vad6qgRX5MaZzPE2 .image-shape .label,#mermaid-svg-vad6qgRX5MaZzPE2 .icon-shape .label{text-align:center;}#mermaid-svg-vad6qgRX5MaZzPE2 .node.clickable{cursor:pointer;}#mermaid-svg-vad6qgRX5MaZzPE2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-vad6qgRX5MaZzPE2 .arrowheadPath{fill:#333333;}#mermaid-svg-vad6qgRX5MaZzPE2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-vad6qgRX5MaZzPE2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-vad6qgRX5MaZzPE2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vad6qgRX5MaZzPE2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-vad6qgRX5MaZzPE2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vad6qgRX5MaZzPE2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-vad6qgRX5MaZzPE2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-vad6qgRX5MaZzPE2 .cluster text{fill:#333;}#mermaid-svg-vad6qgRX5MaZzPE2 .cluster span{color:#333;}#mermaid-svg-vad6qgRX5MaZzPE2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-vad6qgRX5MaZzPE2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-vad6qgRX5MaZzPE2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-vad6qgRX5MaZzPE2 .icon-shape,#mermaid-svg-vad6qgRX5MaZzPE2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vad6qgRX5MaZzPE2 .icon-shape p,#mermaid-svg-vad6qgRX5MaZzPE2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-vad6qgRX5MaZzPE2 .icon-shape .label rect,#mermaid-svg-vad6qgRX5MaZzPE2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vad6qgRX5MaZzPE2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-vad6qgRX5MaZzPE2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-vad6qgRX5MaZzPE2 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    用户查询: iPhone 15 手机壳

    Query处理(分词/纠错)

    Query向量化(Qwen模型)

    BM25检索(倒排索引)

    稠密向量检索(HNSW索引)

    稀疏向量检索(词元权重)

    RRF 融合排序score = Σ 1/(k + rank_i(d))

    业务规则过滤与重排(价格区间/品牌/平台/销量排序)

    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近似最近邻索引加速检索

    向量化流程:

    #mermaid-svg-6nPyv03CdORlxZuz{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-6nPyv03CdORlxZuz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-6nPyv03CdORlxZuz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-6nPyv03CdORlxZuz .error-icon{fill:#552222;}#mermaid-svg-6nPyv03CdORlxZuz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6nPyv03CdORlxZuz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-6nPyv03CdORlxZuz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6nPyv03CdORlxZuz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6nPyv03CdORlxZuz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-6nPyv03CdORlxZuz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6nPyv03CdORlxZuz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6nPyv03CdORlxZuz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6nPyv03CdORlxZuz .marker.cross{stroke:#333333;}#mermaid-svg-6nPyv03CdORlxZuz svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6nPyv03CdORlxZuz p{margin:0;}#mermaid-svg-6nPyv03CdORlxZuz .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-6nPyv03CdORlxZuz .cluster-label text{fill:#333;}#mermaid-svg-6nPyv03CdORlxZuz .cluster-label span{color:#333;}#mermaid-svg-6nPyv03CdORlxZuz .cluster-label span p{background-color:transparent;}#mermaid-svg-6nPyv03CdORlxZuz .label text,#mermaid-svg-6nPyv03CdORlxZuz span{fill:#333;color:#333;}#mermaid-svg-6nPyv03CdORlxZuz .node rect,#mermaid-svg-6nPyv03CdORlxZuz .node circle,#mermaid-svg-6nPyv03CdORlxZuz .node ellipse,#mermaid-svg-6nPyv03CdORlxZuz .node polygon,#mermaid-svg-6nPyv03CdORlxZuz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6nPyv03CdORlxZuz .rough-node .label text,#mermaid-svg-6nPyv03CdORlxZuz .node .label text,#mermaid-svg-6nPyv03CdORlxZuz .image-shape .label,#mermaid-svg-6nPyv03CdORlxZuz .icon-shape .label{text-anchor:middle;}#mermaid-svg-6nPyv03CdORlxZuz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-6nPyv03CdORlxZuz .rough-node .label,#mermaid-svg-6nPyv03CdORlxZuz .node .label,#mermaid-svg-6nPyv03CdORlxZuz .image-shape .label,#mermaid-svg-6nPyv03CdORlxZuz .icon-shape .label{text-align:center;}#mermaid-svg-6nPyv03CdORlxZuz .node.clickable{cursor:pointer;}#mermaid-svg-6nPyv03CdORlxZuz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-6nPyv03CdORlxZuz .arrowheadPath{fill:#333333;}#mermaid-svg-6nPyv03CdORlxZuz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-6nPyv03CdORlxZuz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-6nPyv03CdORlxZuz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6nPyv03CdORlxZuz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-6nPyv03CdORlxZuz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6nPyv03CdORlxZuz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-6nPyv03CdORlxZuz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-6nPyv03CdORlxZuz .cluster text{fill:#333;}#mermaid-svg-6nPyv03CdORlxZuz .cluster span{color:#333;}#mermaid-svg-6nPyv03CdORlxZuz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-6nPyv03CdORlxZuz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-6nPyv03CdORlxZuz rect.text{fill:none;stroke-width:0;}#mermaid-svg-6nPyv03CdORlxZuz .icon-shape,#mermaid-svg-6nPyv03CdORlxZuz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6nPyv03CdORlxZuz .icon-shape p,#mermaid-svg-6nPyv03CdORlxZuz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-6nPyv03CdORlxZuz .icon-shape .label rect,#mermaid-svg-6nPyv03CdORlxZuz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6nPyv03CdORlxZuz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-6nPyv03CdORlxZuz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-6nPyv03CdORlxZuz :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    用户搜索时

    查询: 苹果手机保护套

    Qwen Encoder

    [0.11, -0.33, 0.55, …](查询向量)

    ES HNSW向量检索返回Top-K相似商品

    商品入库时

    商品标题苹果iPhone 15 Pro Max手机壳

    Qwen Encoder

    [0.12, -0.34, 0.56, …](1024维稠密向量)

    写入EStitle.dense_vector

    相似度计算:

    余弦相似度 = (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缓存已计算的相似度 避免重复计算
    批量向量化 一次处理多条 提升向量化效率

    分层去重流程:

    #mermaid-svg-npfqYAdhJUjxhfat{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-npfqYAdhJUjxhfat .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-npfqYAdhJUjxhfat .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-npfqYAdhJUjxhfat .error-icon{fill:#552222;}#mermaid-svg-npfqYAdhJUjxhfat .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-npfqYAdhJUjxhfat .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-npfqYAdhJUjxhfat .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-npfqYAdhJUjxhfat .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-npfqYAdhJUjxhfat .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-npfqYAdhJUjxhfat .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-npfqYAdhJUjxhfat .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-npfqYAdhJUjxhfat .marker{fill:#333333;stroke:#333333;}#mermaid-svg-npfqYAdhJUjxhfat .marker.cross{stroke:#333333;}#mermaid-svg-npfqYAdhJUjxhfat svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-npfqYAdhJUjxhfat p{margin:0;}#mermaid-svg-npfqYAdhJUjxhfat .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-npfqYAdhJUjxhfat .cluster-label text{fill:#333;}#mermaid-svg-npfqYAdhJUjxhfat .cluster-label span{color:#333;}#mermaid-svg-npfqYAdhJUjxhfat .cluster-label span p{background-color:transparent;}#mermaid-svg-npfqYAdhJUjxhfat .label text,#mermaid-svg-npfqYAdhJUjxhfat span{fill:#333;color:#333;}#mermaid-svg-npfqYAdhJUjxhfat .node rect,#mermaid-svg-npfqYAdhJUjxhfat .node circle,#mermaid-svg-npfqYAdhJUjxhfat .node ellipse,#mermaid-svg-npfqYAdhJUjxhfat .node polygon,#mermaid-svg-npfqYAdhJUjxhfat .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-npfqYAdhJUjxhfat .rough-node .label text,#mermaid-svg-npfqYAdhJUjxhfat .node .label text,#mermaid-svg-npfqYAdhJUjxhfat .image-shape .label,#mermaid-svg-npfqYAdhJUjxhfat .icon-shape .label{text-anchor:middle;}#mermaid-svg-npfqYAdhJUjxhfat .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-npfqYAdhJUjxhfat .rough-node .label,#mermaid-svg-npfqYAdhJUjxhfat .node .label,#mermaid-svg-npfqYAdhJUjxhfat .image-shape .label,#mermaid-svg-npfqYAdhJUjxhfat .icon-shape .label{text-align:center;}#mermaid-svg-npfqYAdhJUjxhfat .node.clickable{cursor:pointer;}#mermaid-svg-npfqYAdhJUjxhfat .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-npfqYAdhJUjxhfat .arrowheadPath{fill:#333333;}#mermaid-svg-npfqYAdhJUjxhfat .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-npfqYAdhJUjxhfat .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-npfqYAdhJUjxhfat .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-npfqYAdhJUjxhfat .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-npfqYAdhJUjxhfat .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-npfqYAdhJUjxhfat .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-npfqYAdhJUjxhfat .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-npfqYAdhJUjxhfat .cluster text{fill:#333;}#mermaid-svg-npfqYAdhJUjxhfat .cluster span{color:#333;}#mermaid-svg-npfqYAdhJUjxhfat div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-npfqYAdhJUjxhfat .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-npfqYAdhJUjxhfat rect.text{fill:none;stroke-width:0;}#mermaid-svg-npfqYAdhJUjxhfat .icon-shape,#mermaid-svg-npfqYAdhJUjxhfat .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-npfqYAdhJUjxhfat .icon-shape p,#mermaid-svg-npfqYAdhJUjxhfat .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-npfqYAdhJUjxhfat .icon-shape .label rect,#mermaid-svg-npfqYAdhJUjxhfat .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-npfqYAdhJUjxhfat .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-npfqYAdhJUjxhfat .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-npfqYAdhJUjxhfat :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    相似度>=0.85

    0.70<=相似度<0.85

    相似度<0.70

    新商品到来

    第一层:粗筛品牌相同? 类目相同? 价格接近?

    通过?

    独立入库

    第二层:向量召回标题向量检索Top-10候选

    第三层:精判多维度相似度计算综合得分判定

    判定结果

    合并数据

    标记待审核

    独立入库

    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

    赞(0)
    未经允许不得转载:171主机测评 » 电商商品全网聚合平台 - 技术实现方案
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址