Authored by zhaojun2

Merge branch 'zj_productanalysis' into 0710

package com.yoho.search.cache.beans;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import com.yoho.search.base.utils.MD5Util;
import com.yoho.search.cache.impls.EhCache;
... ... @@ -77,7 +78,7 @@ public abstract class AbstractCacheComponent<T> {
if (!useRedis()) {
return;
}
String jsonString = JSON.toJSONString(result);
String jsonString = JSON.toJSONString(result, SerializerFeature.WriteMapNullValue,SerializerFeature.DisableCircularReferenceDetect);
CacheObject toCacheResult = new CacheObject(jsonString);
searchRedis.addOrUpdate(redisKeyBuilder, toCacheResult, this.cacheTimeInMinute());
}
... ...
package com.yoho.search.cache.beans;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import com.yoho.search.base.utils.MD5Util;
import com.yoho.search.cache.model.CacheObject;
... ... @@ -19,116 +19,114 @@ import java.lang.reflect.Type;
@Service
public class SearchCacheService {
@Autowired
private SearchServiceConfiger searchServiceConfiger;
@Autowired
private SearchServiceConfiger searchServiceConfiger;
private void addObjectToCache(RedisKeyBuilder redisKeyBuilder, Object object, SearchCache searchCache) {
// 1、如果不适用缓存,则直接返回
if (!searchServiceConfiger.useCache()) {
return;
}
// 2、如果缓存不存在,则直接返回
if (searchCache == null || searchCache.getCache() == null) {
return;
}
// 3、加入缓存
CacheObject cacheObject = null;
if (object instanceof JSONObject) {
cacheObject = new CacheObject((JSONObject) object);
} else if (object instanceof JSONArray) {
cacheObject = new CacheObject((JSONArray) object);
} else {
cacheObject = new CacheObject(object);
}
searchCache.getCache().addOrUpdate(redisKeyBuilder, cacheObject, searchCache.getCacheInMinute());
}
private void addObjectToCache(RedisKeyBuilder redisKeyBuilder, Object object, SearchCache searchCache) {
// 1、如果不适用缓存,则直接返回
if (!searchServiceConfiger.useCache()) {
return;
}
// 2、如果缓存不存在,则直接返回
if (searchCache == null || searchCache.getCache() == null) {
return;
}
// 3、加入缓存
CacheObject cacheObject = null;
if (object instanceof JSONObject) {
cacheObject = new CacheObject((JSONObject) object);
} else {
cacheObject = new CacheObject(object);
}
searchCache.getCache().addOrUpdate(redisKeyBuilder, cacheObject, searchCache.getCacheInMinute());
}
/**
* 从缓存中取数据
*
* @param redisKeyBuilder
* @return
*/
private CacheObject getCacheObjectFromCache(RedisKeyBuilder redisKeyBuilder, SearchCache searchCache) {
// 1、如果不适用缓存,则直接返回
if (!searchServiceConfiger.useCache()) {
return null;
}
// 2、如果缓存不存在,则直接返回
if (searchCache == null || searchCache.getCache() == null) {
return null;
}
// 3、增加缓存访问次数
searchCache.incTotalCount();
/**
* 从缓存中取数据
*
* @param redisKeyBuilder
* @return
*/
private CacheObject getCacheObjectFromCache(RedisKeyBuilder redisKeyBuilder, SearchCache searchCache) {
// 1、如果不适用缓存,则直接返回
if (!searchServiceConfiger.useCache()) {
return null;
}
// 2、如果缓存不存在,则直接返回
if (searchCache == null || searchCache.getCache() == null) {
return null;
}
// 3、增加缓存访问次数
searchCache.incTotalCount();
// 4、从缓存中获取cacheObject
CacheObject cacheObject = searchCache.getCache().get(redisKeyBuilder);
// 4、从缓存中获取cacheObject
CacheObject cacheObject = searchCache.getCache().get(redisKeyBuilder);
// 5、如果从缓存中拿不到数据,则直接返回
if (cacheObject == null) {
return null;
}
// 6、增加缓存命中次数,并返回缓存对象
searchCache.incMatchCount();
return cacheObject;
}
// 5、如果从缓存中拿不到数据,则直接返回
if (cacheObject == null) {
return null;
}
// 6、增加缓存命中次数,并返回缓存对象
searchCache.incMatchCount();
return cacheObject;
}
/*********************************** JSONObject *****************************************/
public RedisKeyBuilder genSearchParamString(String indexName, SearchParam searchParam) {
//1、拼装内容
StringBuilder redisKeyValue = new StringBuilder();
redisKeyValue.append("indexName:").append(indexName).append(';');
redisKeyValue.append("searchType:").append(searchParam.getSearchType() == null ? "" : searchParam.getSearchType().name()).append(';');
SearchSourceBuilder searchSourceBuilder = SearchParamUtils.genSearchSourceBuilderFromSearchParam(searchParam);
redisKeyValue.append("searchSource:").append(searchSourceBuilder).append(';');
/*********************************** JSONObject *****************************************/
public RedisKeyBuilder genSearchParamString(String indexName, SearchParam searchParam) {
//1、拼装内容
StringBuilder redisKeyValue = new StringBuilder();
redisKeyValue.append("indexName:").append(indexName).append(';');
redisKeyValue.append("searchType:").append(searchParam.getSearchType() == null ? "" : searchParam.getSearchType().name()).append(';');
SearchSourceBuilder searchSourceBuilder = SearchParamUtils.genSearchSourceBuilderFromSearchParam(searchParam);
redisKeyValue.append("searchSource:").append(searchSourceBuilder).append(';');
//2、构建RedisKeyBuilder
RedisKeyBuilder redisKeyBuilder = RedisKeyBuilder.newInstance();
redisKeyBuilder.appendFixed("YOHOSEARCH:");
redisKeyBuilder.appendFixed("DEFAULT1:");
redisKeyBuilder.appendVar(MD5Util.string2MD5(redisKeyValue.toString()));
return redisKeyBuilder;
}
//2、构建RedisKeyBuilder
RedisKeyBuilder redisKeyBuilder = RedisKeyBuilder.newInstance();
redisKeyBuilder.appendFixed("YOHOSEARCH:");
redisKeyBuilder.appendFixed("DEFAULT1:");
redisKeyBuilder.appendVar(MD5Util.string2MD5(redisKeyValue.toString()));
return redisKeyBuilder;
}
public void addJSONObjectToCache(SearchCache searchCache, String indexName, SearchParam searchParam, JSONObject jsonObject) {
RedisKeyBuilder key = this.genSearchParamString(indexName, searchParam);
this.addObjectToCache(key, jsonObject, searchCache);
}
public void addJSONObjectToCache(SearchCache searchCache, String indexName, SearchParam searchParam, JSONObject jsonObject) {
RedisKeyBuilder key = this.genSearchParamString(indexName, searchParam);
this.addObjectToCache(key, jsonObject, searchCache);
}
public JSONObject getJSONObjectFromCache(SearchCache searchCache, String indexName, SearchParam searchParam) {
RedisKeyBuilder key = this.genSearchParamString(indexName, searchParam);
CacheObject cacheObject = this.getCacheObjectFromCache(key, searchCache);
if (cacheObject == null) {
return null;
}
return cacheObject.toJSONObject();
}
public JSONObject getJSONObjectFromCache(SearchCache searchCache, String indexName, SearchParam searchParam) {
RedisKeyBuilder key = this.genSearchParamString(indexName, searchParam);
CacheObject cacheObject = this.getCacheObjectFromCache(key, searchCache);
if (cacheObject == null) {
return null;
}
return cacheObject.toJSONObject();
}
/*********************************** object *****************************************/
public <T> T getSerializableObjectFromCache(SearchCache searchCache, RedisKeyBuilder redisKeyBuilder, Type type, boolean useJsonSerializable) {
try {
CacheObject cacheObject = this.getCacheObjectFromCache(redisKeyBuilder, searchCache);
if (cacheObject == null) {
return null;
}
if (useJsonSerializable) {
String stringValue = (String)cacheObject.toObject();
return JSON.parseObject(stringValue, type);
} else {
return (T) cacheObject.getValue();
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/*********************************** object *****************************************/
public <T> T getSerializableObjectFromCache(SearchCache searchCache, RedisKeyBuilder redisKeyBuilder, Type type, boolean useJsonSerializable) {
try {
CacheObject cacheObject = this.getCacheObjectFromCache(redisKeyBuilder, searchCache);
if (cacheObject == null) {
return null;
}
if (useJsonSerializable) {
String stringValue = (String) cacheObject.toObject();
return JSON.parseObject(stringValue, type);
} else {
return (T) cacheObject.getValue();
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public <T> void addSerializableObjectToCache(SearchCache searchCache, RedisKeyBuilder redisKeyBuilder, T object, boolean useJsonSerializable) {
if (useJsonSerializable) {
String jsonStr = JSON.toJSONString(object);
this.addObjectToCache(redisKeyBuilder, jsonStr, searchCache);
} else {
this.addObjectToCache(redisKeyBuilder, object, searchCache);
}
}
public <T> void addSerializableObjectToCache(SearchCache searchCache, RedisKeyBuilder redisKeyBuilder, T object, boolean useJsonSerializable) {
if (useJsonSerializable) {
String jsonStr = JSON.toJSONString(object, SerializerFeature.WriteMapNullValue, SerializerFeature.DisableCircularReferenceDetect);
this.addObjectToCache(redisKeyBuilder, jsonStr, searchCache);
} else {
this.addObjectToCache(redisKeyBuilder, object, searchCache);
}
}
}
... ...
package com.yoho.search.cache.model;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import java.io.Serializable;
/**
* 暂时只支持JSONObject和jsonArray
*
* @author hugufei
*
*/
public class CacheObject implements Serializable {
private static final long serialVersionUID = -3949382156604252137L;
private String type;
private Object value;
public CacheObject() {
}
public CacheObject(Object object) {
super();
this.type = "Object";
this.value = object;
}
public CacheObject(JSONObject jsonObject) {
super();
this.type = "JSONObject";
this.value = JSON.toJSONString(jsonObject, SerializerFeature.WriteMapNullValue);
}
public CacheObject(JSONArray jsonArray) {
super();
this.type = "JSONArray";
this.value = JSON.toJSONString(jsonArray, SerializerFeature.WriteMapNullValue);
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public JSONObject toJSONObject() {
try {
if (value == null) {
return null;
}
if ("JSONObject".equals(type)) {
return JSON.parseObject(value.toString());
}
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public JSONArray toJSONArray() {
try {
if (value == null) {
return null;
}
if ("JSONArray".equals(type)) {
return JSON.parseArray(value.toString());
}
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public Object toObject() {
try {
if (value == null) {
return null;
}
if ("Object".equals(type)) {
return value;
}
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
package com.yoho.search.cache.model;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import java.io.Serializable;
/**
* 暂时只支持JSONObject和jsonArray
*
* @author hugufei
*
*/
public class CacheObject implements Serializable {
private static final long serialVersionUID = -3949382156604252137L;
private String type;
private Object value;
public CacheObject() {
}
public CacheObject(Object object) {
super();
this.type = "Object";
this.value = object;
}
public CacheObject(JSONObject jsonObject) {
super();
this.type = "JSONObject";
this.value = JSON.toJSONString(jsonObject, SerializerFeature.WriteMapNullValue,SerializerFeature.DisableCircularReferenceDetect);
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public JSONObject toJSONObject() {
try {
if (value == null) {
return null;
}
if ("JSONObject".equals(type)) {
return JSON.parseObject(value.toString());
}
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public Object toObject() {
try {
if (value == null) {
return null;
}
if ("Object".equals(type)) {
return value;
}
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
... ...
... ... @@ -83,7 +83,7 @@ public class RedisCacheUtils {
* @return
*/
private static <T> String serializeToString(T t) {
return JSON.toJSONString(t, SerializerFeature.WriteMapNullValue);
return JSON.toJSONString(t, SerializerFeature.WriteMapNullValue,SerializerFeature.DisableCircularReferenceDetect);
}
private static <T> T unserializeFromString(String cacheObjectValue, Class<T> clazz) {
... ...
package com.yoho.search.restapi.scene;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.yoho.search.service.scene.searchlike.SearchLikeNotInShopService;
import com.yoho.search.service.scene.searchlike.SearchLikeHelper;
import com.yoho.search.common.utils.HttpServletRequestUtils;
import com.yoho.search.models.SearchApiResult;
import com.yoho.search.service.scene.searchlike.*;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
... ... @@ -13,89 +10,92 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.yoho.search.common.utils.HttpServletRequestUtils;
import com.yoho.search.models.SearchApiResult;
import com.yoho.search.service.scene.searchlike.SearchLikeInShopService;
import com.yoho.search.service.scene.searchlike.SearchLikeSceneService;
import com.yoho.search.service.scene.searchlike.ProductListWithSupplyService;
import com.yoho.search.service.scene.searchlike.SimilarProductService;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* 找相似相关功能
*
*
* @author hugufei
*/
@Controller
public class SearchLikeSecneController {
@Autowired
private SearchLikeSceneService searchLikeService;
@Autowired
private SearchLikeInShopService searchLikeInShopService;
@Autowired
private ProductListWithSupplyService productListWithSupplyService;
@Autowired
private SimilarProductService similarProductService;
@Autowired
private SearchLikeNotInShopService searchLikeNotInShopService;
@Autowired
private SearchLikeHelper searchLikeHelper;
@RequestMapping(method = RequestMethod.GET, value = "/searchLike")
@ResponseBody
public SearchApiResult searchLike(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return searchLikeService.searchLike(paramMap);
}
@Autowired
private SearchLikeSceneService searchLikeService;
@Autowired
private SearchLikeInShopService searchLikeInShopService;
@Autowired
private ProductListWithSupplyService productListWithSupplyService;
@Autowired
private SimilarProductService similarProductService;
@Autowired
private SearchLikeNotInShopService searchLikeNotInShopService;
@Autowired
private SearchLikeHelper searchLikeHelper;
@RequestMapping(method = RequestMethod.GET, value = "/searchLikeInShop")
@ResponseBody
public SearchApiResult searchLikeInShop(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
int viewNum = MapUtils.getIntValue(paramMap,"viewNum",10);
SearchApiResult result = searchLikeInShopService.searchLikeInShop(paramMap);
return searchLikeHelper.buildSearchApiResultWithViewNum(result,viewNum);
}
@RequestMapping(method = RequestMethod.GET, value = "/searchLike")
@ResponseBody
public SearchApiResult searchLike(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return searchLikeService.searchLike(paramMap);
}
@RequestMapping(method = RequestMethod.GET, value = "/searchLikeNotInShop")
@ResponseBody
public SearchApiResult searchLikeNotInShop(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
int viewNum = MapUtils.getIntValue(paramMap,"viewNum",10);
SearchApiResult result = searchLikeNotInShopService.searchLikeSimilarSknNotInShop(paramMap);
return searchLikeHelper.buildSearchApiResultWithViewNum(result,viewNum);
}
@RequestMapping(method = RequestMethod.GET, value = "/searchLikeInShop")
@ResponseBody
public SearchApiResult searchLikeInShop(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
int viewNum = MapUtils.getIntValue(paramMap, "viewNum", 10);
int uid = MapUtils.getIntValue(paramMap, "uid", 0);
if (uid>0 && uid % 1024 < 512) {
paramMap.put("use_yoho_image", "true");
}
SearchApiResult result = searchLikeInShopService.searchLikeInShop(paramMap);
return searchLikeHelper.buildSearchApiResultWithViewNum(result, viewNum);
}
@RequestMapping(method = RequestMethod.GET, value = "/searchLikeNotInShop")
@ResponseBody
public SearchApiResult searchLikeNotInShop(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
int viewNum = MapUtils.getIntValue(paramMap, "viewNum", 10);
int uid = MapUtils.getIntValue(paramMap, "uid", 0);
if (uid>0 && uid % 1024 < 512) {
paramMap.put("use_yoho_image", "true");
}
SearchApiResult result = searchLikeNotInShopService.searchLikeSimilarSknNotInShop(paramMap);
return searchLikeHelper.buildSearchApiResultWithViewNum(result, viewNum);
}
@RequestMapping(method = RequestMethod.GET, value = "/searchLikeForSaleOut")
@ResponseBody
public SearchApiResult searchLikeForSaleOut(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return searchLikeService.searchLikeForSaleOut(paramMap);
}
@RequestMapping(method = RequestMethod.GET, value = "/searchLikeForSaleOut")
@ResponseBody
public SearchApiResult searchLikeForSaleOut(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return searchLikeService.searchLikeForSaleOut(paramMap);
}
/**
* 获取商品列表,支持如果传入skn无效,补充相似skn
*/
@RequestMapping(method = RequestMethod.GET, value = "/productindex/productListWithSupply")
@ResponseBody
public SearchApiResult productList(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return productListWithSupplyService.productListWithSupply(paramMap);
}
/**
* 获取商品列表,支持如果传入skn无效,补充相似skn
*/
@RequestMapping(method = RequestMethod.GET, value = "/productindex/productListWithSupply")
@ResponseBody
public SearchApiResult productList(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return productListWithSupplyService.productListWithSupply(paramMap);
}
/**
* 根据一堆skn找相似的skn
*
* @param request
* @return
*/
@RequestMapping(method = RequestMethod.GET, value = "/productindex/similarProductList")
@ResponseBody
public SearchApiResult similarProductList(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return similarProductService.similarProductList(paramMap);
}
/**
* 根据一堆skn找相似的skn
*
* @param request
* @return
*/
@RequestMapping(method = RequestMethod.GET, value = "/productindex/similarProductList")
@ResponseBody
public SearchApiResult similarProductList(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return similarProductService.similarProductList(paramMap);
}
}
... ...
... ... @@ -12,24 +12,24 @@ import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilde
import java.util.List;
import java.util.Map;
public class ShopBrandAggregation extends AbstractAggregation {
public class BrandShopAggregation extends AbstractAggregation {
private int firstSize;
private int secondSize;
public ShopBrandAggregation(int firstSize, int secondSize) {
public BrandShopAggregation(int firstSize, int secondSize) {
this.firstSize = firstSize;
this.secondSize = secondSize;
}
@Override
public String aggName() {
return "shopAgg";
return "brandAgg";
}
public String secondAggName() {
return "brandAgg";
return "shopAgg";
}
@Override
... ... @@ -39,8 +39,8 @@ public class ShopBrandAggregation extends AbstractAggregation {
@Override
public AbstractAggregationBuilder<?> getBuilder() {
TermsAggregationBuilder aggBuilder = AggregationBuilders.terms(aggName()).field(ProductIndexEsField.shopId).size(firstSize);
aggBuilder.subAggregation(AggregationBuilders.terms(secondAggName()).field(ProductIndexEsField.brandId).size(secondSize));
TermsAggregationBuilder aggBuilder = AggregationBuilders.terms(aggName()).field(ProductIndexEsField.brandId).size(firstSize);
aggBuilder.subAggregation(AggregationBuilders.terms(secondAggName()).field(ProductIndexEsField.shopId).size(secondSize));
return aggBuilder;
}
... ...
... ... @@ -13,17 +13,17 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class ProductAnalysisShopAggregation extends AbstractAggregation {
public class ProductAnalysisBrandAggregation extends AbstractAggregation {
private int size;
public ProductAnalysisShopAggregation(int size) {
public ProductAnalysisBrandAggregation(int size) {
this.size = size;
}
@Override
public String aggName() {
return "shopIdAgg";
return "brandIdAgg";
}
@Override
... ... @@ -33,7 +33,7 @@ public class ProductAnalysisShopAggregation extends AbstractAggregation {
@Override
public AbstractAggregationBuilder<?> getBuilder() {
return AggregationBuilders.terms(aggName()).field(ProductIndexEsField.shopId).size(size).order(Terms.Order.aggregation("clickuvcount", false))
return AggregationBuilders.terms(aggName()).field(ProductIndexEsField.brandId).size(size).order(Terms.Order.aggregation("clickuvcount", false))
.subAggregation(AggregationBuilders.sum("clickuvcount").field("clickUvCount"));
}
... ... @@ -43,15 +43,15 @@ public class ProductAnalysisShopAggregation extends AbstractAggregation {
if (aggregation == null) {
return null;
}
List<Integer> shopIds = new ArrayList<>();
List<Integer> brandIds = new ArrayList<>();
Iterator<? extends MultiBucketsAggregation.Bucket> itSizeAgg = aggregation.getBuckets().iterator();
while (itSizeAgg.hasNext()) {
MultiBucketsAggregation.Bucket ltSize = itSizeAgg.next();
String[] shopIdArray=ltSize.getKeyAsString().split(",");
for (String shopId : shopIdArray) {
shopIds.add(Integer.valueOf(shopId));
String[] brandIdArray=ltSize.getKeyAsString().split(",");
for (String brandId : brandIdArray) {
brandIds.add(Integer.valueOf(brandId));
}
}
return shopIds;
return brandIds;
}
}
... ...
... ... @@ -20,12 +20,13 @@ import com.yoho.search.models.aggregations.AggKeyCount;
import com.yoho.search.models.aggregations.AggKeyCountTwoLevel;
import com.yoho.search.service.aggregations.AggregationsService;
import com.yoho.search.service.aggregations.impls.ProductAnalysisDateAggregation;
import com.yoho.search.service.aggregations.impls.ProductAnalysisShopAggregation;
import com.yoho.search.service.aggregations.impls.ProductAnalysisBrandAggregation;
import com.yoho.search.service.aggregations.impls.ProductAnalysisSortAggregation;
import com.yoho.search.service.aggregations.impls.ShopBrandAggregation;
import com.yoho.search.service.aggregations.impls.BrandShopAggregation;
import com.yoho.search.service.helper.SearchParamHelper;
import com.yoho.search.service.recall.beans.persional.UserPersionalFactorComponent;
import com.yoho.search.service.recall.beans.vector.BrandVectorCacheBean;
import com.yoho.search.service.recall.config.SpecialShopConstants;
import com.yoho.search.service.scene.activity.recommendshop.ActivityShopBrand;
import com.yoho.search.service.scene.general.SortGroupService;
import org.apache.commons.collections.MapUtils;
... ... @@ -182,8 +183,6 @@ public class RecommendOnProductAnalysisService {
}
private List<Integer> getSeenShops(Map<String, String> paramMap) {
Map<String, String> paramMapClone = new HashMap<>();
paramMapClone.putAll(paramMap);
List<Integer> seenShopIds = new ArrayList<>();
try {
int uid = MapUtils.getIntValue(paramMap, "uid", 0);
... ... @@ -193,9 +192,13 @@ public class RecommendOnProductAnalysisService {
if (userFactor != null && !CollectionUtils.isEmpty(userFactor.getRealTimeSortBrandList())) {
List<Integer> realTimeBrandIds = userFactor.getRealTimeSortBrandList().stream().map(SortBrand::getBrandId).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(realTimeBrandIds)) {
paramMapClone.put(SearchRequestParams.PARAM_SEARCH_BRAND, StringUtils.join(realTimeBrandIds, ","));
addDefaultParamsToParamMap(paramMapClone);
seenShopIds = aggShopId(paramMapClone, 10);
List<AggKeyCountTwoLevel> aggKeyCountTwoLevels = productAggBrandShopIds(paramMap, 10000, 20);
List<ActivityShopBrand> shopBrands = doCombineShopIdAndBrandId(aggKeyCountTwoLevels, realTimeBrandIds);
if (CollectionUtils.isEmpty(shopBrands)) {
return seenShopIds;
}
seenShopIds = shopBrands.stream().map(ActivityShopBrand::getShopId).distinct().collect(Collectors.toList());
return SearchCollectionUtils.safeSubList(seenShopIds, 0, 10);
}
}
}
... ... @@ -205,53 +208,40 @@ public class RecommendOnProductAnalysisService {
return seenShopIds;
}
private List<Integer> aggShopId(Map<String, String> paramMap, int aggCount) throws Exception{
List<Integer> seenShopIds = new ArrayList<>();
JSONObject aggResult = aggregationsService.getShopAggregationResult(paramMap, aggCount);
if (aggResult != null && !CollectionUtils.isEmpty(aggResult.getJSONArray("shopAgg"))) {
JSONArray shopList = aggResult.getJSONArray("shopAgg");
for (Object shop : shopList) {
seenShopIds.add(((JSONObject)shop).getInteger("shop_id"));
}
}
return seenShopIds;
}
private List<Integer> getRecommendShopWithPersonal(Map<String, String> paramMap, int viewNum, int uid, String udid) throws Exception{
List<Integer> recShopIds = new ArrayList<>();
SearchParam searchParam = buildSearchParam(paramMap);
List<Integer> aggBestShopIds = aggBestShopIds(searchParam, 1000);
addDefaultParamsToParamMap(paramMap);
SearchParam searchParam2 = searchParamHelper.buildDefault(paramMap);
List<AggKeyCountTwoLevel> aggKeyCountTwoLevels = productAggShopBrandIds(searchParam2, 100000, 200);
List<ActivityShopBrand> shopBrands = combineShopIdAndBrandId(aggKeyCountTwoLevels, aggBestShopIds, viewNum);
List<Integer> aggBestBrandIds = aggBestBrandIds(searchParam, 1000);
List<AggKeyCountTwoLevel> aggKeyCountTwoLevels = productAggBrandShopIds(paramMap, 10000, 100);
List<ActivityShopBrand> shopBrands = combineShopIdAndBrandId(aggKeyCountTwoLevels, aggBestBrandIds, viewNum + 10);
if (CollectionUtils.isEmpty(shopBrands)) {
return recShopIds;
}
recShopIds = shopBrands.stream().map(ActivityShopBrand::getShopId).collect(Collectors.toList());
if (uid > 0 || StringUtils.isNotBlank(udid)) {
recShopIds = reorderShopOnUserPersonalBrand(shopBrands, aggKeyCountTwoLevels, uid, udid);
}
recShopIds = reorderShopOnUserPersonalBrand(shopBrands, aggKeyCountTwoLevels, uid, udid);
return SearchCollectionUtils.safeSubList(recShopIds, 0, viewNum);
}
//从yoho_product_analysis聚合卖的最好的shopId
private List<Integer> aggBestShopIds(SearchParam searchParam, int shopSize) throws Exception {
IAggregation aggregation = new ProductAnalysisShopAggregation(shopSize);
private List<Integer> aggBestBrandIds(SearchParam searchParam, int shopSize) throws Exception {
IAggregation aggregation = new ProductAnalysisBrandAggregation(shopSize);
searchParam.setAggregationBuilders(Arrays.asList(aggregation.getBuilder()));
JSONObject jsonObject = aggregationsService.getAggNameAndResponseWithCache(aggregation, searchParam, ISearchConstants.INDEX_NAME_YOHO_PRODUCT_ANALYSIS);
List<Integer> aggShopIds = new ArrayList<>();
List<Integer> aggBrandIds = new ArrayList<>();
if (jsonObject != null && jsonObject.get(aggregation.aggName()) != null) {
aggShopIds = JSON.parseArray(JSON.toJSONString(jsonObject.get(aggregation.aggName())), Integer.class);
aggBrandIds = JSON.parseArray(JSON.toJSONString(jsonObject.get(aggregation.aggName())), Integer.class);
}
return aggShopIds;
return aggBrandIds;
}
//从pi聚合所有的的shopId
private List<AggKeyCountTwoLevel> productAggShopBrandIds(SearchParam searchParam, int shopSize, int brandSize) throws Exception {
IAggregation aggregation = new ShopBrandAggregation(shopSize, brandSize);
private List<AggKeyCountTwoLevel> productAggBrandShopIds(Map<String, String> paramMap, int brandSize, int shopSize) throws Exception {
Map<String, String> paramMapDefault = new HashMap<>();
if (StringUtils.isNotBlank(paramMap.get(SearchRequestParams.PARAM_SEARCH_SHELVETIME))) {
paramMapDefault.put(SearchRequestParams.PARAM_SEARCH_SHELVETIME, paramMap.get(SearchRequestParams.PARAM_SEARCH_SHELVETIME));
}
addDefaultParamsToParamMap(paramMapDefault);
SearchParam searchParam = searchParamHelper.buildDefault(paramMapDefault);
IAggregation aggregation = new BrandShopAggregation(brandSize, shopSize);
searchParam.setAggregationBuilders(Arrays.asList(aggregation.getBuilder()));
JSONObject jsonObject = aggregationsService.getAggNameAndResponseWithCache(aggregation, searchParam);
List<AggKeyCountTwoLevel> aggKeyCountTwoLevels = new ArrayList<>();
... ... @@ -263,33 +253,40 @@ public class RecommendOnProductAnalysisService {
//构造卖的最好的shopidbrandid
private List<ActivityShopBrand> combineShopIdAndBrandId(List<AggKeyCountTwoLevel> aggKeyCountTwoLevels, List<Integer> bestShopIds, int viewNum){
private List<ActivityShopBrand> combineShopIdAndBrandId(List<AggKeyCountTwoLevel> aggKeyCountTwoLevels, List<Integer> aggBestBrandIds, int size){
if (CollectionUtils.isEmpty(aggKeyCountTwoLevels)) {
return Collections.emptyList();
}
List<AggKeyCountTwoLevel> intersection = getCandidateShopBrands(aggKeyCountTwoLevels, bestShopIds, viewNum);
List<Integer> realBestShopIds = intersection.stream().map(e -> e.getFirstAggKeyCount().getKey()).collect(Collectors.toList());
List<AggKeyCountTwoLevel> candidateBrandShops = getCandidateBrandShops(aggKeyCountTwoLevels, aggBestBrandIds, size);
if (CollectionUtils.isEmpty(candidateBrandShops)) {
return Collections.emptyList();
}
List<Integer> realBestBrandIds = candidateBrandShops.stream().map(e -> e.getFirstAggKeyCount().getKey()).collect(Collectors.toList());
return doCombineShopIdAndBrandId(candidateBrandShops, realBestBrandIds);
}
private List<ActivityShopBrand> doCombineShopIdAndBrandId(List<AggKeyCountTwoLevel> candidateBrandShops, List<Integer> realBestBrandIds){
List<ActivityShopBrand> shopBrandList = new ArrayList<>();
Set<Integer> filterBrandIds = new HashSet<>();
if (!CollectionUtils.isEmpty(intersection) && !CollectionUtils.isEmpty(realBestShopIds)) {
Map<Integer, AggKeyCountTwoLevel> intersectionMap = intersection.stream().collect(Collectors.toMap(i -> i.getFirstAggKeyCount().getKey(), p -> p));
for (Integer shopId : realBestShopIds) {
if (shopId.equals(0)) {
Set<Integer> filterShopIds = new HashSet<>();
if (!CollectionUtils.isEmpty(candidateBrandShops) && !CollectionUtils.isEmpty(realBestBrandIds)) {
Map<Integer, AggKeyCountTwoLevel> andidateBrandShopsMap = candidateBrandShops.stream().collect(Collectors.toMap(i -> i.getFirstAggKeyCount().getKey(), p -> p));
for (Integer brandId : realBestBrandIds) {
if (brandId.equals(0)) {
continue;
}
AggKeyCountTwoLevel aggKeyCountTwoLevel = intersectionMap.get(shopId);
AggKeyCountTwoLevel aggKeyCountTwoLevel = andidateBrandShopsMap.get(brandId);
if (aggKeyCountTwoLevel != null) {
List<AggKeyCount> secondList = aggKeyCountTwoLevel.getSecondAggKeyCountList();
for (AggKeyCount brandAggKeyCount : secondList) {
Integer brandId = brandAggKeyCount.getKey();
if (brandId.equals(0)) {
for (AggKeyCount shopAggKeyCount : secondList) {
Integer shopId = shopAggKeyCount.getKey();
if (shopId.equals(0)) {
continue;
}
if (filterBrandIds.contains(brandId)) {
if (filterShopIds.contains(shopId)) {
continue;
}
shopBrandList.add(new ActivityShopBrand(shopId, brandId));//取商品数最多的一个店铺即可,防止多品店的问题
filterBrandIds.add(brandId);//每个品牌只赋给一个店铺
filterShopIds.add(shopId);//每个品牌只赋给一个店铺
break;
}
}
... ... @@ -298,18 +295,18 @@ public class RecommendOnProductAnalysisService {
return shopBrandList;
}
private List<AggKeyCountTwoLevel> getCandidateShopBrands(List<AggKeyCountTwoLevel> aggKeyCountTwoLevels, List<Integer> bestShopIds, int viewNum) {
private List<AggKeyCountTwoLevel> getCandidateBrandShops(List<AggKeyCountTwoLevel> aggKeyCountTwoLevels, List<Integer> aggBestBrandIds, int candidateNum) {
List<AggKeyCountTwoLevel> candidates = new ArrayList<>();
int candidateNum = 1000;
if (CollectionUtils.isEmpty(bestShopIds)) {
if (CollectionUtils.isEmpty(aggBestBrandIds)) {
candidates = SearchCollectionUtils.safeSubList(aggKeyCountTwoLevels, 0, candidateNum);
}else {
List<AggKeyCountTwoLevel> filtered = aggKeyCountTwoLevels.stream().filter(e -> bestShopIds.contains(e.getFirstAggKeyCount().getKey())).collect(Collectors.toList());
List<AggKeyCountTwoLevel> filtered = aggKeyCountTwoLevels.stream().filter(e -> aggBestBrandIds.contains(e.getFirstAggKeyCount().getKey())).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(filtered)) {
Map<Integer, AggKeyCountTwoLevel> filteredMap = filtered.stream().collect(Collectors.toMap(i -> i.getFirstAggKeyCount().getKey(), p -> p));
for (Integer shopId : bestShopIds) {
if (filteredMap.get(shopId) != null) {
candidates.add(filteredMap.get(shopId));
for (Integer brandId : aggBestBrandIds) {
if (filteredMap.get(brandId) != null) {
candidates.add(filteredMap.get(brandId));
}
}
}
... ... @@ -326,23 +323,24 @@ public class RecommendOnProductAnalysisService {
//获取用户有行为的品类 排序sort, RealTimeSort加分放前面,预测的放后面
private List<Integer> reorderShopOnUserPersonalBrand(List<ActivityShopBrand> shopBrands, List<AggKeyCountTwoLevel> aggKeyCountTwoLevels, int uid, String udid) {
List<Integer> aggBestShopIds = shopBrands.stream().map(ActivityShopBrand::getShopId).collect(Collectors.toList());
UserPersonalFactorRspNew userFactor = getUserPersonalFactor(uid, udid);
if (userFactor != null && !CollectionUtils.isEmpty(userFactor.getRealTimeSortBrandList())) {
if (!CollectionUtils.isEmpty(userFactor.getBrandVectorW2v())) {
calScore(shopBrands, userFactor.getBrandVectorW2v(), false);
} else {
calScore(shopBrands, userFactor.getBrandVector(), true);
if (uid > 0 || StringUtils.isNotBlank(udid)) {
UserPersonalFactorRspNew userFactor = getUserPersonalFactor(uid, udid);
if (userFactor != null && !CollectionUtils.isEmpty(userFactor.getRealTimeSortBrandList())) {
if (!CollectionUtils.isEmpty(userFactor.getBrandVectorW2v())) {
calScore(shopBrands, userFactor.getBrandVectorW2v(), false);
} else {
calScore(shopBrands, userFactor.getBrandVector(), true);
}
Collections.sort(shopBrands, (o1, o2) -> (o2.getScore()).compareTo(o1.getScore()));
List<Integer> orderedAggBestShopIds = shopBrands.stream().map(ActivityShopBrand::getShopId).collect(Collectors.toList());
List<Integer> personalBrandIds = userFactor.getRealTimeSortBrandList().stream().map(SortBrand::getBrandId).collect(Collectors.toList());
List<ActivityShopBrand> personalShopBrands = doCombineShopIdAndBrandId(aggKeyCountTwoLevels, personalBrandIds);
List<Integer> personalShopIds = personalShopBrands.stream().map(ActivityShopBrand::getShopId).collect(Collectors.toList());
personalShopIds.addAll(orderedAggBestShopIds);
return personalShopIds.stream().distinct().collect(Collectors.toList());
}
Collections.sort(shopBrands, (o1, o2) -> (o2.getScore()).compareTo(o1.getScore()));
List<Integer> orderedAggBestShopIds = shopBrands.stream().map(ActivityShopBrand::getShopId).collect(Collectors.toList());
List<Integer> personalBrandIds = userFactor.getRealTimeSortBrandList().stream().map(SortBrand::getBrandId).collect(Collectors.toList());
Map<Integer, Integer> brandId2ShopIdMap = shopBrands.stream().collect(Collectors.toMap(ActivityShopBrand::getBrandId, ActivityShopBrand::getShopId));
List<Integer> personalShopIds = personalBrandIds.stream().filter(e -> brandId2ShopIdMap.get(e) != null).map(e -> brandId2ShopIdMap.get(e)).distinct().collect(Collectors.toList());
personalShopIds.addAll(orderedAggBestShopIds);
return personalShopIds.stream().distinct().collect(Collectors.toList());
}
return aggBestShopIds;
return shopBrands.stream().map(ActivityShopBrand::getShopId).distinct().collect(Collectors.toList());
}
/**
... ... @@ -443,10 +441,15 @@ public class RecommendOnProductAnalysisService {
//SearchParam
private SearchParam buildSearchParam(Map<String, String> paramMap) {
paramMap.put(SearchRequestParams.PARAM_SEARCH_NOT_SHOP_ID, SpecialShopConstants.JISHOU_SHOP_ID.toString());// 非寄售店铺
QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();
addMustIntTermsQuery(boolFilter, paramMap, SearchRequestParams.PARAM_SEARCH_GENDER, ProductIndexEsField.gender);
addMustIntTermsQuery(boolFilter, paramMap, SearchRequestParams.PARAM_SEARCH_YH_CHANNEL, "yhChannel");
addMustIntTermsQuery(boolFilter, paramMap, SearchRequestParams.PARAM_SEARCH_MAXSORT, ProductIndexEsField.maxSortId);
addMustIntTermsQuery(boolFilter, paramMap, SearchRequestParams.PARAM_SEARCH_MIDDLESORT, ProductIndexEsField.middleSortId);
addMustIntTermsQuery(boolFilter, paramMap, SearchRequestParams.PARAM_SEARCH_SMALLSORT, ProductIndexEsField.smallSortId);
addMustNotIntTermsQuery(boolFilter,paramMap, SearchRequestParams.PARAM_SEARCH_NOT_SHOP_ID,ProductIndexEsField.shopId);
addMustDoubleRangeQuery(boolFilter, paramMap, SearchRequestParams.PARAM_SEARCH_SHELVETIME, ProductIndexEsField.shelveTime);
try {
List<String> day_date = dateRange.get("DAY_DATE");
... ... @@ -475,6 +478,15 @@ public class RecommendOnProductAnalysisService {
boolFilter.must(QueryBuilders.termsQuery(esField, values));
}
private void addMustNotIntTermsQuery(BoolQueryBuilder boolFilter,Map<String, String> paramMap, String paramName, String esField){
List<Integer> values = ConvertUtils.stringToIntList(paramMap.get(paramName), ",");
if(values==null || values.isEmpty()){
return;
}
boolFilter.mustNot(QueryBuilders.termsQuery(esField, values));
}
private void addMustDoubleRangeQuery(BoolQueryBuilder boolFilter, Map<String, String> paramMap, String paramName, String esField) {
List<Double> values = ConvertUtils.stringToDoubleList(paramMap.get(paramName), ",");
if (values == null || values.isEmpty() || values.size() != 2) {
... ... @@ -490,6 +502,7 @@ public class RecommendOnProductAnalysisService {
paramMap.put(SearchRequestParams.PARAM_SEARCH_SHOWSOLDOUT, "1");// 显示延期显示的商品
paramMap.put(SearchRequestParams.PARAM_SEARCH_ISOUTLETS, "2");// 非奥莱
paramMap.put(SearchRequestParams.PARAM_SEARCH_ATTRIBUTE_NOT, "2");// 非赠品
paramMap.put(SearchRequestParams.PARAM_SEARCH_NOT_SHOP_ID, SpecialShopConstants.JISHOU_SHOP_ID.toString());// 非寄售店铺
}
private void addShelveTime(Map<String, String> paramMap) {
... ...
package com.yoho.search.service.scene.searchlike;
import com.alibaba.fastjson.JSONObject;
import com.yoho.search.base.utils.SearchCollectionUtils;
import com.yoho.search.base.utils.ProductIndexEsField;
import com.yoho.search.aop.cache.SearchCacheAble;
import com.yoho.search.base.utils.ProductIndexEsField;
import com.yoho.search.base.utils.SearchCollectionUtils;
import com.yoho.search.bo.BigdataSimilarSknIndexBO;
import com.yoho.search.common.SearchRequestParams;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.models.SearchApiResult;
import com.yoho.search.service.helper.ProductListHelper;
import com.yoho.search.service.index.BigdataSimilarSknIndexBaseService;
import com.yoho.search.service.index.ProductIndexBaseService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
... ... @@ -29,113 +32,182 @@ import java.util.Map;
/**
* 店铺内找相似
*
*
* @author gufei.hu
*/
@Service
public class SearchLikeInShopService {
private static final Logger logger = LoggerFactory.getLogger(SearchLikeInShopService.class);
@Autowired
private SearchLikeHelper searchLikeHelper;
@Autowired
private ProductIndexBaseService productIndexBaseService;
@Autowired
private ProductListHelper productListHelper;
/**
* 店铺内推荐
*
* @param paramMap
* @return
*/
@SearchCacheAble(cacheInMinute = 600, cacheName = "SEARCH_LIKE_IN_SHOP_NEW", includeParams = { "product_skn"})
public SearchApiResult searchLikeInShop(Map<String, String> paramMap) {
try {
// 1、获取参数
String productSkn = paramMap.get(SearchRequestParams.PARAM_SEARCH_PRODUCT_SKN);
if (StringUtils.isBlank(productSkn)) {
return new SearchApiResult().setCode(400).setMessage("请输入SKN");
}
// 2、检测分页参数【默认30条】
int viewNum = 30;
// 3、获取当前查询的SKN的基本信息
JSONObject productInfoInEs = searchLikeHelper.getProductInfoInEs(productSkn);
if (productInfoInEs == null) {
return new SearchApiResult().setCode(400).setMessage("SKN不存在");
}
// 4、设置SearchParams
List<SearchParam> searchParams = new ArrayList<SearchParam>();
searchParams.add(this.builderSearchParam(productInfoInEs, Arrays.asList(productSkn), viewNum));
// 5、获取搜索结果[截取条数]
List<Map<String, Object>> tempProductList = searchLikeHelper.queryProductList(searchParams);
if (tempProductList.size() > viewNum) {
tempProductList = SearchCollectionUtils.safeSubList(tempProductList,0, viewNum);
}
//6、保留偶数
if (tempProductList.size() % 2 > 0) {
tempProductList = SearchCollectionUtils.safeSubList(tempProductList, 0, tempProductList.size() - 1);
}
// 7、构造返回结果
List<Map<String, Object>> productListResults = new ArrayList<Map<String, Object>>();
if (!tempProductList.isEmpty()) {
productListResults = productListHelper.buildReturnInfoByEsSourceList(tempProductList);
}
JSONObject result = new JSONObject();
result.put("product_info", searchLikeHelper.genProductInfoResult(productInfoInEs));
result.put("product_list", productListResults);
return new SearchApiResult().setData(result);
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new SearchApiResult().setData(null).setMessage("searchLikeInShop Exception").setCode(500);
}
}
private SearchParam builderSearchParam(JSONObject productInfoInEs, List<String> productSkns, int pageSize) {
// 1、设置SearchParam
SearchParam searchParam = new SearchParam();
// 2)设置query和filter
searchParam.setQuery(this.buildCharsetQueryBuilder(productInfoInEs, "20%"));
searchParam.setFiter(this.builderFilterBuilder(productInfoInEs, productSkns));
// 3、设置排序规则[按打分排序]
List<SortBuilder<?>> sortBuilders = new ArrayList<SortBuilder<?>>();
sortBuilders.add(SortBuilders.scoreSort().order(SortOrder.DESC));
searchParam.setSortBuilders(sortBuilders);
// 4、设置分页参数
searchParam.setOffset(0);
searchParam.setSize(pageSize);
// 5)设置返回的参数【节省带宽】
List<String> includeFields = productIndexBaseService.getProductIndexIncludeFields();
searchParam.setIncludeFields(includeFields);
return searchParam;
}
private QueryBuilder builderFilterBuilder(JSONObject productInfoInEs, List<String> notProductSkns) {
String isGlobalInEs = productInfoInEs.getString(ProductIndexEsField.isGlobal);
boolean isGlobal = "Y".equalsIgnoreCase(isGlobalInEs);
BoolQueryBuilder boolFilter = searchLikeHelper.genDefaultSearchLikeFilter(notProductSkns, isGlobal);
// 1)设置此SKN相关的性别过滤条件
String gender = productInfoInEs.getString(ProductIndexEsField.gender);
List<String> genderList = searchLikeHelper.getGenderInfo(gender);
if (genderList != null && !genderList.isEmpty()) {
boolFilter.must(QueryBuilders.termsQuery(ProductIndexEsField.gender, genderList));
}
// 2)设置品牌或店铺信息
Integer brandId = productInfoInEs.getInteger(ProductIndexEsField.brandId);
Integer shopId = productInfoInEs.getInteger(ProductIndexEsField.shopId);
if (searchLikeHelper.isLegalInteger(shopId)) {
boolFilter.must(QueryBuilders.termQuery(ProductIndexEsField.shopId, shopId));
} else if (searchLikeHelper.isLegalInteger(brandId)) {
boolFilter.must(QueryBuilders.termQuery(ProductIndexEsField.brandId, brandId));
}
return boolFilter;
}
private QueryBuilder buildCharsetQueryBuilder(JSONObject productInfoInEs, String minimumShouldMatch) {
String queryString = searchLikeHelper.genYohoQueryStringWithBrandName(productInfoInEs);
QueryBuilder queryBuilder = searchLikeHelper.buildCharsetQueryBuilder(queryString, minimumShouldMatch);
return queryBuilder;
}
private static final Logger logger = LoggerFactory.getLogger(SearchLikeInShopService.class);
@Autowired
private SearchLikeHelper searchLikeHelper;
@Autowired
private ProductIndexBaseService productIndexBaseService;
@Autowired
private ProductListHelper productListHelper;
@Autowired
private BigdataSimilarSknIndexBaseService bigdataSimilarSknIndexBaseService;
/**
* 店铺内推荐
*
* @param paramMap
* @return
*/
@SearchCacheAble(cacheInMinute = 600, cacheName = "SEARCH_LIKE_IN_SHOP_NEW", includeParams = {"product_skn", "use_yoho_image"})
public SearchApiResult searchLikeInShop(Map<String, String> paramMap) {
try {
// 1、获取参数
String productSkn = paramMap.get(SearchRequestParams.PARAM_SEARCH_PRODUCT_SKN);
if (StringUtils.isBlank(productSkn)) {
return new SearchApiResult().setCode(400).setMessage("请输入SKN");
}
// 2、检测分页参数【默认30条】
int viewNum = 30;
// 3、获取当前查询的SKN的基本信息
JSONObject productInfoInEs = searchLikeHelper.getProductInfoInEs(productSkn);
if (productInfoInEs == null) {
return new SearchApiResult().setCode(400).setMessage("SKN不存在");
}
//4、获取similarskn
BigdataSimilarSknIndexBO bigdataSimilarSkn = bigdataSimilarSknIndexBaseService.querySimilarSkn(productSkn);
boolean use_yoho_image = MapUtils.getBooleanValue(paramMap, "use_yoho_image", false);
// 5、设置SearchParams
List<SearchParam> searchParams = new ArrayList<SearchParam>();
//5.1)图片[同性别+同店铺]
List<String> sameShopImgSimilarSknsYoho = new ArrayList<>();
if (use_yoho_image && bigdataSimilarSkn != null && StringUtils.isNotEmpty(bigdataSimilarSkn.getSameShopImgSimilarSknsYoho())) {
sameShopImgSimilarSknsYoho = searchLikeHelper.getDistinctSknList(bigdataSimilarSkn.getSameShopImgSimilarSknsYoho());
}
searchParams.add(this.builderSimilarSknSearchParam(productInfoInEs, sameShopImgSimilarSknsYoho));
//5.2)文字相似
searchParams.add(this.buildCharactersSearchParam(productInfoInEs, viewNum));
// 6、获取搜索结果
List<List<Map<String, Object>>> queryResults = searchLikeHelper.queryProductLists(searchParams);
// 7、处理图片和文字的顺序
List<Map<String, Object>> sameShopImgSimilarProducts = searchLikeHelper.sortProductList(queryResults.get(0), sameShopImgSimilarSknsYoho, viewNum / 2);
List<Map<String, Object>> charsetSimilarProducts = queryResults.get(1);
// 8、获取临时结果
List<Map<String, Object>> tempProductList = new ArrayList<>();
tempProductList.addAll(sameShopImgSimilarProducts);
tempProductList.addAll(charsetSimilarProducts);
if (tempProductList.size() > viewNum) {
tempProductList = SearchCollectionUtils.safeSubList(tempProductList, 0, viewNum);
}
// 8.1 保留偶数
if (tempProductList.size() % 2 > 0) {
tempProductList = SearchCollectionUtils.safeSubList(tempProductList, 0, tempProductList.size() - 1);
}
// 9、构造真实返回结果
List<Map<String, Object>> productListResults = new ArrayList<>();
if (!tempProductList.isEmpty()) {
productListResults = productListHelper.buildReturnInfoByEsSourceList(tempProductList);
}
JSONObject result = new JSONObject();
result.put("product_info", searchLikeHelper.genProductInfoResult(productInfoInEs));
result.put("product_list", productListResults);
return new SearchApiResult().setData(result);
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new SearchApiResult().setData(null).setMessage("searchLikeInShop Exception").setCode(500);
}
}
/**
* 构建SimilarSknSearchParam[考虑productSkns为空的情况]
*
* @param productInfoInEs
* @param productSkns
* @return
*/
private SearchParam builderSimilarSknSearchParam(JSONObject productInfoInEs, List<String> productSkns) {
// 1、设置SearchParam
SearchParam searchParam = new SearchParam();
// 2)设置query和filter
searchParam.setFiter(this.builderSearchLikeInShopFilter(productInfoInEs, productSkns, true));
// 3、设置分页参数
searchParam.setOffset(0);
searchParam.setSize(productSkns.size());
// 4)设置返回的参数【节省带宽】
List<String> includeFields = productIndexBaseService.getProductIndexIncludeFields();
searchParam.setIncludeFields(includeFields);
return searchParam;
}
/**
* 店铺内按文字找相似
*
* @param productInfoInEs
* @param pageSize
* @return
*/
public SearchParam buildCharactersSearchParam(JSONObject productInfoInEs, int pageSize) {
// 1、设置SearchParam
SearchParam searchParam = new SearchParam();
// 2)设置query和filter
searchParam.setQuery(this.buildeCharactersQueryBuilder(productInfoInEs, "20%"));
searchParam.setFiter(this.builderSearchLikeInShopFilter(productInfoInEs, null, false));
// 3、设置排序规则[按打分排序]
List<SortBuilder<?>> sortBuilders = new ArrayList<>();
sortBuilders.add(SortBuilders.scoreSort().order(SortOrder.DESC));
searchParam.setSortBuilders(sortBuilders);
// 4、设置分页参数
searchParam.setOffset(0);
searchParam.setSize(pageSize);
// 5)设置返回的参数【节省带宽】
List<String> includeFields = productIndexBaseService.getProductIndexIncludeFields();
searchParam.setIncludeFields(includeFields);
return searchParam;
}
private QueryBuilder buildeCharactersQueryBuilder(JSONObject productInfoInEs, String minimumShouldMatch) {
String queryString = searchLikeHelper.genYohoQueryStringWithBrandName(productInfoInEs);
QueryBuilder queryBuilder = searchLikeHelper.buildCharsetQueryBuilder(queryString, minimumShouldMatch);
return queryBuilder;
}
private BoolQueryBuilder builderSearchLikeInShopFilter(JSONObject productInfoInEs, List<String> inProductSkns, boolean needSameSort) {
//1) 默认参数
String productSkn = productInfoInEs.getString(ProductIndexEsField.productSkn);
String isGlobalInEs = productInfoInEs.getString(ProductIndexEsField.isGlobal);
boolean isGlobal = "Y".equalsIgnoreCase(isGlobalInEs);
BoolQueryBuilder boolFilter = searchLikeHelper.genDefaultSearchLikeFilter(Arrays.asList(productSkn), isGlobal);
// 2)设置此SKN相关的性别过滤条件
String gender = productInfoInEs.getString(ProductIndexEsField.gender);
List<String> genderList = searchLikeHelper.getGenderInfo(gender);
if (genderList != null && !genderList.isEmpty()) {
boolFilter.must(QueryBuilders.termsQuery(ProductIndexEsField.gender, genderList));
}
// 3)设置品牌或店铺信息
Integer brandId = productInfoInEs.getInteger(ProductIndexEsField.brandId);
Integer shopId = productInfoInEs.getInteger(ProductIndexEsField.shopId);
if (searchLikeHelper.isLegalInteger(shopId)) {
boolFilter.must(QueryBuilders.termQuery(ProductIndexEsField.shopId, shopId));
} else if (searchLikeHelper.isLegalInteger(brandId)) {
boolFilter.must(QueryBuilders.termQuery(ProductIndexEsField.brandId, brandId));
}
// 4)设置productskn
if (CollectionUtils.isNotEmpty(inProductSkns)) {
boolFilter.must(QueryBuilders.termsQuery(ProductIndexEsField.productSkn, inProductSkns));
}
// 5)同品类
Integer middleSortId = productInfoInEs.getInteger(ProductIndexEsField.middleSortId);
if (needSameSort && searchLikeHelper.isLegalInteger(middleSortId)) {
boolFilter.must(QueryBuilders.termQuery(ProductIndexEsField.middleSortId, middleSortId));
}
return boolFilter;
}
}
... ...
... ... @@ -11,6 +11,8 @@ import com.yoho.search.models.SearchApiResult;
import com.yoho.search.service.helper.ProductListHelper;
import com.yoho.search.service.index.BigdataSimilarSknIndexBaseService;
import com.yoho.search.service.index.ProductIndexBaseService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
... ... @@ -42,7 +44,7 @@ public class SearchLikeNotInShopService {
@Autowired
private BigdataSimilarSknIndexBaseService bigdataSimilarSknIndexBaseService;
@SearchCacheAble(cacheInMinute = 600, cacheName = "SEARCH_LIKE_NOT_IN_SHOP_SIMILAR_NEW", includeParams = {"product_skn"})
@SearchCacheAble(cacheInMinute = 600, cacheName = "SEARCH_LIKE_NOT_IN_SHOP_SIMILAR_NEW", includeParams = {"product_skn", "use_yoho_image"})
public SearchApiResult searchLikeSimilarSknNotInShop(Map<String, String> paramMap) {
try {
// 1、获取参数
... ... @@ -51,31 +53,34 @@ public class SearchLikeNotInShopService {
return new SearchApiResult().setCode(400).setMessage("请输入SKN");
}
// 2、检测分页参数【默认30条,最多60条】
int pageSize = 30;
int viewNum = 30;
// 3、获取当前查询的SKN的基本信息
JSONObject productInfoInEs = searchLikeHelper.getProductInfoInEs(productSkn);
if (productInfoInEs == null) {
return new SearchApiResult().setCode(400).setMessage("SKN不存在");
}
//4、获取similarskn
BigdataSimilarSknIndexBO bigdataSimilarSkn = bigdataSimilarSknIndexBaseService.querySimilarSkn(productSkn);
boolean use_yoho_image = MapUtils.getBooleanValue(paramMap, "use_yoho_image", false);
//5、构造searchParams
List<SearchParam> searchParams = new ArrayList<>();
//5.1)图片[性别+不同店铺+同品类]
//5.1)有货图片相似[性别+不同店铺+同品类]
List<String> diffShopImgSimilarSknsYoho = new ArrayList<>();
if (use_yoho_image && bigdataSimilarSkn != null && StringUtils.isNotEmpty(bigdataSimilarSkn.getDiffShopImgSimilarSknsYoho())) {
diffShopImgSimilarSknsYoho = searchLikeHelper.getDistinctSknList(bigdataSimilarSkn.getDiffShopImgSimilarSknsYoho());
}
searchParams.add(this.builderSimilarSknSearchParam(productInfoInEs, diffShopImgSimilarSknsYoho));
//5.2)图片[性别+不同店铺+同品类]
List<String> diffShopImgSimilarSkns = new ArrayList<>();
if (bigdataSimilarSkn != null && StringUtils.isNotEmpty(bigdataSimilarSkn.getDiffShopImgSimilarSkns())) {
if (!use_yoho_image && bigdataSimilarSkn != null && StringUtils.isNotEmpty(bigdataSimilarSkn.getDiffShopImgSimilarSkns())) {
diffShopImgSimilarSkns = searchLikeHelper.getDistinctSknList(bigdataSimilarSkn.getDiffShopImgSimilarSkns());
}
searchParams.add(this.builderSimilarSknSearchParam(productInfoInEs, diffShopImgSimilarSkns));
//5.2)有货图片相似[性别+不同店铺+同品类]
List<String> diffShopImgSimilarSknsYoho = new ArrayList<>();
// if (bigdataSimilarSkn != null && StringUtils.isNotEmpty(bigdataSimilarSkn.getDiffShopImgSimilarSknsYoho())) {
// diffShopImgSimilarSknsYoho = searchLikeHelper.getDistinctSknList(bigdataSimilarSkn.getDiffShopImgSimilarSknsYoho());
// }
searchParams.add(this.builderSimilarSknSearchParam(productInfoInEs, diffShopImgSimilarSknsYoho));
//5.3)行为[性别+不同店铺+同品类]
List<String> diffShopActionSimilarSkns = new ArrayList<>();
if (bigdataSimilarSkn != null && StringUtils.isNotEmpty(bigdataSimilarSkn.getDiffShopActionSimilarSkns())) {
... ... @@ -84,15 +89,15 @@ public class SearchLikeNotInShopService {
searchParams.add(this.builderSimilarSknSearchParam(productInfoInEs, diffShopActionSimilarSkns));
//5.4)文字兜底[性别+不同店铺+文字相似性]
searchParams.add(this.buildCharactersSearchParam(productInfoInEs, Arrays.asList(productSkn), pageSize));
searchParams.add(this.buildCharactersSearchParam(productInfoInEs, viewNum));
// 6、获取搜索结果
List<List<Map<String, Object>>> queryResults = searchLikeHelper.queryProductLists(searchParams);
// 7、处理图片和行为的顺序
List<Map<String, Object>> diffShopImgSimilarProducts = searchLikeHelper.sortProductList(queryResults.get(0), diffShopImgSimilarSkns, pageSize / 2);
List<Map<String, Object>> diffShopImgSimilarProductsYoho = searchLikeHelper.sortProductList(queryResults.get(1), diffShopImgSimilarSknsYoho, pageSize / 2);
List<Map<String, Object>> diffShopActionSimilarProducts = searchLikeHelper.sortProductList(queryResults.get(2), diffShopActionSimilarSkns, pageSize / 2);
List<Map<String, Object>> diffShopImgSimilarProducts = searchLikeHelper.sortProductList(queryResults.get(0), diffShopImgSimilarSkns, viewNum / 2);
List<Map<String, Object>> diffShopImgSimilarProductsYoho = searchLikeHelper.sortProductList(queryResults.get(1), diffShopImgSimilarSknsYoho, viewNum / 2);
List<Map<String, Object>> diffShopActionSimilarProducts = searchLikeHelper.sortProductList(queryResults.get(2), diffShopActionSimilarSkns, viewNum / 2);
List<Map<String, Object>> charsetSimilarProducts = queryResults.get(3);
// 8、获取临时结果
... ... @@ -101,8 +106,8 @@ public class SearchLikeNotInShopService {
tempProductList.addAll(diffShopImgSimilarProductsYoho);
tempProductList.addAll(diffShopActionSimilarProducts);
tempProductList.addAll(charsetSimilarProducts);
if (tempProductList.size() > pageSize) {
tempProductList = SearchCollectionUtils.safeSubList(tempProductList, 0, pageSize);
if (tempProductList.size() > viewNum) {
tempProductList = SearchCollectionUtils.safeSubList(tempProductList, 0, viewNum);
}
// 8.1 保留偶数
if (tempProductList.size() % 2 > 0) {
... ... @@ -130,11 +135,11 @@ public class SearchLikeNotInShopService {
* @param productSkns
* @return
*/
private SearchParam builderSimilarSknSearchParam(JSONObject productInfoInEs, List<String> productSkns) {
private SearchParam builderSimilarSknSearchParam(JSONObject productInfoInEs, List<String> productSkns){
// 1、设置SearchParam
SearchParam searchParam = new SearchParam();
// 2)设置query和filter
searchParam.setFiter(this.builderSimilarSknFilter(productInfoInEs, productSkns));
searchParam.setFiter(this.buildSearchLikeNotInShopFilter(productInfoInEs, productSkns));
// 3、设置分页参数
searchParam.setOffset(0);
searchParam.setSize(productSkns.size());
... ... @@ -144,50 +149,19 @@ public class SearchLikeNotInShopService {
return searchParam;
}
private QueryBuilder builderSimilarSknFilter(JSONObject productInfoInEs, List<String> inProductSkns) {
String isGlobalInEs = productInfoInEs.getString(ProductIndexEsField.isGlobal);
boolean isGlobal = "Y".equalsIgnoreCase(isGlobalInEs);
BoolQueryBuilder boolFilter = searchLikeHelper.genDefaultSearchLikeFilter(null, isGlobal);
// 1)设置此SKN相关的性别过滤条件
String gender = productInfoInEs.getString(ProductIndexEsField.gender);
List<String> genderList = searchLikeHelper.getGenderInfo(gender);
if (genderList != null && !genderList.isEmpty()) {
boolFilter.must(QueryBuilders.termsQuery(ProductIndexEsField.gender, genderList));
}
// 2)设置productskn
if (inProductSkns != null && !inProductSkns.isEmpty()) {
boolFilter.must(QueryBuilders.termsQuery(ProductIndexEsField.productSkn, inProductSkns));
}
// 3)设置品牌或店铺信息
Integer brandId = productInfoInEs.getInteger(ProductIndexEsField.brandId);
Integer shopId = productInfoInEs.getInteger(ProductIndexEsField.shopId);
if (searchLikeHelper.isLegalInteger(shopId)) {
boolFilter.mustNot(QueryBuilders.termQuery(ProductIndexEsField.shopId, shopId));
} else if (searchLikeHelper.isLegalInteger(brandId)) {
boolFilter.mustNot(QueryBuilders.termQuery(ProductIndexEsField.brandId, brandId));
}
// 4)同品类
Integer middleSortId = productInfoInEs.getInteger(ProductIndexEsField.middleSortId);
if (searchLikeHelper.isLegalInteger(middleSortId)) {
boolFilter.must(QueryBuilders.termQuery(ProductIndexEsField.middleSortId, middleSortId));
}
return boolFilter;
}
/**
* 店铺外按文字找相似
*
* @param productInfoInEs
* @param notProductSkns
* @param pageSize
* @return
*/
public SearchParam buildCharactersSearchParam(JSONObject productInfoInEs, List<String> notProductSkns, int pageSize) {
public SearchParam buildCharactersSearchParam(JSONObject productInfoInEs, int pageSize) {
// 1、设置SearchParam
SearchParam searchParam = new SearchParam();
// 2)设置query和filter
searchParam.setQuery(this.buildeCharactersQueryBuilder(productInfoInEs, "30%"));
searchParam.setFiter(this.buildCharactersFilter(productInfoInEs, notProductSkns));
searchParam.setFiter(this.buildSearchLikeNotInShopFilter(productInfoInEs, null));
// 3、设置排序规则[按打分排序]
List<SortBuilder<?>> sortBuilders = new ArrayList<SortBuilder<?>>();
sortBuilders.add(SortBuilders.scoreSort().order(SortOrder.DESC));
... ... @@ -207,17 +181,21 @@ public class SearchLikeNotInShopService {
return queryBuilder;
}
private BoolQueryBuilder buildCharactersFilter(JSONObject productInfoInEs, List<String> notProductSkns) {
private BoolQueryBuilder buildSearchLikeNotInShopFilter(JSONObject productInfoInEs, List<String> inProductSkns) {
//1) 默认参数
String productSkn = productInfoInEs.getString(ProductIndexEsField.productSkn);
String isGlobalInEs = productInfoInEs.getString(ProductIndexEsField.isGlobal);
boolean isGlobal = "Y".equalsIgnoreCase(isGlobalInEs);
BoolQueryBuilder boolFilter = searchLikeHelper.genDefaultSearchLikeFilter(notProductSkns, isGlobal);
// 1)设置此SKN相关的性别过滤条件
BoolQueryBuilder boolFilter = searchLikeHelper.genDefaultSearchLikeFilter(Arrays.asList(productSkn), isGlobal);
// 2)设置此SKN相关的性别过滤条件
String gender = productInfoInEs.getString(ProductIndexEsField.gender);
List<String> genderList = searchLikeHelper.getGenderInfo(gender);
if (genderList != null && !genderList.isEmpty()) {
boolFilter.must(QueryBuilders.termsQuery(ProductIndexEsField.gender, genderList));
}
// 2)设置品牌或店铺信息
// 3)设置品牌或店铺信息
Integer brandId = productInfoInEs.getInteger(ProductIndexEsField.brandId);
Integer shopId = productInfoInEs.getInteger(ProductIndexEsField.shopId);
if (searchLikeHelper.isLegalInteger(shopId)) {
... ... @@ -225,7 +203,13 @@ public class SearchLikeNotInShopService {
} else if (searchLikeHelper.isLegalInteger(brandId)) {
boolFilter.mustNot(QueryBuilders.termQuery(ProductIndexEsField.brandId, brandId));
}
// 3)设置品类信息
// 4)设置productskn
if (CollectionUtils.isNotEmpty(inProductSkns)) {
boolFilter.must(QueryBuilders.termsQuery(ProductIndexEsField.productSkn, inProductSkns));
}
// 5)同品类
Integer middleSortId = productInfoInEs.getInteger(ProductIndexEsField.middleSortId);
if (searchLikeHelper.isLegalInteger(middleSortId)) {
boolFilter.must(QueryBuilders.termQuery(ProductIndexEsField.middleSortId, middleSortId));
... ...