当前位置: 首页 > article >正文

实现电商网站商品检索

项目描述
本项目旨在构建一个基于 Vue3、Spring Boot 和 Elasticsearch 的电商网站商品检索系统,旨在为电商平台提供高效、精准的商品搜索体验,助力提升用户购物满意度和转化率。系统将融合现代前端技术、稳健后端架构以及强大的全文检索引擎,实现对海量商品数据的实时搜索、智能筛选、个性化推荐等功能,打造卓越的线上购物搜索体验。

应用场景
综合电商平台:大型综合性电商平台,涵盖各类商品品类,需要高效处理用户对不同商品的搜索请求。
垂直领域商城:专注于某一特定行业(如电子产品、服装、家居等)的电商平台,需精准匹配用户在该领域的商品搜索需求。
跨境电商平台:支持多语言搜索,处理国际商品信息,为全球用户提供跨地域的商品检索服务。
技术选型
Vue3
ElementPlus UI
Spring Boot
Elasticsearch
Spring Data Elasticsearch
功能点
用户端
用户输入关键词时,系统实时显示搜索建议,并随着输入变化即时更新搜索结果
提供品牌、价格区间、销量、评价等级等丰富的筛选条件,帮助用户快速定位目标商品。
点击搜索结果,跳转至商品详情页,展示详细商品信息
后台
商品分类管理
商品管理
从商品数据库同步商品信息至 Elasticsearch,构建商品索引,支持多字段、多类型数据的高效检索。
项目实现参考
前端开发:使用 Vue3 结合 ElementPlus UI 库构建现代化电商界面,实现搜索框、筛选面板、商品列表等组件。

后端开发:

使用 Spring Boot 构建 RESTful API,处理商品数据同步、搜索请求、筛选参数解析等工作。
集成 Spring Data Elasticsearch,实现与 Elasticsearch 的便捷交互,构建复杂的搜索查询DSL(Domain Specific Language,领域特定语言)。
分词配置:根据商品属性定义索引结构,包括商品ID、标题、描述、价格、库存、分类、品牌等字段,设置合适的分词器(如 ik_smart)处理中文文本

—云端源想整理

电商商品检索系统实现方案


一、系统架构设计
用户端Vue3
Nginx
SpringBoot API
Elasticsearch集群
MySQL
管理后台
Logstash数据同步

二、核心功能实现
1. Elasticsearch索引设计
// 商品索引映射
PUT /products
{
  "settings": {
    "analysis": {
      "analyzer": {
        "ik_pinyin_analyzer": {
          "type": "custom",
          "tokenizer": "ik_smart",
          "filter": ["pinyin_filter"]
        }
      },
      "filter": {
        "pinyin_filter": {
          "type": "pinyin",
          "keep_first_letter": true
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "id": {"type": "keyword"},
      "title": {
        "type": "text",
        "analyzer": "ik_pinyin_analyzer",
        "fields": {
          "raw": {"type": "keyword"}
        }
      },
      "category_path": {"type": "keyword"},
      "price": {"type": "double"},
      "sales": {"type": "integer"},
      "brand": {"type": "keyword"},
      "specs": {"type": "nested"}
    }
  }
}
2. 数据同步方案
# Logstash配置示例 (mysql-to-es.conf)
input {
  jdbc {
    jdbc_driver_library => "/mysql-connector-java.jar"
    jdbc_driver_class => "com.mysql.jdbc.Driver"
    jdbc_connection_string => "jdbc:mysql://mysql:3306/ecommerce"
    jdbc_user => "root"
    jdbc_password => "password"
    schedule => "*/5 * * * *"
    statement => "SELECT * FROM products WHERE update_time > :sql_last_value"
  }
}

output {
  elasticsearch {
    hosts => ["elasticsearch:9200"]
    index => "products"
    document_id => "%{id}"
  }
}

三、后端实现(Spring Boot)
1. 搜索接口实现
// 商品搜索Repository
public interface ProductSearchRepository extends ElasticsearchRepository<ProductEs, String> {
  
    @Query("{\"bool\": {\"must\": [" +
           "{\"match\": {\"title\": \"?0\"}}," +
           "{\"range\": {\"price\": {\"gte\": ?1, \"lte\": ?2}}}" +
           "]}}")
    Page<ProductEs> searchByKeywordAndPriceRange(String keyword, 
                                                Double minPrice, 
                                                Double maxPrice, 
                                                Pageable pageable);
}

// 搜索服务实现
@Service
public class SearchService {
  
    @Autowired
    private ProductSearchRepository repository;

    public SearchResultDTO searchProducts(SearchRequest request) {
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder()
            .withQuery(buildQuery(request))
            .withPageable(PageRequest.of(request.getPage(), request.getSize()))
            .withSort(buildSort(request.getSortBy()));

        if (request.getFilters() != null) {
            addFilters(queryBuilder, request.getFilters());
        }

        SearchHits<ProductEs> hits = repository.search(queryBuilder.build());
        return convertToResultDTO(hits);
    }

    private BoolQueryBuilder buildQuery(SearchRequest request) {
        return QueryBuilders.boolQuery()
            .must(QueryBuilders.multiMatchQuery(request.getKeyword())
                .field("title", 3.0f)
                .field("brand", 2.0f)
                .type(MultiMatchQueryBuilder.Type.BEST_FIELDS));
    }
}
2. 搜索建议实现
// 搜索建议Controller
@RestController
@RequestMapping("/api/search")
public class SearchController {
  
    @GetMapping("/suggest")
    public List<String> getSuggestions(@RequestParam String prefix) {
        CompletionSuggestionBuilder suggestion = SuggestBuilders
            .completionSuggestion("suggest")
            .prefix(prefix)
            .size(5);

        SearchRequest searchRequest = new SearchRequest("products")
            .suggest(new SuggestBuilder().addSuggestion("title-suggest", suggestion));

        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        return parseSuggestions(response);
    }
}

**四、前端实现(Vue3 + ElementPlus)
1. 搜索组件实现
<template>
  <div class="search-container">
    <el-autocomplete
      v-model="keyword"
      :fetch-suggestions="fetchSuggestions"
      placeholder="搜索商品名称/品牌"
      @select="handleSearch"
    >
      <template #prefix>
        <el-icon><search /></el-icon>
      </template>
    </el-autocomplete>

    <div class="filters">
      <el-select v-model="brandFilter" placeholder="品牌">
        <el-option 
          v-for="brand in brands" 
          :key="brand" 
          :label="brand" 
          :value="brand"
        />
      </el-select>
    
      <el-slider
        v-model="priceRange"
        range
        :min="0"
        :max="5000"
        :step="100"
      />
    </div>

    <div class="results">
      <el-card 
        v-for="product in products" 
        :key="product.id"
        @click="gotoDetail(product.id)"
      >
        <img :src="product.thumbnail" class="product-image"/>
        <h3>{{ product.title }}</h3>
        <p class="price">¥{{ product.price }}</p>
      </el-card>
    </div>
  </div>
</template>

<script setup>
import { ref, watchDebounced } from 'vue'
import { Search } from '@element-plus/icons-vue'

const keyword = ref('')
const products = ref([])
const priceRange = ref([0, 5000])

// 带防抖的搜索
watchDebounced(
  [keyword, priceRange],
  () => searchProducts(),
  { debounce: 300 }
)

const fetchSuggestions = async (query, cb) => {
  const res = await fetch(`/api/search/suggest?prefix=${query}`)
  const data = await res.json()
  cb(data.map(text => ({ value: text })))
}
</script>
2. 结果列表优化
// 搜索结果样式优化
.results {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 20px;
  padding: 20px;

  .product-image {
    height: 200px;
    object-fit: cover;
    transition: transform 0.3s;
  
    &:hover {
      transform: scale(1.05);
    }
  }

  .price {
    color: #f56c6c;
    font-size: 1.2em;
    font-weight: bold;
  }
}

五、后台管理实现
1. 商品管理接口
// 商品管理Controller
@RestController
@RequestMapping("/admin/products")
public class ProductAdminController {

    @PostMapping("/sync-to-es")
    public ResponseEntity<?> syncAllToEs() {
        List<Product> products = productRepository.findAll();
        products.forEach(product -> {
            ProductEs esEntity = convertToEsEntity(product);
            elasticsearchOperations.save(esEntity);
        });
        return ResponseEntity.ok("同步完成");
    }

    @PostMapping("/{id}/reindex")
    public ResponseEntity<?> reindexProduct(@PathVariable Long id) {
        Product product = productRepository.findById(id).orElseThrow();
        ProductEs esEntity = convertToEsEntity(product);
        elasticsearchOperations.save(esEntity);
        return ResponseEntity.ok("索引更新成功");
    }
}
2. 分类树组件
<template>
  <el-tree
    :data="categories"
    node-key="id"
    :props="defaultProps"
    :expand-on-click-node="false"
    draggable
    @node-drop="handleCategoryDrop"
  >
    <template #default="{ node, data }">
      <span class="category-node">
        {{ data.name }}
        <el-tag v-if="data.isLeaf" type="info" size="small">末级类目</el-tag>
      </span>
    </template>
  </el-tree>
</template>

<script setup>
const defaultProps = {
  children: 'children',
  label: 'name'
}

const handleCategoryDrop = async (draggingNode, dropNode, position) => {
  await api.updateCategoryTree({
    dragId: draggingNode.data.id,
    dropId: dropNode.data.id,
    position: position
  })
}
</script>

六、性能优化策略
1. 搜索缓存机制
// Redis搜索缓存
@Cacheable(value = "searchResults", key = "#request.hashCode()")
public SearchResultDTO searchWithCache(SearchRequest request) {
    return searchProducts(request);
}

// 缓存配置
@Configuration
@EnableCaching
public class RedisConfig {
    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
        return RedisCacheManager.builder(factory)
            .withCacheConfiguration("searchResults", 
                RedisCacheConfiguration.defaultCacheConfig()
                    .entryTtl(Duration.ofMinutes(10))
                    .disableCachingNullValues()
            ).build();
    }
}
2. 索引优化方案
# 索引分片策略
PUT /products/_settings
{
  "index": {
    "number_of_shards": 3,
    "number_of_replicas": 2,
    "refresh_interval": "30s"
  }
}

# 热门字段预加载
PUT /products/_field_usage_stats
{
  "fields": ["title", "price", "brand"]
}

七、部署架构
用户端
CDN
Nginx集群
SpringBoot集群
Elasticsearch集群
MySQL主从
Logstash
Kibana
Prometheus
Grafana

八、项目里程碑
  1. Phase 1(2周)

    • 完成基础搜索功能
    • 实现ES索引构建
  2. Phase 2(1周)

    • 开发管理后台
    • 实现数据同步管道
  3. Phase 3(1周)

    • 优化搜索建议算法
    • 增加多维度排序
  4. Phase 4(2周)

    • 实现个性化推荐
    • 完成压力测试

本方案通过以下创新点提升搜索体验:

  1. 混合分词策略:结合IK分词与拼音分词,支持"iPhone"和"苹果"双检索
  2. 动态权重调整:根据用户行为自动提升热门商品的搜索排名
  3. 异步索引更新:通过消息队列实现准实时数据同步
  4. 智能缓存淘汰:基于LRU策略自动更新高频查询缓存

建议开发过程中重点关注:

  • 索引重建时的零停机切换
  • 搜索结果的公平性算法
  • 敏感词过滤机制
  • 多语言搜索支持

http://www.kler.cn/a/589996.html

相关文章:

  • UBuntu虚拟机上的redis服务突然消失了
  • 图形编辑器基于Paper.js教程25:材料测试矩阵功能的实现
  • [算法] 贪心--矩阵消除游戏
  • MyBatis SqlSession 是如何创建的? 它与 SqlSessionFactory 有什么关系?
  • 【Android】ListView控件在进入|退出小窗下的异常
  • 【xv6操作系统】页表与写时拷贝解析及相关实验设计
  • TiDB删除大量数据需要注意什么
  • RabbitMQ支持的复杂的消息交换模式
  • HTML中滚动加载的实现
  • 大文件上传实现
  • 推理大模型的后训练增强技术-从系统1到系统2:大语言模型推理能力的综述
  • 安卓屏保调试
  • 机试题——Devops 系统任务调度问题
  • 探索具身多模态大模型:开发、数据集和未来方向(下)
  • Node.js系列(1)--架构设计指南
  • Oracle 19c数据库REDO日志更换
  • 深度学习技巧
  • 【位运算】速算密钥:位运算探秘
  • 负载均衡nginx
  • 探索DB-GPT:革新数据库交互的AI原生框架