Authored by 胡古飞

索引中加入实时计算的断码率

package com.yoho.search.dal.model;
/**
* Created by wangnan on 2016/6/30.
*/
public class ProductSizes {
private Integer productId;
private String sizeIds;
private String sizeNames;
private Integer storageNum;
public Integer getProductId() {
return productId;
}
public void setProductId(Integer productId) {
this.productId = productId;
}
public String getSizeIds() {
return sizeIds;
}
public void setSizeIds(String sizeIds) {
this.sizeIds = sizeIds;
}
public Integer getStorageNum() {
return storageNum;
}
public void setStorageNum(Integer storageNum) {
this.storageNum = storageNum;
}
public String getSizeNames() {
return sizeNames;
}
public void setSizeNames(String sizeNames) {
this.sizeNames = sizeNames;
}
private Integer productId;
private String sizeIds;
private String sizeNames;
private Integer storageNum;
private double breakSizePercent = 100;
public Integer getProductId() {
return productId;
}
public void setProductId(Integer productId) {
this.productId = productId;
}
public String getSizeIds() {
return sizeIds;
}
public void setSizeIds(String sizeIds) {
this.sizeIds = sizeIds;
}
public Integer getStorageNum() {
return storageNum;
}
public void setStorageNum(Integer storageNum) {
this.storageNum = storageNum;
}
public String getSizeNames() {
return sizeNames;
}
public void setSizeNames(String sizeNames) {
this.sizeNames = sizeNames;
}
public double getBreakSizePercent() {
return breakSizePercent;
}
public void setBreakSizePercent(double breakSizePercent) {
this.breakSizePercent = breakSizePercent;
}
}
... ...
... ... @@ -25,76 +25,84 @@ import java.util.stream.Collectors;
@Component
public abstract class AbstractStorageRelatedMqListener extends AbstractMqListener {
@Autowired
private StorageService storageService;
@Autowired
private StorageService storageService;
@Autowired
private SizeService sizeService;
@Autowired
private SizeService sizeService;
@Autowired
private GoodsService goodsService;
@Autowired
private GoodsService goodsService;
@Autowired
private ProductGoodsLogicService productGoodsLogicService;
@Autowired
private ProductGoodsLogicService productGoodsLogicService;
protected void fillStorageNumAndSizeInfo(Integer productId, Map<String, Object> indexData) {
List<Storage> storageList = storageService.getStoragesByProductId(productId);
if (CollectionUtils.isNotEmpty(storageList)) {
// 过滤掉下架的无库存的storage
storageList = storageList.stream()
.filter(storage -> Integer.valueOf(1).equals(storage.getStatus()))
.filter(storage -> storage.getStorageNum() != null && storage.getStorageNum().intValue() > 0)
.collect(Collectors.toList());
}
protected void fillStorageNumAndSizeInfo(Integer productId, Map<String, Object> indexData) {
List<Storage> storageList = storageService.getStoragesByProductId(productId);
// 过滤掉下架的storage
if (CollectionUtils.isNotEmpty(storageList)) {
storageList = storageList.stream().filter(storage -> Integer.valueOf(1).equals(storage.getStatus())).collect(Collectors.toList());
}
int totalSizeCount = storageList.size();
if (CollectionUtils.isEmpty(storageList)) {
indexData.put("storageNum", 0);
indexData.put("isSoonSoldOut", "Y");
indexData.put("isSoldOut", "Y");
indexData.put("soldOut", 0);
indexData.put("sizeIds", null);
} else {
int storageNum = 0;
Set<String> sizeSet = new HashSet<String>();
for (Storage stor : storageList) {
storageNum += stor.getStorageNum();
if (stor.getGoodsDimensionId() != null) {
sizeSet.add(stor.getGoodsDimensionId() + "");
}
}
indexData.put("storageNum", storageNum);
indexData.put("isSoonSoldOut", storageNum <= 2 ? "Y" : "N");
indexData.put("isSoldOut", storageNum == 0 ? "Y" : "N");
indexData.put("soldOut", storageNum == 0 ? 0 : 1);
if (!sizeSet.isEmpty()) {
// 设置尺码信息
indexData.put("sizeIds", StringUtils.join(sizeSet, ","));
indexData.put("sizeNames", sizeService.getSizeNamesBySizeIds(sizeSet.stream().map(Integer::valueOf).collect(Collectors.toList())));
} else {
indexData.put("sizeIds", null);
indexData.put("sizeNames", null);
}
}
}
// 过滤掉无库存的storage
if (CollectionUtils.isNotEmpty(storageList)) {
storageList = storageList.stream().filter(storage -> storage.getStorageNum() != null && storage.getStorageNum().intValue() > 0).collect(Collectors.toList());
}
int effectiveSizeCount = storageList.size();
float breakSizePercent = 100 * (totalSizeCount - effectiveSizeCount)/totalSizeCount;
if (CollectionUtils.isEmpty(storageList)) {
indexData.put("storageNum", 0);
indexData.put("isSoonSoldOut", "Y");
indexData.put("isSoldOut", "Y");
indexData.put("soldOut", 0);
indexData.put("sizeIds", null);
indexData.put("breakSizePercent", 100);
} else {
int storageNum = 0;
Set<String> sizeSet = new HashSet<String>();
for (Storage stor : storageList) {
storageNum += stor.getStorageNum();
if (stor.getGoodsDimensionId() != null) {
sizeSet.add(stor.getGoodsDimensionId() + "");
}
}
indexData.put("storageNum", storageNum);
indexData.put("isSoonSoldOut", storageNum <= 2 ? "Y" : "N");
indexData.put("isSoldOut", storageNum == 0 ? "Y" : "N");
indexData.put("soldOut", storageNum == 0 ? 0 : 1);
if (!sizeSet.isEmpty()) {
// 设置尺码信息
indexData.put("sizeIds", StringUtils.join(sizeSet, ","));
indexData.put("sizeNames", sizeService.getSizeNamesBySizeIds(sizeSet.stream().map(Integer::valueOf).collect(Collectors.toList())));
} else {
indexData.put("sizeIds", null);
indexData.put("sizeNames", null);
}
indexData.put("breakSizePercent", breakSizePercent);
}
}
protected void fillColor(Map<String, Object> indexData, Integer productId) {
Set<String> colorIdSet = new HashSet<String>();
Set<String> colorNameSet = new HashSet<String>();
// 第一步:获取goodsList
List<ProductGoodsBO> productGoodsBOList = goodsService.getProductGoodsByProductId(productId);
// 第二步、组装goods数据
if (productGoodsBOList != null && productGoodsBOList.size() == 1) {
ProductGoodsBO productGoodsBO = productGoodsBOList.get(0);
String goodsListJsonArrayStr = productGoodsBO.getGoodsList();
JSONArray goodsListJsonArray = JSONArray.parseArray(goodsListJsonArrayStr);
productGoodsLogicService.getColorSet(goodsListJsonArray, colorIdSet, colorNameSet);//获取有库存且状态正常的color
indexData.put("goodsList", goodsListJsonArray);
indexData.put("colorIds", StringUtils.join(colorIdSet, ","));
indexData.put("colorNames", StringUtils.join(colorNameSet, ","));
} else {
indexData.put("goodsList", "");
indexData.put("colorIds", "");
indexData.put("colorNames", "");
}
}
protected void fillColor(Map<String, Object> indexData, Integer productId) {
Set<String> colorIdSet = new HashSet<String>();
Set<String> colorNameSet = new HashSet<String>();
// 第一步:获取goodsList
List<ProductGoodsBO> productGoodsBOList = goodsService.getProductGoodsByProductId(productId);
// 第二步、组装goods数据
if (productGoodsBOList != null && productGoodsBOList.size() == 1) {
ProductGoodsBO productGoodsBO = productGoodsBOList.get(0);
String goodsListJsonArrayStr = productGoodsBO.getGoodsList();
JSONArray goodsListJsonArray = JSONArray.parseArray(goodsListJsonArrayStr);
productGoodsLogicService.getColorSet(goodsListJsonArray, colorIdSet, colorNameSet);// 获取有库存且状态正常的color
indexData.put("goodsList", goodsListJsonArray);
indexData.put("colorIds", StringUtils.join(colorIdSet, ","));
indexData.put("colorNames", StringUtils.join(colorNameSet, ","));
} else {
indexData.put("goodsList", "");
indexData.put("colorIds", "");
indexData.put("colorNames", "");
}
}
}
\ No newline at end of file
... ...
... ... @@ -781,6 +781,9 @@
"type": "string",
"analyzer": "comma_spliter"
},
"breakSizePercent": {
"type": "double"
},
"standardIds": {
"type": "string",
"analyzer": "comma_spliter"
... ...
... ... @@ -126,6 +126,8 @@ public class ProductIndexService {
map.put(ProductIndexEsField.colorNames, productIndexBO.getColorNames());
map.put(ProductIndexEsField.sizeIds, productIndexBO.getSizeIds());
map.put(ProductIndexEsField.sizeNames, productIndexBO.getSizeNames());
map.put(ProductIndexEsField.breakSizePercent, productIndexBO.getBreakSizePercent());
map.put(ProductIndexEsField.standardIds, productIndexBO.getStandardIds());
map.put(ProductIndexEsField.standardNames, productIndexBO.getStandardNames());
map.put(ProductIndexEsField.styleIds, productIndexBO.getStyleIds());
... ...
... ... @@ -53,6 +53,7 @@ public class ProductIndexBO extends ProductIBO implements Serializable {
private Integer soldOut;
private String sizeIds;
private String sizeNames;
private double breakSizePercent;
// from product_15day_salesnum
private Integer salesNum;
... ... @@ -416,6 +417,14 @@ public class ProductIndexBO extends ProductIBO implements Serializable {
return sizeNames;
}
public double getBreakSizePercent() {
return breakSizePercent;
}
public void setBreakSizePercent(double breakSizePercent) {
this.breakSizePercent = breakSizePercent;
}
public String getIsStudentPrice() {
return isStudentPrice;
}
... ...
... ... @@ -8,6 +8,7 @@ import com.yoho.search.dal.model.Goods;
import com.yoho.search.dal.model.ProductSizes;
import com.yoho.search.dal.model.Size;
import com.yoho.search.dal.model.Storage;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
... ... @@ -21,93 +22,118 @@ import java.util.stream.Collectors;
@Component
public class ProductSizesLogicService {
private static final Integer VALID_STATUS = Integer.valueOf(1);
@Autowired
private GoodsMapper goodsMapper;
@Autowired
private StorageMapper storageMapper;
@Autowired
private SizeMapper sizeMapper;
@Autowired
private ProductSizesMapper productSizesMapper;
/**
* 获取ProductSizes列表
* @return
*/
public List<ProductSizes> getData(List<Integer> ids) {
//获取ProductId对应的上架的goodsId列表
List<Goods> goodsList = goodsMapper.getByIdsAndStatus(ids);
if(CollectionUtils.isEmpty(goodsList)){
return new ArrayList<>();
}
//获取goodsId对应得Storage列表
List<Integer> goodsIdList = goodsList.parallelStream().map(Goods::getId).collect(Collectors.toList());
List<Storage> storageList = storageMapper.getByGoodsIds(goodsIdList);
if (CollectionUtils.isEmpty(storageList)) {
return new ArrayList<>();
}
//过滤状态是上架的且有库存的Goods和Storage
storageList = storageList.parallelStream().filter(storageItem -> VALID_STATUS.equals(storageItem.getStatus()))
.filter(storageItem -> storageItem.getStorageNum() != null && storageItem.getStorageNum().intValue() > 0).collect(Collectors.toList());
if(CollectionUtils.isEmpty(storageList)){
return new ArrayList<>();
}
// 根据上架的GoodsId筛选Storage数据
Set<Integer> validGoodsIdSet = goodsIdList.stream().collect(Collectors.toSet());
List<Integer> validErpSkuIdList = new ArrayList<>();
for (Storage s : storageList) {
if (validGoodsIdSet.contains(s.getGoodsId())) {
validErpSkuIdList.add(s.getErpSkuId());
}
}
//判断sku列表是否为空
if (validErpSkuIdList == null || validErpSkuIdList.isEmpty()) {
return new ArrayList<>();
}
List<ProductSizes> productSizesList = productSizesMapper.getProductSizes(validErpSkuIdList);
if (CollectionUtils.isEmpty(productSizesList)) {
return new ArrayList<>();
}
// 设置尺码名称,多个名称之间使用逗号分隔
Set<Integer> sizeIdSet = new HashSet<>();
for (ProductSizes ps : productSizesList) {
String sizeArray[] = ps.getSizeIds().split(",");
if (sizeArray != null) {
for (int i = 0; i < sizeArray.length; i++) {
sizeIdSet.add(Integer.valueOf(sizeArray[i]));
}
}
}
List<Size> sizeList = sizeMapper.getByIds(sizeIdSet.stream().collect(Collectors.toList()));
if (CollectionUtils.isNotEmpty(sizeList)) {
Map<Integer, String> sizeMap = sizeList.stream().collect(Collectors.toMap(Size::getId, Size::getSizeName));
//productSizesList.forEach(ps -> ps.setSizeNames(Arrays.stream(ps.getSizeIds().split(",")).map(Integer::valueOf).map(sizeId -> sizeMap.get(sizeId)).collect(Collectors.joining(","))));
for (ProductSizes ps : productSizesList) {
String sizeArray[] = ps.getSizeIds().split(",");
if (sizeArray != null) {
for (int i = 0; i < sizeArray.length; i++) {
if (i == 0) {
ps.setSizeNames(sizeMap.get(Integer.valueOf(sizeArray[i]))+ ",");
} else {
ps.setSizeNames(ps.getSizeNames() + sizeMap.get(Integer.valueOf(sizeArray[i]))+ ",");
}
}
}
}
}
return productSizesList;
}
private static final Integer VALID_STATUS = Integer.valueOf(1);
@Autowired
private GoodsMapper goodsMapper;
@Autowired
private StorageMapper storageMapper;
@Autowired
private SizeMapper sizeMapper;
@Autowired
private ProductSizesMapper productSizesMapper;
/**
* 获取ProductSizes列表
*
* @return
*/
public List<ProductSizes> getData(List<Integer> ids) {
// 获取ProductId对应的上架的goodsId列表
List<Goods> goodsList = goodsMapper.getByIdsAndStatus(ids);
if (CollectionUtils.isEmpty(goodsList)) {
return new ArrayList<>();
}
// 获取goodsId对应得Storage列表
List<Integer> goodsIdList = goodsList.parallelStream().map(Goods::getId).collect(Collectors.toList());
List<Storage> storageList = storageMapper.getByGoodsIds(goodsIdList);
if (CollectionUtils.isEmpty(storageList)) {
return new ArrayList<>();
}
// 过滤掉下架的sku
storageList = storageList.parallelStream().filter(storageItem -> VALID_STATUS.equals(storageItem.getStatus())).collect(Collectors.toList());
// 计算每个skn则总尺码数
Map<Integer, Integer> sknSizeCountMap = new HashMap<Integer, Integer>();
for (Storage storage : storageList) {
Integer productId = storage.getProductId();
int count = sknSizeCountMap.getOrDefault(productId, 0);
sknSizeCountMap.put(productId, count + 1);
}
// 过滤状态是上架的且有库存的Goods和Storage
storageList = storageList.parallelStream().filter(storageItem -> storageItem.getStorageNum() != null && storageItem.getStorageNum().intValue() > 0)
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(storageList)) {
return new ArrayList<>();
}
// 根据上架的GoodsId筛选Storage数据
Set<Integer> validGoodsIdSet = goodsIdList.stream().collect(Collectors.toSet());
List<Integer> validErpSkuIdList = new ArrayList<>();
for (Storage s : storageList) {
if (validGoodsIdSet.contains(s.getGoodsId())) {
validErpSkuIdList.add(s.getErpSkuId());
}
}
// 判断sku列表是否为空
if (validErpSkuIdList == null || validErpSkuIdList.isEmpty()) {
return new ArrayList<>();
}
List<ProductSizes> productSizesList = productSizesMapper.getProductSizes(validErpSkuIdList);
if (CollectionUtils.isEmpty(productSizesList)) {
return new ArrayList<>();
}
// 设置尺码名称,多个名称之间使用逗号分隔
Set<Integer> sizeIdSet = new HashSet<>();
for (ProductSizes ps : productSizesList) {
String sizeArray[] = ps.getSizeIds().split(",");
if (sizeArray != null) {
for (int i = 0; i < sizeArray.length; i++) {
sizeIdSet.add(Integer.valueOf(sizeArray[i]));
}
}
}
// 获取尺码信息
List<Size> sizeList = sizeMapper.getByIds(sizeIdSet.stream().collect(Collectors.toList()));
// 填充尺码信息和断码率
if (CollectionUtils.isNotEmpty(sizeList)) {
Map<Integer, String> sizeMap = sizeList.stream().collect(Collectors.toMap(Size::getId, Size::getSizeName));
for (ProductSizes ps : productSizesList) {
String sizeArray[] = ps.getSizeIds().split(",");
// 计算断码率
double breakSizePercent = this.getBreakSizePercent(sknSizeCountMap.getOrDefault(ps.getProductId(), 0), sizeArray == null ? 0 : sizeArray.length);
ps.setBreakSizePercent(breakSizePercent);
// 填充尺码名称
if (sizeArray != null) {
for (int i = 0; i < sizeArray.length; i++) {
if (i == 0) {
ps.setSizeNames(sizeMap.get(Integer.valueOf(sizeArray[i])) + ",");
} else {
ps.setSizeNames(ps.getSizeNames() + sizeMap.get(Integer.valueOf(sizeArray[i])) + ",");
}
}
}
}
}
return productSizesList;
}
private double getBreakSizePercent(int totalSizeCount, int effectiveSizeCount) {
if (totalSizeCount == 0 || effectiveSizeCount == 0) {
return 100d;
}
return 100d * (effectiveSizeCount - totalSizeCount) / totalSizeCount;
}
}
... ...
... ... @@ -17,37 +17,40 @@ import java.util.stream.Collectors;
@Component
public class ProductSizesBuilder implements ViewBuilder {
@Autowired
private ProductSizesLogicService productSizesLogicService;
/**
* 构建ProductSizes数据
*/
@Override
public void build(List<ProductIndexBO> productIndexBOs, List<Integer> ids, List<Integer> skns) {
List<ProductSizes> productSizess = productSizesLogicService.getData(ids);
Map<Integer, ProductSizes> productSizesMap = productSizess.stream().parallel().collect(Collectors.toMap(ProductSizes::getProductId, (p) -> p));
for (ProductIndexBO productIndexBO : productIndexBOs) {
ProductSizes productSizes = productSizesMap.get(productIndexBO.getProductId());
productIndexBO.setIsSoonSoldOut("N");
productIndexBO.setIsSoldOut("N");
productIndexBO.setSoldOut(1);
if (productSizes != null) {
productIndexBO.setStorageNum(BigDecimal.valueOf(productSizes.getStorageNum()));
if (productSizes.getStorageNum() <= 2) {
productIndexBO.setIsSoonSoldOut("Y");
}
if (productSizes.getStorageNum() == 0) {
productIndexBO.setIsSoldOut("Y");
productIndexBO.setSoldOut(0);
}
productIndexBO.setSizeIds(productSizes.getSizeIds());
productIndexBO.setSizeNames(productSizes.getSizeNames());
}
else {
productIndexBO.setStorageNum(BigDecimal.valueOf(0));
productIndexBO.setIsSoldOut("Y");
productIndexBO.setSoldOut(0);
}
}
}
@Autowired
private ProductSizesLogicService productSizesLogicService;
/**
* 构建ProductSizes数据
*/
@Override
public void build(List<ProductIndexBO> productIndexBOs, List<Integer> ids, List<Integer> skns) {
List<ProductSizes> productSizess = productSizesLogicService.getData(ids);
Map<Integer, ProductSizes> productSizesMap = productSizess.stream().parallel().collect(Collectors.toMap(ProductSizes::getProductId, (p) -> p));
for (ProductIndexBO productIndexBO : productIndexBOs) {
ProductSizes productSizes = productSizesMap.get(productIndexBO.getProductId());
productIndexBO.setIsSoonSoldOut("N");
productIndexBO.setIsSoldOut("N");
productIndexBO.setSoldOut(1);
productIndexBO.setBreakSizePercent(100);
if (productSizes != null) {
productIndexBO.setStorageNum(BigDecimal.valueOf(productSizes.getStorageNum()));
if (productSizes.getStorageNum() <= 2) {
productIndexBO.setIsSoonSoldOut("Y");
}
if (productSizes.getStorageNum() == 0) {
productIndexBO.setIsSoldOut("Y");
productIndexBO.setSoldOut(0);
}
productIndexBO.setSizeIds(productSizes.getSizeIds());
productIndexBO.setSizeNames(productSizes.getSizeNames());
productIndexBO.setBreakSizePercent(productSizes.getBreakSizePercent());
} else {
productIndexBO.setStorageNum(BigDecimal.valueOf(0));
productIndexBO.setIsSoldOut("Y");
productIndexBO.setSoldOut(0);
productIndexBO.setBreakSizePercent(100);
}
}
}
}
... ...