学习笔记(11)商品上架与ES检索
商品上架
商品里有很多SKU:
每个SKU有自己的销售属性:
除此之外,每个商品有共用的商品属性:
检索出来的界面标题是SPU+SKU都有
查询商品的详情
SPU的信息拿来筛选,SKU的信息拿来售卖
SELECT pav.*,pa.`name` FROM `pms_product_attribute_value` pav
LEFT JOIN `pms_product_attribute` pa
ON pa.`id` = pav.`product_attribute_id`
WHERE pav.`product_id` =23
上架5号
dubbo集群容错
查询多试验几次,增删改要快速失败。选择dubbo的快速失败模式
dubbo配置默认在服务上,调不精细
CudSerivce:增删改service
* RService:读service
*
*1)、dubbo的默认集群容错哪几种,怎么做?
* failover/failfast/failsafe/failback/forking;
* @Service注解上一配置就行。
目前本系统未按此设计
* 改掉默认的mapping信息;
* 1)、改掉不分词的字段
* 2)、整个info就是ESProduct,//嵌入式对象的Mapping一定要用nested声明,这样才能正确的检索到数据
不分词用keyword
什么需要评分:只有在搜索框搜的关键字需要评分
/**
* 给数据库插入数据
* 1)、dubbo远程调用插入数据服务,可能经常超时。dubbo默认会重试
* 导致这个方法会被调用多次。可能导致数据库同样的数据有多个。
*
* 2)、dubbo有自己默认的集群容错。
*
* 给数据库做数据的,最好用dubbo的快速失败模式。我们手工重试
*
* @param id
*/
private void saveProductToEs(Long id) {
//1、查出商品的基本新
Product productInfo = productInfo(id);
EsProduct esProduct = new EsProduct();
//1、复制基本信息
BeanUtils.copyProperties(productInfo,esProduct);
//2、复制sku信息,对于es要保存商品信息,还要查出这个商品的sku,给es中保存
List<SkuStock> stocks = skuStockMapper.selectList(new QueryWrapper<SkuStock>().eq("product_id", id));
List<EsSkuProductInfo> esSkuProductInfos = new ArrayList<>(stocks.size());
// List<EsProductAttributeValue> skuAttributeNames = productAttributeValueMapper.selectProductSaleAttrName(id);
// List<EsProductAttributeValue> attributeValues = productAttributeValueMapper.selectProductBaseAttrAndValue(id);
//查出当前商品的sku属性 颜色 尺码
List<ProductAttribute> skuAttributeNames = productAttributeValueMapper.selectProductSaleAttrName(id);
stocks.forEach((skuStock)->{
EsSkuProductInfo info = new EsSkuProductInfo();
BeanUtils.copyProperties(skuStock,info);
//闪亮 黑色
String subTitle = esProduct.getName();
if(!StringUtils.isEmpty(skuStock.getSp1())){
subTitle+=" "+skuStock.getSp1();
}
if(!StringUtils.isEmpty(skuStock.getSp2())){
subTitle+=" "+skuStock.getSp2();
}
if(!StringUtils.isEmpty(skuStock.getSp3())){
subTitle+=" "+skuStock.getSp3();
}
//sku的特色标题
info.setSkuTitle(subTitle);
List<EsProductAttributeValue> skuAttributeValues = new ArrayList<>();
for (int i=0;i<skuAttributeNames.size();i++){
//skuAttr 颜色/尺码
EsProductAttributeValue value = new EsProductAttributeValue();
value.setName(skuAttributeNames.get(i).getName());
value.setProductId(id);
value.setProductAttributeId(skuAttributeNames.get(i).getId());
value.setType(skuAttributeNames.get(i).getType());
//颜色 尺码;让es去统计‘;改掉查询商品的属性分类里面所有属性的时候,按照sort字段排序好
if(i==0){
value.setValue(skuStock.getSp1());
}
if(i==1){
value.setValue(skuStock.getSp2());
}
if(i==2){
value.setValue(skuStock.getSp3());
}
skuAttributeValues.add(value);
}
info.setAttributeValues(skuAttributeValues);
//sku有多个销售属性;颜色,尺码
esSkuProductInfos.add(info);
//查出销售属性的名
});
esProduct.setSkuProductInfos(esSkuProductInfos);
List<EsProductAttributeValue> attributeValues = productAttributeValueMapper.selectProductBaseAttrAndValue(id);
//3、复制公共属性信息,查出这个商品的公共属性
esProduct.setAttrValueList(attributeValues);
try {
//把商品保存到es中
Index build = new Index.Builder(esProduct)
.index(EsConstant.PRODUCT_ES_INDEX)
.type(EsConstant.PRODUCT_INFO_ES_TYPE)
.id(id.toString())
.build();
DocumentResult execute = jestClient.execute(build);
boolean succeeded = execute.isSucceeded();
if(succeeded){
log.info("ES中;id为{}商品上架完成",id);
}else {
log.error("ES中;id为{}商品未保存成功,开始重试",id);
//saveProductToEs(id);
}
}catch (Exception e){
log.error("ES中;id为{}商品数据保存异常;{}",id,e.getMessage());
//saveProductToEs(id);
}
}
1.对于数据库是修改商品的状态位
2.对于es要保存的商品信息
mybatis-plus自带的更新方法是哪个字段有值就更哪个字段(所以所有类型应该用包装类,因为非包装类有默认值)
我们上架的是SKU(仿京东,一些小的商城系统,比如小米,上架的是SPU,之后自己选)
上下架请求:
对于数据库是修改商品的状态位
对于es要保存商品信息
商品的属性分类如下:
SKU有其基本信息,又有销售属性
javaBean应该都去用包装类型
public void setProductPublishStatus(Integer publishStatus, Long id) {
//javaBean应该都去用包装类型
Product product = new Product();
//默认所有属性为null
product.setId(id);
product.setPublishStatus(publishStatus);
//mybatis-plus自带的更新方法是哪个字段有值就更哪个字段
productMapper.updateById(product);
}
es也会占用硬盘空间 ,同步
检索服务
分布式系统下,session不一致,前端第一次请求到达x服务器上,下回请求来到y服务器,就取不出来了,session不一致
后端解决session不一致问题麻烦,但是前端解决容易,访问来访问去就是浏览器。
gmall-shop-portal: 和前端公众访问的商品项目进行对接的web
聚合
第一步:分析页面会传入哪些参数,可以把所有参数写成一个javaBean
第二步:要把哪些结果返回去
/**
* 检索前端传递的数据
*/
@Data
public class SearchParam implements Serializable {
@Data
public class SearchResponse implements Serializable {
private SearchResponseAttrVo brand;//品牌
private SearchResponseAttrVo catelog;//分类
//所有商品的顶头显示的筛选属性
private List<SearchResponseAttrVo> attrs = new ArrayList<SearchResponseAttrVo>();
//检索出来的商品信息
private List<EsProduct> products = new ArrayList<EsProduct>();
private Long total;//总记录数
private Integer pageSize;//每页显示的内容
private Integer pageNum;//当前页面
}
每个 SearchResponseAttrVo相当于上图的一行
启动前端项目:npm install
web服务是消费者
前端查询发来search请求
public class SearchProductServiceImpl implements SearchProductService {
@Autowired
JestClient jestClient;
@Override
public SearchResponse searchProduct(SearchParam searchParam) {
//1、构建检索条件
String dsl = buildDsl(searchParam);
log.error("商品检索的详细数据{}",dsl);
Search search = new Search.Builder(dsl).addIndex(EsConstant.PRODUCT_ES_INDEX)
.addType(EsConstant.PRODUCT_INFO_ES_TYPE)
.build();
SearchResult execute = null;
try {
//2、检索
execute = jestClient.execute(search);
} catch (IOException e) {
e.printStackTrace();
}
//3、将返回的SearchResult转为SearchResponse
SearchResponse searchResponse = buildSearchResponse(execute);
searchResponse.setPageNum(searchParam.getPageNum());
searchResponse.setPageSize(searchParam.getPageSize());
return searchResponse;
}
聚合三大聚,分别为品牌聚,分类聚,属性聚