128-135、商城业务-商品上架-sku在es中存储模型分析、nested数据类型场景、构造基本数据、构造sku检索属性、远程查询库存&泛型结果封装、远程上架接口、上架接口调试&feign源码、上架

128、sku在es中存储模型分析

1、分析两种模型

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
空间和时间不能兼得

PUT product
{
	"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"
			},
			"catelogId": {
				"type": "long"
			},
			"brandName": {
				"type": "keyword",
				"index": false,
				"doc_values": false
			},
			"brandImg": {
				"type": "keyword",
				"index": false,
				"doc_values": false
			},
			"catelogName": {
				"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"
					}
				}
			}
		}
	}
}

2.ES的两个重要作用

全文检索
日志的存储和分析

129、nested数据类型场景

如果不加nested会出现如下问题:

  • 添加索引
PUT my-index-000001/_doc/1
{
  "group" : "fans",
  "user" : [ 
    {
      "first" : "John",
      "last" :  "Smith"
    },
    {
      "first" : "Alice",
      "last" :  "White"
    }
  ]
}
  • 由于数据扁平化处理
{
  "group" :        "fans",
  "user.first" : [ "alice", "john" ],
  "user.last" :  [ "smith", "white" ]
}
  • 导致在执行下面查询时,会查到
GET my-index-000001/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "user.first": "Alice" }},
        { "match": { "user.last":  "Smith" }}
      ]
    }
  }
}
  • 删除索引
GET my-index-000001

解决方法使用nested

  • 创建映射,并将对象设置为nested
  • 添加数据
  • 查询数据,为0条数据,符合预期
PUT my-index-000001
{
  "mappings": {
    "properties": {
      "user": {
        "type": "nested" 
      }
    }
  }
}

PUT my-index-000001/_doc/1
{
  "group" : "fans",
  "user" : [
    {
      "first" : "John",
      "last" :  "Smith"
    },
    {
      "first" : "Alice",
      "last" :  "White"
    }
  ]
}

GET my-index-000001/_search
{
  "query": {
    "nested": {
      "path": "user",
      "query": {
        "bool": {
          "must": [
            { "match": { "user.first": "Alice" }},
            { "match": { "user.last":  "Smith" }} 
          ]
        }
      }
    }
  }
}

GET my-index-000001/_search
{
  "query": {
    "nested": {
      "path": "user",
      "query": {
        "bool": {
          "must": [
            { "match": { "user.first": "Alice" }},
            { "match": { "user.last":  "White" }} 
          ]
        }
      },
      "inner_hits": { 
        "highlight": {
          "fields": {
            "user.first": {}
          }
        }
      }
    }
  }
}

130、构造基本数据

  • SpuInfoController
    //商品上架
    ///product/spuinfo/{spuId}/up
    @PostMapping(value = "/{spuId}/up")
    public R spuUp(@PathVariable("spuId") Long spuId) {

        spuInfoService.up(spuId);

        return R.ok();
    }
  • SkuEsModel
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;

    }


}

131、构造sku检索属性

思路

  • 根据商品id去属性值表查询此商品所有属性值,并取出id集合
  • 根据id集合去属性表查询,这些属性可以检索的id的集合

代码

  • SpuInfoServiceImpl
    @GlobalTransactional(rollbackFor = Exception.class)
    // @Transactional(rollbackFor = Exception.class)
    @Override
    public void up(Long spuId) {

        //1、查出当前spuId对应的所有sku信息,品牌的名字
        List<SkuInfoEntity> skuInfoEntities = 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.selectSearchAttrs(attrIds);
        //转换为Set集合
        Set<Long> idSet = searchAttrIds.stream().collect(Collectors.toSet());

        List<SkuEsModel.Attrs> attrsList = baseAttrs.stream().filter(item -> {
            return idSet.contains(item.getAttrId());
        }).map(item -> {
            SkuEsModel.Attrs attrs = new SkuEsModel.Attrs();
            BeanUtils.copyProperties(item, attrs);
            return attrs;
        }).collect(Collectors.toList());

        List<Long> skuIdList = skuInfoEntities.stream()
                .map(SkuInfoEntity::getSkuId)
                .collect(Collectors.toList());
        //TODO 1、发送远程调用,库存系统查询是否有库存
        Map<Long, Boolean> stockMap = null;
        try {
            R skuHasStock = wareFeignService.getSkuHasStock(skuIdList);
            //
            TypeReference<List<SkuHasStockVo>> typeReference = new TypeReference<List<SkuHasStockVo>>() {};
            stockMap = skuHasStock.getData(typeReference).stream()
                    .collect(Collectors.toMap(SkuHasStockVo::getSkuId, item -> item.getHasStock()));
        } catch (Exception e) {
            log.error("库存服务查询异常:原因{}",e);
        }

        //2、封装每个sku的信息
        Map<Long, Boolean> finalStockMap = stockMap;
        List<SkuEsModel> collect = skuInfoEntities.stream().map(sku -> {
            //组装需要的数据
            SkuEsModel esModel = new SkuEsModel();
            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(sku.getBrandId());
            esModel.setBrandName(brandEntity.getName());
            esModel.setBrandId(brandEntity.getBrandId());
            esModel.setBrandImg(brandEntity.getLogo());

            CategoryEntity categoryEntity = categoryService.getById(sku.getCatalogId());
            esModel.setCatalogId(categoryEntity.getCatId());
            esModel.setCatalogName(categoryEntity.getName());

            //设置检索属性
            esModel.setAttrs(attrsList);

            BeanUtils.copyProperties(sku,esModel);

            return esModel;
        }).collect(Collectors.toList());

        //TODO 5、将数据发给es进行保存:gulimall-search
        R r = searchFeignService.productStatusUp(collect);

        if (r.getCode() == 0) {
            //远程调用成功
            //TODO 6、修改当前spu的状态
            this.baseMapper.updaSpuStatus(spuId, ProductConstant.ProductStatusEnum.SPU_UP.getCode());
        } else {
            //远程调用失败
            //TODO 7、重复调用?接口幂等性:重试机制
        }
    }
  • AttrServiceImpl
    public List<Long> selectSearchAttrs(List<Long> attrIds) {

        List<Long> searchAttrIds = this.baseMapper.selectSearchAttrIds(attrIds);

        return searchAttrIds;
    }
  • AttrDao.xml
    <select id="selectSearchAttrIds" resultType="java.lang.Long">

        SELECT attr_id FROM pms_attr WHERE attr_id IN
            <foreach collection="attrIds" item="id" separator="," open="(" close=")">
                #{id}
            </foreach>
         AND search_type = 1

    </select>

132、远程查询库存&泛型结果封装

如果每个skuid都要远程调用,这样影响性能,先收集skuid的集合,调用库存服务,一次查询所有的库存信息,并定义vo对象,返回需要的值

133、远程上架接口

  • ElasticSaveController
    /**
     * 上架商品
     * @param skuEsModels
     * @return
     */
    @PostMapping(value = "/product")
    public R productStatusUp(@RequestBody List<SkuEsModel> skuEsModels) {

        boolean status=false;
        try {
            status = productSaveService.productStatusUp(skuEsModels);
        } catch (IOException e) {
            //log.error("商品上架错误{}",e);

            return R.error(BizCodeEnum.PRODUCT_UP_EXCEPTION.getCode(),BizCodeEnum.PRODUCT_UP_EXCEPTION.getMessage());
        }

        if(status){
            return R.error(BizCodeEnum.PRODUCT_UP_EXCEPTION.getCode(),BizCodeEnum.PRODUCT_UP_EXCEPTION.getMessage());
        }else {
            return R.ok();
        }

    }
  • ProductSaveServiceImpl
    public boolean productStatusUp(List<SkuEsModel> skuEsModels) throws IOException {

//1.在es中建立索引,建立号映射关系(doc/json/product-mapping.json)

        //2. 在ES中保存这些数据
        BulkRequest bulkRequest = new BulkRequest();
        for (SkuEsModel skuEsModel : skuEsModels) {
            //构造保存请求
            IndexRequest indexRequest = new IndexRequest(EsConstant.PRODUCT_INDEX);
            indexRequest.id(skuEsModel.getSkuId().toString());
            String jsonString = JSON.toJSONString(skuEsModel);
            indexRequest.source(jsonString, XContentType.JSON);
            bulkRequest.add(indexRequest);
        }


        BulkResponse bulk = esRestClient.bulk(bulkRequest, GulimallElasticSearchConfig.COMMON_OPTIONS);

        //TODO 如果批量错误
        boolean hasFailures = bulk.hasFailures();

        List<String> collect = Arrays.asList(bulk.getItems()).stream().map(item -> {
            return item.getId();
        }).collect(Collectors.toList());

        log.info("商品上架完成:{}",collect);

        return hasFailures;
    }

134、上架接口调试&feign源码

在这里插入图片描述
判断是否是equals、toString等方法,如果不是进入
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
可以看到用json编码了数据,说明Feign在底层会将对象转为json
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

135、抽取响应结果&上架测试完成

有R对象继承了Map,导致setData后,看不到data属性
去掉data属性,修改setData方法,将data数据put到map
获取时,传递类型,先将对象转为json字符串,再将json字符串根据类型转换为指定的对象

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
购物商城的Spu-Sku数据库设计主要是为了管理商品库存和销售信息。Spu(Standard Product Unit)是商品的标准产品单位,通常指的是一组具有相同特征但可能有不同规格的商品,例如同一款衣服的不同颜色或尺码。Sku(Stock Keeping Unit)是商品库存管理单位,是对Spu的具体细分,用于区分不同规格或属性商品。 在数据库设计,可以建立两个主要的表:Spu表和Sku表。Spu表用于存储商品基本信息,包括商品的名称、描述、品牌、分类等。此外,可以为Spu表添加一些扩展字段,例如商品的图片、销售状态等。 Sku表用于存储商品的具体规格和库存信息,其包括Spu的外键关联、商品属性、规格、价格和库存数量等。通过外键关联,可以将Sku与其对应的Spu关联起来,实现Spu与Sku的多对一关系。同时,可以在Sku添加一些扩展字段,例如商品的条形码、上架时间等。 为了提高查询效率,可以在Sku添加索引,例如根据商品的价格、库存数量、销售状态等字段进行索引,以快速获取满足条件的商品信息。 此外,为了提高系统的可维护性和可扩展性,可以添加一些辅助表,例如属性表和属性值表,用于管理商品属性信息。属性表用于存储商品属性名称,属性值表用于存储属性的具体取值范围。 总之,购物商城的Spu-Sku数据库设计需要考虑Spu和Sku之间的关联关系,以及商品基本信息和规格信息的存储和管理。通过合理的设计和优化索引,可以提高系统的查询性能和用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值