商品上架、es应用到商品上架-35

2023-10-27

一:商品上架

  • 上架的商品才可以在网站展示。
  • 上架的商品需要可以被检索。
  • es是将数据保存到内存当中,所以我们不能将什么数据都保存到es当中,我们需要将重要的数据保存到es中。例如商品名称,规格型号,价格等信息。当需要的数据较多时,我们可以将主键id存储到es中,然后通过id再去mysql数据库中查询。并且es中存储的的都是json数据。

1.商品 Mapping

分析:商品上架在 es 中是存 sku 还是 spu?
1)、检索的时候输入名字,是需要按照 sku 的 title 进行全文检索的
2)、检索使用商品规格,规格是 spu 的公共属性,每个 spu 是一样的
3)、按照分类 id 进去的都是直接列出 spu 的,还可以切换。
4)、我们如果将 sku 的全量信息保存到 es 中(包括 spu 属性)就太多量字段了。
5)、我们如果将 spu 以及他包含的 sku 信息保存到 es 中,也可以方便检索。但是 sku 属于 spu 的级联对象,在 es 中需要 nested 模型,这种性能差点。
6)、但是存储与检索我们必须性能折中。
7)、如果我们分拆存储,spu 和 attr 一个索引,sku 单独一个索引可能涉及的问题。 检索商品的名字,如“手机”,对应的 spu 有很多,我们要分析出这些 spu 的所有关联属性, 再做一次查询,就必须将所有 spu_id 都发出去。假设有 1 万个数据,数据传输一次就10000*4=4MB;并发情况下假设 1000 检索请求,那就是 4GB 的数据,,传输阻塞时间会很 长,业务更加无法继续。 所以,我们如下设计,这样才是文档区别于关系型数据库的地方,宽表设计,不能去考虑数 据库范式。

PUT product
## product 的 mapping
{
    "mappings": {
        "properties": {
            "skuId": {
                "type": "long"
            },
            "spuId": {
                "type": "keyword"
            },
            "skuTitle": {
                "type": "text",
                "analyzer": "ik_smart"
            },
            "skuPrice": {
                "type": "keyword"
            },
            "skuImg": {
                "type": "keyword",
                "index": false,
                "doc_values": false
            },
            "saleCount": {
                "type": "long"
            },
            "hasStock": {
                "type": "boolean"
            },
            "hotScore": {
                "type": "long"
            },
            "brandId": {
                "type": "long"
            },
            "catalogId": {
                "type": "long"
            },
            "brandName": {
                "type": "keyword",
                "index": false,
                "doc_values": false
            },
            "brandImg": {
                "type": "keyword",
                "index": false,
                "doc_values": false
            },
            "catalogName": {
                "type": "keyword",
                "index": false,
                "doc_values": false
            },
            "attrs": {
                "type": "nested",
                "properties": {
                    "attrId": {
                        "type": "long"
                    },
                    "attrName": {
                        "type": "keyword",
                        "index": false,
                        "doc_values": false
                    },
                    "attrValue": {
                        "type": "keyword"
                    }
                }
            }
        }
    }
}

index:
默认 true,如果为 false,表示该字段不会被索引,但是检索结果里面有,但字段本身不能 当做检索条件。
doc_values:
默认 true,设置为 false,表示不可以做排序、聚合以及脚本操作,这样更节省磁盘空间。 还可以通过设定 doc_values 为 true,index 为 false 来让字段不能被搜索但可以用于排序、聚 合以及脚本操作:

2.编写上架功能

1)在spuInfoController中添加方法

 /**
     * 商品上架功能
     * @param spuId
     * @return
     */
    @RequestMapping("/{spuId}/up")
    //@RequiresPermissions("product:spuinfo:list")
    public R spuUp(@PathVariable("spuId") Long spuId) {
        spuInfoService.up(spuId);
        return R.ok();
    }

2)在common添加SkuEsModel 实体类,表示sku在es中保存的数据模型

package com.sysg.common.to.es;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
public class SkuEsModel {
    private Long skuId;
    private Long spuId;
    private String skuTitle;  
    private BigDecimal skuPrice;
    private String skuImg;
    private Long saleCount;
    private Boolean hasStock;
    private Long hotScore;
    private Long brandId;
    private Long catalogId;
    private String brandName;
    private String brandImg;
    private String catalogName;
    private List<Attrs> attrs;
    @Data
    public static class Attrs {
        private Long attrId;
        private String attrName;
        private String attrValue;
    }
}

3)编写SpuInfoServiceImpl的up方法

 @Override
    public void up(Long spuId) {
        //1.查出当前spuId对应的所有sku信息,品牌的名字
        List<SkuInfoEntity> skus =  skuInfoService.getSkusBySpuId(spuId);
        //todo 4.查询sku的所有可以被用来检索的规格属性
        List<ProductAttrValueEntity> baseAttrs = productAttrValueService.baseAttrListforspu(spuId);
        List<Long> attrIds = baseAttrs.stream().map(attr -> {
            return attr.getAttrId();
        }).collect(Collectors.toList());
        List<Long> searchAttrIds = attrService.selectSearchAttrIds(attrIds);
        Set<Long> isSet = new HashSet<>(searchAttrIds);
        List<SkuEsModel.Attrs> attrsList = baseAttrs.stream().filter(item -> {
            return isSet.contains(item.getAttrId());
        }).map(item -> {
            SkuEsModel.Attrs attrs1 = new SkuEsModel.Attrs();
            BeanUtils.copyProperties(item, attrs1);
            return attrs1;
        }).collect(Collectors.toList());
        //2.封装每个sku的信息
        List<SkuEsModel> collect = skus.stream().map((sku) -> {
            //组装需要的数据
            SkuEsModel esModel = new SkuEsModel();
            BeanUtils.copyProperties(sku,esModel);
            esModel.setSkuPrice(sku.getPrice());
            esModel.setSkuImg(sku.getSkuDefaultImg());
            //todo 1.发送远程调用,库存系统查询是否有库存

            //todo 2.热度评分。0
            esModel.setHotScore(0L);
            //todo 3.查询品牌和分类的名字信息
            BrandEntity brandEntity = brandService.getById(esModel.getBrandId());
            esModel.setBrandName(brandEntity.getName());
            esModel.setBrandImg(brandEntity.getLogo());
            CategoryEntity categoryEntity = categoryService.getById(esModel.getCatalogId());
            esModel.setCatalogName(categoryEntity.getName());
            //设置检索属性
            esModel.setAttrs(attrsList);
            return esModel;
        }).collect(Collectors.toList());

        //todo 5.将数据发送给es进行保存。发送给gulimail-search
    }

4)远程调用

  • 加入openFeign依赖
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
  • 开启远程调用功能
@EnableFeignClients(basePackages = "com.sysg.gulimail.product.feign")
  • 在feign包下新建WareFeignService,用来远程调用ware相关操作
@FeignClient("gulimail-ware")
public interface WareFeignService {
    /**
     * 1.R可以加上泛型
     * 2.直接返回想要的数据
     * 3.自己封装
     * @param skuIds
     * @return
     */
    @PostMapping("/ware/waresku/hasstock")
    R<List<SkuHasStockVo>> getSkusHasStock(@RequestBody List<Long> skuIds);
}
  • 代码实现
@Override
    public void up(Long spuId) {
        //1.查出当前spuId对应的所有sku信息,品牌的名字
        List<SkuInfoEntity> skus =  skuInfoService.getSkusBySpuId(spuId);
        List<Long> skuIdList = skus.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());
        //todo 4.查询sku的所有可以被用来检索的规格属性
        List<ProductAttrValueEntity> baseAttrs = productAttrValueService.baseAttrListforspu(spuId);
        List<Long> attrIds = baseAttrs.stream().map(attr -> {
            return attr.getAttrId();
        }).collect(Collectors.toList());
        List<Long> searchAttrIds = attrService.selectSearchAttrIds(attrIds);
        Set<Long> isSet = new HashSet<>(searchAttrIds);
        List<SkuEsModel.Attrs> attrsList = baseAttrs.stream().filter(item -> {
            return isSet.contains(item.getAttrId());
        }).map(item -> {
            SkuEsModel.Attrs attrs1 = new SkuEsModel.Attrs();
            BeanUtils.copyProperties(item, attrs1);
            return attrs1;
        }).collect(Collectors.toList());
        //todo 1.发送远程调用,库存系统查询是否有库存
        Map<Long, Boolean> stockMap = null;
        try {
            R<List<SkuHasStockVo>> skusHasStock = wareFeignService.getSkusHasStock(skuIdList);
            stockMap = skusHasStock.getData().stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, item -> item.getHasStock()));
        } catch (Exception e) {
            log.error("库存服务查询异常:原因{}",e);
        }
        //2.封装每个sku的信息
        Map<Long, Boolean> finalStockMap = stockMap;
        List<SkuEsModel> uoProducts= skus.stream().map((sku) -> {
            //组装需要的数据
            SkuEsModel esModel = new SkuEsModel();
            BeanUtils.copyProperties(sku,esModel);
            esModel.setSkuPrice(sku.getPrice());
            esModel.setSkuImg(sku.getSkuDefaultImg());
            //设置库存信息
            if( finalStockMap ==null){
                esModel.setHasStock(true);
            } else {
                esModel.setHasStock(finalStockMap.get(sku.getSkuId()));
            }
            //todo 2.热度评分。0
            esModel.setHotScore(0L);
            //todo 3.查询品牌和分类的名字信息
            BrandEntity brandEntity = brandService.getById(esModel.getBrandId());
            esModel.setBrandName(brandEntity.getName());
            esModel.setBrandImg(brandEntity.getLogo());
            CategoryEntity categoryEntity = categoryService.getById(esModel.getCatalogId());
            esModel.setCatalogName(categoryEntity.getName());
            //设置检索属性
            esModel.setAttrs(attrsList);
            return esModel;
        }).collect(Collectors.toList());

        //todo 5.将数据发送给es进行保存。发送给gulimail-search
    }

注:远程调用需要抛出异常
5)将数据发送到es进行保存

//todo 5.将数据发送给es进行保存。发送给gulimail-search
        try {
            R r = searchFeignService.productStatusUp(uoProducts);
            if(r.getCode() == 0){
                //远程调用成功
                //todo 6、修改当前spu的状态
                baseMapper.updateSpuStatus(spuId, ProductConstant.StatusEnum.SPU_UP.getCode());
            } else {
                //远程调用失败
                //todo 7.重复调用,接口幂等性。重试机制
            }
        } catch (Exception e) {
            log.error("es保存失败");
        }

6)productStatusUp编写

@Slf4j
@RequestMapping("/search/save")
@RestController
public class ElasticSaveController {
    @Autowired
    private ProductSaveService productSaveService;
    /**
     * 商品上架
     * @param skuEsModels
     * @return
     */
    @PostMapping("/product")
    public R productStatusUp(@RequestBody List<SkuEsModel> skuEsModels){
        Boolean b = false;
        try {
            b = productSaveService.productStatusUp(skuEsModels);
        } catch (IOException e) {
            log.error("ElasticSaveController商品上架错误;{}",e);
            return R.error(BizCodeEnume.PRODUCT_UP_EXCEPTION.getCode(),BizCodeEnume.PRODUCT_UP_EXCEPTION.getMsg());
        }
        if(b){
            return R.ok();
        }else {
            return R.error(BizCodeEnume.PRODUCT_UP_EXCEPTION.getCode(),BizCodeEnume.PRODUCT_UP_EXCEPTION.getMsg());
        }

    }
}

二:json数据转化

将json转化为需要的对象类型

1.构造typeReference 对象

TypeReference<List<SkuHasStockVo>> typeReference = new TypeReference<List<SkuHasStockVo>>() {};

泛型里面为需要转化为得对象类型

2.获取对象,进行转化

        Object data = get("data");
        String s = JSON.toJSONString(data);
        T t = JSON.parseObject(s,typeReference);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

商品上架、es应用到商品上架-35 的相关文章

随机推荐

  • 【平衡车】TB6612+编码器电机的使用

    一 编码器电机的使用 1 电线 电机 用于控制电机正 反转 2 编码器5V GND 使编码器工作 3 编码器A B相 连接在单片机 用于反馈电机运动状态 用于输出角度 速度数据 stm32的定时器有具备输入捕获功能 从而读取脉冲 获得速度值
  • selenium对元素进行操作(二):点击&输入

    1分钟了解一个测开小知识 selenium对元素进行操作 二 其他常规操作 鼠标单击 click 在定位的元素后 使用增加 click 即对该元素进行点击操作 例如 driver find element by Xpath id s xma
  • 启用已签名的 kubelet 服务证书

    默认情况下 kubeadm 所部署的 kubelet 服务证书是自签名 Self Signed 这意味着从 metrics server 这类外部服务发起向 kubelet 的链接时无法使用 TLS 来完成保护 要在新的 kubeadm 集
  • Window查看apache的版本

    我使用的是xampp进入shell命令界面的 1 点击shell 进入 2 直接输入命令 httpd v 就可以看到你电脑平时使用的Apache版本了
  • 在线Qt查看源码网站

    Woboq Code Browser Explore C code on the web
  • Tomcat Manager 账号密码设置

    Windows版本 下载https tomcat apache org 我选择Tomcat9 可以查看包信息 详细信息介绍 所以Windows版本下载 我这里先下载了9 0 37 所以没有下载 解压以后 启动bin startup bat
  • 3-排序算法

    冒泡排序 冒泡排序的思路是将每两个数据之间进行大小比对 将大的数据后移 反复比对移动数据 直至数组排列整齐 include
  • Vosviewer+Pajek实现知网社交网络(解决中文乱码问题)

    Vosviewer Pajek实现知网社交网络 一 软件准备 Vosviewer安装 下载地址https www vosviewer com download 安装JDKhttps www oracle com java technolog
  • Python+Selenium_UI自动化操作(3)——刷新页面

    UI自动化 刷新页面 语法 refresh class TestRefreshWeb unittest TestCase def setUp self setUp是一个初始化方法 为test案例做数据准备 当前方法的数据准备动作是 启动ch
  • MQTT通讯协议简介和测试 [MQTT.fx]

    一 介绍 1 MQTT简介 MQTT Message Queuing Telemetry Transport 消息队列遥测传输 是IBM开发的一个即时通讯协议 有可能成为物联网的重要组成部分 该协议支持所有平台 几乎可以把所有联网物品和外部
  • 使用 POI创建一个简单的 Excel 文件

    初级程序员一枚 看到公司大佬写的生成Excel文件 做下记录 同时也分享给大家参考 实现原理是用workBook 然后还有OutputStream 首先是一个ExcelDataBean 这个实体类 用来 声明 Excel的最大行数 最大列数
  • 用tornado ,Supervisord ,nginx架网站

    最近使用 Tornado 重写了博客 于是查看了很多关于部署基于 Tornado 开发的网站的资料 比较成熟的方案就是使用 Nginx 来做反向代理 使用 Supervisord 来作为进程管理工具 至于什么叫反向代理 为什么 Tornad
  • 小鱼深度产品测评之:阿里云低代码开发平台魔笔,一站式的应用全生命周期管理,高效解决应用研发、迭代、运维的问题。

    低代码开发平台魔笔测评 1 引言 2 购买流程 3 魔笔 3 1添加应用 3 2 应用列表 3 1 1 列表应用展示 3 2 1 列应用操作 3 2 1 1 自动保存 3 2 1 2 复制功能 3 2 1 3 编辑功能 3 2 1 4 删除
  • (二)Android导航栏和菜单资源的结合使用

    ActionBar是Android3 0的重要更新之一 位于传统标题栏的位置 1 注意在使用ActionBar时保证该应用的目标版本应高于11 Android3 0的版本号
  • 知乎Python大佬带你10分钟入门Python爬虫(推荐收藏)

    一 基础入门 1 1 什么是爬虫 爬虫 spider 又网络爬虫 是指向网站 网络发起请求 获取资源后分析并提取有用数据的程序 从技术层面来说就是 通过程序模拟浏览器请求站点的行为 把站点返回的HTML代码 JSON数据 二进制数据 图片
  • 《软件调试的艺术》笔记--调试多线程程序

    下面是于线程相关的GDB命令用法汇总 info threads 给出关于当前所有线程的信息 thread 3 改成线程3 break 88 thread 3 当线程到达源代码88时停止执行 break 88 thread 3 if i 2
  • LaTeX教程(三)——文档格式排版

    文章目录 1 章节目录 1 1 生成章节 1 2 生成目录 2 交叉引用和脚注 2 1 交叉引用 2 2 脚注 3 特殊环境 3 1 列表 3 2 文本对齐 3 3 引用环境 3 4 代码环境 1 章节目录 1 1 生成章节 写文章或者论文
  • 关于程序员认知和编程学习,没有任何一篇文章会讲得如此透彻

    程序猿问科比 你为什么这么成功 科比 你知道洛杉矶凌晨四点是什么样子吗 程序猿 知道 一般那个时候我还在写代码 怎么了 科比 额 你以为程序员都是这样生活的 别瞎 他们只是在历劫 度过这段日子 他们就飞升上仙 乃至上神 过上另一种生活 就像
  • 【北京工业大学申请个人学生邮箱】

    北京工业大学申请个人学生邮箱 由于近期想要购买苹果设备 但是苹果更新了unidays认证 需要用到学生邮箱认证 因此花了几个小时查找北工大的邮箱注册方法 一趟下来 说实在的流程有些阴间 在此进行下记录 也方便后人的查找 一 进入 内网综合服
  • 商品上架、es应用到商品上架-35

    一 商品上架 上架的商品才可以在网站展示 上架的商品需要可以被检索 es是将数据保存到内存当中 所以我们不能将什么数据都保存到es当中 我们需要将重要的数据保存到es中 例如商品名称 规格型号 价格等信息 当需要的数据较多时 我们可以将主键