es导入数据和检索数据 过滤(通过产品名称,品牌名称) 高亮 -- 排序等

es常用方法–开发

微服务模块搭建

创建一个搜索微服务 qc_service-search-api 作为 feign 调用的api

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AC5vEHlZ-1625378745907)(img\项目搭建1.png)]

在 es api导入es data包

    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
    </dependencies>
     
               //lombok的支持
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

es api pojo 需要导入的 商品 类

Data
@Document(indexName = "skuinfo", type = "docs")
public class SkuInfo implements Serializable {
    //商品id,同时也是商品编号
    @Id
    private Long id;
    //SKU名称
    @Field(type = FieldType.Text, analyzer = "ik_smart")
    private String name;

    //商品价格,单位为:元
    @Field(type = FieldType.Double)
    private Double price;

    //库存数量
    private Integer num;

    //商品图片
    private String image;

    //商品状态,1-正常,2-下架,3-删除
    private String status;

    //创建时间
    private Date createTime;

    //更新时间
    private Date updateTime;

    //是否默认
    private String isDefault;

    //SPUID
    private Long spuId;

    //类目ID
    private Long categoryId;

    //类目名称
    @Field(type = FieldType.Keyword)
    private String categoryName;

    //品牌名称
    @Field(type = FieldType.Keyword)
    private String brandName;   //1

    //规格
  // @Field(type =FieldType.Text,fielddata = true)
    private String spec;

    //规格参数
    private Map<String, Object> specMap;


}

商品导入es api 的 feign 的接口


@FeignClient(name = "service-goods")
@RequestMapping(value = "goods/sku")
public interface SkuFeign {
    /***
     * 根据审核状态查询Sku
     * @param status
     * @return
     */
    @GetMapping("/q/{status}/p/{pageNum}/s/{pageSize}")
    ServerResponse findByStatus(@PathVariable String status, @PathVariable Integer pageNum,
                                @PathVariable Integer pageSize);
    /**
     * 通过spuid 查询 SpuEntity
     */
    @GetMapping("getSpu/{skuid}")
    SpuEntity getSpu(@PathVariable String skuid);
}

2 創建ES 搜索微服务的service

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Z6YKql2-1625378745909)(\img\项目搭建2.png)]

启动类的实现

package com.qc_shop.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;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@ComponentScan({"com.qc_shop.search.feign","com.qc_shop.search"})

public class SearchApplication {
    public static void main(String[] args) {
        /**
         * Springboot整合Elasticsearch 在项目启动前设置一下的属性,防止报错
         * 解决netty冲突后初始化client时还会抛出异常
         * availableProcessors is already set to [12], rejecting [12]
         ***/
        //System.setProperty("es.set.netty.runtime.available.processors", "false");

        SpringApplication.run(SearchApplication.class, args);

    }
}
package com.qc_shop.search.dao;

import com.qc_shop.search.pojo.SkuInfo;
import org.springframework.data.elasticsearch.repository.ElasticsearchCrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface SkuFeignDao  extends ElasticsearchCrudRepository<SkuInfo,Long> {

}

contrller 中的实现


@RestController
@RequestMapping("/search/sku")
public class SkuFeignController {

    @Autowired
    private SkuFeignService skuFeignService;

   //导入数据
    @GetMapping("/ipt/q/{status}/p/{pageNum}/s/{pageSize}")
    private ServerResponse importSku(@PathVariable String status, @PathVariable Integer pageNum,
                                     @PathVariable Integer pageSize) {

        return skuFeignService.importSku(status,pageNum,pageSize);

    }
        //检索数据
    @PostMapping("/searchMap")
    private ServerResponse getSku(@RequestBody Map searchMap) {

        System.out.println(searchMap);
        return skuFeignService.searchSku(searchMap);

    }
        //检索spec 的数据
    @PostMapping("/searchSpecMap")
    private ServerResponse getSkuSpec(@RequestBody(required = false) Map searchMap) {
        return skuFeignService.searchSkuSpec(searchMap);
    }

 /*   @PostMapping("/searchSkuPrice")
    private ServerResponse getSkuPrice(@RequestBody(required = false) Map searchMap) {
        return skuFeignService.getSkuPrice(searchMap);
    }*/
    /**
     * 组合条件筛选
     * @param
     * @return
     */

    @PostMapping("/searchSpecAndCategoryMap")
    private ServerResponse searchSpecAndCategoryMap(@RequestBody(required = false) Map searchMap) {
        return skuFeignService.searchSpecAndCategoryMap(searchMap);

    }

}

service 的实现

导入数据到es

contrller


@RestController
@RequestMapping("/search/sku")
public class SkuFeignController {

    @Autowired
    private SkuFeignService skuFeignService;


    @GetMapping("/ipt/q/{status}/p/{pageNum}/s/{pageSize}")
    private ServerResponse importSku(@PathVariable String status, @PathVariable Integer pageNum,
                                     @PathVariable Integer pageSize) {

        return skuFeignService.importSku(status,pageNum,pageSize);

    }

导入数据的serviceimpl 的实现类

   @SneakyThrows
    @Override
    public ServerResponse importSku(String status, Integer pageNum, Integer pageSize) {
     // 将feign注入 调用feign接口  
        ServerResponse skuMap = skuFeign.findByStatus(status, pageNum, pageSize);
         //创建一个list 来封装 SkuInfo类个es
        LinkedList<SkuInfo> skuInfos = new LinkedList<>();
         //将封装在ServerResponse的数据page取出来
        List<Object> skuEntities = (List<Object>) skuMap.getpage();
           //取出来的格式需要转换 当前 为 List<Map<>> 类型的 
        for (Object skuEntity : skuEntities) {
           // getSkuInfo((Map) skuEntity)); 封装skuInfo
            skuInfos.add(getSkuInfo((Map) skuEntity));
        }
        if (skuInfos.size() < 1) {
            log.info("待导入数据不存在");
            return ServerResponse.createBySuccess("待导入数据不存在");
        }
        skuFeignDao.saveAll(skuInfos);
        log.info("导入成功");
        return ServerResponse.createBySuccess("导入成功");
    }

 /**
     * 封装skuInfo
     *
     * @param skuEntity
     * @return
     */
    @SneakyThrows
    private SkuInfo getSkuInfo(Map skuEntity) {
        //需要将数据从map 取出来强转为skuinfo需要的数据类型
        SkuInfo skuInfo = new SkuInfo();
        skuInfo.setBrandName((String) skuEntity.get("brandName"));

        skuInfo.setCategoryId(Long.valueOf((Integer) skuEntity.get("categoryId")));
        skuInfo.setCategoryName((String) skuEntity.get("categoryName"));
        skuInfo.setImage((String) skuEntity.get("image"));
        //时间转换
        String createTime = (String) skuEntity.get("createTime");
        skuInfo.setCreateTime(MyDateTimeUtil.strToDate_No_H_m_s(createTime));
        String updateTime = (String) skuEntity.get("updateTime");

        skuInfo.setUpdateTime(MyDateTimeUtil.strToDate_No_H_m_s(updateTime));

        skuInfo.setId(Long.valueOf((String) skuEntity.get("id")));
        //查询spu  拿到IsDefault 的数据设置进去
        SpuEntity spuEntity = skuFeign.getSpu((String) skuEntity.get("id"));
        skuInfo.setIsDefault(spuEntity.getIsDelete());

        skuInfo.setPrice(Double.valueOf((Integer) skuEntity.get("price")));
        skuInfo.setNum((Integer) skuEntity.get("num"));
        skuInfo.setSpec((String) skuEntity.get("spec"));
        skuInfo.setStatus((String) skuEntity.get("status"));
        skuInfo.setSpuId(Long.valueOf((String) skuEntity.get("spuId")));
        skuInfo.setName((String) skuEntity.get("name"));

        String spec = (String) skuEntity.get("spec");
        spec = spec.replaceAll("\'", "\"");
        Map<String, Object> specMap = objectMapper.readValue(spec, new TypeReference<HashMap<String, Object>>() {
        });
        skuInfo.setSpecMap(specMap);
        return skuInfo;
    }



skufeign调用接口 这个接口一定加上@FeignClient 直接去找到服务

并且一下的feign的接口函数和调用服务的接口函数要一致 sku 下的controller

@RestController
@RequestMapping("/goods/sku")
public class SkuController {

    @Autowired
    private SkuService skuService;

    /**
     * 列表
     */
    @GetMapping("/q/{status}/p/{pageNum}/s/{pageSize}")
    public ServerResponse<List<SkuEntity>> findByStatus(@PathVariable String status, @PathVariable Integer pageNum,
                                                        @PathVariable Integer pageSize) {


        return skuService.findByStatus(status, pageNum, pageSize);
    }
}
import com.qc_shop.goods_api.entity.SpuEntity;
import com.qc_shop.util.ServerResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Random;
import java.util.Scanner;

@FeignClient(name = "service-goods")
@RequestMapping(value = "goods/sku")
public interface SkuFeign {
    /***
     * 根据审核状态查询Sku
     * @param status
     * @return
     */
    @GetMapping("/q/{status}/p/{pageNum}/s/{pageSize}")
    ServerResponse findByStatus(@PathVariable String status, @PathVariable Integer pageNum,
                                @PathVariable Integer pageSize);

    /**
     * 通过spuid 查询 SpuEntity
     */
    @GetMapping("getSpu/{skuid}")
    SpuEntity getSpu(@PathVariable String skuid);
}

对商品聚合搜索,通过分类名称,和产品名称


    /**
     * sku产品 聚合检索
     *
     * @param map
     * @return
     */
    @Override
    public ServerResponse searchSku(Map<String, String> map) {
        String keywords = map.get("keywords");
        if (StringUtils.isEmpty(keywords)) {
            //设置一个默认值
            keywords = "娃娃";
        }
        //构建查询对象---> 的构建对象
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

        //设置主关键字查询
        nativeSearchQueryBuilder.withQuery(QueryBuilders.multiMatchQuery(keywords, "name", "brandName", "categoryName"));
        nativeSearchQueryBuilder.withFilter(boolQueryBuilder);
        //设置查询条件 分类名称查询
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuCategoryGroup").field("categoryName").size(50));
        //设置品牌查询条件
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuBrandGroup").field("brandName").size(50));
        //设置规格查询条件
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuSpecGroup").field("spec.keyword").size(50));
        // 设置查询添加  价格查询
        nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("name", keywords));
        //构建查询对象
        NativeSearchQuery query = nativeSearchQueryBuilder.build();
        //执行查询

        AggregatedPage<SkuInfo> skuInfos = elasticsearchTemplate.queryForPage(query, SkuInfo.class);
        
        if (skuInfos.isEmpty()) {
            return ServerResponse.createByError("查询数据不存在");
        }
        //获取分组
        StringTerms skuCategoryGroup = (StringTerms) skuInfos.getAggregation("skuCategoryGroup");
        //获取categoryList 分类列表
        List categoryList = getGroupTOList(skuCategoryGroup);
        //获取brandList 分类列表
        StringTerms skuBrandGroup = (StringTerms) skuInfos.getAggregation("skuBrandGroup");
        List brandList = getGroupTOList(skuBrandGroup);
        //spec{"KYE","VALUE"} 分类 map
        StringTerms skuSpecGroup = (StringTerms) skuInfos.getAggregation("skuSpecGroup");
        Map skuSpecMap = getGroupToMap(skuSpecGroup);
        
        HashMap rs = new HashMap<>();
        rs.put("categoryList", categoryList);
        rs.put("brandList", brandList);
        rs.put("row", skuInfos.getContent());
        rs.put("total", skuInfos.getTotalPages());
        rs.put("totalPages", skuInfos.getTotalPages());
        rs.put("pageSize", skuInfos.getSize());
        rs.put("scroll", skuInfos.getScrollId());
        return ServerResponse.createBySuccess("查询成功", rs);
    }

通过条件筛选在上面代碼加入以下筛选条件

通过QueryBuilders.boolQuery();

  // 该方法底层页数和上面一样,是一个 new BoolQueryBuilder() 返回一个条件而已
    public static BoolQueryBuilder boolQuery() {
        return new BoolQueryBuilder();
    }

        /*添加过滤条件*/
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //类型名称做过滤
        if (map.get("categoryName") != null) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("categoryName", map.get("categoryName")));
            log.info("----------------------------------categoryName" + map.get("categoryName"));
        }
        
        //品牌名称做过滤
        if (map.get("brandName") != null) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("brandName", map.get("brandName")));
            log.info("----------------------------------brandName" + map.get("categoryName"));
        }
        
        
        //产品规格做过滤   QueryBuilders.matchQuery 匹配的第一个参数名称必须做匹配es 中导入        实体的字段  
        
        for (String key : map.keySet()) {
            if (key.startsWith("spec_")) {
                boolQueryBuilder.must(QueryBuilders.matchQuery("specMap." + key.substring(5) + ".keyword", map.get(key)));
                log.info("specMap." + key.substring(5) + ".keyword" + "-------------------------");
            }
        }
        
        
        //价格过滤  gte :大于等于  lte 小于等于
        if (map.get("price") != null) {
            String price = map.get("price");
            String[] split = price.split("-");
            if (split.length > 1) {
                boolQueryBuilder.must(QueryBuilders.rangeQuery("price").from(split[0], true).to(split[1], true));
                log.info("price------------------");
            } else {
                boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gte(split[0]));
            }
        }
           
        //增加分页 
        if (map.get("pageNum") != null || map.get("pageSize") != null) {
            Integer pageNum = Integer.valueOf(map.get("pageNum"));
            Integer pageSize = Integer.valueOf(map.get("pageSize"));
            log.info(pageNum + "----------------" + pageSize);
            nativeSearchQueryBuilder.withPageable(PageRequest.of(pageNum - 1, pageSize));
        }
       //增加 排序ortBuilders.fieldSort("需要排序的字段").order("排序的规则 升序还是降序")
        //根据?排序;比如根据价格排序sortFiled=price
        if (map.get("sortRule") != null || map.get("sortFiled") != null) {
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(map.get("sortFiled")).
                    order(map.get("sortRule").equals("DESC") ? SortOrder.DESC : SortOrder.ASC));
        }


        //设置高亮条件  .field("需要高亮的字段").preTags("选择的标签").postTags(结束标签)
        // .fragmenter("20")  分段,可有可以无

        nativeSearchQueryBuilder.withHighlightBuilder(new HighlightBuilder()
                .field("name")
                .preTags("<i style=\"color:red\">")
                .postTags("</i>")
                .fragmenter("20")
        );

elasticsearchTemplate 的高亮处理

AggregatedPage<SkuInfo> skuInfos = elasticsearchTemplate.queryForPage(query, SkuInfo.class, myHighlight);

创建一个MyHighlight接口来实现

package com.qc_shop.search.service.Impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.qc_shop.search.pojo.SkuInfo;
import lombok.SneakyThrows;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Map;

@Component
public class MyHighlight implements SearchResultMapper {
    @Autowired
    private ObjectMapper objectMapper;
        @SneakyThrows
        @Override
        public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
            ArrayList<T> skuInfoList = new ArrayList<>();
            //做空判断
            if (searchResponse.getHits()==null){
                return new AggregatedPageImpl<>(skuInfoList);
            }
            for (SearchHit hit : searchResponse.getHits()) {
                //获取到高亮字段
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                //拿到高亮的值
                HighlightField higValue = highlightFields.get("name");
                //if 高亮的值为null  返回空
                if (null==higValue) {
                    return new AggregatedPageImpl<>(skuInfoList);
                }
                StringBuffer sb = new StringBuffer();
                for (Text fragment : higValue.getFragments()) {
                    sb.append(fragment);
                }
                SkuInfo skuInfo = objectMapper.readValue(hit.getSourceAsString(), SkuInfo.class);
                skuInfo.setName(sb.toString());
                skuInfoList.add((T) skuInfo);
            }
            return new AggregatedPageImpl<T>(skuInfoList, pageable, searchResponse.getHits().getTotalHits(),searchResponse.getAggregations());
        }

    @Override
    public <T> T mapSearchHit(SearchHit searchHit, Class<T> aClass) {
        return null;
    }

}

serviceimpl需要注入

 @Autowired
    private MyHighlight myHighlight;

dao

package com.qc_shop.search.dao;

import com.qc_shop.search.pojo.SkuInfo;
import org.springframework.data.elasticsearch.repository.ElasticsearchCrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface SkuFeignDao  extends ElasticsearchCrudRepository<SkuInfo,Long> {
}

s().getTotalHits(),searchResponse.getAggregations());
}

@Override
public <T> T mapSearchHit(SearchHit searchHit, Class<T> aClass) {
    return null;
}

}


serviceimpl需要注入

```java
 @Autowired
    private MyHighlight myHighlight;

dao

package com.qc_shop.search.dao;

import com.qc_shop.search.pojo.SkuInfo;
import org.springframework.data.elasticsearch.repository.ElasticsearchCrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface SkuFeignDao  extends ElasticsearchCrudRepository<SkuInfo,Long> {
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值