SceneRecallService.java 5.9 KB
package com.yoho.search.recall.scene;

import com.alibaba.fastjson.JSONObject;
import com.yoho.search.base.utils.CollectionUtils;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.base.utils.ProductIndexEsField;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.model.SearchResult;
import com.yoho.search.models.SearchApiResult;
import com.yoho.search.recall.scene.beans.BacthSknInfoComponent;
import com.yoho.search.recall.scene.strategy.helper.SortBuilderHelper;
import com.yoho.search.recall.scene.models.*;
import com.yoho.search.recall.scene.builder.request.RecallParamsBuilder;
import com.yoho.search.service.base.SearchCommonService;
import com.yoho.search.service.base.index.ProductIndexBaseService;
import com.yoho.search.service.helper.SearchCommonHelper;
import org.apache.commons.collections.MapUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

@Component
public class SceneRecallService {

    private static final Logger logger = LoggerFactory.getLogger(SceneRecallService.class);

    @Autowired
    private RecallParamsBuilder recallParamsBuilder;
    @Autowired
    private SearchCommonHelper searchCommonHelper;
    @Autowired
    private ProductIndexBaseService productIndexBaseService;
    @Autowired
    private SearchCommonService searchCommonService;
    @Autowired
    private BacthSknInfoComponent bacthSknInfoComponent;
    @Autowired
    private RecallService recallService;


    public SearchApiResult sceneRecall(Map<String, String> paramMap) {
        try {
            //1、分页参数验证
            int page = MapUtils.getIntValue(paramMap, "page", 1);
            int pageSize = MapUtils.getIntValue(paramMap, "viewNum", 20);
            if (page < 1 || pageSize < 0 || page * pageSize > 1000000) {
                return new SearchApiResult().setCode(400).setMessage("分页参数不合法");
            }
            //2、构造召回相关参数
            RecallSknParams recallSknParams = recallParamsBuilder.buildRecallParams(paramMap,pageSize);
            //3、执行召回
            RecallSknResult recallSknResult = recallService.doRecallSknResult(recallSknParams);
            //4、根据召回结果查询商品信息
            List<Map<String, Object>> productList = this.queryProductList(recallSknParams,recallSknResult,page,pageSize);
            //5、构造返回结果
            JSONObject dataMap = new JSONObject();
            dataMap.put("total", recallSknResult.getTotal());
            dataMap.put("page", page);
            dataMap.put("page_size", recallSknParams.getPageSize());
            dataMap.put("page_total", searchCommonHelper.getTotalPage(recallSknResult.getTotal(), recallSknParams.getPageSize()));
            dataMap.put("product_list", productList);
            return new SearchApiResult().setData(dataMap);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return new SearchApiResult().setData(null).setCode(500).setMessage("Exception");
        }
    }

    private List<Map<String, Object>> queryProductList( RecallSknParams recallSknParams,RecallSknResult recallSknResult,int page,int pageSize) {
        //1、判断当前页码是否在召回的页码里
        int recallTotalPage = recallSknResult.getRecallTotalPage();
        //2、在召回结果中则直接根据skn去查询
        List<Integer> productSkns = null;
        if(page<=recallTotalPage){
            productSkns = CollectionUtils.safeSubList(recallSknResult.getSknList(),(page-1)*pageSize,page*pageSize);
        }else{
            //3、过滤召回的skn,修改真实页码,执行查询
            productSkns = this.queryProductSknByFilterSkn(recallSknParams, recallSknResult.getSknList(), recallTotalPage-page, pageSize);
        }
        return bacthSknInfoComponent.queryProductListBySkn(productSkns,productSkns.size());
    }

    /**
     * 过滤掉已召回的skn,并按人气排序
     * @param notProductSkns
     * @param realPage
     * @param pageSize
     * @return
     */
    private List<Integer> queryProductSknByFilterSkn(RecallSknParams recallSknParams,List<Integer> notProductSkns,int realPage,int pageSize){
        SearchParam searchParam = new SearchParam();

        //1、设置query
        searchParam.setQuery(recallSknParams.getParamQueryFilter().getParamQuery());

        //2、设置filter
        BoolQueryBuilder filter = recallSknParams.getParamQueryFilter().getParamFilter();
        filter.mustNot(QueryBuilders.termsQuery(ProductIndexEsField.productSkn,notProductSkns));
        searchParam.setFiter(filter);

        //3、设置分页参数
        searchParam.setOffset((realPage-1)*pageSize);
        searchParam.setSize(pageSize);

        //4、设置IncludeFields
        searchParam.setIncludeFields(Arrays.asList(ProductIndexEsField.productSkn));

        //5、设置排序
        List<SortBuilder<?>> sortBuilders = new ArrayList<>();
        sortBuilders.add(SortBuilderHelper.getSevendayMoneyDescSort());
        sortBuilders.add(SortBuilderHelper.getIdDescSort());
        searchParam.setSortBuilders(sortBuilders);
        SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_PRODUCT_BASE_INDEX,searchParam);

        List<Integer> results = new ArrayList<>();
        for (Map<String, Object> product : searchResult.getResultList()) {
            results.add(MapUtils.getIntValue(product,ProductIndexEsField.productSkn,0));
        }
        return results;
    }

}