From 336232541a9d1f3945a6ed44a06b4999495b8352 Mon Sep 17 00:00:00 2001 From: liujiang <569804566@qq.com> Date: Mon, 24 Nov 2025 00:01:00 +0800 Subject: [PATCH] =?UTF-8?q?master=EF=BC=9A=E6=89=B9=E9=87=8F=E6=93=8D?= =?UTF-8?q?=E4=BD=9CES=E4=B8=AD=E7=9A=84=E6=95=B0=E6=8D=AE=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=AE=8C=E5=96=84=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xkt/ElasticSearchController.java | 47 ++- .../vo/elasticSearch/EsProdBatchCreateVO.java | 26 ++ .../vo/elasticSearch/EsProdBatchDeleteVO.java | 26 ++ .../src/main/resources/application-local.yml | 4 +- .../elasticSearch/EsProdBatchCreateDTO.java | 23 ++ .../elasticSearch/EsProdBatchDeleteDTO.java | 23 ++ .../xkt/service/IElasticSearchService.java | 25 +- .../impl/ElasticSearchServiceImpl.java | 270 +++++++++++++----- 8 files changed, 352 insertions(+), 92 deletions(-) create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/elasticSearch/EsProdBatchCreateVO.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/elasticSearch/EsProdBatchDeleteVO.java create mode 100644 xkt/src/main/java/com/ruoyi/xkt/dto/elasticSearch/EsProdBatchCreateDTO.java create mode 100644 xkt/src/main/java/com/ruoyi/xkt/dto/elasticSearch/EsProdBatchDeleteDTO.java diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ElasticSearchController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ElasticSearchController.java index fcfcbc93a..9e63c8529 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ElasticSearchController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ElasticSearchController.java @@ -2,25 +2,19 @@ package com.ruoyi.web.controller.xkt; import cn.hutool.core.bean.BeanUtil; import com.ruoyi.common.annotation.Log; -import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.controller.XktBaseController; import com.ruoyi.common.core.domain.R; -import com.ruoyi.common.core.page.Page; import com.ruoyi.common.enums.BusinessType; -import com.ruoyi.web.controller.xkt.vo.notice.*; -import com.ruoyi.xkt.dto.notice.*; +import com.ruoyi.web.controller.xkt.vo.elasticSearch.EsProdBatchCreateVO; +import com.ruoyi.web.controller.xkt.vo.elasticSearch.EsProdBatchDeleteVO; +import com.ruoyi.xkt.dto.elasticSearch.EsProdBatchCreateDTO; +import com.ruoyi.xkt.dto.elasticSearch.EsProdBatchDeleteDTO; import com.ruoyi.xkt.service.IElasticSearchService; -import com.ruoyi.xkt.service.INoticeService; -import com.ruoyi.xkt.service.IStoreProductService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import java.util.List; - /** * ES相关处理 * @@ -34,10 +28,35 @@ public class ElasticSearchController extends XktBaseController { final IElasticSearchService esService; @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") - @Log(title = "往ES中批量新增数据", businessType = BusinessType.INSERT) - @PutMapping("/batch") - public R batchCreate() { - return R.ok(esService.batchCreate()); + @Log(title = "ES批量新增数据", businessType = BusinessType.INSERT) + @PutMapping("/batch-create") + public R batchCreate(@RequestParam(required = false) Long storeId) { + esService.batchCreate(storeId); + return R.ok(); + } + + @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") + @Log(title = "ES批量新增数据(特定商品)", businessType = BusinessType.INSERT) + @PutMapping("/prod/batch-create") + public R batchCreateProd(@Validated @RequestBody EsProdBatchCreateVO createVO) { + esService.batchCreateProd(BeanUtil.toBean(createVO, EsProdBatchCreateDTO.class)); + return R.ok(); + } + + @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") + @Log(title = "ES批量删除数据", businessType = BusinessType.DELETE) + @DeleteMapping("/batch-delete") + public R batchDelete(@RequestParam(required = false) Long storeId) { + esService.batchDelete(storeId); + return R.ok(); + } + + @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") + @Log(title = "ES批量删除数据(特定商品)", businessType = BusinessType.DELETE) + @DeleteMapping("/prod/batch-delete") + public R batchDeleteProd(@Validated @RequestBody EsProdBatchDeleteVO deleteVO) { + esService.batchDeleteProd(BeanUtil.toBean(deleteVO, EsProdBatchDeleteDTO.class)); + return R.ok(); } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/elasticSearch/EsProdBatchCreateVO.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/elasticSearch/EsProdBatchCreateVO.java new file mode 100644 index 000000000..1cfc13c1c --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/elasticSearch/EsProdBatchCreateVO.java @@ -0,0 +1,26 @@ +package com.ruoyi.web.controller.xkt.vo.elasticSearch; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@Data +@ApiModel +public class EsProdBatchCreateVO { + + @NotNull(message = "档口ID不能为空") + @ApiModelProperty(value = "档口ID", required = true) + private Long storeId; + @NotNull(message = "商品ID列表不能为空") + @ApiModelProperty(value = "商品ID列表", required = true) + private List storeProdIdList; + +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/elasticSearch/EsProdBatchDeleteVO.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/elasticSearch/EsProdBatchDeleteVO.java new file mode 100644 index 000000000..a928cd79e --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/vo/elasticSearch/EsProdBatchDeleteVO.java @@ -0,0 +1,26 @@ +package com.ruoyi.web.controller.xkt.vo.elasticSearch; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@Data +@ApiModel +public class EsProdBatchDeleteVO { + + @NotNull(message = "档口ID不能为空") + @ApiModelProperty(value = "档口ID", required = true) + private Long storeId; + @NotNull(message = "商品ID列表不能为空") + @ApiModelProperty(value = "商品ID列表", required = true) + private List storeProdIdList; + +} diff --git a/ruoyi-admin/src/main/resources/application-local.yml b/ruoyi-admin/src/main/resources/application-local.yml index 34af175db..1ba82219f 100644 --- a/ruoyi-admin/src/main/resources/application-local.yml +++ b/ruoyi-admin/src/main/resources/application-local.yml @@ -53,10 +53,10 @@ ocr: endpoint: ocr-api.cn-hangzhou.aliyuncs.com es: #多个用","分割 - hosts: es-cn-em94bkrrl0005djma.public.elasticsearch.aliyuncs.com:9200 + hosts: 47.99.90.75:9200 ssl: false username: elastic - password: 0tP&3!GZZDMrglBm&kWJyw + password: wXd3iRUcqHzxZPtKsDRn maxConnTotal: 4 maxConnPerRoute: 2 indexName: dev_product_info diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/elasticSearch/EsProdBatchCreateDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/elasticSearch/EsProdBatchCreateDTO.java new file mode 100644 index 000000000..4476f120e --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/elasticSearch/EsProdBatchCreateDTO.java @@ -0,0 +1,23 @@ +package com.ruoyi.xkt.dto.elasticSearch; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@Data +@ApiModel +public class EsProdBatchCreateDTO { + + @ApiModelProperty(value = "档口ID") + private Long storeId; + @ApiModelProperty(value = "商品ID列表") + private List storeProdIdList; + +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/elasticSearch/EsProdBatchDeleteDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/elasticSearch/EsProdBatchDeleteDTO.java new file mode 100644 index 000000000..105885649 --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/elasticSearch/EsProdBatchDeleteDTO.java @@ -0,0 +1,23 @@ +package com.ruoyi.xkt.dto.elasticSearch; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * @author liujiang + * @version v1.0 + * @date 2025/3/27 15:12 + */ +@Data +@ApiModel +public class EsProdBatchDeleteDTO { + + @ApiModelProperty(value = "档口ID") + private Long storeId; + @ApiModelProperty(value = "商品ID列表") + private List storeProdIdList; + +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/IElasticSearchService.java b/xkt/src/main/java/com/ruoyi/xkt/service/IElasticSearchService.java index c100f19e3..eeb2eef26 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/IElasticSearchService.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/IElasticSearchService.java @@ -1,6 +1,8 @@ package com.ruoyi.xkt.service; import com.ruoyi.common.core.page.Page; +import com.ruoyi.xkt.dto.elasticSearch.EsProdBatchCreateDTO; +import com.ruoyi.xkt.dto.elasticSearch.EsProdBatchDeleteDTO; import com.ruoyi.xkt.dto.es.ESProductDTO; import com.ruoyi.xkt.dto.website.IndexSearchDTO; @@ -17,9 +19,17 @@ public interface IElasticSearchService { /** * 批量往ES新增商品数据 * + * @param storeId 档口ID * @return Integer */ - Integer batchCreate(); + void batchCreate(Long storeId); + + /** + * 批量删除商品数据 + * + * @param storeId 档口ID + */ + void batchDelete(Long storeId); /** * 网站首页搜索 @@ -28,4 +38,17 @@ public interface IElasticSearchService { */ Page search(IndexSearchDTO searchDTO) throws IOException; + /** + * 批量新增商品数据 + * + * @param createProdDTO 新增商品入参 + */ + void batchCreateProd(EsProdBatchCreateDTO createProdDTO); + + /** + * 批量删除商品数据 + * + * @param deleteDTO 删除商品入参 + */ + void batchDeleteProd(EsProdBatchDeleteDTO deleteDTO); } diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/impl/ElasticSearchServiceImpl.java b/xkt/src/main/java/com/ruoyi/xkt/service/impl/ElasticSearchServiceImpl.java index 17a46e917..f672ff335 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/impl/ElasticSearchServiceImpl.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/impl/ElasticSearchServiceImpl.java @@ -10,7 +10,9 @@ import co.elastic.clients.elasticsearch.core.bulk.BulkOperation; import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.constant.HttpStatus; import com.ruoyi.common.core.page.Page; +import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.framework.es.EsClientWrapper; import com.ruoyi.framework.notice.fs.FsNotice; @@ -18,6 +20,8 @@ import com.ruoyi.xkt.domain.Store; import com.ruoyi.xkt.domain.StoreProduct; import com.ruoyi.xkt.domain.StoreProductCategoryAttribute; import com.ruoyi.xkt.domain.SysProductCategory; +import com.ruoyi.xkt.dto.elasticSearch.EsProdBatchCreateDTO; +import com.ruoyi.xkt.dto.elasticSearch.EsProdBatchDeleteDTO; import com.ruoyi.xkt.dto.es.ESProductDTO; import com.ruoyi.xkt.dto.storeProdColorPrice.StoreProdMinPriceDTO; import com.ruoyi.xkt.dto.storeProductFile.StoreProdMainPicDTO; @@ -67,89 +71,86 @@ public class ElasticSearchServiceImpl implements IElasticSearchService { /** * 批量往ES新增商品数据 * + * @param storeId 档口ID * @return Integer */ @Override @Transactional - public Integer batchCreate() { - List storeProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper() - .eq(StoreProduct::getDelFlag, Constants.UNDELETED)); + public void batchCreate(Long storeId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .eq(StoreProduct::getDelFlag, Constants.UNDELETED); + if (ObjectUtils.isNotEmpty(storeId)) { + wrapper.eq(StoreProduct::getStoreId, storeId); + } + List storeProdList = this.storeProdMapper.selectList(wrapper); if (CollectionUtils.isEmpty(storeProdList)) { - return 0; + throw new ServiceException("商品不存在", HttpStatus.ERROR); } - final List storeProdIdList = storeProdList.stream().map(StoreProduct::getId).map(String::valueOf).collect(Collectors.toList()); - // 所有的分类 - List prodCateList = this.prodCateMapper.selectList(new LambdaQueryWrapper() - .eq(SysProductCategory::getDelFlag, Constants.UNDELETED)); - Map prodCateMap = prodCateList.stream().collect(Collectors.toMap(SysProductCategory::getId, x -> x)); - List mainPicDTOList = this.prodFileMapper.selectMainPicByStoreProdIdList(storeProdIdList.stream() - .map(Long::valueOf).collect(Collectors.toList()), FileType.MAIN_PIC.getValue(), Constants.ORDER_NUM_1); - Map mainPicMap = mainPicDTOList.stream().collect(Collectors.toMap(StoreProdMainPicDTO::getStoreProdId, StoreProdMainPicDTO::getFileUrl)); - // 获取当前商品最低价格 - Map prodMinPriceMap = this.prodColorSizeMapper.selectStoreProdMinPriceList(storeProdIdList).stream().collect(Collectors - .toMap(StoreProdMinPriceDTO::getStoreProdId, StoreProdMinPriceDTO::getPrice)); - // 档口商品的属性map - Map cateAttrMap = this.prodCateAttrMapper.selectList(new LambdaQueryWrapper() - .eq(StoreProductCategoryAttribute::getDelFlag, Constants.UNDELETED).in(StoreProductCategoryAttribute::getStoreProdId, storeProdIdList)) - .stream().collect(Collectors.toMap(StoreProductCategoryAttribute::getStoreProdId, x -> x)); - // 档口商品对应的档口 - Map storeMap = this.storeMapper.selectList(new LambdaQueryWrapper().eq(Store::getDelFlag, Constants.UNDELETED) - .in(Store::getId, storeProdList.stream().map(StoreProduct::getStoreId).collect(Collectors.toList()))) - .stream().collect(Collectors.toMap(Store::getId, x -> x)); - List esProductDTOList = new ArrayList<>(); - for (StoreProduct product : storeProdList) { - final SysProductCategory cate = prodCateMap.get(product.getProdCateId()); - final SysProductCategory parCate = ObjectUtils.isEmpty(cate) ? null : prodCateMap.get(cate.getParentId()); - final Store store = storeMap.get(product.getStoreId()); - final BigDecimal prodMinPrice = prodMinPriceMap.get(product.getId()); - final StoreProductCategoryAttribute cateAttr = cateAttrMap.get(product.getId()); - ESProductDTO esProductDTO = new ESProductDTO().setStoreProdId(product.getId().toString()).setProdArtNum(product.getProdArtNum()) - .setHasVideo(Boolean.FALSE).setProdCateId(product.getProdCateId().toString()).setCreateTime(DateUtils.getTime()) - .setProdCateName(ObjectUtils.isNotEmpty(cate) ? cate.getName() : "") - .setSaleWeight(WEIGHT_DEFAULT_ZERO.toString()).setRecommendWeight(WEIGHT_DEFAULT_ZERO.toString()) - .setPopularityWeight(WEIGHT_DEFAULT_ZERO.toString()) - .setMainPicUrl(mainPicMap.get(product.getId())).setMainPicName("").setMainPicSize(BigDecimal.ZERO) - .setParCateId(ObjectUtils.isNotEmpty(parCate) ? parCate.getId().toString() : "") - .setParCateName(ObjectUtils.isNotEmpty(parCate) ? parCate.getName() : "") - .setProdPrice(ObjectUtils.isNotEmpty(prodMinPrice) ? prodMinPrice.toString() : "") - .setSeason(ObjectUtils.isNotEmpty(cateAttr) ? cateAttr.getSuitableSeason() : "") - .setProdStatus(product.getProdStatus().toString()).setStoreId(product.getStoreId().toString()) - .setStoreWeight(ObjectUtils.isNotEmpty(store) ? store.getStoreWeight().toString() : WEIGHT_DEFAULT_ZERO.toString()) - .setStoreName(ObjectUtils.isNotEmpty(store) ? store.getStoreName() : "") - .setStyle(ObjectUtils.isNotEmpty(cateAttr) ? cateAttr.getStyle() : "") - .setProdTitle(product.getProdTitle()); - if (ObjectUtils.isNotEmpty(cateAttr) && StringUtils.isNotBlank(cateAttr.getStyle())) { - esProductDTO.setTags(Collections.singletonList(cateAttr.getStyle())); - } - esProductDTOList.add(esProductDTO); - } - // 构建批量操作请求 - List bulkOperations = new ArrayList<>(); - for (ESProductDTO esProductDTO : esProductDTOList) { - BulkOperation bulkOperation = new BulkOperation.Builder() - .index(i -> i.id(esProductDTO.getStoreProdId()).index(ES_INDEX_NAME).document(esProductDTO)) - .build(); - bulkOperations.add(bulkOperation); - } - // 执行批量插入 - try { - BulkResponse response = esClientWrapper.getEsClient().bulk(b -> b.index(ES_INDEX_NAME).operations(bulkOperations)); - log.info("全量新增到 ES 成功的 id列表: {}", response.items().stream().map(BulkResponseItem::id).collect(Collectors.toList())); - // 有哪些没执行成功的,需要发飞书通知 - List successIdList = response.items().stream().map(BulkResponseItem::id).collect(Collectors.toList()); - List unExeIdList = storeProdIdList.stream().map(String::valueOf).filter(x -> !successIdList.contains(x)).collect(Collectors.toList()); - if (CollectionUtils.isNotEmpty(unExeIdList)) { - fsNotice.sendMsg2DefaultChat("全量新增商品到 ES 失败", "以下storeProdId未执行成功: " + unExeIdList); - } else { - fsNotice.sendMsg2DefaultChat("全量新增商品到 ES 成功", "共处理 " + response.items().size() + " 条记录"); - } - } catch (Exception e) { - log.error("批量新增到 ES 失败", e); - fsNotice.sendMsg2DefaultChat("全量新增商品到 ES 失败", e.getMessage()); - } - return 1; + // 创建商品到ES中 + this.createProdToEs(storeProdList); } + /** + * 批量新增商品数据 + * + * @param createProdDTO 新增商品入参 + * @return Integer + */ + @Override + @Transactional + public void batchCreateProd(EsProdBatchCreateDTO createProdDTO) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .eq(StoreProduct::getDelFlag, Constants.UNDELETED).eq(StoreProduct::getStoreId, createProdDTO.getStoreId()) + .in(StoreProduct::getId, createProdDTO.getStoreProdIdList()); + List storeProdList = this.storeProdMapper.selectList(wrapper); + if (CollectionUtils.isEmpty(storeProdList)) { + throw new ServiceException("商品不存在", HttpStatus.ERROR); + } + // 创建商品到ES中 + this.createProdToEs(storeProdList); + } + + /** + * 批量删除商品数据 + * + * @param storeId 档口ID + * @return Integer + */ + @Override + @Transactional + public void batchDelete(Long storeId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() + .eq(StoreProduct::getDelFlag, Constants.UNDELETED); + if (ObjectUtils.isNotEmpty(storeId)) { + queryWrapper.eq(StoreProduct::getStoreId, storeId); + } + List storeProdList = this.storeProdMapper.selectList(queryWrapper); + if (CollectionUtils.isEmpty(storeProdList)) { + throw new ServiceException("商品不存在", HttpStatus.ERROR); + } + // 批量删除商品 + this.deleteEsProd(storeProdList); + } + + + /** + * 批量删除商品数据 + * + * @param deleteDTO 删除商品入参 + */ + @Override + @Transactional + public void batchDeleteProd(EsProdBatchDeleteDTO deleteDTO) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() + .eq(StoreProduct::getDelFlag, Constants.UNDELETED).eq(StoreProduct::getStoreId, deleteDTO.getStoreId()) + .in(StoreProduct::getId, deleteDTO.getStoreProdIdList()); + List storeProdList = this.storeProdMapper.selectList(queryWrapper); + if (CollectionUtils.isEmpty(storeProdList)) { + throw new ServiceException("商品不存在", HttpStatus.ERROR); + } + // 批量删除商品 + this.deleteEsProd(storeProdList); + } /** @@ -288,6 +289,7 @@ public class ElasticSearchServiceImpl implements IElasticSearchService { /** * 处理混合文本搜索(中英文数字混合) + * * @param searchTerm * @param searchBoolQuery */ @@ -331,6 +333,7 @@ public class ElasticSearchServiceImpl implements IElasticSearchService { /** * 处理短英文数字搜索 + * * @param searchTerm * @param searchBoolQuery */ @@ -362,6 +365,7 @@ public class ElasticSearchServiceImpl implements IElasticSearchService { /** * 处理短中文搜索 + * * @param searchTerm * @param searchBoolQuery */ @@ -377,6 +381,7 @@ public class ElasticSearchServiceImpl implements IElasticSearchService { /** * 处理标准长文本搜索 + * * @param searchTerm * @param searchBoolQuery */ @@ -393,6 +398,7 @@ public class ElasticSearchServiceImpl implements IElasticSearchService { /** * 判断是否包含中文 + * * @param str * @return */ @@ -409,6 +415,7 @@ public class ElasticSearchServiceImpl implements IElasticSearchService { /** * 判断是否包含英文或数字 + * * @param str * @return */ @@ -425,6 +432,7 @@ public class ElasticSearchServiceImpl implements IElasticSearchService { /** * 提取英文数字部分 + * * @param str * @return */ @@ -442,6 +450,7 @@ public class ElasticSearchServiceImpl implements IElasticSearchService { /** * 提取中文部分 + * * @param str * @return */ @@ -457,4 +466,115 @@ public class ElasticSearchServiceImpl implements IElasticSearchService { return sb.toString(); } + /** + * 创建商品数据到ES中 + * + * @param storeProdList + */ + private void createProdToEs(List storeProdList) { + final List storeProdIdList = storeProdList.stream().map(StoreProduct::getId).map(String::valueOf).collect(Collectors.toList()); + // 所有的分类 + List prodCateList = this.prodCateMapper.selectList(new LambdaQueryWrapper() + .eq(SysProductCategory::getDelFlag, Constants.UNDELETED)); + Map prodCateMap = prodCateList.stream().collect(Collectors.toMap(SysProductCategory::getId, x -> x)); + List mainPicDTOList = this.prodFileMapper.selectMainPicByStoreProdIdList(storeProdIdList.stream() + .map(Long::valueOf).collect(Collectors.toList()), FileType.MAIN_PIC.getValue(), Constants.ORDER_NUM_1); + Map mainPicMap = mainPicDTOList.stream().collect(Collectors.toMap(StoreProdMainPicDTO::getStoreProdId, StoreProdMainPicDTO::getFileUrl)); + // 获取当前商品最低价格 + Map prodMinPriceMap = this.prodColorSizeMapper.selectStoreProdMinPriceList(storeProdIdList).stream().collect(Collectors + .toMap(StoreProdMinPriceDTO::getStoreProdId, StoreProdMinPriceDTO::getPrice)); + // 档口商品的属性map + Map cateAttrMap = this.prodCateAttrMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProductCategoryAttribute::getDelFlag, Constants.UNDELETED).in(StoreProductCategoryAttribute::getStoreProdId, storeProdIdList)) + .stream().collect(Collectors.toMap(StoreProductCategoryAttribute::getStoreProdId, x -> x)); + // 档口商品对应的档口 + Map storeMap = this.storeMapper.selectList(new LambdaQueryWrapper().eq(Store::getDelFlag, Constants.UNDELETED) + .in(Store::getId, storeProdList.stream().map(StoreProduct::getStoreId).collect(Collectors.toList()))) + .stream().collect(Collectors.toMap(Store::getId, x -> x)); + List esProductDTOList = new ArrayList<>(); + for (StoreProduct product : storeProdList) { + final SysProductCategory cate = prodCateMap.get(product.getProdCateId()); + final SysProductCategory parCate = ObjectUtils.isEmpty(cate) ? null : prodCateMap.get(cate.getParentId()); + final Store store = storeMap.get(product.getStoreId()); + final BigDecimal prodMinPrice = prodMinPriceMap.get(product.getId()); + final StoreProductCategoryAttribute cateAttr = cateAttrMap.get(product.getId()); + ESProductDTO esProductDTO = new ESProductDTO().setStoreProdId(product.getId().toString()).setProdArtNum(product.getProdArtNum()) + .setHasVideo(Boolean.FALSE).setProdCateId(product.getProdCateId().toString()).setCreateTime(DateUtils.getTime()) + .setProdCateName(ObjectUtils.isNotEmpty(cate) ? cate.getName() : "") + .setSaleWeight(WEIGHT_DEFAULT_ZERO.toString()).setRecommendWeight(WEIGHT_DEFAULT_ZERO.toString()) + .setPopularityWeight(WEIGHT_DEFAULT_ZERO.toString()) + .setMainPicUrl(mainPicMap.get(product.getId())).setMainPicName("").setMainPicSize(BigDecimal.ZERO) + .setParCateId(ObjectUtils.isNotEmpty(parCate) ? parCate.getId().toString() : "") + .setParCateName(ObjectUtils.isNotEmpty(parCate) ? parCate.getName() : "") + .setProdPrice(ObjectUtils.isNotEmpty(prodMinPrice) ? prodMinPrice.toString() : "") + .setSeason(ObjectUtils.isNotEmpty(cateAttr) ? cateAttr.getSuitableSeason() : "") + .setProdStatus(product.getProdStatus().toString()).setStoreId(product.getStoreId().toString()) + .setStoreWeight(ObjectUtils.isNotEmpty(store) ? store.getStoreWeight().toString() : WEIGHT_DEFAULT_ZERO.toString()) + .setStoreName(ObjectUtils.isNotEmpty(store) ? store.getStoreName() : "") + .setStyle(ObjectUtils.isNotEmpty(cateAttr) ? cateAttr.getStyle() : "") + .setProdTitle(product.getProdTitle()); + if (ObjectUtils.isNotEmpty(cateAttr) && StringUtils.isNotBlank(cateAttr.getStyle())) { + esProductDTO.setTags(Collections.singletonList(cateAttr.getStyle())); + } + esProductDTOList.add(esProductDTO); + } + // 构建批量操作请求 + List bulkOperations = new ArrayList<>(); + for (ESProductDTO esProductDTO : esProductDTOList) { + BulkOperation bulkOperation = new BulkOperation.Builder() + .index(i -> i.id(esProductDTO.getStoreProdId()).index(ES_INDEX_NAME).document(esProductDTO)) + .build(); + bulkOperations.add(bulkOperation); + } + // 执行批量插入 + try { + BulkResponse response = esClientWrapper.getEsClient().bulk(b -> b.index(ES_INDEX_NAME).operations(bulkOperations)); + log.info("全量新增到 ES 成功的 id列表: {}", response.items().stream().map(BulkResponseItem::id).collect(Collectors.toList())); + // 有哪些没执行成功的,需要发飞书通知 + List successIdList = response.items().stream().map(BulkResponseItem::id).collect(Collectors.toList()); + List unExeIdList = storeProdIdList.stream().map(String::valueOf).filter(x -> !successIdList.contains(x)).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(unExeIdList)) { + fsNotice.sendMsg2DefaultChat("全量新增商品到 ES 失败", "以下storeProdId未执行成功: " + unExeIdList); + } else { + fsNotice.sendMsg2DefaultChat("全量新增商品到 ES 成功", "共处理 " + response.items().size() + " 条记录"); + } + } catch (Exception e) { + log.error("批量新增到 ES 失败", e); + fsNotice.sendMsg2DefaultChat("全量新增商品到 ES 失败", e.getMessage()); + } + } + + /** + * 批量删除商品数据 + * + * @param storeProdList 批量删除商品 + */ + private void deleteEsProd(List storeProdList) { + final List storeProdIdList = storeProdList.stream().map(StoreProduct::getId).map(String::valueOf).collect(Collectors.toList()); + // 构建批量删除操作请求 + List bulkOperations = new ArrayList<>(); + for (String storeProdId : storeProdIdList) { + BulkOperation bulkOperation = new BulkOperation.Builder() + .delete(d -> d.id(storeProdId).index(ES_INDEX_NAME)) + .build(); + bulkOperations.add(bulkOperation); + } + // 执行批量删除 + try { + BulkResponse response = esClientWrapper.getEsClient().bulk(b -> b.index(ES_INDEX_NAME).operations(bulkOperations)); + log.info("全量删除 ES 成功的 id列表: {}", response.items().stream().map(BulkResponseItem::id).collect(Collectors.toList())); + // 有哪些没执行成功的,需要发飞书通知 + List successIdList = response.items().stream().map(BulkResponseItem::id).collect(Collectors.toList()); + List unExeIdList = storeProdIdList.stream().map(String::valueOf).filter(x -> !successIdList.contains(x)).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(unExeIdList)) { + fsNotice.sendMsg2DefaultChat("全量删除商品到 ES 失败", "以下storeProdId未执行成功: " + unExeIdList); + } else { + fsNotice.sendMsg2DefaultChat("全量删除商品到 ES 成功", "共处理 " + response.items().size() + " 条记录"); + } + } catch (Exception e) { + log.error("批量删除 ES 失败", e); + fsNotice.sendMsg2DefaultChat("全量删除商品到 ES 失败", e.getMessage()); + } + } + }