!49 优化商品搜索(增加商品基础分数,同goodsId递减。增加销量分数占比)
Merge pull request !49 from OceansDeep/feature/pg
This commit is contained in:
commit
3dd61f47fc
@ -288,9 +288,11 @@ public class GoodsMessageListener implements RocketMQListener<MessageExt> {
|
|||||||
* @param goodsSkuList 商品sku信息
|
* @param goodsSkuList 商品sku信息
|
||||||
*/
|
*/
|
||||||
private void generatorGoodsIndex(Goods goods, List<GoodsSku> goodsSkuList) {
|
private void generatorGoodsIndex(Goods goods, List<GoodsSku> goodsSkuList) {
|
||||||
|
int skuSource = 100;
|
||||||
for (GoodsSku goodsSku : goodsSkuList) {
|
for (GoodsSku goodsSku : goodsSkuList) {
|
||||||
EsGoodsIndex esGoodsOld = goodsIndexService.findById(goodsSku.getId());
|
EsGoodsIndex esGoodsOld = goodsIndexService.findById(goodsSku.getId());
|
||||||
EsGoodsIndex goodsIndex = this.settingUpGoodsIndexData(goods, goodsSku);
|
EsGoodsIndex goodsIndex = this.settingUpGoodsIndexData(goods, goodsSku);
|
||||||
|
goodsIndex.setSkuSource(skuSource--);
|
||||||
//如果商品库存不为0,并且es中有数据
|
//如果商品库存不为0,并且es中有数据
|
||||||
if (goodsSku.getQuantity() > 0 && esGoodsOld == null) {
|
if (goodsSku.getQuantity() > 0 && esGoodsOld == null) {
|
||||||
log.info("生成商品索引 {}", goodsIndex);
|
log.info("生成商品索引 {}", goodsIndex);
|
||||||
|
@ -197,6 +197,9 @@ public abstract class BaseElasticsearchService {
|
|||||||
" \"commentNum\": {\n" +
|
" \"commentNum\": {\n" +
|
||||||
" \"type\": \"long\"\n" +
|
" \"type\": \"long\"\n" +
|
||||||
" },\n" +
|
" },\n" +
|
||||||
|
" \"skuSource\": {\n" +
|
||||||
|
" \"type\": \"long\"\n" +
|
||||||
|
" },\n" +
|
||||||
" \"goodsId\": {\n" +
|
" \"goodsId\": {\n" +
|
||||||
" \"type\": \"text\",\n" +
|
" \"type\": \"text\",\n" +
|
||||||
" \"fields\": {\n" +
|
" \"fields\": {\n" +
|
||||||
|
@ -126,7 +126,7 @@ public class Goods extends BaseEntity {
|
|||||||
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "是否为推荐商品", required = true)
|
@ApiModelProperty(value = "是否为推荐商品", required = true)
|
||||||
private boolean recommend;
|
private Boolean recommend;
|
||||||
|
|
||||||
@ApiModelProperty(value = "销售模式", required = true)
|
@ApiModelProperty(value = "销售模式", required = true)
|
||||||
private String salesModel;
|
private String salesModel;
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package cn.lili.modules.goods.entity.dos;
|
package cn.lili.modules.goods.entity.dos;
|
||||||
|
|
||||||
import cn.lili.mybatis.BaseEntity;
|
|
||||||
import cn.lili.modules.goods.entity.enums.GoodsAuthEnum;
|
import cn.lili.modules.goods.entity.enums.GoodsAuthEnum;
|
||||||
import cn.lili.modules.goods.entity.enums.GoodsStatusEnum;
|
import cn.lili.modules.goods.entity.enums.GoodsStatusEnum;
|
||||||
|
import cn.lili.mybatis.BaseEntity;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import org.hibernate.validator.constraints.Length;
|
import org.hibernate.validator.constraints.Length;
|
||||||
|
|
||||||
import javax.validation.constraints.Max;
|
import javax.validation.constraints.Max;
|
||||||
@ -19,6 +20,7 @@ import java.util.Date;
|
|||||||
* @author pikachu
|
* @author pikachu
|
||||||
* @since 2020-02-23 9:14:33
|
* @since 2020-02-23 9:14:33
|
||||||
*/
|
*/
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Data
|
@Data
|
||||||
@TableName("li_goods_sku")
|
@TableName("li_goods_sku")
|
||||||
@ApiModel(value = "商品sku对象")
|
@ApiModel(value = "商品sku对象")
|
||||||
@ -146,7 +148,7 @@ public class GoodsSku extends BaseEntity {
|
|||||||
private String goodsVideo;
|
private String goodsVideo;
|
||||||
|
|
||||||
@ApiModelProperty(value = "是否为推荐商品", required = true)
|
@ApiModelProperty(value = "是否为推荐商品", required = true)
|
||||||
private boolean recommend;
|
private Boolean recommend;
|
||||||
|
|
||||||
@ApiModelProperty(value = "销售模式", required = true)
|
@ApiModelProperty(value = "销售模式", required = true)
|
||||||
private String salesModel;
|
private String salesModel;
|
||||||
|
@ -587,6 +587,7 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
|
|||||||
sku.setStoreName(goods.getStoreName());
|
sku.setStoreName(goods.getStoreName());
|
||||||
sku.setStoreCategoryPath(goods.getStoreCategoryPath());
|
sku.setStoreCategoryPath(goods.getStoreCategoryPath());
|
||||||
sku.setFreightTemplateId(goods.getTemplateId());
|
sku.setFreightTemplateId(goods.getTemplateId());
|
||||||
|
sku.setRecommend(goods.getRecommend());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,6 +63,7 @@ public class ParametersServiceImpl extends ServiceImpl<ParametersMapper, Paramet
|
|||||||
queryWrapper.like(Goods::getParams, parameters.getGroupId());
|
queryWrapper.like(Goods::getParams, parameters.getGroupId());
|
||||||
List<Map<String, Object>> goodsList = this.goodsService.listMaps(queryWrapper);
|
List<Map<String, Object>> goodsList = this.goodsService.listMaps(queryWrapper);
|
||||||
|
|
||||||
|
if (!goodsList.isEmpty()) {
|
||||||
for (Map<String, Object> goods : goodsList) {
|
for (Map<String, Object> goods : goodsList) {
|
||||||
String params = (String) goods.get("params");
|
String params = (String) goods.get("params");
|
||||||
List<GoodsParamsDTO> goodsParamsDTOS = JSONUtil.toList(params, GoodsParamsDTO.class);
|
List<GoodsParamsDTO> goodsParamsDTOS = JSONUtil.toList(params, GoodsParamsDTO.class);
|
||||||
@ -72,10 +73,10 @@ public class ParametersServiceImpl extends ServiceImpl<ParametersMapper, Paramet
|
|||||||
goodsIds.add(goods.get("id").toString());
|
goodsIds.add(goods.get("id").toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
String destination = rocketmqCustomProperties.getGoodsTopic() + ":" + GoodsTagsEnum.UPDATE_GOODS_INDEX.name();
|
String destination = rocketmqCustomProperties.getGoodsTopic() + ":" + GoodsTagsEnum.UPDATE_GOODS_INDEX.name();
|
||||||
//发送mq消息
|
//发送mq消息
|
||||||
rocketMQTemplate.asyncSend(destination, JSONUtil.toJsonStr(goodsIds), RocketmqSendCallbackBuilder.commonCallback());
|
rocketMQTemplate.asyncSend(destination, JSONUtil.toJsonStr(goodsIds), RocketmqSendCallbackBuilder.commonCallback());
|
||||||
|
}
|
||||||
return this.updateById(parameters);
|
return this.updateById(parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,6 +259,12 @@ public class EsGoodsIndex implements Serializable {
|
|||||||
@ApiModelProperty(value = "商品类型", required = true)
|
@ApiModelProperty(value = "商品类型", required = true)
|
||||||
private String goodsType;
|
private String goodsType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see cn.lili.modules.goods.entity.enums.GoodsTypeEnum
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "商品sku基础分数", required = true)
|
||||||
|
private Integer skuSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 商品属性(参数和规格)
|
* 商品属性(参数和规格)
|
||||||
*/
|
*/
|
||||||
@ -289,7 +295,7 @@ public class EsGoodsIndex implements Serializable {
|
|||||||
this.categoryPath = sku.getCategoryPath();
|
this.categoryPath = sku.getCategoryPath();
|
||||||
this.goodsVideo = sku.getGoodsVideo();
|
this.goodsVideo = sku.getGoodsVideo();
|
||||||
this.mobileIntro = sku.getMobileIntro();
|
this.mobileIntro = sku.getMobileIntro();
|
||||||
this.buyCount = sku.getBuyCount();
|
this.buyCount = sku.getBuyCount() != null ? sku.getBuyCount() : 0;
|
||||||
this.commentNum = sku.getCommentNum();
|
this.commentNum = sku.getCommentNum();
|
||||||
this.small = sku.getSmall();
|
this.small = sku.getSmall();
|
||||||
this.brandId = sku.getBrandId();
|
this.brandId = sku.getBrandId();
|
||||||
@ -302,6 +308,7 @@ public class EsGoodsIndex implements Serializable {
|
|||||||
this.isAuth = sku.getIsAuth();
|
this.isAuth = sku.getIsAuth();
|
||||||
this.intro = sku.getIntro();
|
this.intro = sku.getIntro();
|
||||||
this.grade = sku.getGrade();
|
this.grade = sku.getGrade();
|
||||||
|
this.recommend = sku.getRecommend();
|
||||||
this.releaseTime = new Date();
|
this.releaseTime = new Date();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,48 +126,30 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
|
|||||||
queryWrapper.eq(GoodsSku::getIsAuth, GoodsAuthEnum.PASS.name());
|
queryWrapper.eq(GoodsSku::getIsAuth, GoodsAuthEnum.PASS.name());
|
||||||
queryWrapper.eq(GoodsSku::getMarketEnable, GoodsStatusEnum.UPPER.name());
|
queryWrapper.eq(GoodsSku::getMarketEnable, GoodsStatusEnum.UPPER.name());
|
||||||
|
|
||||||
List<GoodsSku> list = goodsSkuService.list(queryWrapper);
|
|
||||||
List<EsGoodsIndex> esGoodsIndices = new ArrayList<>();
|
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);
|
|
||||||
|
|
||||||
//商品参数索引
|
LambdaQueryWrapper<Goods> goodsQueryWrapper = new LambdaQueryWrapper<>();
|
||||||
if (goods.getParams() != null && !goods.getParams().isEmpty()) {
|
goodsQueryWrapper.eq(Goods::getIsAuth, GoodsAuthEnum.PASS.name());
|
||||||
List<GoodsParamsDTO> goodsParamDTOS = JSONUtil.toList(goods.getParams(), GoodsParamsDTO.class);
|
goodsQueryWrapper.eq(Goods::getMarketEnable, GoodsStatusEnum.UPPER.name());
|
||||||
index = new EsGoodsIndex(goodsSku, goodsParamDTOS);
|
|
||||||
}
|
for (Goods goods : goodsService.list(goodsQueryWrapper)) {
|
||||||
//商品分类索引
|
LambdaQueryWrapper<GoodsSku> skuQueryWrapper = new LambdaQueryWrapper<>();
|
||||||
if (goods.getCategoryPath() != null) {
|
skuQueryWrapper.eq(GoodsSku::getGoodsId, goods.getId());
|
||||||
List<Category> categories = categoryService.listByIdsOrderByLevel(Arrays.asList(goods.getCategoryPath().split(",")));
|
skuQueryWrapper.eq(GoodsSku::getIsAuth, GoodsAuthEnum.PASS.name());
|
||||||
if (!categories.isEmpty()) {
|
skuQueryWrapper.eq(GoodsSku::getMarketEnable, GoodsStatusEnum.UPPER.name());
|
||||||
index.setCategoryNamePath(ArrayUtil.join(categories.stream().map(Category::getName).toArray(), ","));
|
|
||||||
}
|
List<GoodsSku> goodsSkuList = goodsSkuService.list(skuQueryWrapper);
|
||||||
}
|
int skuSource = 100;
|
||||||
//商品品牌索引
|
for (GoodsSku goodsSku : goodsSkuList) {
|
||||||
Brand brand = brandService.getById(goods.getBrandId());
|
EsGoodsIndex esGoodsIndex = wrapperEsGoodsIndex(goodsSku, goods);
|
||||||
if (brand != null) {
|
esGoodsIndex.setSkuSource(skuSource--);
|
||||||
index.setBrandName(brand.getName());
|
esGoodsIndices.add(esGoodsIndex);
|
||||||
index.setBrandUrl(brand.getLogo());
|
//库存锁是在redis做的,所以生成索引,同时更新一下redis中的库存数量
|
||||||
}
|
|
||||||
//店铺分类索引
|
|
||||||
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());
|
cache.put(GoodsSkuService.getStockCacheKey(goodsSku.getId()), goodsSku.getQuantity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//初始化商品索引
|
//初始化商品索引
|
||||||
this.initIndex(esGoodsIndices);
|
this.initIndex(esGoodsIndices);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -663,6 +645,40 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements
|
|||||||
return elasticsearchProperties.getIndexPrefix() + "_" + EsSuffix.GOODS_INDEX_NAME;
|
return elasticsearchProperties.getIndexPrefix() + "_" + EsSuffix.GOODS_INDEX_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private EsGoodsIndex wrapperEsGoodsIndex(GoodsSku goodsSku, Goods goods) {
|
||||||
|
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);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
private ActionListener<BulkByScrollResponse> actionListener() {
|
private ActionListener<BulkByScrollResponse> actionListener() {
|
||||||
return new ActionListener<BulkByScrollResponse>() {
|
return new ActionListener<BulkByScrollResponse>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -17,11 +17,15 @@ import cn.lili.modules.search.entity.dto.SelectorOptions;
|
|||||||
import cn.lili.modules.search.service.EsGoodsSearchService;
|
import cn.lili.modules.search.service.EsGoodsSearchService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.lucene.search.join.ScoreMode;
|
import org.apache.lucene.search.join.ScoreMode;
|
||||||
|
import org.elasticsearch.common.lucene.search.function.FieldValueFactorFunction;
|
||||||
import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery;
|
import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery;
|
||||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||||
|
import org.elasticsearch.index.query.MatchQueryBuilder;
|
||||||
import org.elasticsearch.index.query.Operator;
|
import org.elasticsearch.index.query.Operator;
|
||||||
import org.elasticsearch.index.query.QueryBuilders;
|
import org.elasticsearch.index.query.QueryBuilders;
|
||||||
|
import org.elasticsearch.index.query.functionscore.FieldValueFactorFunctionBuilder;
|
||||||
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
|
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
|
||||||
|
import org.elasticsearch.index.query.functionscore.GaussDecayFunctionBuilder;
|
||||||
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
|
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
|
||||||
import org.elasticsearch.search.aggregations.*;
|
import org.elasticsearch.search.aggregations.*;
|
||||||
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
|
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
|
||||||
@ -38,7 +42,7 @@ import org.springframework.data.elasticsearch.core.SearchHits;
|
|||||||
import org.springframework.data.elasticsearch.core.SearchPage;
|
import org.springframework.data.elasticsearch.core.SearchPage;
|
||||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
||||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
||||||
import org.springframework.data.redis.core.DefaultTypedTuple;
|
import org.springframework.data.redis.core.ZSetOperations;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@ -58,6 +62,8 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService {
|
|||||||
private static final String ATTR_NAME = "attrList.name";
|
private static final String ATTR_NAME = "attrList.name";
|
||||||
private static final String ATTR_SORT = "attrList.sort";
|
private static final String ATTR_SORT = "attrList.sort";
|
||||||
private static final String ATTR_BRAND_ID = "brandId";
|
private static final String ATTR_BRAND_ID = "brandId";
|
||||||
|
private static final String ATTR_BRAND_NAME = "brandNameAgg";
|
||||||
|
private static final String ATTR_BRAND_URL = "brandUrlAgg";
|
||||||
private static final String ATTR_NAME_KEY = "nameList";
|
private static final String ATTR_NAME_KEY = "nameList";
|
||||||
private static final String ATTR_VALUE_KEY = "valueList";
|
private static final String ATTR_VALUE_KEY = "valueList";
|
||||||
/**
|
/**
|
||||||
@ -69,14 +75,14 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService {
|
|||||||
* 缓存
|
* 缓存
|
||||||
*/
|
*/
|
||||||
@Autowired
|
@Autowired
|
||||||
private Cache cache;
|
private Cache<Object> cache;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SearchPage<EsGoodsIndex> searchGoods(EsGoodsSearchDTO searchDTO, PageVO pageVo) {
|
public SearchPage<EsGoodsIndex> searchGoods(EsGoodsSearchDTO searchDTO, PageVO pageVo) {
|
||||||
if (CharSequenceUtil.isNotEmpty(searchDTO.getKeyword())) {
|
if (CharSequenceUtil.isNotEmpty(searchDTO.getKeyword())) {
|
||||||
cache.incrementScore(CachePrefix.HOT_WORD.getPrefix(), searchDTO.getKeyword());
|
cache.incrementScore(CachePrefix.HOT_WORD.getPrefix(), searchDTO.getKeyword());
|
||||||
}
|
}
|
||||||
NativeSearchQueryBuilder searchQueryBuilder = createSearchQueryBuilder(searchDTO, pageVo, true);
|
NativeSearchQueryBuilder searchQueryBuilder = createSearchQueryBuilder(searchDTO, pageVo);
|
||||||
NativeSearchQuery searchQuery = searchQueryBuilder.build();
|
NativeSearchQuery searchQuery = searchQueryBuilder.build();
|
||||||
log.info("searchGoods DSL:{}", searchQuery.getQuery());
|
log.info("searchGoods DSL:{}", searchQuery.getQuery());
|
||||||
SearchHits<EsGoodsIndex> search = restTemplate.search(searchQuery, EsGoodsIndex.class);
|
SearchHits<EsGoodsIndex> search = restTemplate.search(searchQuery, EsGoodsIndex.class);
|
||||||
@ -91,11 +97,11 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService {
|
|||||||
List<String> hotWords = new ArrayList<>();
|
List<String> hotWords = new ArrayList<>();
|
||||||
// redis 排序中,下标从0开始,所以这里需要 -1 处理
|
// redis 排序中,下标从0开始,所以这里需要 -1 处理
|
||||||
count = count - 1;
|
count = count - 1;
|
||||||
Set<DefaultTypedTuple<Object>> set = cache.reverseRangeWithScores(CachePrefix.HOT_WORD.getPrefix(), count);
|
Set<ZSetOperations.TypedTuple<Object>> set = cache.reverseRangeWithScores(CachePrefix.HOT_WORD.getPrefix(), count);
|
||||||
if (set == null || set.isEmpty()) {
|
if (set == null || set.isEmpty()) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
for (DefaultTypedTuple<Object> defaultTypedTuple : set) {
|
for (ZSetOperations.TypedTuple<Object> defaultTypedTuple : set) {
|
||||||
hotWords.add(Objects.requireNonNull(defaultTypedTuple.getValue()).toString());
|
hotWords.add(Objects.requireNonNull(defaultTypedTuple.getValue()).toString());
|
||||||
}
|
}
|
||||||
return hotWords;
|
return hotWords;
|
||||||
@ -108,15 +114,15 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EsGoodsRelatedInfo getSelector(EsGoodsSearchDTO goodsSearch, PageVO pageVo) {
|
public EsGoodsRelatedInfo getSelector(EsGoodsSearchDTO goodsSearch, PageVO pageVo) {
|
||||||
NativeSearchQueryBuilder builder = createSearchQueryBuilder(goodsSearch, null, true);
|
NativeSearchQueryBuilder builder = createSearchQueryBuilder(goodsSearch, null);
|
||||||
//分类
|
//分类
|
||||||
AggregationBuilder categoryNameBuilder = AggregationBuilders.terms("categoryNameAgg").field("categoryNamePath.keyword");
|
AggregationBuilder categoryNameBuilder = AggregationBuilders.terms("categoryNameAgg").field("categoryNamePath.keyword");
|
||||||
builder.addAggregation(AggregationBuilders.terms("categoryAgg").field("categoryPath").subAggregation(categoryNameBuilder));
|
builder.addAggregation(AggregationBuilders.terms("categoryAgg").field("categoryPath").subAggregation(categoryNameBuilder));
|
||||||
|
|
||||||
//品牌
|
//品牌
|
||||||
AggregationBuilder brandNameBuilder = AggregationBuilders.terms("brandNameAgg").field("brandName.keyword");
|
AggregationBuilder brandNameBuilder = AggregationBuilders.terms(ATTR_BRAND_NAME).field("brandName.keyword");
|
||||||
builder.addAggregation(AggregationBuilders.terms("brandIdNameAgg").field(ATTR_BRAND_ID).size(Integer.MAX_VALUE).subAggregation(brandNameBuilder));
|
builder.addAggregation(AggregationBuilders.terms("brandIdNameAgg").field(ATTR_BRAND_ID).size(Integer.MAX_VALUE).subAggregation(brandNameBuilder));
|
||||||
AggregationBuilder brandUrlBuilder = AggregationBuilders.terms("brandUrlAgg").field("brandUrl.keyword");
|
AggregationBuilder brandUrlBuilder = AggregationBuilders.terms(ATTR_BRAND_URL).field("brandUrl.keyword");
|
||||||
builder.addAggregation(AggregationBuilders.terms("brandIdUrlAgg").field(ATTR_BRAND_ID).size(Integer.MAX_VALUE).subAggregation(brandUrlBuilder));
|
builder.addAggregation(AggregationBuilders.terms("brandIdUrlAgg").field(ATTR_BRAND_ID).size(Integer.MAX_VALUE).subAggregation(brandUrlBuilder));
|
||||||
//参数
|
//参数
|
||||||
AggregationBuilder valuesBuilder = AggregationBuilders.terms("valueAgg").field(ATTR_VALUE);
|
AggregationBuilder valuesBuilder = AggregationBuilders.terms("valueAgg").field(ATTR_VALUE);
|
||||||
@ -152,6 +158,96 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService {
|
|||||||
ParsedStringTerms categoryTerms = (ParsedStringTerms) aggregationMap.get("categoryAgg");
|
ParsedStringTerms categoryTerms = (ParsedStringTerms) aggregationMap.get("categoryAgg");
|
||||||
List<? extends Terms.Bucket> categoryBuckets = categoryTerms.getBuckets();
|
List<? extends Terms.Bucket> categoryBuckets = categoryTerms.getBuckets();
|
||||||
if (categoryBuckets != null && !categoryBuckets.isEmpty()) {
|
if (categoryBuckets != null && !categoryBuckets.isEmpty()) {
|
||||||
|
categoryOptions = this.convertCategoryOptions(categoryBuckets);
|
||||||
|
}
|
||||||
|
esGoodsRelatedInfo.setCategories(categoryOptions);
|
||||||
|
|
||||||
|
//品牌
|
||||||
|
ParsedStringTerms brandNameTerms = (ParsedStringTerms) aggregationMap.get("brandIdNameAgg");
|
||||||
|
ParsedStringTerms brandUrlTerms = (ParsedStringTerms) aggregationMap.get("brandIdUrlAgg");
|
||||||
|
List<? extends Terms.Bucket> brandBuckets = brandNameTerms.getBuckets();
|
||||||
|
List<? extends Terms.Bucket> brandUrlBuckets = brandUrlTerms.getBuckets();
|
||||||
|
List<SelectorOptions> brandOptions = new ArrayList<>();
|
||||||
|
if (brandBuckets != null && !brandBuckets.isEmpty()) {
|
||||||
|
brandOptions = this.convertBrandOptions(goodsSearch, brandBuckets, brandUrlBuckets);
|
||||||
|
}
|
||||||
|
esGoodsRelatedInfo.setBrands(brandOptions);
|
||||||
|
|
||||||
|
//参数
|
||||||
|
ParsedNested attrTerms = (ParsedNested) aggregationMap.get("attrAgg");
|
||||||
|
if (!goodsSearch.getNotShowCol().isEmpty()) {
|
||||||
|
if (goodsSearch.getNotShowCol().containsKey(ATTR_NAME_KEY) && goodsSearch.getNotShowCol().containsKey(ATTR_VALUE_KEY)) {
|
||||||
|
esGoodsRelatedInfo.setParamOptions(buildGoodsParam(attrTerms, goodsSearch.getNotShowCol().get(ATTR_NAME_KEY)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
esGoodsRelatedInfo.setParamOptions(buildGoodsParam(attrTerms, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
return esGoodsRelatedInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将品牌聚合结果转换品牌选择项
|
||||||
|
*
|
||||||
|
* @param goodsSearch 查询参数
|
||||||
|
* @param brandBuckets 品牌聚合结果桶
|
||||||
|
* @param brandUrlBuckets 品牌地址聚合结果桶
|
||||||
|
* @return 品牌选择项列表
|
||||||
|
*/
|
||||||
|
private List<SelectorOptions> convertBrandOptions(EsGoodsSearchDTO goodsSearch, List<? extends Terms.Bucket> brandBuckets, List<? extends Terms.Bucket> brandUrlBuckets) {
|
||||||
|
List<SelectorOptions> brandOptions = new ArrayList<>();
|
||||||
|
for (int i = 0; i < brandBuckets.size(); i++) {
|
||||||
|
String brandId = brandBuckets.get(i).getKey().toString();
|
||||||
|
//当商品品牌id为0时,代表商品没有选择品牌,所以过滤掉品牌选择器
|
||||||
|
if (brandId.equals("0") ||
|
||||||
|
(CharSequenceUtil.isNotEmpty(goodsSearch.getBrandId())
|
||||||
|
&& Arrays.asList(goodsSearch.getBrandId().split("@")).contains(brandId))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String brandName = "";
|
||||||
|
if (brandBuckets.get(i).getAggregations() != null && brandBuckets.get(i).getAggregations().get(ATTR_BRAND_NAME) != null) {
|
||||||
|
brandName = this.getAggregationsBrandOptions(brandBuckets.get(i).getAggregations().get(ATTR_BRAND_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
String brandUrl = "";
|
||||||
|
if (brandUrlBuckets != null && !brandUrlBuckets.isEmpty() &&
|
||||||
|
brandUrlBuckets.get(i).getAggregations() != null &&
|
||||||
|
brandUrlBuckets.get(i).getAggregations().get(ATTR_BRAND_URL) != null) {
|
||||||
|
brandUrl = this.getAggregationsBrandOptions(brandUrlBuckets.get(i).getAggregations().get(ATTR_BRAND_URL));
|
||||||
|
}
|
||||||
|
SelectorOptions so = new SelectorOptions();
|
||||||
|
so.setName(brandName);
|
||||||
|
so.setValue(brandId);
|
||||||
|
so.setUrl(brandUrl);
|
||||||
|
brandOptions.add(so);
|
||||||
|
}
|
||||||
|
return brandOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取品牌聚合结果内的参数
|
||||||
|
*
|
||||||
|
* @param brandAgg 品牌聚合结果
|
||||||
|
* @return 品牌聚合结果内的参数
|
||||||
|
*/
|
||||||
|
private String getAggregationsBrandOptions(ParsedStringTerms brandAgg) {
|
||||||
|
List<? extends Terms.Bucket> brandAggBuckets = brandAgg.getBuckets();
|
||||||
|
if (brandAggBuckets != null && !brandAggBuckets.isEmpty()) {
|
||||||
|
return brandAggBuckets.get(0).getKey().toString();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将分类聚合结果转换分类选择项
|
||||||
|
*
|
||||||
|
* @param categoryBuckets 分类聚合结果
|
||||||
|
* @return 分类选择项集合
|
||||||
|
*/
|
||||||
|
private List<SelectorOptions> convertCategoryOptions(List<? extends Terms.Bucket> categoryBuckets) {
|
||||||
|
List<SelectorOptions> categoryOptions = new ArrayList<>();
|
||||||
for (Terms.Bucket categoryBucket : categoryBuckets) {
|
for (Terms.Bucket categoryBucket : categoryBuckets) {
|
||||||
String categoryPath = categoryBucket.getKey().toString();
|
String categoryPath = categoryBucket.getKey().toString();
|
||||||
ParsedStringTerms categoryNameAgg = categoryBucket.getAggregations().get("categoryNameAgg");
|
ParsedStringTerms categoryNameAgg = categoryBucket.getAggregations().get("categoryNameAgg");
|
||||||
@ -175,70 +271,7 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return categoryOptions;
|
||||||
esGoodsRelatedInfo.setCategories(categoryOptions);
|
|
||||||
|
|
||||||
//品牌
|
|
||||||
ParsedStringTerms brandNameTerms = (ParsedStringTerms) aggregationMap.get("brandIdNameAgg");
|
|
||||||
ParsedStringTerms brandUrlTerms = (ParsedStringTerms) aggregationMap.get("brandIdUrlAgg");
|
|
||||||
List<? extends Terms.Bucket> brandBuckets = brandNameTerms.getBuckets();
|
|
||||||
List<? extends Terms.Bucket> brandUrlBuckets = brandUrlTerms.getBuckets();
|
|
||||||
List<SelectorOptions> brandOptions = new ArrayList<>();
|
|
||||||
if (brandBuckets != null && !brandBuckets.isEmpty()) {
|
|
||||||
for (int i = 0; i < brandBuckets.size(); i++) {
|
|
||||||
String brandId = brandBuckets.get(i).getKey().toString();
|
|
||||||
//当商品品牌id为0时,代表商品没有选择品牌,所以过滤掉品牌选择器
|
|
||||||
if (brandId.equals("0")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (CharSequenceUtil.isNotEmpty(goodsSearch.getBrandId())) {
|
|
||||||
List<String> brandList = Arrays.asList(goodsSearch.getBrandId().split("@"));
|
|
||||||
if (brandList.contains(brandId)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String brandName = "";
|
|
||||||
if (brandBuckets.get(i).getAggregations() != null && brandBuckets.get(i).getAggregations().get("brandNameAgg") != null) {
|
|
||||||
ParsedStringTerms brandNameAgg = brandBuckets.get(i).getAggregations().get("brandNameAgg");
|
|
||||||
List<? extends Terms.Bucket> categoryNameBuckets = brandNameAgg.getBuckets();
|
|
||||||
if (categoryNameBuckets != null && !categoryNameBuckets.isEmpty()) {
|
|
||||||
brandName = categoryNameBuckets.get(0).getKey().toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String brandUrl = "";
|
|
||||||
if (brandUrlBuckets != null && !brandUrlBuckets.isEmpty() &&
|
|
||||||
brandUrlBuckets.get(i).getAggregations() != null &&
|
|
||||||
brandUrlBuckets.get(i).getAggregations().get("brandUrlAgg") != null) {
|
|
||||||
|
|
||||||
ParsedStringTerms brandUrlAgg = brandUrlBuckets.get(i).getAggregations().get("brandUrlAgg");
|
|
||||||
List<? extends Terms.Bucket> categoryUrlBuckets = brandUrlAgg.getBuckets();
|
|
||||||
if (categoryUrlBuckets != null && !categoryUrlBuckets.isEmpty()) {
|
|
||||||
brandUrl = categoryUrlBuckets.get(0).getKey().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
SelectorOptions so = new SelectorOptions();
|
|
||||||
so.setName(brandName);
|
|
||||||
so.setValue(brandId);
|
|
||||||
so.setUrl(brandUrl);
|
|
||||||
brandOptions.add(so);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
esGoodsRelatedInfo.setBrands(brandOptions);
|
|
||||||
|
|
||||||
//参数
|
|
||||||
ParsedNested attrTerms = (ParsedNested) aggregationMap.get("attrAgg");
|
|
||||||
if (!goodsSearch.getNotShowCol().isEmpty()) {
|
|
||||||
if (goodsSearch.getNotShowCol().containsKey(ATTR_NAME_KEY) && goodsSearch.getNotShowCol().containsKey(ATTR_VALUE_KEY)) {
|
|
||||||
esGoodsRelatedInfo.setParamOptions(buildGoodsParam(attrTerms, goodsSearch.getNotShowCol().get(ATTR_NAME_KEY), goodsSearch.getNotShowCol().get(ATTR_VALUE_KEY)));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
esGoodsRelatedInfo.setParamOptions(buildGoodsParam(attrTerms, null, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
return esGoodsRelatedInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -246,17 +279,31 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService {
|
|||||||
*
|
*
|
||||||
* @param attrTerms 商品参数搜索结果
|
* @param attrTerms 商品参数搜索结果
|
||||||
* @param nameList 查询的规格名
|
* @param nameList 查询的规格名
|
||||||
* @param valueList 查询的规格项
|
|
||||||
* @return 商品参数信息
|
* @return 商品参数信息
|
||||||
*/
|
*/
|
||||||
private List<ParamOptions> buildGoodsParam(ParsedNested attrTerms, List<String> nameList, List<String> valueList) {
|
private List<ParamOptions> buildGoodsParam(ParsedNested attrTerms, List<String> nameList) {
|
||||||
List<ParamOptions> paramOptions = new ArrayList<>();
|
|
||||||
if (attrTerms != null) {
|
if (attrTerms != null) {
|
||||||
Aggregations attrAggregations = attrTerms.getAggregations();
|
Aggregations attrAggregations = attrTerms.getAggregations();
|
||||||
Map<String, Aggregation> attrMap = attrAggregations.getAsMap();
|
Map<String, Aggregation> attrMap = attrAggregations.getAsMap();
|
||||||
ParsedStringTerms nameAgg = (ParsedStringTerms) attrMap.get("nameAgg");
|
ParsedStringTerms nameAgg = (ParsedStringTerms) attrMap.get("nameAgg");
|
||||||
|
|
||||||
if (nameAgg != null) {
|
if (nameAgg != null) {
|
||||||
|
return this.buildGoodsParamOptions(nameAgg, nameList);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造商品参数属性
|
||||||
|
*
|
||||||
|
* @param nameAgg 商品参数聚合内容
|
||||||
|
* @param nameList 查询的规格名
|
||||||
|
* @return 商品参数属性集合
|
||||||
|
*/
|
||||||
|
private List<ParamOptions> buildGoodsParamOptions(ParsedStringTerms nameAgg, List<String> nameList) {
|
||||||
|
List<ParamOptions> paramOptions = new ArrayList<>();
|
||||||
List<? extends Terms.Bucket> nameBuckets = nameAgg.getBuckets();
|
List<? extends Terms.Bucket> nameBuckets = nameAgg.getBuckets();
|
||||||
|
|
||||||
for (Terms.Bucket bucket : nameBuckets) {
|
for (Terms.Bucket bucket : nameBuckets) {
|
||||||
@ -280,24 +327,17 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService {
|
|||||||
paramOptions.add(paramOptions1);
|
paramOptions.add(paramOptions1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return paramOptions;
|
return paramOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建es搜索builder
|
* 创建es搜索builder
|
||||||
*
|
*
|
||||||
* @param searchDTO 搜索条件
|
* @param searchDTO 搜索条件
|
||||||
* @param pageVo 分页参数
|
* @param pageVo 分页参数
|
||||||
* @param isAggregation 是否是聚合查询
|
|
||||||
* @return es搜索builder
|
* @return es搜索builder
|
||||||
*/
|
*/
|
||||||
private NativeSearchQueryBuilder createSearchQueryBuilder(EsGoodsSearchDTO searchDTO, PageVO pageVo, boolean isAggregation) {
|
private NativeSearchQueryBuilder createSearchQueryBuilder(EsGoodsSearchDTO searchDTO, PageVO pageVo) {
|
||||||
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
|
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
|
||||||
if (pageVo != null) {
|
if (pageVo != null) {
|
||||||
int pageNumber = pageVo.getPageNumber() - 1;
|
int pageNumber = pageVo.getPageNumber() - 1;
|
||||||
@ -312,11 +352,9 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService {
|
|||||||
if (searchDTO != null) {
|
if (searchDTO != null) {
|
||||||
//过滤条件
|
//过滤条件
|
||||||
BoolQueryBuilder filterBuilder = QueryBuilders.boolQuery();
|
BoolQueryBuilder filterBuilder = QueryBuilders.boolQuery();
|
||||||
//查询条件
|
|
||||||
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
|
|
||||||
|
|
||||||
//对查询条件进行处理
|
//对查询条件进行处理
|
||||||
this.commonSearch(filterBuilder, queryBuilder, searchDTO, isAggregation);
|
this.commonSearch(filterBuilder, searchDTO);
|
||||||
|
|
||||||
//未上架的商品不显示
|
//未上架的商品不显示
|
||||||
filterBuilder.must(QueryBuilders.matchQuery("marketEnable", GoodsStatusEnum.UPPER.name()));
|
filterBuilder.must(QueryBuilders.matchQuery("marketEnable", GoodsStatusEnum.UPPER.name()));
|
||||||
@ -328,16 +366,12 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService {
|
|||||||
if (CharSequenceUtil.isEmpty(searchDTO.getKeyword())) {
|
if (CharSequenceUtil.isEmpty(searchDTO.getKeyword())) {
|
||||||
nativeSearchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());
|
nativeSearchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());
|
||||||
} else {
|
} else {
|
||||||
this.keywordSearch(filterBuilder, queryBuilder, searchDTO.getKeyword(), isAggregation);
|
this.keywordSearch(filterBuilder, searchDTO.getKeyword());
|
||||||
}
|
}
|
||||||
|
|
||||||
//如果是聚合查询
|
//如果是聚合查询
|
||||||
if (isAggregation) {
|
|
||||||
nativeSearchQueryBuilder.withQuery(filterBuilder);
|
nativeSearchQueryBuilder.withQuery(filterBuilder);
|
||||||
} else {
|
|
||||||
nativeSearchQueryBuilder.withQuery(queryBuilder);
|
|
||||||
nativeSearchQueryBuilder.withFilter(filterBuilder);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (pageVo != null && CharSequenceUtil.isNotEmpty(pageVo.getOrder()) && CharSequenceUtil.isNotEmpty(pageVo.getSort())) {
|
if (pageVo != null && CharSequenceUtil.isNotEmpty(pageVo.getOrder()) && CharSequenceUtil.isNotEmpty(pageVo.getSort())) {
|
||||||
@ -354,11 +388,9 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService {
|
|||||||
* 查询属性处理
|
* 查询属性处理
|
||||||
*
|
*
|
||||||
* @param filterBuilder 过滤构造器
|
* @param filterBuilder 过滤构造器
|
||||||
* @param queryBuilder 查询构造器
|
|
||||||
* @param searchDTO 查询参数
|
* @param searchDTO 查询参数
|
||||||
* @param isAggregation 是否为聚合查询
|
|
||||||
*/
|
*/
|
||||||
private void commonSearch(BoolQueryBuilder filterBuilder, BoolQueryBuilder queryBuilder, EsGoodsSearchDTO searchDTO, boolean isAggregation) {
|
private void commonSearch(BoolQueryBuilder filterBuilder, EsGoodsSearchDTO searchDTO) {
|
||||||
//品牌判定
|
//品牌判定
|
||||||
if (CharSequenceUtil.isNotEmpty(searchDTO.getBrandId())) {
|
if (CharSequenceUtil.isNotEmpty(searchDTO.getBrandId())) {
|
||||||
String[] brands = searchDTO.getBrandId().split("@");
|
String[] brands = searchDTO.getBrandId().split("@");
|
||||||
@ -385,6 +417,31 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService {
|
|||||||
}
|
}
|
||||||
//属性判定
|
//属性判定
|
||||||
if (CharSequenceUtil.isNotEmpty(searchDTO.getProp())) {
|
if (CharSequenceUtil.isNotEmpty(searchDTO.getProp())) {
|
||||||
|
this.propSearch(filterBuilder, searchDTO);
|
||||||
|
}
|
||||||
|
//价格区间判定
|
||||||
|
if (CharSequenceUtil.isNotEmpty(searchDTO.getPrice())) {
|
||||||
|
String[] prices = searchDTO.getPrice().split("_");
|
||||||
|
if (prices.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
double min = Convert.toDouble(prices[0], 0.0);
|
||||||
|
double max = Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
if (prices.length == 2) {
|
||||||
|
max = Convert.toDouble(prices[1], Double.MAX_VALUE);
|
||||||
|
}
|
||||||
|
filterBuilder.must(QueryBuilders.rangeQuery("price").from(min).to(max).includeLower(true).includeUpper(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品参数查询处理
|
||||||
|
*
|
||||||
|
* @param filterBuilder 过滤构造器
|
||||||
|
* @param searchDTO 查询参数
|
||||||
|
*/
|
||||||
|
private void propSearch(BoolQueryBuilder filterBuilder, EsGoodsSearchDTO searchDTO) {
|
||||||
String[] props = searchDTO.getProp().split("@");
|
String[] props = searchDTO.getProp().split("@");
|
||||||
List<String> nameList = new ArrayList<>();
|
List<String> nameList = new ArrayList<>();
|
||||||
List<String> valueList = new ArrayList<>();
|
List<String> valueList = new ArrayList<>();
|
||||||
@ -408,81 +465,68 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService {
|
|||||||
valueMap.get(name).add(value);
|
valueMap.get(name).add(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoolQueryBuilder usedQueryBuilder;
|
|
||||||
if (isAggregation) {
|
|
||||||
usedQueryBuilder = filterBuilder;
|
|
||||||
} else {
|
|
||||||
usedQueryBuilder = queryBuilder;
|
|
||||||
}
|
|
||||||
//遍历所有的规格
|
//遍历所有的规格
|
||||||
for (Map.Entry<String, List<String>> entry : valueMap.entrySet()) {
|
for (Map.Entry<String, List<String>> entry : valueMap.entrySet()) {
|
||||||
usedQueryBuilder.must(QueryBuilders.nestedQuery(ATTR_PATH, QueryBuilders.wildcardQuery(ATTR_NAME, "*" + entry.getKey() + "*"), ScoreMode.None));
|
filterBuilder.must(QueryBuilders.nestedQuery(ATTR_PATH, QueryBuilders.matchQuery(ATTR_NAME, entry.getKey()), ScoreMode.None));
|
||||||
BoolQueryBuilder shouldBuilder = QueryBuilders.boolQuery();
|
BoolQueryBuilder shouldBuilder = QueryBuilders.boolQuery();
|
||||||
for (String s : entry.getValue()) {
|
for (String s : entry.getValue()) {
|
||||||
shouldBuilder.should(QueryBuilders.nestedQuery(ATTR_PATH, QueryBuilders.wildcardQuery(ATTR_VALUE, "*" + s + "*"), ScoreMode.None));
|
shouldBuilder.should(QueryBuilders.nestedQuery(ATTR_PATH, QueryBuilders.matchQuery(ATTR_VALUE, s), ScoreMode.None));
|
||||||
}
|
}
|
||||||
usedQueryBuilder.must(shouldBuilder);
|
filterBuilder.must(shouldBuilder);
|
||||||
}
|
}
|
||||||
searchDTO.getNotShowCol().put(ATTR_NAME_KEY, nameList);
|
searchDTO.getNotShowCol().put(ATTR_NAME_KEY, nameList);
|
||||||
searchDTO.getNotShowCol().put(ATTR_VALUE_KEY, valueList);
|
searchDTO.getNotShowCol().put(ATTR_VALUE_KEY, valueList);
|
||||||
}
|
}
|
||||||
//价格区间判定
|
|
||||||
if (CharSequenceUtil.isNotEmpty(searchDTO.getPrice())) {
|
|
||||||
String[] prices = searchDTO.getPrice().split("_");
|
|
||||||
if (prices.length == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
double min = Convert.toDouble(prices[0], 0.0);
|
|
||||||
double max = Integer.MAX_VALUE;
|
|
||||||
|
|
||||||
if (prices.length == 2) {
|
|
||||||
max = Convert.toDouble(prices[1], Double.MAX_VALUE);
|
|
||||||
}
|
|
||||||
filterBuilder.must(QueryBuilders.rangeQuery("price").from(min).to(max).includeLower(true).includeUpper(true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关键字查询处理
|
* 关键字查询处理
|
||||||
*
|
*
|
||||||
* @param filterBuilder 过滤构造器
|
* @param filterBuilder 过滤构造器
|
||||||
* @param queryBuilder 查询构造器
|
|
||||||
* @param keyword 关键字
|
* @param keyword 关键字
|
||||||
* @param isAggregation 是否为聚合查询
|
|
||||||
*/
|
*/
|
||||||
private void keywordSearch(BoolQueryBuilder filterBuilder, BoolQueryBuilder queryBuilder, String keyword, boolean isAggregation) {
|
private void keywordSearch(BoolQueryBuilder filterBuilder, String keyword) {
|
||||||
List<FunctionScoreQueryBuilder.FilterFunctionBuilder> filterFunctionBuilders = new ArrayList<>();
|
List<FunctionScoreQueryBuilder.FilterFunctionBuilder> filterFunctionBuilders = new ArrayList<>();
|
||||||
if (keyword.contains(" ")) {
|
if (keyword.contains(" ")) {
|
||||||
for (String s : keyword.split(" ")) {
|
for (String s : keyword.split(" ")) {
|
||||||
filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("goodsName", s).operator(Operator.AND),
|
filterFunctionBuilders.addAll(this.buildKeywordSearch(s));
|
||||||
ScoreFunctionBuilders.weightFactorFunction(10)));
|
|
||||||
//属性匹配
|
|
||||||
filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.nestedQuery(ATTR_PATH, QueryBuilders.wildcardQuery(ATTR_VALUE, "*" + s + "*"), ScoreMode.None),
|
|
||||||
ScoreFunctionBuilders.weightFactorFunction(8)));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//分词匹配
|
filterFunctionBuilders = this.buildKeywordSearch(keyword);
|
||||||
filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("goodsName", keyword).operator(Operator.AND),
|
|
||||||
ScoreFunctionBuilders.weightFactorFunction(10)));
|
|
||||||
//属性匹配
|
|
||||||
filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.nestedQuery(ATTR_PATH, QueryBuilders.wildcardQuery(ATTR_VALUE, "*" + keyword + "*"), ScoreMode.None),
|
|
||||||
ScoreFunctionBuilders.weightFactorFunction(8)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FunctionScoreQueryBuilder.FilterFunctionBuilder[] builders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[filterFunctionBuilders.size()];
|
FunctionScoreQueryBuilder.FilterFunctionBuilder[] builders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[filterFunctionBuilders.size()];
|
||||||
filterFunctionBuilders.toArray(builders);
|
filterFunctionBuilders.toArray(builders);
|
||||||
FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(builders)
|
FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(builders)
|
||||||
.scoreMode(FunctionScoreQuery.ScoreMode.SUM)
|
.scoreMode(FunctionScoreQuery.ScoreMode.SUM)
|
||||||
.setMinScore(2);
|
.setMinScore(2);
|
||||||
//聚合搜索则将结果放入过滤条件
|
//聚合搜索则将结果放入过滤条件
|
||||||
if (isAggregation) {
|
|
||||||
filterBuilder.must(functionScoreQueryBuilder);
|
filterBuilder.must(functionScoreQueryBuilder);
|
||||||
}
|
}
|
||||||
//否则放入查询条件
|
|
||||||
else {
|
/**
|
||||||
queryBuilder.must(functionScoreQueryBuilder);
|
* 构造关键字查询
|
||||||
}
|
*
|
||||||
|
* @param keyword 关键字
|
||||||
|
* @return 构造查询的集合
|
||||||
|
*/
|
||||||
|
private List<FunctionScoreQueryBuilder.FilterFunctionBuilder> buildKeywordSearch(String keyword) {
|
||||||
|
List<FunctionScoreQueryBuilder.FilterFunctionBuilder> filterFunctionBuilders = new ArrayList<>();
|
||||||
|
MatchQueryBuilder goodsNameQuery = QueryBuilders.matchQuery("goodsName", keyword).operator(Operator.AND);
|
||||||
|
//分词匹配
|
||||||
|
filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(goodsNameQuery,
|
||||||
|
ScoreFunctionBuilders.weightFactorFunction(10)));
|
||||||
|
//属性匹配
|
||||||
|
filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.nestedQuery(ATTR_PATH, QueryBuilders.wildcardQuery(ATTR_VALUE, "*" + keyword + "*"), ScoreMode.None),
|
||||||
|
ScoreFunctionBuilders.weightFactorFunction(8)));
|
||||||
|
|
||||||
|
GaussDecayFunctionBuilder skuNoScore = ScoreFunctionBuilders.gaussDecayFunction("skuSource", 100, 10).setWeight(7);
|
||||||
|
FunctionScoreQueryBuilder.FilterFunctionBuilder skuNoBuilder = new FunctionScoreQueryBuilder.FilterFunctionBuilder(goodsNameQuery, skuNoScore);
|
||||||
|
filterFunctionBuilders.add(skuNoBuilder);
|
||||||
|
|
||||||
|
FieldValueFactorFunctionBuilder buyCountScore = ScoreFunctionBuilders.fieldValueFactorFunction("buyCount").modifier(FieldValueFactorFunction.Modifier.LOG1P).setWeight(6);
|
||||||
|
FunctionScoreQueryBuilder.FilterFunctionBuilder buyCountBuilder = new FunctionScoreQueryBuilder.FilterFunctionBuilder(goodsNameQuery, buyCountScore);
|
||||||
|
filterFunctionBuilders.add(buyCountBuilder);
|
||||||
|
return filterFunctionBuilders;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user