SpringCloud使用ElasticSearch

SpringCloud使用ElasticSearch

搜索微服務模塊結構

在這裏插入圖片描述

配置文件

  1. pom.xml----->elasticsearch依賴

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency>
    
  2. pom.xml----->該搜索微服務全部依賴

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>leyou</artifactId>
            <groupId>com.leyou.parent</groupId>
            <version>1.0.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.leyou.search</groupId>
        <artifactId>ly-search</artifactId>
    
        <dependencies>
            <!-- web -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!-- elasticsearch -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
            </dependency>
            <!-- eureka -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <!-- feign 因爲每一個微服務都是獨立的, 所以我們這裏要用feign來遠程調用商品微服務 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
    
            <!-- 測試 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
            </dependency>
    
            <!-- 需要用到商品實體類, 所以這裏需要引用 -->
            <dependency>
                <groupId>com.leyou.upload.service</groupId>
                <artifactId>ly-item-interface</artifactId>
                <version>1.0.0-SNAPSHOT</version>
            </dependency>
        </dependencies>
    
    </project>
    
  3. application.yml----->配置elasticsearch

    data:
        elasticsearch:
          cluster-name: elasticsearch  # 集羣名稱
          cluster-nodes: 192.168.79.128:9300 # 集羣地址
    
  4. application.yml----->該搜索微服務全部配置

    server:
      port: 8084
    spring:
      application:
        name: search-service
      data:
        elasticsearch:
          cluster-name: elasticsearch  # 集羣名稱
          cluster-nodes: 192.168.79.128:9300 # 集羣地址
      Jackson:
        default-property-inclusion: non_null  # 返回的結果是null的就排除
    eureka:
      client:
        service-url:
          defaultZone: http://127.0.0.1:10086/eureka
        registry-fetch-interval-seconds: 5 # 每5秒拉一次註冊信息
      instance:
        prefer-ip-address: true
        ip-address: 127.0.0.1
    

啓動類

  1. LySearchApplication

    package com.leyou.search;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    
    /**
     * @program: leyou
     * @description:
     * @author: Mr.Xiao
     * @create: 2020-06-11 14:39
     **/
    @SpringBootApplication
    @EnableDiscoveryClient  // eureka
    @EnableFeignClients // feign
    public class LySearchApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(LySearchApplication.class);
        }
    
    }
    
    

實體類

  1. Goods

    package com.leyou.search.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import org.springframework.data.annotation.Id;
    import org.springframework.data.elasticsearch.annotations.Document;
    import org.springframework.data.elasticsearch.annotations.Field;
    import org.springframework.data.elasticsearch.annotations.FieldType;
    
    import java.util.Date;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    @Document(indexName = "goods", type = "docs", shards = 1, replicas = 0)
    public class Goods {
        @Id
        private Long id; // spuId
    
        @Field(type = FieldType.Text, analyzer = "ik_max_word")
        private String all; // 所有需要被搜索的信息,包含標題,分類,甚至品牌
    
        @Field(type = FieldType.Keyword, index = false)
        private String subTitle;// 賣點
    
        // 過濾字段 不加註解, spring會自動映射進去
        private Long brandId;// 品牌id
        private Long cid1;// 1級分類id
        private Long cid2;// 2級分類id
        private Long cid3;// 3級分類id
        private Date createTime;// 創建時間
        private Set<Long> price;// 價格
    
    
        @Field(type = FieldType.Keyword, index = false)
        private String skus;// sku信息的json結構
    
        private Map<String, Object> specs;// 可搜索的規格參數,key是參數名,值是參數值
    }
    
  2. SearchRequest

    package com.leyou.search.pojo;
    
    import lombok.Data;
    import org.bouncycastle.jcajce.provider.symmetric.IDEA;
    
    import java.util.Map;
    
    /**
     * @program: leyou
     * @description:
     * @author: Mr.Xiao
     * @create: 2020-06-12 17:49
     **/
    public class SearchRequest {
        // 當前頁碼
        private Integer page;
    
        // 搜索字段
        private String key;
    
        // 因爲是給用戶看的頁面, 所以每頁大小必須定死, 不可修改, 要是給用戶輸入的話如果是1千萬那不搜索服務器直接掛了
        private static final int DEFAULT_PAGE = 1;
        private static final int DEFAULT_SIZE = 20;
    
        // 過濾字段
        private Map<String, String> filter;
    
        public Integer getPage() {
            if (page == null) {
                return DEFAULT_PAGE;
            }
    
            // 比較兩個數的大小, page 大於 DEFAULT_PAGE用page, 小於DEFAULT_PAGE用DEFAULT_PAGE
            return Math.max(DEFAULT_PAGE, page);
        }
    
        public void setPage(Integer page) {
            this.page = page;
        }
    
        public String getKey() {
            return key;
        }
    
        public void setKey(String key) {
            this.key = key;
        }
    
        public int getSize() {
            return DEFAULT_SIZE;
        }
    
        public Map<String, String> getFilter() {
            return filter;
        }
    
        public void setFilter(Map<String, String> filter) {
            this.filter = filter;
        }
    }
    
  3. SearchResult

    package com.leyou.search.pojo;
    
    import com.leyou.common.vo.PageResult;
    import com.leyou.item.pojo.Brand;
    import com.leyou.item.pojo.Category;
    import lombok.Data;
    
    import java.util.List;
    import java.util.Map;
    
    @Data
    public class SearchResult extends PageResult<Goods> {
    
        private List<Category> categories;  // 分類待選項
    
        private List<Brand> brands; // 品牌待選項
    
        private List<Map<String, Object>> specs; // 規格參數 key及待選項
    
        public SearchResult() {
        }
    
        public SearchResult(Long total, Long totalPage, List<Goods> items, List<Category> categories, List<Brand> brands, List<Map<String, Object>> specs) {
            super(total, totalPage, items);
            this.categories = categories;
            this.brands = brands;
            this.specs = specs;
        }
    }
    

client---->繼承的是別的微服務下的接口, 接口中提供了對應的可以遠程調用的方法

  1. BrandClient

    package com.leyou.search.client;
    
    import com.leyou.item.api.BrandApi;
    import org.springframework.cloud.openfeign.FeignClient;
    
    /**
     * @program: leyou
     * @description: 告訴feign 請求服務 請求方式 請求路徑 請求參數 返回結果
     * @author: Mr.Xiao
     * @create: 2020-06-11 17:00
     **/
    @FeignClient("item-service")  // 參數是服務名稱
    public interface BrandClient extends BrandApi {
    }
    
    
  2. CategoryClient

    package com.leyou.search.client;
    
    import com.leyou.item.api.CategoryApi;
    import org.springframework.cloud.openfeign.FeignClient;
    
    /**
     * @program: leyou
     * @description:
     * @author: Mr.Xiao
     * @create: 2020-06-11 17:00
     **/
    @FeignClient("item-service")
    public interface CategoryClient extends CategoryApi {
    }
    
  3. GoodsClient

    package com.leyou.search.client;
    
    import com.leyou.item.api.GoodsApi;
    import org.springframework.cloud.openfeign.FeignClient;
    
    /**
     * @program: leyou
     * @description:
     * @author: Mr.Xiao
     * @create: 2020-06-11 16:59
     **/
    @FeignClient("item-service")
    public interface GoodsClient extends GoodsApi {
    }
    
  4. SpecificationClient

    package com.leyou.search.client;
    
    import com.leyou.item.api.SpecificationApi;
    import org.springframework.cloud.openfeign.FeignClient;
    
    /**
     * @program: leyou
     * @description:
     * @author: Mr.Xiao
     * @create: 2020-06-11 17:01
     **/
    @FeignClient("item-service")
    public interface SpecificationClient extends SpecificationApi {
    }
    
    

repository---->(操作ElasticSearch接口, 提供了各種方法)

  1. GoodsRepository

    package com.leyou.search.repository;
    
    import com.leyou.search.pojo.Goods;
    import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
    
    /**
     * @program: leyou
     * @description: ElasticsearchRepository 第一個參數實體類類型, 第二個參數id類型
     * @author: Mr.Xiao
     * @create: 2020-06-12 12:13
     **/ 
    // ElasticsearchRepository 跟 通用mapper一樣, 裏面包含了各種增刪改查
    public interface GoodsRepository extends ElasticsearchRepository<Goods, Long> {
    }
    

Controller

  1. SearchController

    package com.leyou.search.web;
    
    import com.leyou.common.vo.PageResult;
    import com.leyou.search.pojo.Goods;
    import com.leyou.search.pojo.SearchRequest;
    import com.leyou.search.pojo.SearchResult;
    import com.leyou.search.service.SearchService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @program: leyou
     * @description: 搜索服務 表現層
     * @author: Mr.Xiao
     * @create: 2020-06-12 17:57
     **/
    @RestController
    public class SearchController {
    
        @Autowired
        private SearchService searchService;
    
        @PostMapping("/page")
        public ResponseEntity<SearchResult> search(@RequestBody SearchRequest request) {
           return ResponseEntity.ok(searchService.search(request));
        }
    
    }
    

Service

  1. SearchService接口

    package com.leyou.search.service;
    
    import com.leyou.common.vo.PageResult;
    import com.leyou.item.pojo.Spu;
    import com.leyou.search.pojo.Goods;
    import com.leyou.search.pojo.SearchRequest;
    import com.leyou.search.pojo.SearchResult;
    
    
    /**
     * @program: leyou
     * @description:
     * @author: Mr.Xiao
     * @create: 2020-06-12 09:32
     **/
    public interface SearchService {
    
    /**
     * 封裝goods對象
     * @param spu
     * @return
     */
    Goods buildGoods(Spu spu);
    
    /**
     * 獲取搜索結果
     * @param request
     * @return
     */
    SearchResult search(SearchRequest request);
    }
    
  2. SearchServiceImpl實體類

    package com.leyou.search.service.impl;
    
    import com.fasterxml.jackson.core.type.TypeReference;
    import com.leyou.common.enums.ExceptionEnum;
    import com.leyou.common.exception.LyException;
    import com.leyou.common.utils.JsonUtils;
    import com.leyou.common.utils.NumberUtils;
    import com.leyou.common.vo.PageResult;
    import com.leyou.item.pojo.*;
    import com.leyou.search.client.BrandClient;
    import com.leyou.search.client.CategoryClient;
    import com.leyou.search.client.GoodsClient;
    import com.leyou.search.client.SpecificationClient;
    import com.leyou.search.pojo.Goods;
    import com.leyou.search.pojo.SearchRequest;
    import com.leyou.search.pojo.SearchResult;
    import com.leyou.search.repository.GoodsRepository;
    import com.leyou.search.service.SearchService;
    import javafx.beans.binding.ObjectExpression;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    import org.bouncycastle.asn1.esf.SPUserNotice;
    import org.elasticsearch.index.query.BoolQueryBuilder;
    import org.elasticsearch.index.query.MatchQueryBuilder;
    import org.elasticsearch.index.query.QueryBuilder;
    import org.elasticsearch.index.query.QueryBuilders;
    import org.elasticsearch.search.aggregations.Aggregation;
    import org.elasticsearch.search.aggregations.AggregationBuilders;
    import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
    import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
    import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
    import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
    import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
    import org.springframework.stereotype.Service;
    import org.springframework.util.CollectionUtils;
    
    import javax.swing.plaf.ScrollPaneUI;
    import java.util.*;
    import java.util.stream.Collectors;
    
    /**
     * @program: leyou
     * @description:
     * @author: Mr.Xiao
     * @create: 2020-06-12 09:32
     **/
    @Slf4j
    @Service("searchService")
    public class SearchServiceImpl implements SearchService {
    
        @Autowired
        private BrandClient brandClient;
    
        @Autowired
        private CategoryClient categoryClient;
    
        @Autowired
        private GoodsClient goodsClient;
    
        @Autowired
        private SpecificationClient specificationClient;
    
        @Autowired
        private GoodsRepository goodsRepository;
        
        @Autowired
    	private ElasticsearchTemplate template;
    
        /**
         * 封裝goods對象
         * @param spu
         * @return
         */
        @Override
        public Goods buildGoods(Spu spu) {
    
            // 獲取spu id
            Long spuId = spu.getId();
    
            // 獲取all 所有需要被搜索的信息,包含標題,分類,甚至品牌
            String all = "";
    
            // 獲取分類信息
            List<Category> categoryList = categoryClient.queryCategoryListByIds(Arrays.asList(spu.getCid1(), spu.getCid2(), spu.getCid3()));
    
            if (CollectionUtils.isEmpty(categoryList)) {
                throw new LyException(ExceptionEnum.CATEGORY_NOT_FOUND);
            }
    
            // 獲取分類名稱 以 空格 隔開
            List<String> cnames = categoryList.stream().map(Category::getName).collect(Collectors.toList());
    
            // 獲取品牌
            Brand brand = brandClient.queryBrandById(spu.getBrandId());
    
            if (brand == null) {
                throw new LyException(ExceptionEnum.BRAND_NOT_FOUND);
            }
    
            all = spu.getTitle() + StringUtils.join(cnames, " ") + brand.getName();
    
            // 獲取sku商品信息
            List<Sku> skuList = goodsClient.querySkuListBySpuId(spuId);
    
            if (CollectionUtils.isEmpty(skuList)) {
                throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
            }
    
            // sku 商品集合
            ArrayList<Map<String, Object>> skus = new ArrayList<>();
            // sku 價格集合
            HashSet<Long> prices = new HashSet<>();
    
            // 優於展示字段只是sku中的幾個字段, 所以我們這裏不需要全部字段, 需要做抽離
            for (Sku sku : skuList) {
                HashMap<String, Object> map = new HashMap<>();
                map.put("id", sku.getId());
                map.put("title", sku.getTitle());
                map.put("price", sku.getPrice());
                // 獲取第一張圖片信息
                map.put("image", StringUtils.substringBefore(sku.getImages(), ","));
    
                // 添加sku商品
                skus.add(map);
    
                // 添加sku價格
                prices.add(sku.getPrice());
            }
    
            // 規格參數
            Map<String, Object> specs = new HashMap<>();
    
            // 獲取存儲規格參數鍵對象
            // 可搜索字段, 分類id是3級分類
            List<SpecParam> specParams = specificationClient.queryParamByList(null, spu.getCid3(), true);
    
            if (CollectionUtils.isEmpty(specParams)) {
                throw new LyException(ExceptionEnum.SPEC_PARAM_NOT_FOUND);
            }
    
            // 獲取spu詳細信息
            SpuDetail spuDetail = goodsClient.querySpuDetailBySpuId(spuId);
    
            if (spuDetail == null) {
                throw new LyException(ExceptionEnum.SPU_NOT_FOUND);
            }
    
            // 獲取通用規格參數
            Map<Long, Object> genericSpec = JsonUtils.parseMap(spuDetail.getGenericSpec(), Long.class, Object.class);
    
            // 獲取特有規格參數
            Map<Long, List<Object>> specialSpec = JsonUtils.nativeRead(spuDetail.getSpecialSpec(),
                    new TypeReference<Map<Long, List<Object>>>() {});
    
            // 遍歷處理specs
            for (SpecParam specParam : specParams) {
                String key = specParam.getName();
                Object value = "";
                // 是通用規格參數
                if (specParam.getGeneric()) {
                    value = genericSpec.get(specParam.getId());
                    if (specParam.getNumeric()) {
                        // 是數值類型
                        if (StringUtils.isNotBlank(specParam.getSegments())) {
                            // 處理成段
                            value = chooseSegment(value.toString(), specParam);
                        }
                    }
                } else {
                    value = specialSpec.get(specParam.getId());
                }
                specs.put(key, value);
            }
    
            // 封裝對象
            Goods goods = new Goods();
            goods.setCid1(spu.getCid1());
            goods.setCid2(spu.getCid2());
            goods.setCid3(spu.getCid3());
            goods.setBrandId(spu.getBrandId());
            goods.setCreateTime(spu.getCreateTime());
            goods.setId(spuId);
            goods.setSubTitle(spu.getSubTitle());
            goods.setAll(all); //  所有需要被搜索的信息,包含標題,分類,甚至品牌
            goods.setSkus(JsonUtils.serialize(skus)); // sku商品
            goods.setPrice(prices); // sku 價格集合
            goods.setSpecs(specs); // 可搜索的規格參數,key是參數名,值是參數值
            return goods;
        }
    
        /**
         * 獲取搜索結果
         * @param request
         * @return
         */
        @Override
        public SearchResult search(SearchRequest request) {
            // 獲取參數
            int page = request.getPage() - 1; // 注意: elasticsearch分頁是以0開始的
            int size = request.getSize();
    
            // 1. 創建查詢構建器
            NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
    
            // 2. 結果過濾
            queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{"id", "subTitle", "skus"}, null));
    
            // 3. 分頁
            queryBuilder.withPageable(PageRequest.of(page, size));
    
            // 4. 創建查詢條件
            QueryBuilder basicQuery = buildConditions(request);
            queryBuilder.withQuery(basicQuery);
    
            // 5. 聚合
            // 5.1品牌聚合
            String brandAggName = "brand_agg";
            queryBuilder.addAggregation(AggregationBuilders.terms(brandAggName).field("brandId"));
    
            // 5.2分類集合
            String categoryAggName = "category_agg";
            queryBuilder.addAggregation(AggregationBuilders.terms(categoryAggName).field("cid3"));
    
            // 6. 執行這裏用了聚合, 所以只能用template
            AggregatedPage<Goods> goodsList = template.queryForPage(queryBuilder.build(), Goods.class);
    
            // 7. 結果解析
            long total = goodsList.getTotalElements();
            int totalPages = goodsList.getTotalPages();
            List<Goods> content = goodsList.getContent();
    
            // 7. 獲取品牌List
            List<Brand> brandList = parseBrand((LongTerms) goodsList.getAggregation(brandAggName));
    
            // 8. 獲取分類List
            List<Category> categoryList = parseCategory((LongTerms) goodsList.getAggregation(categoryAggName));
    
            // 9. 判斷分類不問空, 並且爲1才聚合規格參數
            List<Map<String, Object>> specs = null;
            if (categoryList != null && categoryList.size() == 1) {
                // 構建規格參數
                specs = buildSpecificationAgg(categoryList.get(0).getId(), basicQuery);
            }
    
            return new SearchResult(total, Long.valueOf(totalPages), content, categoryList, brandList, specs);
    
        }
    
        /**
         * 構建查詢過濾條件
         * @param request
         * @return
         */
        private QueryBuilder buildConditions(SearchRequest request) {
            // 1. 構建布爾條件
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
    
            // 2. 構建查詢條件
            queryBuilder.must(QueryBuilders.matchQuery("all", request.getKey()));
    
            // 3. 構建過濾條件
            Map<String, String> filter = request.getFilter();
            if (filter != null) {
                for (Map.Entry<String, String> map : filter.entrySet()) {
                    // 獲取, 過濾條件的鍵
                    String key = map.getKey();
                    // 如果不是分類或者品牌id
                    if (!"cid3".equals(key) && !"brandId".equals(key)) {
                        key = "specs." + key + ".keyword";
                    }
                    queryBuilder.filter(QueryBuilders.termQuery(key, map.getValue()));
                }
            }
    
            return queryBuilder;
    
        }
    
        /**
         * 構建規格參數集合
         * @param cid
         * @param basicQuery
         * @return
         */
        private List<Map<String, Object>> buildSpecificationAgg(Long cid, QueryBuilder basicQuery) {
            // 1. 創建查詢構建器
            NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
    
            // 2. 把搜索條件添加進去
            queryBuilder.withQuery(basicQuery);
    
            // 3. 獲取規格參數
            List<SpecParam> specParams = specificationClient.queryParamByList(null, cid, true);
    
            // 4. 判斷是否爲空
            if (CollectionUtils.isEmpty(specParams)) {
                throw new LyException(ExceptionEnum.SPEC_PARAM_NOT_FOUND);
            }
    
            // 5. 創建對象
            List<Map<String, Object>> specs = new ArrayList<>();
    
            // 6. 遍歷規格參數, 聚合每一個規格參數
            for (SpecParam specParam : specParams) {
                String name = specParam.getName();
                queryBuilder.addAggregation(AggregationBuilders.terms(name).field("specs." + name + ".keyword"));
            }
    
            // 在原有的搜索條件上加上現在聚合的規格參數條件進行查詢
            AggregatedPage<Goods> goods = template.queryForPage(queryBuilder.build(), Goods.class);
    
            // 7. 解析結果集
            // 7.1 遍歷規格參數構造, 規格參數待選項
            for (SpecParam specParam : specParams) {
                String name = specParam.getName();
                StringTerms terms = (StringTerms) goods.getAggregation(name);
                List<StringTerms.Bucket> buckets = terms.getBuckets();
    
                // 構建map對象
                Map<String, Object> map = new HashMap<>();
                map.put("k", name);
                map.put("options", buckets.stream().map(b -> b.getKeyAsString()).collect(Collectors.toList()));
                // 添加進規格參數集合中
                specs.add(map);
            }
            return specs;
        }
    
        /**
         * 獲取聚合後所有的 品牌
         * @param terms
         * @return
         */
        private List<Brand> parseBrand(LongTerms terms) {
            try{
                List<Long> ids = terms.getBuckets().stream().map(b -> b.getKeyAsNumber().longValue()).collect(Collectors.toList());
    
                List<Brand> brands = brandClient.queryBrandByIds(ids);
    
                return brands;
            } catch (Exception e) {
                log.error("[搜索服務]查詢品牌異常: ", e);
                return null;
            }
        }
    
        /**
         * 獲取聚合後所有的分類
         * @param terms
         * @return
         */
        private List<Category> parseCategory(LongTerms terms) {
            try{
                List<Long> ids = terms.getBuckets().stream().map(b -> b.getKeyAsNumber().longValue()).collect(Collectors.toList());
    
                List<Category> categories = categoryClient.queryCategoryListByIds(ids);
    
                return categories;
            } catch (Exception e) {
                log.error("[搜索服務]查詢品牌分類異常: ", e);
                return null;
            }
    
        }
    
    
        /**
         * 拼接規格參數
         * @param value
         * @param p
         * @return
         */
        private String chooseSegment(String value, SpecParam p) {
            double val = NumberUtils.toDouble(value);
            String result = "其它";
            // 保存數值段
            for (String segment : p.getSegments().split(",")) {
                String[] segs = segment.split("-");
                // 獲取數值範圍
                double begin = NumberUtils.toDouble(segs[0]);
                double end = Double.MAX_VALUE;
                if(segs.length == 2){
                    end = NumberUtils.toDouble(segs[1]);
                }
                // 判斷是否在範圍內
                if(val >= begin && val < end){
                    if(segs.length == 1){
                        result = segs[0] + p.getUnit() + "以上";
                    }else if(begin == 0){
                        result = segs[1] + p.getUnit() + "以下";
                    }else{
                        result = segment + p.getUnit();
                    }
                    break;
                }
            }
            return result;
        }
    }
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章