搜索接口开发

背景

在电商业务场景下,我们为加快查询效率。一般会使用ES对数据进行存储,ES中的数据通常由数据库中的数据导入。

导入进ES进行存储时,主要使用以下两种数据类型,当然,我们也不可忽略了IK分词器:

  • text: 分词,索引,模糊精确查询,不支持聚合
  • keyword: 不分词,索引,精确查询,支持聚合

数据导入到ES之后再到ES中进行查询,查询时主要考虑以下三点:

  • 分页
  • 高亮
  • 排序

编码

public SearchGoodsRes search(Integer page, Integer size, SearchGoodsParam param){
        SearchGoodsRes res = new SearchGoodsRes();
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

        //分组汇总 类目 品牌 规格
        //select category_name from goods where name "%key%" group by category_name

        //类目聚合List
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("goodsCategory").field("categoryName.keyword").size(100));
        //品牌聚合List
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("goodsBrand").field("brandName").size(100));
        //规格
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("goodsSpecs").field("specsJson"));

        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();

        if (param.getKey() != null) {
            boolQueryBuilder.must(QueryBuilders.multiMatchQuery(param.getKey(), "name", "category_name"));
        }

        if (!StringUtils.isEmpty(param.getCategory())){
            res.setCategory(param.getCategory());
            boolQueryBuilder.filter(QueryBuilders.termQuery("categoryName", param.getCategory()));
        }
        if (!StringUtils.isEmpty(param.getBrand())){
            res.setCategory(param.getCategory());
            boolQueryBuilder.filter(QueryBuilders.termQuery("brandName", param.getBrand()));
        }
        if (param.getSpecsValueMap() != null){
            res.setSpecsValueMap(param.getSpecsValueMap());
            for (Map.Entry<String, String> entry : param.getSpecsValueMap().entrySet()) {
                boolQueryBuilder.filter(QueryBuilders.termQuery("specsMap." + entry.getKey() + ".keyword", entry.getValue()));
            }
        }

        RangeQueryBuilder rangeQueryBuilder = new RangeQueryBuilder("price");
        rangeQueryBuilder.gte(param.getMinPrice());
        if (param.getMaxPrice() > 0){
            rangeQueryBuilder.lte(param.getMaxPrice());
        }
        boolQueryBuilder.must(rangeQueryBuilder);


        FieldSortBuilder scoreSortBuilder = null;
        if (StringUtils.isEmpty(param.getOrderField()) && StringUtils.isEmpty(param.getOrderType())
                && param.getOrderType().equalsIgnoreCase("asc")
                || param.getOrderType().equalsIgnoreCase("desc")){
            scoreSortBuilder = SortBuilders.fieldSort(param.getOrderField());
            scoreSortBuilder.order(SortOrder.fromString(param.getOrderType()));
        }

        HighlightBuilder hignlightBuilder = new HighlightBuilder();
        hignlightBuilder
                .field("name").preTags("").postTags("")
                .field("brandName").preTags("").postTags("")
                .field("categoryName").preTags("").postTags("");

        PageRequest pageRequest = PageRequest.of(page - 1, size);

        NativeSearchQuery searchQuery = nativeSearchQueryBuilder
                .withQuery(boolQueryBuilder)
                .withPageable(pageRequest)
                .withSort(scoreSortBuilder)
                .withHighlightBuilder(hignlightBuilder)
                .build();

        SearchHits<GoodsESInfo> goodsESInfoSearchHits = elasticsearchRestTemplate.search(searchQuery, GoodsESInfo.class);

        //结果构造
        List<String> categoryNames = null;
        if (StringUtils.isNotEmpty(param.getCategory())){
            categoryNames = new ArrayList<>();
            ParsedStringTerms goodsCategoryAggregation = goodsESInfoSearchHits.getAggregations().get("goodsCategory");
            for (Terms.Bucket bucket : goodsCategoryAggregation.getBuckets()){
                categoryNames.add(bucket.getKeyAsString());
            }
        }
        List<String> brandNames = null;
        if (StringUtils.isEmpty(param.getBrand())){
            brandNames = new ArrayList<>();
            ParsedStringTerms brandAggregation = goodsESInfoSearchHits.getAggregations().get("goodsBrand");
            for (Terms.Bucket bucket : brandAggregation.getBuckets()){
                brandNames.add(bucket.getKeyAsString());
            }
        }

        ParsedStringTerms goodsSpecs = goodsESInfoSearchHits.getAggregations().get("goodsSpecs");
        Map<String, Set<String>> specsRes = new HashMap<>();
        for (Terms.Bucket bucket : goodsSpecs.getBuckets()){
            JSONObject specsJsonObj = JSONObject.parseObject(bucket.getKeyAsString());
            for (Map.Entry<String, Object> specsEntry : specsJsonObj.entrySet()){
                if (param.getSpecsValueMap() != null && param.getSpecsValueMap().containsKey(specsEntry.getKey())){
                    continue;
                }
                Set<String> specOptions = specsRes.get(specsEntry.getKey());
                if (specOptions == null){
                    specOptions = new HashSet<>();
                }
                specOptions.add((String) specsEntry.getValue());
                specsRes.put(specsEntry.getKey(), specOptions);
            }
        }

        List<GoodsESInfo> rows = new ArrayList<>();
        for (SearchHit<GoodsESInfo> searchHit : goodsESInfoSearchHits){
            GoodsESInfo goodsESInfo =  searchHit.getContent();

            List<String> nameList = searchHit.getHighlightField("name");
            if (nameList.size() > 0){
                goodsESInfo.setName(nameList.get(0));
            }

            List<String> categoryNameList = searchHit.getHighlightField("categoryName");
            if (categoryNameList.size() > 0){
                goodsESInfo.setCategoryName(categoryNameList.get(0));
            }

            List<String> brandNameList = searchHit.getHighlightField("brandName");
            if (brandNameList.size() > 0){
                goodsESInfo.setBrandName(brandNameList.get(0));
            }

            rows.add(goodsESInfo);
        }

        long totalSize = goodsESInfoSearchHits.getTotalHits();
        long pages = totalSize / size + (totalSize % size > 0 ? 1 : 0);

        res.setPage(page);
        res.setTotal(totalSize);
        res.setGoodsESInfoList(rows);
        res.setTotalPages(pages);
        res.setBrandList(brandNames);
        res.setSpecsList(specsRes);

        return res;
    }

你可能感兴趣的:(java,elasticsearch)