商品索引生成代码迁移,结构稍微优化

This commit is contained in:
Chopper 2021-10-28 14:40:38 +08:00
parent bc8885c5b8
commit 036ad56093
4 changed files with 128 additions and 90 deletions

View File

@ -449,7 +449,8 @@ public enum ResultCode {
CUSTOM_WORDS_SECRET_KEY_ERROR(90002, "秘钥验证失败!"), CUSTOM_WORDS_SECRET_KEY_ERROR(90002, "秘钥验证失败!"),
CONNECT_NOT_EXIST(90000, "登录方式不存在!"), CONNECT_NOT_EXIST(90000, "登录方式不存在!"),
ELASTICSEARCH_INDEX_INIT_ERROR(90003, "索引初始化失败!"), ELASTICSEARCH_INDEX_INIT_ERROR(90003, "索引初始化失败!"),
PURCHASE_ORDER_DEADLINE_ERROR(90004, "供求单,已超过报名截止时间"); PURCHASE_ORDER_DEADLINE_ERROR(90004, "供求单,已超过报名截止时间"),
INDEX_BUILDING(90005, "索引正在生成");
private final Integer code; private final Integer code;
private final String message; private final String message;

View File

@ -18,6 +18,16 @@ import java.util.Map;
**/ **/
public interface EsGoodsIndexService { public interface EsGoodsIndexService {
/**
* 全局索引初始化
*/
void init();
/**
* 获取es生成索引进度
* @return
*/
Map<String, Integer> getProgress();
/** /**
* 添加商品索引 * 添加商品索引
* *

View File

@ -2,6 +2,8 @@ package cn.lili.modules.search.serviceimpl;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.ReflectUtil;
import cn.hutool.extra.pinyin.PinyinUtil; import cn.hutool.extra.pinyin.PinyinUtil;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
@ -9,14 +11,18 @@ import cn.hutool.json.JSONUtil;
import cn.lili.cache.Cache; import cn.lili.cache.Cache;
import cn.lili.cache.CachePrefix; import cn.lili.cache.CachePrefix;
import cn.lili.common.enums.PromotionTypeEnum; import cn.lili.common.enums.PromotionTypeEnum;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.enums.ResultUtil;
import cn.lili.common.exception.ServiceException;
import cn.lili.elasticsearch.BaseElasticsearchService; import cn.lili.elasticsearch.BaseElasticsearchService;
import cn.lili.elasticsearch.EsSuffix; import cn.lili.elasticsearch.EsSuffix;
import cn.lili.elasticsearch.config.ElasticsearchProperties; import cn.lili.elasticsearch.config.ElasticsearchProperties;
import cn.lili.modules.goods.entity.dos.GoodsSku; import cn.lili.modules.goods.entity.dos.*;
import cn.lili.modules.goods.entity.dos.GoodsWords;
import cn.lili.modules.goods.entity.dto.GoodsParamsDTO; import cn.lili.modules.goods.entity.dto.GoodsParamsDTO;
import cn.lili.modules.goods.entity.enums.GoodsAuthEnum;
import cn.lili.modules.goods.entity.enums.GoodsStatusEnum;
import cn.lili.modules.goods.entity.enums.GoodsWordsTypeEnum; import cn.lili.modules.goods.entity.enums.GoodsWordsTypeEnum;
import cn.lili.modules.goods.service.GoodsWordsService; import cn.lili.modules.goods.service.*;
import cn.lili.modules.promotion.entity.dos.PromotionGoods; import cn.lili.modules.promotion.entity.dos.PromotionGoods;
import cn.lili.modules.promotion.entity.dto.BasePromotion; import cn.lili.modules.promotion.entity.dto.BasePromotion;
import cn.lili.modules.promotion.entity.enums.PromotionStatusEnum; import cn.lili.modules.promotion.entity.enums.PromotionStatusEnum;
@ -27,6 +33,8 @@ import cn.lili.modules.search.entity.dto.EsGoodsSearchDTO;
import cn.lili.modules.search.repository.EsGoodsIndexRepository; import cn.lili.modules.search.repository.EsGoodsIndexRepository;
import cn.lili.modules.search.service.EsGoodsIndexService; import cn.lili.modules.search.service.EsGoodsIndexService;
import cn.lili.modules.search.service.EsGoodsSearchService; import cn.lili.modules.search.service.EsGoodsSearchService;
import cn.lili.modules.store.entity.dos.StoreGoodsLabel;
import cn.lili.modules.store.service.StoreGoodsLabelService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.IterableUtil; import org.assertj.core.util.IterableUtil;
@ -78,9 +86,111 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
private GoodsWordsService goodsWordsService; private GoodsWordsService goodsWordsService;
@Autowired @Autowired
private PromotionService promotionService; private PromotionService promotionService;
@Autowired
private GoodsSkuService goodsSkuService;
@Autowired
private GoodsService goodsService;
@Autowired
private BrandService brandService;
@Autowired
private CategoryService categoryService;
@Autowired
private StoreGoodsLabelService storeGoodsLabelService;
@Autowired @Autowired
private Cache<Object> cache; private Cache<Object> cache;
@Override
public void init() {
//获取索引任务标识
Boolean flag = (Boolean) cache.get(CachePrefix.INIT_INDEX_FLAG.getPrefix());
//为空则默认写入没有任务
if (flag == null) {
cache.put(CachePrefix.INIT_INDEX_FLAG.getPrefix(), false);
}
//有正在初始化的任务则提示异常
if (Boolean.TRUE.equals(flag)) {
throw new ServiceException(ResultCode.INDEX_BUILDING);
}
//初始化标识
cache.put(CachePrefix.INIT_INDEX_PROCESS.getPrefix(), null);
cache.put(CachePrefix.INIT_INDEX_FLAG.getPrefix(), true);
ThreadUtil.execAsync(() -> {
try {
//查询商品信息
LambdaQueryWrapper<GoodsSku> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(GoodsSku::getIsAuth, GoodsAuthEnum.PASS.name());
queryWrapper.eq(GoodsSku::getMarketEnable, GoodsStatusEnum.UPPER.name());
List<GoodsSku> list = goodsSkuService.list(queryWrapper);
List<EsGoodsIndex> esGoodsIndices = new ArrayList<>();
//库存锁是在redis做的所以生成索引同时更新一下redis中的库存数量
for (GoodsSku goodsSku : list) {
Goods goods = goodsService.getById(goodsSku.getGoodsId());
//如果出现极端情况有sku没有与之匹配的商品则跳过
if (goods == null) {
continue;
}
EsGoodsIndex index = new EsGoodsIndex(goodsSku);
//商品参数索引
if (goods.getParams() != null && !goods.getParams().isEmpty()) {
List<GoodsParamsDTO> goodsParamDTOS = JSONUtil.toList(goods.getParams(), GoodsParamsDTO.class);
index = new EsGoodsIndex(goodsSku, goodsParamDTOS);
}
//商品分类索引
if (goods.getCategoryPath() != null) {
List<Category> categories = categoryService.listByIdsOrderByLevel(Arrays.asList(goods.getCategoryPath().split(",")));
if (!categories.isEmpty()) {
index.setCategoryNamePath(ArrayUtil.join(categories.stream().map(Category::getName).toArray(), ","));
}
}
//商品品牌索引
Brand brand = brandService.getById(goods.getBrandId());
if (brand != null) {
index.setBrandName(brand.getName());
index.setBrandUrl(brand.getLogo());
}
//店铺分类索引
if (goods.getStoreCategoryPath() != null && CharSequenceUtil.isNotEmpty(goods.getStoreCategoryPath())) {
List<StoreGoodsLabel> storeGoodsLabels = storeGoodsLabelService.listByStoreIds(Arrays.asList(goods.getStoreCategoryPath().split(",")));
if (!storeGoodsLabels.isEmpty()) {
index.setStoreCategoryNamePath(ArrayUtil.join(storeGoodsLabels.stream().map(StoreGoodsLabel::getLabelName).toArray(), ","));
}
}
//促销索引
Map<String, Object> goodsCurrentPromotionMap = promotionService.getGoodsCurrentPromotionMap(index);
index.setPromotionMap(goodsCurrentPromotionMap);
esGoodsIndices.add(index);
cache.put(GoodsSkuService.getStockCacheKey(goodsSku.getId()), goodsSku.getQuantity().toString());
}
//初始化商品索引
this.initIndex(esGoodsIndices);
} catch (Exception e) {
log.error("商品索引生成异常:", e);
//如果出现异常则将进行中的任务标识取消掉打印日志
cache.put(CachePrefix.INIT_INDEX_PROCESS.getPrefix(), null);
cache.put(CachePrefix.INIT_INDEX_FLAG.getPrefix(), false);
}
});
}
@Override
public Map<String, Integer> getProgress() {
Map<String, Integer> map = (Map<String, Integer>) cache.get(CachePrefix.INIT_INDEX_PROCESS.getPrefix());
if (map == null) {
return null;
}
Boolean flag = (Boolean) cache.get(CachePrefix.INIT_INDEX_FLAG.getPrefix());
map.put("flag", Boolean.TRUE.equals(flag) ? 1 : 0);
return map;
}
@Override @Override
public void addIndex(EsGoodsIndex goods) { public void addIndex(EsGoodsIndex goods) {
try { try {

View File

@ -6,6 +6,7 @@ import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import cn.lili.cache.Cache; import cn.lili.cache.Cache;
import cn.lili.cache.CachePrefix; import cn.lili.cache.CachePrefix;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.enums.ResultUtil; import cn.lili.common.enums.ResultUtil;
import cn.lili.common.vo.ResultMessage; import cn.lili.common.vo.ResultMessage;
import cn.lili.modules.goods.entity.dos.Brand; import cn.lili.modules.goods.entity.dos.Brand;
@ -52,101 +53,17 @@ public class ElasticsearchController {
@Autowired @Autowired
private EsGoodsIndexService esGoodsIndexService; private EsGoodsIndexService esGoodsIndexService;
@Autowired
private GoodsSkuService goodsSkuService;
@Autowired
private GoodsService goodsService;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private PromotionService promotionService;
@Autowired
private CategoryService categoryService;
@Autowired
private BrandService brandService;
@Autowired
private StoreGoodsLabelService storeGoodsLabelService;
@Autowired @Autowired
private Cache cache; private Cache cache;
@GetMapping @GetMapping
public ResultMessage<String> init() { public ResultMessage<String> init() {
esGoodsIndexService.init();
Boolean flag = (Boolean) cache.get(CachePrefix.INIT_INDEX_FLAG.getPrefix());
if (flag == null) {
cache.put(CachePrefix.INIT_INDEX_FLAG.getPrefix(), false);
}
if (Boolean.TRUE.equals(flag)) {
return ResultUtil.error(100000, "当前有任务在执行");
}
cache.put(CachePrefix.INIT_INDEX_PROCESS.getPrefix(), null);
cache.put(CachePrefix.INIT_INDEX_FLAG.getPrefix(), true);
ThreadUtil.execAsync(() -> {
try {
//查询商品信息
LambdaQueryWrapper<GoodsSku> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(GoodsSku::getIsAuth, GoodsAuthEnum.PASS.name());
queryWrapper.eq(GoodsSku::getMarketEnable, GoodsStatusEnum.UPPER.name());
List<GoodsSku> list = goodsSkuService.list(queryWrapper);
List<EsGoodsIndex> esGoodsIndices = new ArrayList<>();
//库存锁是在redis做的所以生成索引同时更新一下redis中的库存数量
for (GoodsSku goodsSku : list) {
Goods goods = goodsService.getById(goodsSku.getGoodsId());
EsGoodsIndex index = new EsGoodsIndex(goodsSku);
if (goods.getParams() != null && !goods.getParams().isEmpty()) {
List<GoodsParamsDTO> goodsParamDTOS = JSONUtil.toList(goods.getParams(), GoodsParamsDTO.class);
index = new EsGoodsIndex(goodsSku, goodsParamDTOS);
}
if (goods.getCategoryPath() != null) {
List<Category> categories = categoryService.listByIdsOrderByLevel(Arrays.asList(goods.getCategoryPath().split(",")));
if (!categories.isEmpty()) {
index.setCategoryNamePath(ArrayUtil.join(categories.stream().map(Category::getName).toArray(), ","));
}
}
Brand brand = brandService.getById(goods.getBrandId());
if (brand != null) {
index.setBrandName(brand.getName());
index.setBrandUrl(brand.getLogo());
}
if (goods.getStoreCategoryPath() != null && CharSequenceUtil.isNotEmpty(goods.getStoreCategoryPath())) {
List<StoreGoodsLabel> storeGoodsLabels = storeGoodsLabelService.listByStoreIds(Arrays.asList(goods.getStoreCategoryPath().split(",")));
if (!storeGoodsLabels.isEmpty()) {
index.setStoreCategoryNamePath(ArrayUtil.join(storeGoodsLabels.stream().map(StoreGoodsLabel::getLabelName).toArray(), ","));
}
}
Map<String, Object> goodsCurrentPromotionMap = promotionService.getGoodsCurrentPromotionMap(index);
index.setPromotionMap(goodsCurrentPromotionMap);
esGoodsIndices.add(index);
stringRedisTemplate.opsForValue().set(GoodsSkuService.getStockCacheKey(goodsSku.getId()), goodsSku.getQuantity().toString());
}
//初始化商品索引
esGoodsIndexService.initIndex(esGoodsIndices);
} catch (Exception e) {
cache.put(CachePrefix.INIT_INDEX_PROCESS.getPrefix(), null);
cache.put(CachePrefix.INIT_INDEX_FLAG.getPrefix(), false);
}
});
return ResultUtil.success(); return ResultUtil.success();
} }
@GetMapping("/progress") @GetMapping("/progress")
public ResultMessage<Map<String, Integer>> getProgress() { public ResultMessage<Map<String, Integer>> getProgress() {
try { return ResultUtil.data(esGoodsIndexService.getProgress());
Map<String, Integer> map = (Map<String, Integer>) cache.get(CachePrefix.INIT_INDEX_PROCESS.getPrefix());
Boolean flag = (Boolean) cache.get(CachePrefix.INIT_INDEX_FLAG.getPrefix());
map.put("flag", Boolean.TRUE.equals(flag) ? 1 : 0);
return ResultUtil.data(map);
} catch (Exception e) {
return ResultUtil.data(null);
}
} }
} }