优化商品索引更新字段方法;

修复店铺信息修改后,商品索引的店铺信息不会随之更改;
This commit is contained in:
paulGao 2021-10-14 15:37:57 +08:00
parent 099708390d
commit 55c9a63301
10 changed files with 246 additions and 62 deletions

View File

@ -2,6 +2,7 @@ package cn.lili.listener;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.lili.event.GoodsCommentCompleteEvent;
import cn.lili.modules.distribution.entity.dos.DistributionGoods;
@ -42,6 +43,7 @@ import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* 商品消息
@ -137,16 +139,25 @@ public class GoodsMessageListener implements RocketMQListener<MessageExt> {
case UPDATE_GOODS_INDEX:
try {
String goodsIdsJsonStr = new String(messageExt.getBody());
List<Goods> goodsList = new ArrayList<>();
for (String goodsId : JSONUtil.toList(goodsIdsJsonStr, String.class)) {
Goods goods = goodsService.getById(goodsId);
goodsList.add(goods);
}
List<Goods> goodsList = goodsService.list(new LambdaQueryWrapper<Goods>().in(Goods::getId, JSONUtil.toList(goodsIdsJsonStr, String.class)));
this.updateGoodsIndex(goodsList);
} catch (Exception e) {
log.error("更新商品索引事件执行异常,商品信息 {}", new String(messageExt.getBody()));
}
break;
case UPDATE_GOODS_INDEX_FIELD:
try {
String updateIndexFieldsJsonStr = new String(messageExt.getBody());
JSONObject updateIndexFields = JSONUtil.parseObj(updateIndexFieldsJsonStr);
@SuppressWarnings("unchecked")
Map<String, Object> queryFields = updateIndexFields.get("queryFields", Map.class);
@SuppressWarnings("unchecked")
Map<String, Object> updateFields = updateIndexFields.get("updateFields", Map.class);
goodsIndexService.updateIndex(queryFields, updateFields);
} catch (Exception e) {
log.error("更新商品索引事件执行异常,商品信息 {}", new String(messageExt.getBody()));
}
break;
case RESET_GOODS_INDEX:
try {
String goodsIdsJsonStr = new String(messageExt.getBody());

View File

@ -40,6 +40,14 @@ public interface EsGoodsIndexService {
*/
void updateIndex(String id, EsGoodsIndex goods);
/**
* 更新商品索引的的部分属性
*
* @param queryFields 查询字段
* @param updateFields 更新字段
*/
void updateIndex(Map<String, Object> queryFields, Map<String, Object> updateFields);
/**
* 批量商品索引的的属性ID 必填, 其他字段只填写更新的字段不需要更新的字段不要填写
*
@ -105,10 +113,12 @@ public interface EsGoodsIndexService {
/**
* 删除索引中指定的促销活动id的促销活动
*
* @param skuId 商品skuId
* @param promotionId 促销活动Id
*/
void deleteEsGoodsPromotionByPromotionId(String skuId, String promotionId);
/**
* 清除所以商品索引的无效促销活动
*/

View File

@ -30,11 +30,18 @@ import cn.lili.modules.search.service.EsGoodsSearchService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.IterableUtil;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.indices.AnalyzeRequest;
import org.elasticsearch.client.indices.AnalyzeResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.UpdateByQueryRequest;
import org.elasticsearch.script.Script;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.SearchHit;
@ -76,11 +83,9 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
@Override
public void addIndex(EsGoodsIndex goods) {
//索引名称拼接
String indexName = elasticsearchProperties.getIndexPrefix() + "_" + EsSuffix.GOODS_INDEX_NAME;
try {
//分词器分词
AnalyzeRequest analyzeRequest = AnalyzeRequest.withIndexAnalyzer(indexName, "ik_max_word", goods.getGoodsName());
AnalyzeRequest analyzeRequest = AnalyzeRequest.withIndexAnalyzer(getIndexName(), "ik_max_word", goods.getGoodsName());
AnalyzeResponse analyze = client.indices().analyze(analyzeRequest, RequestOptions.DEFAULT);
List<AnalyzeResponse.AnalyzeToken> tokens = analyze.getTokens();
@ -126,6 +131,29 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
goodsIndexRepository.save(goods);
}
/**
* 更新商品索引的的部分属性只填写更新的字段不需要更新的字段不要填写
*
* @param queryFields 查询字段
* @param updateFields 更新字段
*/
@Override
public void updateIndex(Map<String, Object> queryFields, Map<String, Object> updateFields) {
UpdateByQueryRequest update = new UpdateByQueryRequest(getIndexName());
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
for (Map.Entry<String, Object> entry : queryFields.entrySet()) {
TermQueryBuilder termQueryBuilder = new TermQueryBuilder(entry.getKey(), entry.getValue());
queryBuilder.filter(termQueryBuilder);
}
update.setQuery(queryBuilder);
StringBuilder script = new StringBuilder();
for (Map.Entry<String, Object> entry : updateFields.entrySet()) {
script.append("ctx._source.").append(entry.getKey()).append("=").append("'").append(entry.getValue()).append("'").append(";");
}
update.setScript(new Script(script.toString()));
client.updateByQueryAsync(update, RequestOptions.DEFAULT, this.actionListener());
}
/**
* 批量商品索引的的属性ID 必填, 其他字段只填写更新的字段不需要更新的字段不要填写
*
@ -135,7 +163,7 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
public void updateBulkIndex(List<EsGoodsIndex> goodsIndices) {
try {
//索引名称拼接
String indexName = elasticsearchProperties.getIndexPrefix() + "_" + EsSuffix.GOODS_INDEX_NAME;
String indexName = getIndexName();
BulkRequest request = new BulkRequest();
@ -178,7 +206,7 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
return;
}
//索引名称拼接
String indexName = elasticsearchProperties.getIndexPrefix() + "_" + EsSuffix.GOODS_INDEX_NAME;
String indexName = this.getIndexName();
//索引初始化因为mapping结构问题
//但是如果索引已经自动生成过这里就不会创建索引设置mapping所以这里决定在初始化索引的同时将已有索引删除重新创建
@ -383,7 +411,7 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
}
return promotionMap;
}
return null;
return new HashMap<>();
}
/**
@ -519,4 +547,22 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
}
}
private String getIndexName() {
//索引名称拼接
return elasticsearchProperties.getIndexPrefix() + "_" + EsSuffix.GOODS_INDEX_NAME;
}
private ActionListener<BulkByScrollResponse> actionListener() {
return new ActionListener<BulkByScrollResponse>() {
@Override
public void onResponse(BulkByScrollResponse bulkByScrollResponse) {
log.debug("UpdateByQueryResponse: {}", bulkByScrollResponse);
}
@Override
public void onFailure(Exception e) {
log.error("UpdateByQueryRequestFailure: ", e);
}
};
}
}

View File

@ -0,0 +1,45 @@
package cn.lili.modules.search.utils;
import cn.hutool.core.util.ReflectUtil;
import cn.lili.modules.search.entity.dos.EsGoodsIndex;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
* @author paulG
* @since 2021/10/11
**/
public class EsIndexUtil {
private static final String IGNORE_FIELD = "serialVersionUID,promotionMap,id,goodsId";
public static Map<String, Object> getUpdateIndexFieldsMap(EsGoodsIndex queryGoodsIndex, EsGoodsIndex updateGoodsIndex) {
Map<Object, Object> queryFieldsMap = new HashMap<>();
Map<Object, Object> updateFieldsMap = new HashMap<>();
for (Map.Entry<String, Field> entry : ReflectUtil.getFieldMap(EsGoodsIndex.class).entrySet()) {
Object queryFieldValue = ReflectUtil.getFieldValue(queryGoodsIndex, entry.getValue());
Object updateFieldValue = ReflectUtil.getFieldValue(updateGoodsIndex, entry.getValue());
if (queryFieldValue != null && !IGNORE_FIELD.contains(entry.getKey())) {
ReflectUtil.setFieldValue(queryFieldsMap, entry.getValue(), queryFieldValue);
}
if (updateFieldValue != null && !IGNORE_FIELD.contains(entry.getKey())) {
ReflectUtil.setFieldValue(updateFieldsMap, entry.getValue(), updateFieldValue);
}
}
return getUpdateIndexFieldsMap(queryFieldsMap, updateFieldsMap);
}
public static Map<String, Object> getUpdateIndexFieldsMap(Map<Object, Object> queryFieldsMap, Map<Object, Object> updateFieldsMap) {
Map<String, Object> updateIndexMap = new HashMap<>();
updateIndexMap.put("queryFields", queryFieldsMap);
updateIndexMap.put("updateFields", updateFieldsMap);
return updateIndexMap;
}
}

View File

@ -1,10 +1,12 @@
package cn.lili.modules.store.service;
import cn.lili.modules.store.entity.dos.Store;
import cn.lili.modules.store.entity.dos.StoreDetail;
import cn.lili.modules.store.entity.dto.StoreAfterSaleAddressDTO;
import cn.lili.modules.store.entity.dto.StoreSettingDTO;
import cn.lili.modules.store.entity.vos.StoreBasicInfoVO;
import cn.lili.modules.store.entity.vos.StoreDetailVO;
import cn.lili.modules.store.entity.vos.StoreManagementCategoryVO;
import cn.lili.modules.store.entity.vos.StoreOtherVO;
import com.baomidou.mybatisplus.extension.service.IService;
@ -95,7 +97,7 @@ public interface StoreDetailService extends IService<StoreDetail> {
* @param storeId 店铺ID
* @return 店铺经营范围
*/
List goodsManagementCategory(String storeId);
List<StoreManagementCategoryVO> goodsManagementCategory(String storeId);
/**
* 获取店铺其他信息
@ -104,4 +106,11 @@ public interface StoreDetailService extends IService<StoreDetail> {
* @return 店铺其他信息
*/
StoreOtherVO getStoreOtherVO(String storeId);
/**
* 更新店铺内所有商品信息
*
* @param store 店铺信息
*/
void updateStoreGoodsInfo(Store store);
}

View File

@ -1,10 +1,18 @@
package cn.lili.modules.store.serviceimpl;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONUtil;
import cn.lili.common.properties.RocketmqCustomProperties;
import cn.lili.common.security.AuthUser;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.utils.BeanUtil;
import cn.lili.modules.goods.entity.dos.Category;
import cn.lili.modules.goods.entity.dos.Goods;
import cn.lili.modules.goods.entity.dos.GoodsSku;
import cn.lili.modules.goods.service.CategoryService;
import cn.lili.modules.goods.service.GoodsService;
import cn.lili.modules.goods.service.GoodsSkuService;
import cn.lili.modules.search.utils.EsIndexUtil;
import cn.lili.modules.store.entity.dos.Store;
import cn.lili.modules.store.entity.dos.StoreDetail;
import cn.lili.modules.store.entity.dto.StoreAfterSaleAddressDTO;
@ -16,16 +24,20 @@ import cn.lili.modules.store.entity.vos.StoreOtherVO;
import cn.lili.modules.store.mapper.StoreDetailMapper;
import cn.lili.modules.store.service.StoreDetailService;
import cn.lili.modules.store.service.StoreService;
import cn.lili.rocketmq.RocketmqSendCallbackBuilder;
import cn.lili.rocketmq.tags.GoodsTagsEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
@ -49,6 +61,18 @@ public class StoreDetailServiceImpl extends ServiceImpl<StoreDetailMapper, Store
@Autowired
private CategoryService categoryService;
@Autowired
private GoodsService goodsService;
@Autowired
private GoodsSkuService goodsSkuService;
@Autowired
private RocketmqCustomProperties rocketmqCustomProperties;
@Autowired
private RocketMQTemplate rocketMQTemplate;
@Override
public StoreDetailVO getStoreDetailVO(String storeId) {
return this.baseMapper.getStoreDetail(storeId);
@ -72,7 +96,30 @@ public class StoreDetailServiceImpl extends ServiceImpl<StoreDetailMapper, Store
//修改店铺
Store store = storeService.getById(tokenUser.getStoreId());
BeanUtil.copyProperties(storeSettingDTO, store);
return storeService.updateById(store);
boolean result = storeService.updateById(store);
if (result) {
this.updateStoreGoodsInfo(store);
}
return result;
}
public void updateStoreGoodsInfo(Store store) {
goodsService.update(new LambdaUpdateWrapper<Goods>()
.eq(Goods::getStoreId, store.getId())
.set(Goods::getStoreName, store.getStoreName())
.set(Goods::getSelfOperated, store.getSelfOperated()));
goodsSkuService.update(new LambdaUpdateWrapper<GoodsSku>()
.eq(GoodsSku::getStoreId, store.getId())
.set(GoodsSku::getStoreName, store.getStoreName())
.set(GoodsSku::getSelfOperated, store.getSelfOperated()));
Map<String, Object> updateIndexFieldsMap = EsIndexUtil.getUpdateIndexFieldsMap(
MapUtil.builder().put("storeId", store.getId()).build(),
MapUtil.builder().put("storeName", store.getStoreName()).put("selfOperated", store.getSelfOperated()).build());
String destination = rocketmqCustomProperties.getGoodsTopic() + ":" + GoodsTagsEnum.UPDATE_GOODS_INDEX_FIELD.name();
//发送mq消息
rocketMQTemplate.asyncSend(destination, JSONUtil.toJsonStr(updateIndexFieldsMap), RocketmqSendCallbackBuilder.commonCallback());
}
@Override
@ -118,7 +165,7 @@ public class StoreDetailServiceImpl extends ServiceImpl<StoreDetailMapper, Store
}
@Override
public List goodsManagementCategory(String storeId) {
public List<StoreManagementCategoryVO> goodsManagementCategory(String storeId) {
//获取顶部分类列表
List<Category> categoryList = categoryService.firstCategory();

View File

@ -2,12 +2,12 @@ package cn.lili.modules.store.serviceimpl;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.security.AuthUser;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.utils.BeanUtil;
import cn.lili.common.utils.StringUtils;
import cn.lili.common.vo.PageVO;
import cn.lili.modules.goods.entity.dos.Goods;
import cn.lili.modules.goods.entity.enums.GoodsAuthEnum;
@ -39,6 +39,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Objects;
import java.util.Optional;
/**
@ -89,7 +90,7 @@ public class StoreServiceImpl extends ServiceImpl<StoreMapper, Store> implements
@Override
public StoreVO getStoreDetail() {
AuthUser currentUser = UserContext.getCurrentUser();
AuthUser currentUser = Objects.requireNonNull(UserContext.getCurrentUser());
StoreVO storeVO = this.baseMapper.getStoreDetail(currentUser.getStoreId());
storeVO.setNickName(currentUser.getNickName());
return storeVO;
@ -99,7 +100,7 @@ public class StoreServiceImpl extends ServiceImpl<StoreMapper, Store> implements
public Store add(AdminStoreApplyDTO adminStoreApplyDTO) {
//判断店铺名称是否存在
QueryWrapper queryWrapper = Wrappers.query();
QueryWrapper<Store> queryWrapper = Wrappers.query();
queryWrapper.eq("store_name", adminStoreApplyDTO.getStoreName());
if (this.getOne(queryWrapper) != null) {
throw new ServiceException(ResultCode.STORE_NAME_EXIST_ERROR);
@ -111,7 +112,7 @@ public class StoreServiceImpl extends ServiceImpl<StoreMapper, Store> implements
throw new ServiceException(ResultCode.USER_NOT_EXIST);
}
//判断是否拥有店铺
if (member.getHaveStore()) {
if (Boolean.TRUE.equals(member.getHaveStore())) {
throw new ServiceException(ResultCode.STORE_APPLY_DOUBLE_ERROR);
}
@ -138,7 +139,7 @@ public class StoreServiceImpl extends ServiceImpl<StoreMapper, Store> implements
if (storeEditDTO != null) {
//判断店铺名是否唯一
Store storeTmp = getOne(new QueryWrapper<Store>().eq("store_name", storeEditDTO.getStoreName()));
if (storeTmp != null && !StringUtils.equals(storeTmp.getId(), storeEditDTO.getStoreId())) {
if (storeTmp != null && !CharSequenceUtil.equals(storeTmp.getId(), storeEditDTO.getStoreId())) {
throw new ServiceException(ResultCode.STORE_NAME_EXIST_ERROR);
}
//修改店铺详细信息
@ -160,7 +161,10 @@ public class StoreServiceImpl extends ServiceImpl<StoreMapper, Store> implements
if (store != null) {
BeanUtil.copyProperties(storeEditDTO, store);
store.setId(storeEditDTO.getStoreId());
this.updateById(store);
boolean result = this.updateById(store);
if (result) {
storeDetailService.updateStoreGoodsInfo(store);
}
}
return store;
}
@ -232,7 +236,8 @@ public class StoreServiceImpl extends ServiceImpl<StoreMapper, Store> implements
Store store = getStoreByMember();
//如果没有申请过店铺新增店铺
if (!Optional.ofNullable(store).isPresent()) {
Member member = memberService.getById(UserContext.getCurrentUser().getId());
AuthUser authUser = Objects.requireNonNull(UserContext.getCurrentUser());
Member member = memberService.getById(authUser.getId());
store = new Store(member);
BeanUtil.copyProperties(storeCompanyDTO, store);
this.save(store);
@ -336,11 +341,12 @@ public class StoreServiceImpl extends ServiceImpl<StoreMapper, Store> implements
/**
* 获取当前登录操作的店铺
*
* @return
* @return 店铺信息
*/
private Store getStoreByMember() {
AuthUser authUser = Objects.requireNonNull(UserContext.getCurrentUser());
LambdaQueryWrapper<Store> lambdaQueryWrapper = Wrappers.lambdaQuery();
lambdaQueryWrapper.eq(Store::getMemberId, UserContext.getCurrentUser().getId());
lambdaQueryWrapper.eq(Store::getMemberId, authUser.getId());
return this.getOne(lambdaQueryWrapper);
}

View File

@ -14,6 +14,11 @@ public enum GoodsTagsEnum {
* "更新商品索引"
*/
UPDATE_GOODS_INDEX("更新商品索引"),
/**
* "更新商品索引部分字段"
*/
UPDATE_GOODS_INDEX_FIELD("更新商品索引部分字段"),
/**
* "重置商品索引"
*/

View File

@ -90,6 +90,7 @@ public class ElasticsearchController {
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());
@ -129,6 +130,10 @@ public class ElasticsearchController {
}
//初始化商品索引
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();
}

View File

@ -3,11 +3,11 @@ package cn.lili.controller.store;
import cn.lili.common.enums.ResultUtil;
import cn.lili.common.vo.PageVO;
import cn.lili.common.vo.ResultMessage;
import cn.lili.modules.goods.entity.vos.CategoryVO;
import cn.lili.modules.store.entity.dos.Store;
import cn.lili.modules.store.entity.dto.AdminStoreApplyDTO;
import cn.lili.modules.store.entity.dto.StoreEditDTO;
import cn.lili.modules.store.entity.vos.StoreDetailVO;
import cn.lili.modules.store.entity.vos.StoreManagementCategoryVO;
import cn.lili.modules.store.entity.vos.StoreSearchParams;
import cn.lili.modules.store.entity.vos.StoreVO;
import cn.lili.modules.store.service.StoreDetailService;
@ -112,7 +112,7 @@ public class StoreManagerController {
@ApiOperation(value = "查询一级分类列表")
@ApiImplicitParam(name = "storeId", value = "店铺id", required = true, dataType = "String", paramType = "path")
@GetMapping(value = "/managementCategory/{storeId}")
public ResultMessage<List<CategoryVO>> firstCategory(@PathVariable String storeId) {
public ResultMessage<List<StoreManagementCategoryVO>> firstCategory(@PathVariable String storeId) {
return ResultUtil.data(this.storeDetailService.goodsManagementCategory(storeId));
}