SearchServiceHelper.java 16.1 KB
package com.yohomars.search.service;

import com.yohomars.search.utils.ISearchConstans;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.common.geo.GeoDistance;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;

/**
 * Created by wangnan on 2016/8/27.
 */
@Service
public class SearchServiceHelper {


    /**
     * 构造距离查询范围
     *
     * @param paramMap
     * @return
     */
    public QueryBuilder constructGeoDistanceRangeQueryBuilder(Map<String, String> paramMap) {
        if (paramMap.get("range_start") != null && paramMap.get("range_end") != null) {
            QueryBuilder builder = new GeoDistanceRangeQueryBuilder("pin.location")
                    .point(Double.valueOf(paramMap.get("latitude")), Double.valueOf(paramMap.get("longitude")))//注意纬度在前,经度在后
                    .from(paramMap.get("range_start") + "m")
                    .to(paramMap.get("range_end") + "m")
                    .includeLower(true)
                    .includeUpper(false)
                    .optimizeBbox("memory")
                    .geoDistance(GeoDistance.PLANE);
            return builder;
        } else {
            QueryBuilder builder = new GeoDistanceRangeQueryBuilder("pin.location")
                    .point(Double.valueOf(paramMap.get("latitude")), Double.valueOf(paramMap.get("longitude")))//注意纬度在前,经度在后
                    .includeLower(true)
                    .includeUpper(false)
                    .optimizeBbox("memory")
                    .geoDistance(GeoDistance.PLANE);
            return builder;
        }
    }

    /**
     * 构造距离查询排序
     *
     * @param paramMap
     * @return
     */
    public GeoDistanceSortBuilder constructGeoDistanceSortBuilder(Map<String, String> paramMap) {
        GeoDistanceSortBuilder sort = new GeoDistanceSortBuilder("pin.location");
        sort.unit(DistanceUnit.METERS);//距离单位米
        sort.order(SortOrder.ASC);
        if (StringUtils.isNotBlank(paramMap.get("distance_order"))) {
            if (paramMap.get("distance_order").equals("desc")) {
                sort.order(SortOrder.DESC);
            }
        }
        sort.point(Double.valueOf(paramMap.get("latitude")), Double.valueOf(paramMap.get("longitude")));//注意纬度在前,经度在后
        return sort;
    }


    /**
     * 构造Query
     *
     * @param paramMap
     * @return
     */

    public QueryBuilder constructQueryBuilder(Map<String, String> paramMap, String indexName, boolean isSuggest) {
        String keyword = paramMap.get("query");

        //如果query参数为空,则设置为matchAllQuery
        if (StringUtils.isBlank(keyword)) {
            return QueryBuilders.matchAllQuery();
        }

        if (isSuggest) {
            WildcardQueryBuilder wildcardQueryBuilder = QueryBuilders.wildcardQuery("suggest", "*" + keyword + "*");
            return wildcardQueryBuilder;
        } else {
            //构建MultiMatch
            MultiMatchQueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(keyword);

            //获取MultiMatchQueryType
            MultiMatchQueryBuilder.Type multiMatchQueryBuilderType = this.getMultiMatchQueryBuilderType();
            if (multiMatchQueryBuilderType != null) {
                queryBuilder.type(multiMatchQueryBuilderType);
            }

            if (paramMap.containsKey("queryField") && StringUtils.isNotBlank(paramMap.get("queryField"))) {
                String[] fields = paramMap.get("queryField").split(",");
                for (int i = 0; i < fields.length; i++) {
                    queryBuilder.field(fields[i]);
                }
            } else {
                //设置searchfield和权重
                this.setDefaultSearchField(queryBuilder, indexName);
            }

            //设置Operator
            if (ISearchConstans.SEARCH_OPERATOR.equalsIgnoreCase("or")) {
                queryBuilder.operator(MatchQueryBuilder.Operator.OR);
                queryBuilder.minimumShouldMatch(ISearchConstans.SEARCH_MINIMUM_SHOULD_MATCH);
            } else {
                queryBuilder.operator(MatchQueryBuilder.Operator.AND);

            }
            return queryBuilder;
        }
    }


    /**
     * 构造Filter
     *
     * @param paramMap
     * @return
     * @throws Exception
     */
    public BoolQueryBuilder constructFilterBuilder(Map<String, String> paramMap) throws Exception {

        //创建BoolQueryBuilder
        BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();


        //添加过滤请求
        boolFilter = BoolQueryBuilder(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_ID);
        boolFilter = BoolQueryBuilder(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_CITYID);
        boolFilter = BoolQueryBuilder(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_ISTOP);
        boolFilter = BoolQueryBuilder(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_ISRECOMMEND);
        boolFilter = BoolQueryBuilder(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_SORT);
        boolFilter = BoolQueryBuilder(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_BIZID);
        boolFilter = BoolQueryBuilder(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_ORDERBY);
        boolFilter = BoolQueryBuilder(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_SCORE);
        boolFilter = BoolQueryBuilder(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_ASSESSMENTNUM);
        boolFilter = BoolQueryBuilder(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_TAGS);
        boolFilter = BoolQueryBuilder(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_CONSUMPTION);
        //boolFilter = BoolQueryBuilder(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_LATITUDE);
        //boolFilter = BoolQueryBuilder(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_LONGITUDE);
        boolFilter = BoolQueryBuilder(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_PUBLISHTIME);
        boolFilter = BoolQueryBuilder(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_USERTYPE);
        boolFilter = BoolQueryBuilder(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_USERAUTH);
        boolFilter = BoolQueryBuilder(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_ISDELETED);
        boolFilter = BoolQueryBuilder(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_UID);


        boolFilter = BoolQueryBuilderGte(paramMap, boolFilter, ISearchConstans.PARAM_SEARCH_STORENUM);

        // 通用的过滤请求
        for (String key : paramMap.keySet()) {
            if (key.startsWith("not_")) {
                String[] values = paramMap.get(key).split(",");
                boolFilter.mustNot(QueryBuilders.termsQuery(key.substring(4, key.length()), values));
            }
            if (key.startsWith("filter_")) {
                String field = key.substring(7, key.length());
                boolFilter.must(QueryBuilders.termQuery(field, paramMap.get(key).split(",")));
            }
            if (key.startsWith("missing_")) {
                String field = key.substring(8, key.length());
                boolFilter.mustNot(QueryBuilders.existsQuery(field));
            }
        }
        return boolFilter;

    }

    /**
     * 构造Sort  格式: order=shelve_time:desc
     *
     * @param paramMap
     * @return
     */
    public LinkedHashMap<String, String> buildSort(Map<String, String> paramMap) {
        LinkedHashMap<String, String> sortFields = new LinkedHashMap<String, String>();
        if (StringUtils.isNotBlank(paramMap.get("order"))) {
            String[] sortTypes = paramMap.get("order").split(",");
            for (String sortType : sortTypes) {
                if (sortType.split(ISearchConstans.SPLIT_CHAR_COLON).length != 2) {
                    throw new IllegalArgumentException("order参数格式不正确,请检查");
                }
                String field = sortType.split(ISearchConstans.SPLIT_CHAR_COLON)[0];
                String type = sortType.split(ISearchConstans.SPLIT_CHAR_COLON)[1];
                sortFields.put(field, type);
            }
        }
        return sortFields;
    }


    /**
     * 判断MultiMatchQueryBuilder的类型
     *
     * @return
     */
    private MultiMatchQueryBuilder.Type getMultiMatchQueryBuilderType() {
        String configMultiMatchQueryType = ISearchConstans.SEARCH_MULTIMATCHQUERY_TYPE;
        if (configMultiMatchQueryType.equalsIgnoreCase(MultiMatchQueryBuilder.Type.BEST_FIELDS.name())) {
            return MultiMatchQueryBuilder.Type.BEST_FIELDS;
        }
        if (configMultiMatchQueryType.equalsIgnoreCase(MultiMatchQueryBuilder.Type.MOST_FIELDS.name())) {
            return MultiMatchQueryBuilder.Type.MOST_FIELDS;
        }
        if (configMultiMatchQueryType.equalsIgnoreCase(MultiMatchQueryBuilder.Type.CROSS_FIELDS.name())) {
            return MultiMatchQueryBuilder.Type.CROSS_FIELDS;
        }
        if (configMultiMatchQueryType.equalsIgnoreCase(MultiMatchQueryBuilder.Type.PHRASE.name())) {
            return MultiMatchQueryBuilder.Type.PHRASE;
        }
        if (configMultiMatchQueryType.equalsIgnoreCase(MultiMatchQueryBuilder.Type.PHRASE_PREFIX.name())) {
            return MultiMatchQueryBuilder.Type.PHRASE_PREFIX;
        }
        return null;
    }

    /**
     * 设置默认搜索字段(字段+权重)
     *
     * @param queryBuilder
     */
    private void setDefaultSearchField(MultiMatchQueryBuilder queryBuilder, String indexName) {
        List<String> fields = new ArrayList<>();
        if (indexName.equals(ISearchConstans.INDEX_NAME_BIZAREA)) {
            fields = ISearchConstans.SEARCH_DEFAULT_FIELD_BIZAREA;
        }
        if (indexName.equals(ISearchConstans.INDEX_NAME_COMMENT)) {
            fields = ISearchConstans.SEARCH_DEFAULT_FIELD_COMMENT;
        }
        if (indexName.equals(ISearchConstans.INDEX_NAME_LINE)) {
            fields = ISearchConstans.SEARCH_DEFAULT_FIELD_LINE;
        }
        if (indexName.equals(ISearchConstans.INDEX_NAME_STORE)) {
            fields = ISearchConstans.SEARCH_DEFAULT_FIELD_STORE;
        }
        if (indexName.equals(ISearchConstans.INDEX_NAME_TOPIC)) {
            fields = ISearchConstans.SEARCH_DEFAULT_FIELD_TOPIC;
        }
        for (String field : fields) {
            String[] fieldBoost = field.split("^");
            if (fieldBoost.length == 2) {
                queryBuilder.field(fieldBoost[0], Float.parseFloat(fieldBoost[1]));
            } else if (fieldBoost.length == 1) {
                queryBuilder.field(fieldBoost[0]);
            }
        }
    }


    /**
     * 增加一个筛选项
     *
     * @param paramMap
     * @param boolFilter
     * @param fieldName
     * @return
     */
    private BoolQueryBuilder BoolQueryBuilder(Map<String, String> paramMap, BoolQueryBuilder boolFilter, String fieldName) {
        if (paramMap.containsKey(fieldName) && StringUtils.isNotBlank(paramMap.get(fieldName))) {
            boolFilter.must(QueryBuilders.termsQuery(fieldName, paramMap.get(fieldName)));
        }
        return boolFilter;
    }

    /**
     * 增加一个筛选项,筛选大于某个数值的项
     *
     * @param paramMap
     * @param boolFilter
     * @param fieldName
     * @return
     */
    private BoolQueryBuilder BoolQueryBuilderGte(Map<String, String> paramMap, BoolQueryBuilder boolFilter, String fieldName) {
        if (paramMap.containsKey(fieldName) && StringUtils.isNotBlank(paramMap.get(fieldName))) {
            int begin = Integer.parseInt(paramMap.get(fieldName));
            if (begin == 0) {
                boolFilter.must(QueryBuilders.termQuery(fieldName, begin));
            } else {
                boolFilter.must(QueryBuilders.rangeQuery(fieldName).gte(begin));
            }
        }
        return boolFilter;
    }


    /**
     * 获取返回结果
     *
     * @param resultList
     * @return
     */
//    public List<Map<String, Map<String, Object>>> getMapList(Map<String, String> paramMap, List<Map<String, Object>> resultList, boolean isSuggest) {
//        List<Map<String, Map<String, Object>>> returnList = new ArrayList<Map<String, Map<String, Object>>>();
//        Map<String, Map<String, Object>> dataMap = new HashMap<>();
//        for (Map<String, Object> map : resultList) {
//            if (isSuggest) {
//                dataMap.put(map.get("id").toString(), getSuggestMap(map));
//            } else if (paramMap.containsKey("returnField") && StringUtils.isNotBlank(paramMap.get("returnField"))) {
//                dataMap.put(map.get("id").toString(), getReturnMap(map, paramMap));
//            } else {
//                dataMap.put(map.get("id").toString(), map);
//            }
//        }
//        returnList.add(dataMap);
//        return returnList;
//    }


    /**
     * 获取商品列表返回结果
     *
     * @param resultList
     * @return
     */
    public List<Map<String, Object>> getMapList(Map<String, String> paramMap, List<Map<String, Object>> resultList, boolean isSuggest) {
        List<Map<String, Object>> pageList = new ArrayList<Map<String, Object>>();
        for (Map<String, Object> map : resultList) {
            if (isSuggest) {
                pageList.add(getSuggestMap(map));
            } else if (paramMap.containsKey("returnField") && StringUtils.isNotBlank(paramMap.get("returnField"))) {
                pageList.add(getReturnMap(map, paramMap));
            } else {
                pageList.add(map);
            }

        }
        return pageList;
    }

    /**
     * 拼装返回结果
     *
     * @param map
     * @return
     */
    private Map<String, Object> getSuggestMap(Map<String, Object> map) {
        Map<String, Object> dataMap = new HashMap<String, Object>();
        //dataMap.put("id", map.get("id") == null ? "" : map.get("id"));
//        dataMap.put("city_id", map.get("city_id") == null ? "" : map.get("city_id"));
//        dataMap.put("is_top", map.get("is_top") == null ? "" : map.get("is_top"));
//        dataMap.put("store_num", map.get("store_num") == null ? "" : map.get("store_num"));
//        dataMap.put("sort", map.get("sort") == null ? "" : map.get("sort"));
//        dataMap.put("name", map.get("name") == null ? "" : map.get("name"));
//        dataMap.put("english_name", map.get("english_name") == null ? "" : map.get("english_name"));
//        dataMap.put("name_tc", map.get("name_tc") == null ? "" : map.get("name_tc"));
//        dataMap.put("des", map.get("des") == null ? "" : map.get("des"));
        dataMap.put("suggest", map.get("suggest") == null ? "" : map.get("suggest"));
        return dataMap;
    }

    /**
     * 拼装返回结果
     *
     * @param map
     * @return
     */
    private Map<String, Object> getReturnMap(Map<String, Object> map, Map<String, String> paramMap) {
        Map<String, Object> dataMap = new LinkedHashMap<String, Object>();
        if (paramMap.containsKey("returnField") && StringUtils.isNotBlank(paramMap.get("returnField"))) {
            dataMap.put("id", map.get("id") == null ? "" : map.get("id"));
            String[] fields = paramMap.get("returnField").split(",");
            for (int i = 0; i < fields.length; i++) {
                dataMap.put(fields[i], map.get(fields[i]) == null ? "" : map.get(fields[i]));
            }
            return dataMap;
        }
        return dataMap;
    }

    public static void main(String[] args) throws IOException {
        String jsonData = null;
        XContentBuilder jsonBuild = XContentFactory.jsonBuilder();
        com.yoho.search.dal.model.Store store = new com.yoho.search.dal.model.Store();
        store.setId(123);
        store.setStoreName("name");
        store.setLatitude(123.2);
        store.setLongitude(321.1);

        jsonBuild.startObject().field("id", store.getId()).field("name", store.getStoreName()).startArray("location").value(store.getLatitude()).value(store.getLongitude()).endArray()
                .endObject();
        jsonData = jsonBuild.string();
        System.out.println(jsonData);
    }

}