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;
        }
    }
    

    源码地址:https://download.csdn.net/download/zsx1314lovezyf/85302523

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
Spring Cloud集成Elasticsearch可以通过使用Spring Data Elasticsearch来实现。Spring Data ElasticsearchSpring Data项目的一部分,它提供了与Elasticsearch交互的API和工具。 要使用Spring Data Elasticsearch,需要在项目中添加以下依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> ``` 然后,需要配置Elasticsearch的连接信息,可以在application.properties文件中添加以下配置: ``` spring.data.elasticsearch.cluster-name=myClusterName spring.data.elasticsearch.cluster-nodes=localhost:930 ``` 接下来,就可以使用Spring Data Elasticsearch提供的API来操作Elasticsearch了。例如,可以定义一个Elasticsearch的Repository接口,用于操作索引: ``` public interface BookRepository extends ElasticsearchRepository<Book, String> { List<Book> findByTitle(String title); } ``` 在这个例子中,Book是一个实体类,它对应了Elasticsearch中的一个文档。findByTitle方法是一个自定义查询方法,用于根据书名查询书籍。 最后,可以在Spring Boot应用中注入BookRepository,然后使用它来操作Elasticsearch: ``` @Autowired private BookRepository bookRepository; public void saveBook(Book book) { bookRepository.save(book); } public List<Book> searchBooks(String title) { return bookRepository.findByTitle(title); } ``` 这样,就可以在Spring Cloud应用中集成Elasticsearch了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

只因为你温柔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值