ElastaicSearch-第三天

目标

  • 根据搜索关键字查询
  • 条件筛选
  • 规格过滤
  • 价格区间搜索
  • 分页查询
  • 排序查询
  • 高亮查询

搭建框架

关键字查询-构建搜索条件

需求:01页面原型-》search.html

1搜索服务 com.changgou.search.service

public interface SearchService {
    //按照查询条件进行数据查询
    Map search(Map<String,String> searchMap);
}

2com.changgou.search.service.impl

@Service
public class SearchServiceImpl implements SearchService {
@Autowired
ElasticsearchTemplate elasticsearchTemplate;

@Override
public Map search(Map<String, String> searchMap) {
    //构建查询
    if(searchMap!=null){
         //  条件构建对象
        NativeSearchQueryBuilder nativeSearchQueryBuilder=new NativeSearchQueryBuilder();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //关键字查询
        if(StringUtils.isNotEmpty(searchMap.get("keywords"))){
            boolQueryBuilder.must(QueryBuilders.matchQuery("name", searchMap.get("keywords")).operator(Operator.AND));
        }
        
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);

        //开启查询
        /**
         * 条件构建对象
         * 查询实体类
         * 查询结果对象
         */
        AggregatedPage<SkuInfo> resultInfo = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuInfo.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                            return null;
            }
        });

    }
    
    return null;
}
}

封装查询结果

完善com.changgou.search.service.impl

@Service
public class SearchServiceImpl implements SearchService {
@Autowired
ElasticsearchTemplate elasticsearchTemplate;

@Override
public Map search(Map<String, String> searchMap) {
    //结果map
    Map<String,Object> resultMap=new HashMap<>();

    //构建查询
    if(searchMap!=null){
         //  条件构建对象
        NativeSearchQueryBuilder nativeSearchQueryBuilder=new NativeSearchQueryBuilder();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //关键字查询
        if(StringUtils.isNotEmpty(searchMap.get("keywords"))){
            boolQueryBuilder.must(QueryBuilders.matchQuery("name", searchMap.get("keywords")).operator(Operator.AND));
        }

        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);

        //开启查询
        /**
         * 条件构建对象
         * 查询实体类
         * 查询结果对象
         */
        //封装查询结果
        AggregatedPage<SkuInfo> resultInfo = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuInfo.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                // 查询结果操作
                List<T> list=new ArrayList<>();

                // 获取结果
                SearchHits hits = searchResponse.getHits();
                if (hits!=null){
                    for (SearchHit hit : hits) {
                        // hit对象转为skuinfo
                        SkuInfo skuInfo = JSON.parseObject(hit.getSourceAsString(), SkuInfo.class);

                        list.add((T) skuInfo);
                    }
                }
                //构建返回对象
                return new AggregatedPageImpl<>(list,pageable,hits.getTotalHits(),searchResponse.getAggregations());
            }
        });
                // 封装最终返回结果
        //总记录数
        resultMap.put("total", resultInfo.getTotalElements());
        //总页数
        resultMap.put("totalPages",resultInfo.getTotalPages());
        //数据集合
        resultMap.put("rows", resultInfo.getContent());
    }
    return resultMap;
}
}

表现层定义

1 com.changgou.search.controller

@RestController
@RequestMapping("/search")
public class SearchController {
    @Autowired
    SearchService searchService;
    @GetMapping
public  Map search(@RequestParam Map<String,String> searchMap){
    //特殊符号处理
    this.handleSearchMap(searchMap);

    Map searchResult = searchService.search(searchMap);
    return searchResult;
}

private void handleSearchMap(Map<String, String> searchMap) {
    Set<Map.Entry<String, String>> entries = searchMap.entrySet();
    for (Map.Entry<String, String> entry : entries) {
        if (entry.getKey().startsWith("spec_")){
            searchMap.put(entry.getKey(), entry.getValue().replace("+", "%2B"));
        }
    }
}
}

测试

postman测试 http://localhost:9009/search?keywords=手机

结果:默认分页 每页10条

各种查询

条件查询需求

在这里插入图片描述

用户有可能会根据分类搜索、品牌搜索,还有可能根据规格搜索,以及价格搜索和排序 操作。根据分类和品牌搜索的时候,可以直接根据指定域搜索,而规格搜索的域数据是不确定的,价格是一个区间搜索,所以我们可以分为三段实现,先实现分类、品牌搜索,再实现规格搜索,然后实现价格区间搜索。

品牌过滤查询

1完善 SearchServiceImpl

//按照品牌查询       
if(StringUtils.isNotEmpty(searchMap.get("brand"))){         
	boolQueryBuilder.filter(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
}

测试 http://localhost:9009/search?keywords=手机&brand=华为

品牌聚合查询

需求:查看静态页面,品牌的显示要根据搜索结果不同展现。

1完善 SearchServiceImpl

//按照品牌聚合
String skuBrand="skuBrand";        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuBrand).field("brandName"));
//封装品牌分组结果
StringTerms brandTerms = (StringTerms) resultInfo.getAggregation(skuBrand);
List<String> brandList = brandTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
resultMap.put("brandList", brandList);

测试: http://localhost:9009/search?keywords=手机

按照规格过滤

在这里插入图片描述
需求:

(1)前端发来规格查询:

 http://localhost:9009/search?keywords=手机&spec_颜色=红色&spec_网络制式=电信3G&spec_版本=8G%2B256G

(2)后台接到数据后,可以根据前缀spec_来区分是否是规格,如果以 spec_xxx 开始的数据 则为规格数据,需要根据指定规格找信息。

(3)
在这里插入图片描述

上图是规格的索引存储格式,真实数据在 “specMap.规格名字.keyword” 中,所以找数据 也是按照如下格式去找。

1完善 SearchServiceImpl

//按照规格过滤查询
        for (String key : searchMap.keySet()) {
            if(key.startsWith("spec_")){
                String value = searchMap.get(key).replace("%2B", "+");                boolQueryBuilder.filter(QueryBuilders.termQuery("specMap."+key.substring(5)+".keyword", value));
            }
        }

测试: http://localhost:9009/search?keywords=手机&spec_颜色=红色

按照规格聚合

1完善 SearchServiceImpl

//按照规格聚合
String skuSpec="skuSpec";        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuSpec).field("spec.keyword"));
//封装规格分组结果
StringTerms specTerms = (StringTerms) resultInfo.getAggregation(skuSpec);
List<String> specList = specTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
resultMap.put("specList", specList);

测试: http://localhost:9009/search?keywords=手机

text 类型 不能进行聚合和排序

keyword 类型 能进行聚合和排序

价格区间查询

在这里插入图片描述
需求:价格区间查询,每次需要将价格传入到后台,前端传入后台的价格大概是 price=0‐500 或者 price=500‐1000 依次类推,最后一个是 price=3000 ,后台可以根据-分割,如果分割 得到的结果最多有2个,第1个表示 x<price ,第2个表示 price<=y。

1完善 SearchServiceImpl

        //价格区间过滤查询
      if(StringUtils.isNotEmpty(searchMap.get("price"))){
            String[] prices = searchMap.get("price").split("-");
            //500-1000
            if(prices.length==2){
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lte(prices[1]));
            }           
          boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(prices[0]));
        }

测试: http://localhost:9009/search?keywords=手机&price=0-500

分页

1完善 SearchServiceImpl

        //分页查询
        String pageNum = searchMap.get("pageNum");
        String pageSize = searchMap.get("pageSize");
        if(StringUtils.isEmpty(pageNum)){
            pageNum="1";
        }
        if(StringUtils.isEmpty(pageSize)){
            pageSize="30";
        }
        nativeSearchQueryBuilder.withPageable(PageRequest.of(Integer.parseInt(pageNum)-1, Integer.parseInt(pageSize)));
        
		// 当前页
        resultMap.put("pageNum", pageNum);

测试: http://localhost:9009/search?keywords=手机&pageNum=5&pageSize=20

排序

在这里插入图片描述

  • 排序这里总共有根据价格排序、根据评价排序、根据新品排序、根据销量排序,排序要 想实现非常简单,只需要告知排序的域以及排序方式即可实现。

  • 价格排序:只需要根据价格高低排序即可,降序价格高->低,升序价格低->高
    评价排序:评价分为好评、中评、差评,可以在数据库中设计3个列,用来记录好评、中 评、差评的量,每次排序的时候,好评的比例来排序,当然还要有

  • 条数限制,评价条数 需要超过N条。

  • 新品排序:直接根据商品的发布时间或者更新时间排序。

  • 销量排序:销量排序除了销售数量外,还应该要有时间段限制。

    1完善 SearchServiceImpl

          //排序
          //1当前域2升序降序
          if (StringUtils.isNotEmpty(searchMap.get("sortField")) && StringUtils.isNotEmpty(searchMap.get("sortRule"))) {
              if ("ASC".equals(searchMap.get("sortRule"))) {
                  //升序
                  nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(searchMap.get("sortField")).order(SortOrder.ASC));
              } else {
                  //降序
               nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(searchMap.get("sortField")).order(SortOrder.DESC));
              }
          }
    

    测试: http://localhost:9009/search?keywords=手机&pageSize=1000&sortField=price&sortRule=Desc

高亮介绍

需求:京东搜索电脑

什么是高亮:搜索结果文字样式不同于其他。

<font class="skcolor_ljg">P30</font>

实现步骤:

1.指定高亮字段:name字段。关键词前后加标签。

2.将高亮字段提取,替换高亮字段:name。

高亮实现

//1设置高亮域
HighlightBuilder.Field field = new HighlightBuilder.Field("name");
//前缀
field.preTags("<span style='color:red'>");
//后缀
field.postTags("</span>");      
nativeSearchQueryBuilder.withHighlightFields(field);


//2获取高亮字段
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
if (highlightFields != null&&highlightFields.size()>0) {                       	    skuInfo.setName(highlightFields.get("name").getFragments()[0].toString());
}

测试: http://localhost:9009/search?keywords=手机

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值