文章目录
- 介绍下你们电商搜索的整体技术架构?
- 为什么我们需要一个靠谱的搜索系统?
- 整体架构概述
- 数据采集与处理
- 数据来源
- 数据清洗
- 数据索引
- Elasticsearch的配置与优化
- 分片与副本
- 索引设计
- 性能优化
- 搜索服务层的设计
- 商品数据的同步
- 搜索请求的处理
- 展示层的设计
- 搜索结果的排序与展示
- 搜索建议
- 实际案例与经验总结
- 拼音转换与纠错
- 搜索结果的相关性优化
- 总结
- 如果你在实际开发中遇到什么问题,欢迎随时交流!
- 📚 领取 | 1000+ 套高质量面试题大合集(无套路,闫工带你飞一把)!
介绍下你们电商搜索的整体技术架构?
大家好,我是都叫我闫工,今天要跟大家分享的是我们团队的电商搜索整体技术架构。作为一个主管,我得先提醒大家:这篇文章可能会有点长,但我会尽量用幽默的方式带大家走过这段技术之旅。
为什么我们需要一个靠谱的搜索系统?
在电商领域,搜索是一个非常关键的功能模块。用户打开你的网站或者App,第一件事很可能就是输入关键词进行搜索。比如,我有个朋友,他经常会在网上买手机,有一次他在我们平台上搜索“手机”,结果看到了一堆跟手机完全不相关的产品,比如充电宝、耳机,甚至还有一些奇怪的家具(这让我有点头大)。所以,一个靠谱的搜索系统不仅要能准确理解用户的意图,还要能在海量商品中快速找到最符合用户需求的结果。
整体架构概述
我们的电商搜索系统大致可以分为以下几个模块:
- 数据采集与处理:将商品信息从各个来源(比如数据库、第三方API)采集并清洗。
- 存储层:使用Elasticsearch作为核心的搜索引擎,同时也会有一些预处理的数据存储在Redis中。
- 搜索服务层:负责接收用户的搜索请求,调用Elasticsearch进行查询,并对结果进行后处理(比如排序、去重)。
- 展示层:将处理后的结果以友好的方式展示给用户。
下面我会逐一详细讲解这些模块的设计和实现细节。
数据采集与处理
数据来源
我们的数据来源主要有以下几种:
- 数据库:这是最直接的数据源,包括商品信息、库存、价格等。
- 第三方API:比如一些物流公司或者支付平台的接口,但对于我们搜索系统来说,这部分数据更多的是辅助性质。
- 用户行为数据:这部分数据主要用于优化搜索结果的排序逻辑,比如用户的点击率、购买率等。
数据清洗
在采集到数据后,我们需要对这些数据进行清洗。这一步非常重要,因为脏数据会直接影响搜索的结果质量。举个例子,假设我们有一个商品标题是“【限时特惠】iPhone 13 Pro Max”,我们需要提取出核心关键词“iPhone”、“13”、“Pro”、“Max”,并去掉一些干扰词比如“限时特惠”。
数据索引
清洗后的数据会被索引到Elasticsearch中。这里需要注意的是,我们并不是直接把所有字段都存储在Elasticsearch里,而是会根据搜索的需求进行一些预处理和特征提取。
Elasticsearch的配置与优化
Elasticsearch是我们整个搜索系统的核心,它的配置和优化直接影响系统的性能和稳定性。下面我会分享一些我们在实际项目中用到的配置和优化技巧。
分片与副本
分片的数量决定了Elasticsearch的水平扩展能力,而副本的数量则影响了系统的可用性和数据冗余。一般来说,我们会根据具体的硬件资源和QPS来调整这两个参数。比如,如果我们有3个节点,每个节点有2个CPU核心,那么设置3个主分片和1个副本可能是一个比较合理的选择。
{"settings":{"number_of_shards":3,"number_of_replicas":1}}索引设计
在Elasticsearch中,索引的设计非常重要。我们需要根据查询的场景来决定哪些字段需要被分词,哪些字段需要被作为关键词存储。
举个例子,在我们的商品搜索中,标题、描述这些字段通常会被分词处理,而品牌、分类等字段则可能会以关键词的方式存储。
{"mappings":{"properties":{"title":{"type":"text","analyzer":"ik_max_word"},"brand":{"type":"keyword"}}}}性能优化
性能优化是一个持续的过程,我们需要根据实际的使用情况不断调整和优化。比如,我们可以通过设置合理的缓存策略来提高查询速度,或者通过垂直分片的方式将不同的数据类型分开存储。
{"cache":{"field":{"size":10000,"ttl":3600000}}}搜索服务层的设计
搜索服务层是整个系统的核心业务逻辑所在,它负责接收用户的请求,调用Elasticsearch进行查询,并对结果进行后处理。
商品数据的同步
由于商品信息可能会频繁变化(比如库存更新、价格调整),我们需要一个高效的机制来保证Elasticsearch中的数据能够及时反映这些变化。通常我们会使用类似于消息队列的方式来实现异步同步。
publicclassProductSyncService{privatefinalElasticsearchClientclient;privatefinalQueue<Product>queue=newLinkedList<>();publicvoidaddProduct(Productproduct){queue.add(product);// 使用线程池异步处理executor.execute(this::syncToEs);}privatevoidsyncToEs(){while(!queue.isEmpty()){Productproduct=queue.poll();client.index(indexRequest->indexRequest.index("products").document(mapper.toJson(product)));}}}搜索请求的处理
搜索请求的处理主要包括以下几个步骤:
- 解析用户的查询词:比如提取关键词、分析用户意图。
- 调用Elasticsearch进行查询:根据解析后的关键词生成查询DSL,并调用Elasticsearch进行查询。
- 结果后处理:对返回的结果进行排序、去重、补全等操作。
publicclassSearchService{privatefinalElasticsearchClientclient;privatefinalRedisTemplateredisTemplate;publicList<Product>search(Stringquery){// 分析用户意图String[]keywords=QueryAnalyzer.analyze(query);// 调用Elasticsearch查询List<Product>results=client.search(searchRequest->searchRequest.index("products").body(newSearchSourceBuilder().query(QueryBuilders.multiMatchQuery(keywords)).size(20)));// 结果后处理returnPostProcessor.process(results,redisTemplate);}}展示层的设计
展示层是用户与系统交互的最直接体现,我们需要保证搜索结果不仅准确,还要直观、友好。
搜索结果的排序与展示
搜索结果的排序是一个非常关键的环节。我们会根据多个因素(比如相关性、销量、价格)来综合排序。
publicclassPostProcessor{publicstaticList<Product>process(List<Product>results,RedisTemplateredisTemplate){// 根据销量和评分进行二次排序results.sort((a,b)->{doubleaScore=a.getSales()*a.getRating();doublebScore=b.getSales()*b.getRating();returnDouble.compare(bScore,aScore);});returnresults;}}搜索建议
搜索建议(也称为联想搜索)是提升用户体验的重要功能。当用户输入关键词时,系统会实时给出一些相关的建议词。
publicclassSearchSuggestion{publicList<String>getSuggestions(Stringprefix){// 使用Elasticsearch的prefix查询returnclient.search(searchRequest->searchRequest.index("products").body(newSearchSourceBuilder().query(QueryBuilders.prefixQuery("title",prefix)).size(5)));}}实际案例与经验总结
在实际项目中,我们遇到了一些挑战和问题。比如,如何处理用户的拼写错误、如何提升搜索结果的相关性等。
拼音转换与纠错
为了处理用户的拼音输入或拼写错误,我们会将关键词进行拼音转换,并结合Elasticsearch的fuzzy查询功能来提高召回率。
publicclassQueryAnalyzer{publicstaticString[]analyze(Stringquery){// 将中文转为拼音Stringpinyin=PinyinHelper.convertToPinyin(query);returnnewString[]{query,pinyin};}}搜索结果的相关性优化
为了提高搜索结果的相关性,我们会结合用户的点击数据和反馈来进行实时优化。
publicclassRelevanceOptimizer{publicvoidoptimize(Stringquery,List<Product>clickedProducts){// 更新相关性评分for(Productproduct:clickedProducts){updateScore(product.getId(),1.0);}}privatevoidupdateScore(LongproductId,doubledelta){// 使用Redis进行评分更新redisTemplate.execute((connection)->{Doublecurrent=connection.zIncrBy("relevance_scores",delta,productId.toString());returnnull;});}}总结
通过以上的设计和优化,我们成功地构建了一个高效、稳定的商品搜索系统。当然,这只是一个大致的框架,在实际应用中还需要根据具体业务需求进行调整和优化。
如果你在实际开发中遇到什么问题,欢迎随时交流!
📚 领取 | 1000+ 套高质量面试题大合集(无套路,闫工带你飞一把)!
你想做外包吗?闫工就是外包出身,但我已经上岸了!你也想上岸吗?
闫工精心准备了程序准备面试?想系统提升技术实力?闫工精心整理了1000+ 套涵盖前端、后端、算法、数据库、操作系统、网络、设计模式等方向的面试真题 + 详细解析,并附赠高频考点总结、简历模板、面经合集等实用资料!
✅ 覆盖大厂高频题型
✅ 按知识点分类,查漏补缺超方便
✅ 持续更新,助你拿下心仪 Offer!
📥免费领取👉 点击这里获取资料
已帮助数千位开发者成功上岸,下一个就是你!✨