peng
17 小时以前 e9d5414e66da2b2a7b040c2271ba50a6705fe30c
framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsSearchServiceImpl.java
@@ -3,12 +3,19 @@
import cn.hutool.core.convert.Convert;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.lili.base.Result;
import cn.lili.cache.Cache;
import cn.lili.cache.CachePrefix;
import cn.lili.common.enums.PromotionTypeEnum;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.vo.PageVO;
import cn.lili.modules.goods.entity.enums.GoodsAuthEnum;
import cn.lili.modules.goods.entity.enums.GoodsStatusEnum;
import cn.lili.modules.lmk.domain.query.VideoGoodsEsQuery;
import cn.lili.modules.promotion.entity.dos.Coupon;
import cn.lili.modules.promotion.entity.enums.PromotionsScopeTypeEnum;
import cn.lili.modules.promotion.service.CouponService;
import cn.lili.modules.search.entity.dos.EsGoodsIndex;
import cn.lili.modules.search.entity.dos.EsGoodsRelatedInfo;
import cn.lili.modules.search.entity.dto.EsGoodsSearchDTO;
@@ -17,6 +24,7 @@
import cn.lili.modules.search.service.EsGoodsSearchService;
import cn.lili.modules.search.utils.SqlFilter;
import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.search.join.ScoreMode;
@@ -29,6 +37,7 @@
import org.elasticsearch.index.query.functionscore.FieldValueFactorFunctionBuilder;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.index.search.MultiMatchQuery;
import org.elasticsearch.search.aggregations.*;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
@@ -38,11 +47,16 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
@@ -79,6 +93,9 @@
    @Autowired
    private Cache<Object> cache;
    @Autowired
    private CouponService couponService;
    @Override
    public SearchPage<EsGoodsIndex> searchGoods(EsGoodsSearchDTO searchDTO, PageVO pageVo) {
@@ -88,16 +105,57 @@
            cache.incrementScore(CachePrefix.HOT_WORD.getPrefix(), searchDTO.getKeyword());
        }
        NativeSearchQueryBuilder searchQueryBuilder = createSearchQueryBuilder(searchDTO, pageVo);
//        searchQueryBuilder.withCollapseField("goodsId.keyword");
        if (Objects.nonNull(searchDTO.getCanFilter()) && searchDTO.getCanFilter()) {
            // 使用sn字段排序并在折叠时选择sn最小的记录
            searchQueryBuilder.withCollapseField("goodsId.keyword");
            searchQueryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));
        }
        NativeSearchQuery searchQuery = searchQueryBuilder.build();
        searchQuery.setTrackTotalHits(true);
        log.debug("searchGoods DSL:{}", searchQuery.getQuery());
        log.info("searchGoods DSL:{}", searchQuery.getQuery().toString());
        log.info("searchGoods sort:{}", searchQuery.getElasticsearchSorts().toString());
        SearchHits<EsGoodsIndex> search = restTemplate.search(searchQuery, EsGoodsIndex.class);
        return SearchHitSupport.searchPageFor(search, searchQuery.getPageable());
    }
    @Override
    public Page<EsGoodsIndex> searchGoodsByPage(EsGoodsSearchDTO searchDTO, PageVO pageVo) {
        if (PromotionTypeEnum.COUPON.name().equals(searchDTO.getPromotionType())) {
            Coupon coupon = couponService.getById(searchDTO.getPromotionsId());
            if (coupon != null) {
                if (PromotionsScopeTypeEnum.ALL.name().equals(coupon.getScopeType())) {
                    searchDTO.setPromotionType(null);
                    searchDTO.setPromotionsId(null);
                } else if (PromotionsScopeTypeEnum.PORTION_GOODS.name().equals(coupon.getScopeType())) {
                    String promotionsId = coupon.getScopeId();
                    if (cn.lili.common.utils.StringUtils.isNotBlank(promotionsId)) {
                        List<String> skuIds = new ArrayList<>(Arrays.asList(promotionsId.split(",")));
                        Page<EsGoodsIndex> resultPage = new Page<>();
                        List<EsGoodsIndex> esGoodsBySkuIds = getEsGoodsBySkuIds(skuIds, pageVo);
                        System.err.println(JSON.toJSONString(esGoodsBySkuIds));
                        resultPage.setRecords(esGoodsBySkuIds);
                        resultPage.setPages(1);
                        resultPage.setCurrent(1);
                        resultPage.setSize(1);
                        resultPage.setTotal(esGoodsBySkuIds.size());
                        return resultPage;
                    }
                } else if (PromotionsScopeTypeEnum.PORTION_SHOP_CATEGORY.name().equals(coupon.getScopeType())) {
                    searchDTO.setPromotionType(null);
                    searchDTO.setCategoryId(searchDTO.getPromotionsId());
                    searchDTO.setPromotionsId(null);
                } else if (PromotionsScopeTypeEnum.PORTION_GOODS_CATEGORY.name().equals(coupon.getScopeType())) {
                    String promotionsId = searchDTO.getPromotionsId();
                    if (cn.lili.common.utils.StringUtils.isNotBlank(promotionsId)) {
                        searchDTO.setPromotionType(null);
                        searchDTO.setCategoryId(coupon.getScopeId());
                        searchDTO.setPromotionsId(null);
                    }
                }
            }
        }
        // 判断商品索引是否存在
        if (!restTemplate.indexOps(EsGoodsIndex.class).exists()) {
            return null;
@@ -174,6 +232,38 @@
    @Override
    public EsGoodsIndex getEsGoodsById(String id) {
        return this.restTemplate.get(id, EsGoodsIndex.class);
    }
    @Override
    public Result videoGoodsEsPage(VideoGoodsEsQuery q) {
        // 判断商品索引是否存在
        if (!restTemplate.indexOps(EsGoodsIndex.class).exists()) {
            return Result.ok();
        }
        // 根据销量倒序排列
        Pageable pageable = PageRequest.of(q.getPageNumber(), q.getPageSize(), Sort.by("buyCount").descending());
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        queryBuilder.withPageable(pageable);
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        // 关键词匹配商品名称、商品编号
        if (!StringUtils.isEmpty(q.getKeyword())) {
            boolQuery.must(QueryBuilders.multiMatchQuery(q.getKeyword(), "goodsName", "sn"));
        }
        if (q.getSearchFromSelfStore()) {
            // 如果只查自家店铺商品
            boolQuery.must(QueryBuilders.termQuery("storeId", UserContext.getCurrentUser().getStoreId()));
        }
        queryBuilder.withQuery(boolQuery);
        NativeSearchQuery query = queryBuilder.build();
        SearchHits<EsGoodsIndex> searchHits = restTemplate.search(query, EsGoodsIndex.class);
        List<EsGoodsIndex> data = searchHits.stream().map(hit -> hit.getContent()).collect(Collectors.toList());
        return Result.ok().data(data).total(searchHits.getTotalHits());
    }
    /**
@@ -411,8 +501,16 @@
                FunctionScoreQueryBuilder.FilterFunctionBuilder[] builders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[filterFunctionBuilders.size()];
                filterFunctionBuilders.toArray(builders);
                FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(QueryBuilders.matchAllQuery(), builders)
                        .scoreMode(FunctionScoreQuery.ScoreMode.SUM)
                        .setMinScore(2);
                        .scoreMode(FunctionScoreQuery.ScoreMode.SUM);
                functionScoreQueryBuilder.setMinScore(0);
//                if (CharSequenceUtil.isNotEmpty(searchDTO.getPromotionsId()) && CharSequenceUtil.isNotEmpty(searchDTO.getPromotionType())) {
//                    functionScoreQueryBuilder.setMinScore(0);
//                }else if (cn.lili.common.utils.StringUtils.isNotBlank(searchDTO.getCategoryId())){
//                    functionScoreQueryBuilder.setMinScore(0);
//                }
//                else {
//                    functionScoreQueryBuilder.setMinScore(2);
//                }
                //聚合搜索则将结果放入过滤条件
                filterBuilder.must(functionScoreQueryBuilder);
            } else {
@@ -425,7 +523,7 @@
            if (pageVo != null && CharSequenceUtil.isNotEmpty(pageVo.getOrder()) && CharSequenceUtil.isNotEmpty(pageVo.getSort())) {
                nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(pageVo.getSort()).order(SortOrder.valueOf(pageVo.getOrder().toUpperCase())));
                nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(pageVo.getSort()).order(SortOrder.valueOf(pageVo.getOrder().toUpperCase())).missing("_last"));
            } else {
                nativeSearchQueryBuilder.withSort(SortBuilders.scoreSort().order(SortOrder.DESC));
            }
@@ -518,6 +616,23 @@
        if (CharSequenceUtil.isNotEmpty(searchDTO.getPromotionsId()) && CharSequenceUtil.isNotEmpty(searchDTO.getPromotionType())) {
            filterBuilder.must(QueryBuilders.wildcardQuery("promotionMapJson", "*" + searchDTO.getPromotionType() + "-" + searchDTO.getPromotionsId() + "*"));
        }
        if (Objects.nonNull(searchDTO.getNeedFilterPre()) && searchDTO.getNeedFilterPre()) {
            // 转换为当天 00:00:00 的时间戳(毫秒)
            long time = LocalDate.now().atStartOfDay(ZoneId.systemDefault())
                    .toInstant()
                    .toEpochMilli();
            // 条件2:预售结束时间 >= 当前时间 OR 结束时间为空
            filterBuilder.must(QueryBuilders.boolQuery()
                    .should(QueryBuilders.rangeQuery("preSaleEndDate").gte(time))
                    .should(QueryBuilders.boolQuery()
                            .mustNot(QueryBuilders.existsQuery("preSaleEndDate"))));
            // 条件1:预售开始时间 <= 当前时间 OR 开始时间为空
            filterBuilder.must(QueryBuilders.boolQuery()
                    .should(QueryBuilders.rangeQuery("preSaleBeginDate").lte(time))
                    .should(QueryBuilders.boolQuery()
                            .mustNot(QueryBuilders.existsQuery("preSaleBeginDate"))));
        }
        //价格区间判定
        if (CharSequenceUtil.isNotEmpty(searchDTO.getPrice())) {
            String[] prices = searchDTO.getPrice().split("_");
@@ -604,7 +719,7 @@
        filterFunctionBuilders.toArray(builders);
        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(goodsNameMatchQuery, builders)
                .scoreMode(FunctionScoreQuery.ScoreMode.SUM)
                .setMinScore(2);
                .setMinScore(0);
        //聚合搜索则将结果放入过滤条件
        filterBuilder.must(functionScoreQueryBuilder);
        filterBuilder.should(QueryBuilders.boolQuery().should(QueryBuilders.matchPhraseQuery("goodsName", keyword).boost(10)));