From 318cc0456628c0e657f5dfd2fec74ea0dd6063c7 Mon Sep 17 00:00:00 2001 From: paulGao Date: Wed, 1 Sep 2021 19:07:30 +0800 Subject: [PATCH] add order by goods parameters field sort to aggregation elasticsearch --- .../goods/GoodsBuyerController.java | 5 ++- .../goods/entity/dto/GoodsParamsDTO.java | 5 ++- .../goods/entity/dto/GoodsParamsItemDTO.java | 10 +++-- .../search/entity/dos/EsGoodsAttribute.java | 21 ++++++--- .../search/entity/dos/EsGoodsIndex.java | 3 +- .../search/service/EsGoodsSearchService.java | 4 +- .../serviceimpl/EsGoodsIndexServiceImpl.java | 37 ++++++++------- .../serviceimpl/EsGoodsSearchServiceImpl.java | 45 +++++++++---------- 8 files changed, 73 insertions(+), 57 deletions(-) diff --git a/buyer-api/src/main/java/cn/lili/controller/goods/GoodsBuyerController.java b/buyer-api/src/main/java/cn/lili/controller/goods/GoodsBuyerController.java index 95523e59..cfc844dc 100644 --- a/buyer-api/src/main/java/cn/lili/controller/goods/GoodsBuyerController.java +++ b/buyer-api/src/main/java/cn/lili/controller/goods/GoodsBuyerController.java @@ -24,6 +24,7 @@ import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; +import org.springframework.data.elasticsearch.core.SearchPage; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -99,9 +100,9 @@ public class GoodsBuyerController { @ApiOperation(value = "从ES中获取商品信息") @GetMapping("/es") - public ResultMessage> getGoodsByPageFromEs(EsGoodsSearchDTO goodsSearchParams, PageVO pageVO) { + public ResultMessage> getGoodsByPageFromEs(EsGoodsSearchDTO goodsSearchParams, PageVO pageVO) { pageVO.setNotConvert(true); - Page esGoodsIndices = goodsSearchService.searchGoods(goodsSearchParams, pageVO); + SearchPage esGoodsIndices = goodsSearchService.searchGoods(goodsSearchParams, pageVO); return ResultUtil.data(esGoodsIndices); } diff --git a/framework/src/main/java/cn/lili/modules/goods/entity/dto/GoodsParamsDTO.java b/framework/src/main/java/cn/lili/modules/goods/entity/dto/GoodsParamsDTO.java index 77bc42b3..68313ebd 100644 --- a/framework/src/main/java/cn/lili/modules/goods/entity/dto/GoodsParamsDTO.java +++ b/framework/src/main/java/cn/lili/modules/goods/entity/dto/GoodsParamsDTO.java @@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import java.io.Serializable; import java.util.List; /** @@ -15,7 +16,9 @@ import java.util.List; */ @Data @ApiModel(value = "商品参数分组") -public class GoodsParamsDTO { +public class GoodsParamsDTO implements Serializable { + + private static final long serialVersionUID = 4892783539320159200L; @TableField(value = "group_id") @ApiModelProperty(value = "分组id") diff --git a/framework/src/main/java/cn/lili/modules/goods/entity/dto/GoodsParamsItemDTO.java b/framework/src/main/java/cn/lili/modules/goods/entity/dto/GoodsParamsItemDTO.java index 84eb2113..1b0dcb0b 100644 --- a/framework/src/main/java/cn/lili/modules/goods/entity/dto/GoodsParamsItemDTO.java +++ b/framework/src/main/java/cn/lili/modules/goods/entity/dto/GoodsParamsItemDTO.java @@ -4,8 +4,7 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; +import java.io.Serializable; /** * 商品参数项 @@ -16,7 +15,9 @@ import javax.validation.constraints.Min; */ @Data @ApiModel(value = "商品参数列表") -public class GoodsParamsItemDTO { +public class GoodsParamsItemDTO implements Serializable { + + private static final long serialVersionUID = -8823775607604091035L; @ApiModelProperty(value = "参数ID") private String paramId; @@ -32,4 +33,7 @@ public class GoodsParamsItemDTO { @ApiModelProperty(value = "是否必填,0 不显示 1 显示") private Integer required = 0; + + @ApiModelProperty(value = "排序") + private Integer sort; } diff --git a/framework/src/main/java/cn/lili/modules/search/entity/dos/EsGoodsAttribute.java b/framework/src/main/java/cn/lili/modules/search/entity/dos/EsGoodsAttribute.java index 09254bae..bbfad035 100644 --- a/framework/src/main/java/cn/lili/modules/search/entity/dos/EsGoodsAttribute.java +++ b/framework/src/main/java/cn/lili/modules/search/entity/dos/EsGoodsAttribute.java @@ -9,6 +9,7 @@ import java.io.Serializable; /** * 商品属性索引 + * * @author paulG * @since 2020/10/14 **/ @@ -47,11 +48,19 @@ public class EsGoodsAttribute implements Serializable { @Field(type = FieldType.Text) private String value; - public EsGoodsAttribute(Integer type,String nameId,String name,String valueId,String value){ - this.type=type; - this.nameId=nameId; - this.name=name; - this.valueId=valueId; - this.value=value; + + /** + * 排序 + */ + @Field(type = FieldType.Integer) + private Integer sort; + + public EsGoodsAttribute(Integer type, String nameId, String name, String valueId, String value, Integer sort) { + this.type = type; + this.nameId = nameId; + this.name = name; + this.valueId = valueId; + this.value = value; + this.sort = sort; } } diff --git a/framework/src/main/java/cn/lili/modules/search/entity/dos/EsGoodsIndex.java b/framework/src/main/java/cn/lili/modules/search/entity/dos/EsGoodsIndex.java index 1fbad5e4..7900d82d 100644 --- a/framework/src/main/java/cn/lili/modules/search/entity/dos/EsGoodsIndex.java +++ b/framework/src/main/java/cn/lili/modules/search/entity/dos/EsGoodsIndex.java @@ -27,7 +27,7 @@ import java.util.Map; * @author paulG **/ @Data -@Document(indexName = "#{elasticsearchProperties.indexPrefix}_" + EsSuffix.GOODS_INDEX_NAME) +@Document(indexName = "#{@elasticsearchProperties.indexPrefix}_" + EsSuffix.GOODS_INDEX_NAME) @ToString @NoArgsConstructor public class EsGoodsIndex implements Serializable { @@ -300,6 +300,7 @@ public class EsGoodsIndex implements Serializable { attribute.setType(1); attribute.setName(goodsParam.getParamName()); attribute.setValue(goodsParam.getParamValue()); + attribute.setSort(goodsParam.getSort()); attributes.add(attribute); } } diff --git a/framework/src/main/java/cn/lili/modules/search/service/EsGoodsSearchService.java b/framework/src/main/java/cn/lili/modules/search/service/EsGoodsSearchService.java index d8531110..9449e688 100644 --- a/framework/src/main/java/cn/lili/modules/search/service/EsGoodsSearchService.java +++ b/framework/src/main/java/cn/lili/modules/search/service/EsGoodsSearchService.java @@ -5,7 +5,7 @@ import cn.lili.modules.search.entity.dos.EsGoodsIndex; import cn.lili.modules.search.entity.dos.EsGoodsRelatedInfo; import cn.lili.modules.search.entity.dto.EsGoodsSearchDTO; import cn.lili.modules.search.entity.dto.HotWordsDTO; -import org.springframework.data.domain.Page; +import org.springframework.data.elasticsearch.core.SearchPage; import java.util.List; @@ -24,7 +24,7 @@ public interface EsGoodsSearchService { * @param pageVo 分页参数 * @return 搜索结果 */ - Page searchGoods(EsGoodsSearchDTO searchDTO, PageVO pageVo); + SearchPage searchGoods(EsGoodsSearchDTO searchDTO, PageVO pageVo); /** * 获取热门关键词 diff --git a/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsIndexServiceImpl.java b/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsIndexServiceImpl.java index 2060903c..4a951c8d 100644 --- a/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsIndexServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsIndexServiceImpl.java @@ -1,7 +1,5 @@ package cn.lili.modules.search.serviceimpl; -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.bean.copier.CopyOptions; import cn.hutool.core.date.DateUtil; import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.util.StrUtil; @@ -30,14 +28,13 @@ 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.search.SearchResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.indices.AnalyzeRequest; import org.elasticsearch.client.indices.AnalyzeResponse; -import org.elasticsearch.search.SearchHit; import org.mybatis.spring.MyBatisSystemException; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; +import org.springframework.data.elasticsearch.core.SearchHit; +import org.springframework.data.elasticsearch.core.SearchPage; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; @@ -234,14 +231,16 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements */ @Override public void updateEsGoodsIndexAllByList(BasePromotion promotion, String key) { - List goodsIndices; + List goodsIndices = new ArrayList<>(); //如果storeId不为空,则表示是店铺活动 if (promotion.getStoreId() != null) { EsGoodsSearchDTO searchDTO = new EsGoodsSearchDTO(); searchDTO.setStoreId(promotion.getStoreId()); //查询出店铺商品 - Page esGoodsIndices = goodsSearchService.searchGoods(searchDTO, null); - goodsIndices = esGoodsIndices.getContent(); + SearchPage esGoodsIndices = goodsSearchService.searchGoods(searchDTO, null); + for (SearchHit searchHit : esGoodsIndices.getContent()) { + goodsIndices.add(searchHit.getContent()); + } } else { //否则是平台活动 Iterable all = goodsIndexRepository.findAll(); @@ -494,16 +493,16 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements } } - public List searchList(String index) { - SearchResponse searchResponse = search(index); - SearchHit[] hits = searchResponse.getHits().getHits(); - List goodsIndices = new ArrayList<>(); - Arrays.stream(hits).forEach(hit -> { - Map sourceAsMap = hit.getSourceAsMap(); - EsGoodsIndex person = BeanUtil.mapToBean(sourceAsMap, EsGoodsIndex.class, false, CopyOptions.create()); - goodsIndices.add(person); - }); - return goodsIndices; - } +// public List searchList(String index) { +// SearchResponse searchResponse = search(index); +// SearchHit[] hits = searchResponse.getHits().getHits(); +// List goodsIndices = new ArrayList<>(); +// Arrays.stream(hits).forEach(hit -> { +// Map sourceAsMap = hit.getSourceAsMap(); +// EsGoodsIndex person = BeanUtil.mapToBean(sourceAsMap, EsGoodsIndex.class, false, CopyOptions.create()); +// goodsIndices.add(person); +// }); +// return goodsIndices; +// } } diff --git a/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsSearchServiceImpl.java b/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsSearchServiceImpl.java index fa48b879..deae01e1 100644 --- a/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsSearchServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsSearchServiceImpl.java @@ -4,7 +4,6 @@ import cn.hutool.core.convert.Convert; import cn.hutool.core.text.CharSequenceUtil; import cn.lili.cache.Cache; import cn.lili.cache.CachePrefix; -import cn.lili.common.utils.StringUtils; import cn.lili.common.vo.PageVO; import cn.lili.modules.goods.entity.dos.Brand; import cn.lili.modules.goods.entity.dos.Category; @@ -28,21 +27,19 @@ import org.elasticsearch.index.query.Operator; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder; import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders; -import org.elasticsearch.search.aggregations.Aggregation; -import org.elasticsearch.search.aggregations.AggregationBuilder; -import org.elasticsearch.search.aggregations.AggregationBuilders; -import org.elasticsearch.search.aggregations.Aggregations; +import org.elasticsearch.search.aggregations.*; import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested; import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms; import org.elasticsearch.search.aggregations.bucket.terms.Terms; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; +import org.springframework.data.elasticsearch.core.SearchHitSupport; import org.springframework.data.elasticsearch.core.SearchHits; +import org.springframework.data.elasticsearch.core.SearchPage; import org.springframework.data.elasticsearch.core.query.NativeSearchQuery; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; import org.springframework.data.redis.core.DefaultTypedTuple; @@ -63,6 +60,7 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService { private static final String ATTR_PATH = "attrList"; private static final String ATTR_VALUE = "attrList.value"; private static final String ATTR_NAME = "attrList.name"; + private static final String ATTR_SORT = "attrList.sort"; private static final String ATTR_NAME_KEY = "nameList"; private static final String ATTR_VALUE_KEY = "valueList"; @@ -90,15 +88,15 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService { private Cache cache; @Override - public Page searchGoods(EsGoodsSearchDTO searchDTO, PageVO pageVo) { + public SearchPage searchGoods(EsGoodsSearchDTO searchDTO, PageVO pageVo) { if (CharSequenceUtil.isNotEmpty(searchDTO.getKeyword())) { cache.incrementScore(CachePrefix.HOT_WORD.getPrefix(), searchDTO.getKeyword()); } NativeSearchQueryBuilder searchQueryBuilder = createSearchQueryBuilder(searchDTO, pageVo, true); NativeSearchQuery searchQuery = searchQueryBuilder.build(); log.info("searchGoods DSL:{}", searchQuery.getQuery()); - - return goodsIndexRepository.search(searchQuery); + SearchHits search = restTemplate.search(searchQuery, EsGoodsIndex.class); + return SearchHitSupport.searchPageFor(search, searchQuery.getPageable()); } @Override @@ -106,11 +104,11 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService { List hotWords = new ArrayList<>(); // redis 排序中,下标从0开始,所以这里需要 -1 处理 count = count - 1; - Set set = cache.reverseRangeWithScores(CachePrefix.HOT_WORD.getPrefix(), count); + Set> set = cache.reverseRangeWithScores(CachePrefix.HOT_WORD.getPrefix(), count); if (set == null || set.isEmpty()) { - return new ArrayList(); + return new ArrayList<>(); } - for (DefaultTypedTuple defaultTypedTuple : set) { + for (DefaultTypedTuple defaultTypedTuple : set) { hotWords.add(Objects.requireNonNull(defaultTypedTuple.getValue()).toString()); } return hotWords; @@ -130,7 +128,8 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService { builder.addAggregation(AggregationBuilders.terms("brandAgg").field("brandId").size(Integer.MAX_VALUE)); //参数 AggregationBuilder valuesBuilder = AggregationBuilders.terms("valueAgg").field(ATTR_VALUE); - AggregationBuilder paramsNameBuilder = AggregationBuilders.terms("nameAgg").field(ATTR_NAME).subAggregation(valuesBuilder); + AggregationBuilder sortBuilder = AggregationBuilders.sum("sortAgg").field(ATTR_SORT); + AggregationBuilder paramsNameBuilder = AggregationBuilders.terms("nameAgg").field(ATTR_NAME).subAggregation(sortBuilder).order(BucketOrder.aggregation("sortAgg",false)).subAggregation(valuesBuilder); builder.addAggregation(AggregationBuilders.nested("attrAgg", ATTR_PATH).subAggregation(paramsNameBuilder)); NativeSearchQuery searchQuery = builder.build(); SearchHits search = restTemplate.search(searchQuery, EsGoodsIndex.class); @@ -278,7 +277,7 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService { private NativeSearchQueryBuilder createSearchQueryBuilder(EsGoodsSearchDTO searchDTO, PageVO pageVo, boolean isAggregation) { NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder(); if (pageVo != null) { - Integer pageNumber = pageVo.getPageNumber() - 1; + int pageNumber = pageVo.getPageNumber() - 1; if (pageNumber < 0) { pageNumber = 0; } @@ -303,7 +302,7 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService { //关键字检索 - if (StringUtils.isEmpty(searchDTO.getKeyword())) { + if (CharSequenceUtil.isEmpty(searchDTO.getKeyword())) { nativeSearchQueryBuilder.withQuery(QueryBuilders.matchAllQuery()); } else { this.keywordSearch(filterBuilder, queryBuilder, searchDTO.getKeyword(), isAggregation); @@ -331,10 +330,10 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService { /** * 查询属性处理 * - * @param filterBuilder - * @param queryBuilder - * @param searchDTO - * @param isAggregation + * @param filterBuilder 过滤构造器 + * @param queryBuilder 查询构造器 + * @param searchDTO 查询参数 + * @param isAggregation 是否为聚合查询 */ private void commonSearch(BoolQueryBuilder filterBuilder, BoolQueryBuilder queryBuilder, EsGoodsSearchDTO searchDTO, boolean isAggregation) { //品牌判定 @@ -423,10 +422,10 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService { /** * 关键字查询处理 * - * @param filterBuilder - * @param queryBuilder - * @param keyword - * @param isAggregation + * @param filterBuilder 过滤构造器 + * @param queryBuilder 查询构造器 + * @param keyword 关键字 + * @param isAggregation 是否为聚合查询 */ private void keywordSearch(BoolQueryBuilder filterBuilder, BoolQueryBuilder queryBuilder, String keyword, boolean isAggregation) { List filterFunctionBuilders = new ArrayList<>();