欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

day08-【检索服务】

时间:2023-06-11
检索服务

一、显示页面

1.1、thymeleaf.yml1.2、修改资源路径 二、搜索商品

2.1、参数封装2.3、检索结果封装2.4、修改映射2.5、数据迁移2.6、搜索商品接口

2.6.1、构建检索参数2.6.2、接收检索响应2.6.3、检索不到数据 三、渲染检索页面

3.1、基本数据渲染3.2、筛选条件渲染3.3、搜索按钮渲染3.4、分页数据渲染3.5、页面排序渲染3.6、 面包屑导航3.7、 条件筛选联动3.8、[异步和线程池](https://blog.csdn.net/m0_46914264/article/details/122872613) 一、显示页面

index静态资源复制到:fireflymall-elasticsearch/src/main/resources/static
index页面复制到:fireflymall-elasticsearch/src/main/resources/templates

关闭thymeleaf缓存,方便开发实时看到更新

1.1、thymeleaf.yml

thymeleaf.yml

spring: thymeleaf: cache: false suffix: .html #后缀 prefix: classpath:/templates/ #前缀

引入thymeleaf的命名空间

xmlns:th="http://www.thymeleaf.org"

1.2、修改资源路径

ctrl+r

src="src="/search/

href="href="/search/

二、搜索商品 2.1、参数封装

封装页面所有可能传递的数据

全文检索:skuTitle-》keyword排序:saleCount(销量)、hotScore(热度分)、skuPrice(价格)过滤:hasStock、skuPrice区间、brandId、catalog3Id、attrs聚合:attrs

SearchParamVo

package com.firefly.fireflymall.elasticsearch.vo;import lombok.Data;import java.util.List;@Datapublic class SearchParamVo { //全文检索 private String keyword; private Long catalog3Id; private String sort; private Integer hasStock = 1; private String skuPrice; private Integer skuPrice1; private Integer skuPrice2; private List brandId; private List attrs; //分页 private Integer pageNum = 1; private String _queryString;//原生查询条件}

2.3、检索结果封装

查询得到商品、总记录数、总页码品牌list用于在品牌栏显示,分类list用于在分类栏显示其他栏每栏用AttrVo表示不仅要根据关键字从es中检索到商品还要通过聚合生成品牌等信息,方便分类栏显示

SearchResult

package com.firefly.fireflymall.elasticsearch.vo;import com.firefly.common.to.es.SkuEsModel;import lombok.Data;import java.util.ArrayList;import java.util.List;@Datapublic class SearchResult { private List products; private Integer pageNum;//当前页 private Long total;//总记录数 private Long totalPage;//总页码 private List pageNavs; private List brands;//品牌信息 private List attrs;//属性信息 private List catalogs;//分类信息 private List navs = new ArrayList<>(); private List attrIds = new ArrayList<>(); @Data public static class NavVo{ private String navName; private String navValue; private String link; } @Data public static class BrandVo{ private Long brandId; private String brandName; private String brandImg; } @Data public static class AttrVo{ private Long attrId; private String attrName; private List attrValue; } @Data public static class CatalogVo { private Long catalogId; private String catalogName; }}

2.4、修改映射

此处先写出如何检索指定的商品,如检索"华为"关键字嵌入式的属性highlight:设置该值后,返回的时候就包装过了查出结果后,附属栏也要对应变化嵌入式的聚合时候也要注意

PUT /firefly_product{ "mappings": { "properties": { "skuId": { "type": "long" }, "spuId": { "type": "long" }, "skuTitle": { "type": "text", "analyzer": "ik_smart" }, "skuPrice": { "type": "keyword" }, "skuImg": { "type": "keyword" }, "saleCount": { "type": "long" }, "hosStock": { "type": "boolean" }, "hotScore": { "type": "long" }, "brandId": { "type": "long" }, "catalogId": { "type": "long" }, "brandName": { "type": "keyword" }, "brandImg": { "type": "keyword" }, "catalogName": { "type": "keyword" }, "attrs": { "type": "nested", "properties": { "attrId": { "type": "long" }, "attrName": { "type": "keyword" }, "attrValue": { "type": "keyword" } } } } }}

2.5、数据迁移

POST _reindex{ "source": { "index": "product" }, "dest": { "index": "mall_product" }}

根据一些信息检索出符合条件的文档

GET product/_search{ "query": { "bool": { "must": [ {"match": { "skuTitle": "华为" }} ], "filter": [ { "term": { "catalogId": "225" } }, { "terms": {"brandId": [ "2"] } }, { "term": { "hasStock": "false"} }, { "range": { "skuPrice": { "gte": 1000, "lte": 7000 } } }, { "nested": { "path": "attrs", "query": { "bool": { "must": [ { "term": { "attrs.attrId": { "value": "6"} } } ] } } } } ] } }, "sort": [ {"skuPrice": {"order": "desc" } } ], "from": 0, "size": 5, "highlight": { "fields": {"skuTitle": {}}, "pre_tags": "", "post_tags": "" }, "aggs": { "brandAgg": { "terms": { "field": "brandId", "size": 10 }, "aggs": { "brandNameAgg": { "terms": { "field": "brandName", "size": 10 } }, "brandImgAgg": { "terms": { "field": "brandImg", "size": 10 } } } }, "catalogAgg":{ "terms": { "field": "catalogId", "size": 10 }, "aggs": { "catalogNameAgg": { "terms": { "field": "catalogName", "size": 10 } } } }, "attrs":{ "nested": {"path": "attrs" }, "aggs": { "attrIdAgg": { "terms": { "field": "attrs.attrId", "size": 10 }, "aggs": { "attrNameAgg": { "terms": { "field": "attrs.attrName", "size": 10 } } } } } } }}

返回结果

{ "took" : 37, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 0, "relation" : "eq" }, "max_score" : null, "hits" : [ ] }, "aggregations" : { "brandAgg" : { "doc_count_error_upper_bound" : 0, "sum_other_doc_count" : 0, "buckets" : [ ] }, "catalogAgg" : { "doc_count_error_upper_bound" : 0, "sum_other_doc_count" : 0, "buckets" : [ ] }, "attrs" : { "doc_count" : 0, "attrIdAgg" : { "doc_count_error_upper_bound" : 0, "sum_other_doc_count" : 0, "buckets" : [ ] } } }}

2.6、搜索商品接口

SearchController

package com.firefly.fireflymall.elasticsearch.controller;import com.firefly.fireflymall.elasticsearch.service.MallSearchService;import com.firefly.fireflymall.elasticsearch.vo.SearchParamVo;import com.firefly.fireflymall.elasticsearch.vo.SearchResult;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;@Controller@RequestMappingpublic class SearchController { @Autowired private MallSearchService mallSearchService; @GetMapping("/list.html") public String listPage(SearchParamVo searchParam, Model model) { SearchResult searchResult = (SearchResult) mallSearchService.search(searchParam); model.addAttribute("result", searchResult); return "list"; }}

MallSearchServiceImpl

@Override public SearchResult search(SearchParamVo searchParam) { SearchResult request = null; //1.执行检索请求 SearchRequest searchResult = bulidSearchRequest(searchParam); try { //2.执行检索请求 SearchResponse response = client.search(searchResult, GuliESConfig.COMMON_OPTIONS); //3.封装检索结果 request = buildSearchResult(response, searchParam); } catch (IOException e) { e.printStackTrace(); } System.out.println(request); return request; }

2.6.1、构建检索参数

private SearchRequest bulidSearchRequest(SearchParamVo searchParam) { // 用于构建DSL语句 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); //1、构建bool query BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder(); //1.1 bool must if (!StringUtils.isEmpty(searchParam.getKeyword())) { boolQueryBuilder.must(QueryBuilders.matchQuery("skuTitle", searchParam.getKeyword())); } //1.2 bool filter //1.2.1 catalog if (searchParam.getCatalog3Id()!=null){ boolQueryBuilder.filter(QueryBuilders.termQuery("catalogId", searchParam.getCatalog3Id())); } //1.2.2 brand if (searchParam.getBrandId()!=null&&searchParam.getBrandId().size()>0) { boolQueryBuilder.filter(QueryBuilders.termsQuery("brandId",searchParam.getBrandId())); } //1.2.3 hasStock if (searchParam.getHasStock() != null) { boolQueryBuilder.filter(QueryBuilders.termQuery("hasStock", searchParam.getHasStock() == 1)); } //1.2.4 priceRange RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("skuPrice"); if (!StringUtils.isEmpty(searchParam.getSkuPrice())) { String[] prices = searchParam.getSkuPrice().split("_"); if (prices.length == 1) { if (searchParam.getSkuPrice().startsWith("_")) { rangeQueryBuilder.lte(Integer.parseInt(prices[0])); }else { rangeQueryBuilder.gte(Integer.parseInt(prices[0])); } } else if (prices.length == 2) { //_6000会截取成["","6000"] if (!prices[0].isEmpty()) { rangeQueryBuilder.gte(Integer.parseInt(prices[0])); } rangeQueryBuilder.lte(Integer.parseInt(prices[1])); } boolQueryBuilder.filter(rangeQueryBuilder); } //1.2.5 attrs-nested //attrs=1_5寸:8寸&2_16G:8G List attrs = searchParam.getAttrs(); BoolQueryBuilder queryBuilder = new BoolQueryBuilder(); if (attrs!=null&&attrs.size() > 0) { attrs.forEach(attr->{ String[] attrSplit = attr.split("_"); queryBuilder.must(QueryBuilders.termQuery("attrs.attrId", attrSplit[0])); String[] attrValues = attrSplit[1].split(":"); queryBuilder.must(QueryBuilders.termsQuery("attrs.attrValue", attrValues)); }); } NestedQueryBuilder nestedQueryBuilder = QueryBuilders.nestedQuery("attrs", queryBuilder, ScoreMode.None); boolQueryBuilder.filter(nestedQueryBuilder); //1.X bool query构建完成 searchSourceBuilder.query(boolQueryBuilder); //2、sort eg:sort=saleCount_desc/asc if (!StringUtils.isEmpty(searchParam.getSort())) { String[] sortSplit = searchParam.getSort().split("_"); searchSourceBuilder.sort(sortSplit[0], sortSplit[1].equalsIgnoreCase("asc") ? SortOrder.ASC : SortOrder.DESC); } //3、分页 // 是检测结果分页 searchSourceBuilder.from((searchParam.getPageNum() - 1) * PRODUCT_PAGE_SIZE); searchSourceBuilder.size(PRODUCT_PAGE_SIZE); //4、高亮highlight if (!StringUtils.isEmpty(searchParam.getKeyword())) { HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.field("skuTitle"); highlightBuilder.preTags(""); highlightBuilder.postTags(""); searchSourceBuilder.highlighter(highlightBuilder); } //5、聚合 //5.1 按照brand聚合 TermsAggregationBuilder brandAgg = AggregationBuilders.terms("brandAgg").field("brandId"); TermsAggregationBuilder brandNameAgg = AggregationBuilders.terms("brandNameAgg").field("brandName"); TermsAggregationBuilder brandImgAgg = AggregationBuilders.terms("brandImgAgg").field("brandImg"); brandAgg.subAggregation(brandNameAgg); brandAgg.subAggregation(brandImgAgg); searchSourceBuilder.aggregation(brandAgg); //5.2 按照catalog聚合 TermsAggregationBuilder catalogAgg = AggregationBuilders.terms("catalogAgg").field("catalogId"); // 子聚合 TermsAggregationBuilder catalogNameAgg = AggregationBuilders.terms("catalogNameAgg").field("catalogName"); catalogAgg.subAggregation(catalogNameAgg); searchSourceBuilder.aggregation(catalogAgg); //5.3 按照attrs聚合 NestedAggregationBuilder nestedAggregationBuilder = new NestedAggregationBuilder("attrs", "attrs"); //按照attrId聚合 //按照attrId聚合之后再按照attrName和attrValue聚合 TermsAggregationBuilder attrIdAgg = AggregationBuilders.terms("attrIdAgg" ).field("attrs.attrId"); TermsAggregationBuilder attrNameAgg = AggregationBuilders.terms("attrNameAgg" ).field("attrs.attrName"); TermsAggregationBuilder attrValueAgg = AggregationBuilders.terms("attrValueAgg").field("attrs.attrValue"); attrIdAgg.subAggregation(attrNameAgg); attrIdAgg.subAggregation(attrValueAgg); nestedAggregationBuilder.subAggregation(attrIdAgg); searchSourceBuilder.aggregation(nestedAggregationBuilder); log.debug("构建的DSL语句 {}",searchSourceBuilder.toString()); SearchRequest request = new SearchRequest(new String[]{PRODUCT_INDEX}, searchSourceBuilder); return request; }

{ "from": 0, "size": 2, "query": { "bool": { "must": [ { "match": { "skuTitle": { "query": "小米", "operator": "OR", "prefix_length": 0, "max_expansions": 50, "fuzzy_transpositions": true, "lenient": false, "zero_terms_query": "NONE", "auto_generate_synonyms_phrase_query": true, "boost": 1 } } } ], "filter": [ { "term": { "catalogId": { "value": 165, "boost": 1 } } }, { "terms": { "brandId": [ 8 ], "boost": 1 } }, { "term": { "hasStock": { "value": true, "boost": 1 } } }, { "range": { "skuPrice": { "from": 1, "to": 10000, "include_lower": true, "include_upper": true, "boost": 1 } } }, { "nested": { "query": { "bool": { "must": [ { "term": { "attrs.attrId": { "value": "85", "boost": 1 } } }, { "terms": { "attrs.attrValue": [ "8G", "4G" ], "boost": 1 } } ], "adjust_pure_negative": true, "boost": 1 } }, "path": "attrs", "ignore_unmapped": false, "score_mode": "none", "boost": 1 } } ], "adjust_pure_negative": true, "boost": 1 } }, "sort": [ { "saleCount": { "order": "desc" } } ], "aggregations": { "brandAgg": { "terms": { "field": "brandId", "size": 10, "min_doc_count": 1, "shard_min_doc_count": 0, "show_term_doc_count_error": false, "order": [ { "_count": "desc" }, { "_key": "asc" } ] }, "aggregations": { "brandNameAgg": { "terms": { "field": "brandName", "size": 10, "min_doc_count": 1, "shard_min_doc_count": 0, "show_term_doc_count_error": false, "order": [ { "_count": "desc" }, { "_key": "asc" } ] } }, "brandImgAgg": { "terms": { "field": "brandImg", "size": 10, "min_doc_count": 1, "shard_min_doc_count": 0, "show_term_doc_count_error": false, "order": [ { "_count": "desc" }, { "_key": "asc" } ] } } } }, "catalogAgg": { "terms": { "field": "catalogId", "size": 10, "min_doc_count": 1, "shard_min_doc_count": 0, "show_term_doc_count_error": false, "order": [ { "_count": "desc" }, { "_key": "asc" } ] }, "aggregations": { "catalogNameAgg": { "terms": { "field": "catalogName", "size": 10, "min_doc_count": 1, "shard_min_doc_count": 0, "show_term_doc_count_error": false, "order": [ { "_count": "desc" }, { "_key": "asc" } ] } } } }, "attrs": { "nested": { "path": "attrs" }, "aggregations": { "attrIdAgg": { "terms": { "field": "attrs.attrId", "size": 10, "min_doc_count": 1, "shard_min_doc_count": 0, "show_term_doc_count_error": false, "order": [ { "_count": "desc" }, { "_key": "asc" } ] }, "aggregations": { "attrNameAgg": { "terms": { "field": "attrs.attrName", "size": 10, "min_doc_count": 1, "shard_min_doc_count": 0, "show_term_doc_count_error": false, "order": [ { "_count": "desc" }, { "_key": "asc" } ] } }, "attrValueAgg": { "terms": { "field": "attrs.attrValue", "size": 10, "min_doc_count": 1, "shard_min_doc_count": 0, "show_term_doc_count_error": false, "order": [ { "_count": "desc" }, { "_key": "asc" } ] } } } } } } }, "highlight": { "pre_tags": [ "" ], "post_tags": [ "" ], "fields": { "skuTitle": {} } }}

{ "took" : 0, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 6, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "fire_product", "_type" : "_doc", "_id" : "50", "_score" : 1.0, "_source" : { "attrs" : [ { "attrId" : 85, "attrName" : "内存", "attrValue" : "8G;4G" } ], "brandId" : 8, "brandImg" : "https://fireflymall.oss-cn-beijing.aliyuncs.com/2022-02-03b206b057-f351-4fdc-8eeb-0bf9de0c6277_1582979072845574-lp.jpg", "brandName" : "小米", "catalogId" : 165, "catalogName" : "电子书", "hasStock" : false, "hotScore" : 0, "saleCount" : 0, "skuId" : 50, "skuImg" : "https://fireflymall.oss-cn-beijing.aliyuncs.com/2022-02-0489f04a93-9af3-49a2-8973-efc7bb593427_1582979072845574-lp.jpg", "skuPrice" : 0.0, "skuTitle" : "1 森林绿", "spuId" : 70 } }, { "_index" : "fire_product", "_type" : "_doc", "_id" : "51", "_score" : 1.0, "_source" : { "attrs" : [ { "attrId" : 85, "attrName" : "内存", "attrValue" : "8G;4G" } ], "brandId" : 8, "brandImg" : "https://fireflymall.oss-cn-beijing.aliyuncs.com/2022-02-03b206b057-f351-4fdc-8eeb-0bf9de0c6277_1582979072845574-lp.jpg", "brandName" : "小米", "catalogId" : 165, "catalogName" : "电子书", "hasStock" : false, "hotScore" : 0, "saleCount" : 0, "skuId" : 51, "skuImg" : "https://fireflymall.oss-cn-beijing.aliyuncs.com/2022-02-0489f04a93-9af3-49a2-8973-efc7bb593427_1582979072845574-lp.jpg", "skuPrice" : 0.0, "skuTitle" : "1 玫瑰金", "spuId" : 70 } }, { "_index" : "fire_product", "_type" : "_doc", "_id" : "46", "_score" : 1.0, "_source" : { "attrs" : [ { "attrId" : 85, "attrName" : "内存", "attrValue" : "4G;8G" } ], "brandId" : 8, "brandImg" : "https://fireflymall.oss-cn-beijing.aliyuncs.com/2022-02-03b206b057-f351-4fdc-8eeb-0bf9de0c6277_1582979072845574-lp.jpg", "brandName" : "小米", "catalogId" : 165, "catalogName" : "电子书", "hasStock" : false, "hotScore" : 0, "saleCount" : 0, "skuId" : 46, "skuImg" : "", "skuPrice" : 9990.0, "skuTitle" : "手机 森林绿", "spuId" : 64 } }, { "_index" : "fire_product", "_type" : "_doc", "_id" : "47", "_score" : 1.0, "_source" : { "attrs" : [ { "attrId" : 85, "attrName" : "内存", "attrValue" : "4G;8G" } ], "brandId" : 8, "brandImg" : "https://fireflymall.oss-cn-beijing.aliyuncs.com/2022-02-03b206b057-f351-4fdc-8eeb-0bf9de0c6277_1582979072845574-lp.jpg", "brandName" : "小米", "catalogId" : 165, "catalogName" : "电子书", "hasStock" : false, "hotScore" : 0, "saleCount" : 0, "skuId" : 47, "skuImg" : "", "skuPrice" : 9990.0, "skuTitle" : "手机 玫瑰金", "spuId" : 64 } }, { "_index" : "fire_product", "_type" : "_doc", "_id" : "48", "_score" : 1.0, "_source" : { "attrs" : [ { "attrId" : 85, "attrName" : "内存", "attrValue" : "4G" } ], "brandId" : 8, "brandImg" : "https://fireflymall.oss-cn-beijing.aliyuncs.com/2022-02-03b206b057-f351-4fdc-8eeb-0bf9de0c6277_1582979072845574-lp.jpg", "brandName" : "小米", "catalogId" : 165, "catalogName" : "电子书", "hasStock" : false, "hotScore" : 0, "saleCount" : 0, "skuId" : 48, "skuImg" : "", "skuPrice" : 0.0, "skuTitle" : "12 森林绿", "spuId" : 65 } }, { "_index" : "fire_product", "_type" : "_doc", "_id" : "49", "_score" : 1.0, "_source" : { "attrs" : [ { "attrId" : 85, "attrName" : "内存", "attrValue" : "4G" } ], "brandId" : 8, "brandImg" : "https://fireflymall.oss-cn-beijing.aliyuncs.com/2022-02-03b206b057-f351-4fdc-8eeb-0bf9de0c6277_1582979072845574-lp.jpg", "brandName" : "小米", "catalogId" : 165, "catalogName" : "电子书", "hasStock" : false, "hotScore" : 0, "saleCount" : 0, "skuId" : 49, "skuImg" : "", "skuPrice" : 0.0, "skuTitle" : "12 玫瑰金", "spuId" : 65 } } ] }}

2.6.2、接收检索响应

buildSearchResult

//3.1封装检索结果private SearchResult buildSearchResult(SearchResponse response, SearchParamVo searchParam) { SearchResult searchResult = new SearchResult(); //1、返回查询到的商品 SearchHits hits = response.getHits(); if (hits.getHits() != null && hits.getHits().length > 0) { List skuEsModels = new ArrayList<>(); for (SearchHit hit : hits) { String sourceAsString = hit.getSourceAsString(); SkuEsModel skuEsModel = JSON.parseObject(sourceAsString, SkuEsModel.class); //1.1 判断有无关键字检索 Yes-设置高亮属性 No-不设置高亮属性 if (StringUtils.isNotEmpty(searchParam.getKeyword())) { HighlightField highlightField = hit.getHighlightFields().get("skuTitle"); String skuTitle = highlightField.getFragments()[0].string(); skuEsModel.setSkuTitle(skuTitle); } //1.2 添加到list集合中 skuEsModels.add(skuEsModel); } //1.3 设置查询到的所有商品 searchResult.setProducts(skuEsModels); } //2、当前所有商品涉及到的所有属性信息 //2.1 先获取attrs聚合 ParsedNested attrs = response.getAggregations().get("attrs"); //2.2 获取attrIdAgg聚合 ParsedLongTerms attrIdAgg = attrs.getAggregations().get("attrIdAgg"); List<? extends Terms.Bucket> attrIdAggBuckets = attrIdAgg.getBuckets(); if (attrIdAggBuckets != null && attrIdAggBuckets.size() > 0) { //2.2 创建属性信息list集合 List attrVos = new ArrayList<>(); for (Terms.Bucket bucket : attrIdAggBuckets) { //2.3 获取:属性ID 设置属性名 设置属性值 Long attrId = bucket.getKeyAsNumber().longValue(); ParsedStringTerms attrNameAgg = bucket.getAggregations().get("attrNameAgg"); String attrName = attrNameAgg.getBuckets().get(0).getKeyAsString(); ParsedStringTerms attrValueAgg = bucket.getAggregations().get("attrValueAgg"); List attrValues = attrValueAgg.getBuckets().stream().map(item -> { String keyAsString = item.getKeyAsString(); return keyAsString; }).collect(Collectors.toList()); //2.4 设置:属性ID 设置属性名 设置属性值 SearchResult.AttrVo attrVo = new SearchResult.AttrVo(attrId, attrName, attrValues); attrVos.add(attrVo); } searchResult.setAttrs(attrVos); } //3、当前所有商品涉及到的所有分类信息 //3.1 获取catalogAgg聚合 ParsedLongTerms catalogAgg = response.getAggregations().get("catalogAgg"); List<? extends Terms.Bucket> catalogAggBuckets = catalogAgg.getBuckets(); if (catalogAggBuckets != null && catalogAggBuckets.size() > 0) { //3.2 创建分类信息list集合 ArrayList catalogVos = new ArrayList<>(); for (Terms.Bucket bucket : catalogAggBuckets) { //3.3 获取:分类ID 分类名 Long catalogId = bucket.getKeyAsNumber().longValue(); ParsedStringTerms catalogNameAgg = bucket.getAggregations().get("catalogNameAgg"); String catalogName = catalogNameAgg.getBuckets().get(0).getKeyAsString(); //3.4 设置:分类ID 分类名 SearchResult.CatalogVo catalogVo = new SearchResult.CatalogVo(catalogId, catalogName); catalogVos.add(catalogVo); } searchResult.setCatalogs(catalogVos); } //4、当前所有商品涉及到的所有品牌信息 //4.1 brandAgg获取聚合 ParsedLongTerms brandAgg = response.getAggregations().get("brandAgg"); List<? extends Terms.Bucket> brandAggBuckets = brandAgg.getBuckets(); if (brandAggBuckets != null && brandAggBuckets.size() > 0) { //4.2 创建品牌信息list集合 ArrayList brandVos = new ArrayList<>(); for (Terms.Bucket bucket : brandAggBuckets) { //4.3 获取:品牌ID 品牌图片 品牌名 long brandId = bucket.getKeyAsNumber().longValue(); ParsedStringTerms brandImgAgg = bucket.getAggregations().get("brandImgAgg"); String brandImg = brandImgAgg.getBuckets().get(0).getKeyAsString(); ParsedStringTerms brandNameAgg = bucket.getAggregations().get("brandNameAgg"); String brandName = brandNameAgg.getBuckets().get(0).getKeyAsString(); //4.4 设置:品牌ID 品牌图片 品牌名 SearchResult.BrandVo brandVo = new SearchResult.BrandVo(brandId, brandName, brandImg); brandVos.add(brandVo); } searchResult.setBrands(brandVos); } //5、分页信息 //5.1、设置当前页码 searchResult.setPageNum(searchParam.getPageNum()); //5.2、总记录数 long total = hits.getTotalHits().value; searchResult.setTotal(total); //5.3 设置总页码 Long totalPage = (Long) ((total + PRODUCT_PAGE_SIZE - 1) / PRODUCT_PAGE_SIZE); searchResult.setTotalPage(totalPage); return searchResult;}

SearchResult(products=[SkuEsModel(skuId=52, spuId=71, skuTitle=小米手机 黑色, skuPrice=900.0, skuImg=https://fireflymall.oss-cn-beijing.aliyuncs.com/2022-02-091e36d0d6-d95a-40a3-87a3-d097cca48385_1582979072845574-lp.jpg, saleCount=1000, hasStock=true, hotScore=0, brandId=9, catalogId=225, brandName=小米, brandImg=https://fireflymall.oss-cn-beijing.aliyuncs.com/2022-02-1009e04471-7efd-4f1a-810f-c53675b6923d_598042c9n6e4e79e5.jpg, catalogName=手机, attrs=[SkuEsModel.Attr(attrId=87, attrName=鸿蒙, attrValue=[V1, V2])]), SkuEsModel(skuId=53, spuId=71, skuTitle=小米手机 白色, skuPrice=600.0, skuImg=https://fireflymall.oss-cn-beijing.aliyuncs.com/2022-02-091e36d0d6-d95a-40a3-87a3-d097cca48385_1582979072845574-lp.jpg, saleCount=1000, hasStock=true, hotScore=0, brandId=9, catalogId=225, brandName=小米, brandImg=https://fireflymall.oss-cn-beijing.aliyuncs.com/2022-02-1009e04471-7efd-4f1a-810f-c53675b6923d_598042c9n6e4e79e5.jpg, catalogName=手机, attrs=[SkuEsModel.Attr(attrId=87, attrName=鸿蒙, attrValue=[V1, V2])]), SkuEsModel(skuId=54, spuId=74, skuTitle=1 白色, skuPrice=1.0, skuImg=https://fireflymall.oss-cn-beijing.aliyuncs.com/2022-02-09c9595b7c-09b7-4162-885b-d9a7f97309fc_1582979072845574-lp.jpg, saleCount=2000, hasStock=false, hotScore=0, brandId=9, catalogId=225, brandName=小米, brandImg=https://fireflymall.oss-cn-beijing.aliyuncs.com/2022-02-1009e04471-7efd-4f1a-810f-c53675b6923d_598042c9n6e4e79e5.jpg, catalogName=手机, attrs=[SkuEsModel.Attr(attrId=87, attrName=鸿蒙, attrValue=[V2])])], pageNum=1, total=3, totalPage=1, pageNavs=null, brands=[SearchResult.BrandVo(brandId=9, brandName=小米, brandImg=https://fireflymall.oss-cn-beijing.aliyuncs.com/2022-02-1009e04471-7efd-4f1a-810f-c53675b6923d_598042c9n6e4e79e5.jpg)], attrs=[SearchResult.AttrVo(attrId=87, attrName=鸿蒙, attrValue=[V2, V1])], catalogs=[SearchResult.CatalogVo(catalogId=225, catalogName=手机)], navs=[], attrIds=[])

2.6.3、检索不到数据

注意:查询不到数据可能是因为 DSL语句是:{ "terms": { "attrs.attrValue": [ "V1","V2" ], "boost": 1 }}而es保存的数据是:"attrValue" : "V1;V2",导致匹配不到

修改:SkuEsModel

..... @Data public static class Attr { private Long attrId; private String attrName; private List attrValue; }

修改:SpuInfoServiceImpl

List attrsList = baseAttrs.stream().filter(item -> { return idSet.contains(item.getAttrId()); }).map(item -> { SkuEsModel.Attr attrs1 = new SkuEsModel.Attr(); BeanUtils.copyProperties(item, attrs1); String attrValue = item.getAttrValue(); String[] split = attrValue.split(";"); List attrValues = new ArrayList<>(); for (String i : split) { attrValues.add(i); attrs1.setAttrValue(attrValues); } return attrs1; }).collect(Collectors.toList());

三、渲染检索页面 3.1、基本数据渲染

"rig_tab"> th:each="product : ${result.getProducts()}"> "ico"> "/search/#">关注

th:href="|http://item.fire.flymall.com/${product.skuId}.html|"> "dim" th:src="${product.skuImg}"/>

"/static/search/#" th:title='${product.skuTitle}'> th:src="${product.skuImg}"/>

¥5199.00

"/search/#" th:utext="${product.skuTitle}"> Apple iPhone 7 Plus (A1661) 32G 黑色 移动联通电信4G手机

已有11万+热门评价 "/search/#">二手有售

"/search/#" title="火萤商城Apple产品专营店">火萤商城Apple产品... '#' title="联系供应商进行咨询"> "/search/img/xcxc.png">

"tab_FO"> "FO_one">

自营 火萤商城自营,品质保证

满赠 该商品参加满赠活动

关键字检索高亮显示

http://localhost:13000//search.html?catalog3Id=225&keyword=%E6%89%8B%E6%9C%BA

th:utext="${product.skuTitle}"

3.2、筛选条件渲染

将结果的品牌、分类、商品属性进行遍历显示,并且点击某个属性值时 可以通过拼接url进行跳转。

"JD_selector"> "title" > 手机商品筛选 "st-ext">共10135个商品 "JD_nav_logo"> "JD_nav_wrap"> "sl_key"> 品牌: "sl_value"> "sl_value_logo">

th:href="${'javascript:searchProducts("brandId",'+brand.brandId+')'}"> th:src="${brand.brandImg}" alt=""/> th:text="${brand.brandName}"> 华为(HUAWEI) "sl_ext"> "/search/#"> 更多 "/search/#"> 多选 + + "JD_pre"> "sl_key"> 分类: "sl_value">

th:href="${'javascript:searchProducts("catalogId",'+catalog.catalogId+')'}" th:text="${catalog.catalogName}">属性值 "sl_ext"> "/search/#"> 更多 "/search/#"> 多选 + + "JD_pre" th:each="attr:${result.getAttrs()}"> "sl_key"> 属性名: "sl_value">

th:href="${'javascript:searchProducts("attrs","'+attr.attrId+'_'+val+'")'}" th:text="${val}">属性值 "JD_show"> "/search/#"> 更多选项( CPU核数、网络、机身颜色 等)

searchProducts

function searchProducts(name, value) { //原來的页面 location.href = replaceParamVal(location.href,name,value,true)};

replaceParamVal

function replaceParamVal(url, param, replaceval, forceAdd) { var oUrl = url.toString(); var nUrl; if (oUrl.indexOf(param) != -1) { if (forceAdd && oUrl.indexOf(param + "=" + replaceval) == -1) { if (oUrl.indexOf("?") != -1) { nUrl = oUrl + "&" + param + "=" + replaceval; } else { nUrl = oUrl + "?" + param + "=" + replaceval; } } else { var re = eval('/(' + param + '=)([^&]*)/gi'); nUrl = oUrl.replace(re, param + '=' + replaceval); } } else { if (oUrl.indexOf("?") != -1) { nUrl = oUrl + "&" + param + "=" + replaceval; } else { nUrl = oUrl + "?" + param + "=" + replaceval; } } return nUrl; };

3.3、搜索按钮渲染

"header_form"> "javascript:searchByKeyword();">搜索

searchByKeyword

function searchByKeyword() { var keyWord = $("#keyword_input").val(); location.href = replaceParamVal(location.href, "keyword", keyWord, false); }

3.4、分页数据渲染

"filter_page"> "page_wrap"> "page_a" href="#" th:if="${result.pageNum>1}" th:attr="pn=${result.getPageNum()-1}"> < 上一页 "#" class="page_a" th:each="page :${#numbers.sequence(1,result.totalPage)} " th:if="${result.getTotalPage()>0}" th:text="${page}" th:style="${page==result.pageNum?'border: 0;color:#ee2222;background: #fff':''}" th:attr="pn=${page}" >1 "#" th:if="${result.pageNum 下一页 > 169页到第 "javascript:searchByPage();">确定

function searchByPage(){ var page = $("#page_input").val(); location.href = replaceParamVal(location.href, "pageNum", page, false); }

3.5、页面排序渲染

页面排序功能需要保证,点击某个按钮时,样式会变红,并且其他的样式保持最初的样子;点击某个排序时首先按升序显示,再次点击再变为降序,并且还会显示上升或下降箭头。
页面排序跳转的思路是通过点击某个按钮时会向其class属性添加/去除desc,并根据属性值进行url拼接。

"JD_con_right"> "filter"> "filter_top"> "filter_top_left" th:with="p = ${param.sort}, priceRange = ${param.skuPrice}"> "hotScore" th:class="${(!#strings.isEmpty(p) && #strings.startsWith(p,'hotScore') && #strings.endsWith(p,'desc')) ? 'sort_a desc' : 'sort_a'}" th:attr="style=${(#strings.isEmpty(p) || #strings.startsWith(p,'hotScore')) ? 'color: #fff; border-color: #e4393c; background: #e4393c;':'color: #333; border-color: #ccc; background: #fff;' }"> 综合排序[[${(!#strings.isEmpty(p) && #strings.startsWith(p,'hotScore') && #strings.endsWith(p,'desc')) ?'↓':'↑' }]] "saleCount" th:class="${(!#strings.isEmpty(p) && #strings.startsWith(p,'saleCount') && #strings.endsWith(p,'desc')) ? 'sort_a desc' : 'sort_a'}" th:attr="style=${(!#strings.isEmpty(p) && #strings.startsWith(p,'saleCount')) ? 'color: #fff; border-color: #e4393c; background: #e4393c;':'color: #333; border-color: #ccc; background: #fff;' }"> 销量[[${(!#strings.isEmpty(p) && #strings.startsWith(p,'saleCount') && #strings.endsWith(p,'desc'))?'↓':'↑' }]] "skuPrice" th:class="${(!#strings.isEmpty(p) && #strings.startsWith(p,'skuPrice') && #strings.endsWith(p,'desc')) ? 'sort_a desc' : 'sort_a'}" th:attr="style=${(!#strings.isEmpty(p) && #strings.startsWith(p,'skuPrice')) ? 'color: #fff; border-color: #e4393c; background: #e4393c;':'color: #333; border-color: #ccc; background: #fff;' }"> 价格[[${(!#strings.isEmpty(p) && #strings.startsWith(p,'skuPrice') && #strings.endsWith(p,'desc'))?'↓':'↑' }]] "hotScore" class="fs-tit" src="/search/#">评论分 "hotScore" class="fs-tit" src="/search/#">上架时间 - "filter_top_right"> 共10135个商品 1/169 "filter_bottom"> "filter_bottom_left"> "fs-cell">收货地 "dizhi"> "dizhi_show"> 北京朝阳区三环以内 "dizhi_con">

北京 "/search/image/down-@1x.png" alt=""> 朝阳 "/search/image/down-@1x.png" alt=""> 三环以内 "/search/image/down-@1x.png" alt=""> "container"> "content1" style="z-index: 1;"> "/search/#">北京 "/search/#">上海 "/search/#">天津 "/search/#">重庆 "/search/#">河北 "/search/#">山西 "/search/#">河南 "/search/#">辽宁 "/search/#">吉林 "/search/#">黑龙江 "/search/#">内蒙古 "/search/#">江苏 "/search/#">山东 "/search/#">安徽 "/search/#">浙江 "/search/#">福建 "/search/#">湖北 "/search/#">湖南 "/search/#">广东 "/search/#">广西 "/search/#">江西 "/search/#">四川 "/search/#">海南 "/search/#">贵州 "/search/#">云南 "/search/#">西藏 "/search/#">陕西 "/search/#">甘肃 "/search/#">青海 "/search/#">宁夏 "/search/#">新疆 "/search/#">港澳 "/search/#">台湾 "/search/#">钓鱼岛 "/search/#">海外 "content2"> "/search/#">朝阳区 "/search/#">海淀区 "/search/#">西城区 "/search/#">东城区 "/search/#">大兴区 "/search/#">丰台区 "/search/#">昌平区 "/search/#">顺义区 "content3"> "/search/#">三环以内 "/search/#">管庄 "/search/#">北苑 "/search/#">定福庄 "/search/#">三环到四环之间 "/search/#">四环到五环之间 "/search/#">五环到六环之间 "filter_bottom_right">

"/search/#"> 火萤商城配送 "/search/#"> 京尊达 "/search/#"> 货到付款 "/search/#"> 仅显示有货 "/search/#"> 可配送全球 "rig_tab"> th:each="product : ${result.getProducts()}"> "ico"> "/search/#">关注

th:href="|http://item.fire.flymall.com/${product.skuId}.html|"> "dim" th:src="${product.skuImg}"/>

"/static/search/#" th:title='${product.skuTitle}'> th:src="${product.skuImg}"/>

¥5199.00

"/search/#" th:utext="${product.skuTitle}"> SkuTitle

已有11万+热门评价 "/search/#">二手有售

"/search/#" title="火萤商城Apple产品专营店">火萤商城Apple产品... '#' title="联系供应商进行咨询"> "/search/img/xcxc.png">

"tab_FO"> "FO_one">

自营 火萤商城自营,品质保证

满赠 该商品参加满赠活动

"filter_page"> "page_wrap"> "page_a" href="#" th:if="${result.pageNum>1}" th:attr="pn=${result.getPageNum()-1}"> < 上一页 "#" class="page_a" th:each="page :${#numbers.sequence(1,result.totalPage)} " th:if="${result.getTotalPage()>0}" th:text="${page}" th:style="${page==result.pageNum?'border: 0;color:#ee2222;background: #fff':''}" th:attr="pn=${page}" >1 "#" th:if="${result.pageNum 下一页 > 169页到第 "javascript:searchByPage();">确定

$(".sort_a").click(function () { //添加、剔除desc $(this).toggleClass("desc"); //获取sort属性值并进行url跳转 let sort = $(this).attr("sort"); sort = $(this).hasClass("desc") ? sort + "_desc" : sort + "_asc"; location.href = replaceParamVal(location.href, "sort", sort, false); return false;});

$("#skuPriceSearchBtn").click(function () { var skuPriceFrom = $("#skuPriceFrom").val(); var skuPriceTo = $("#skuPriceTo").val(); location.href = replaceParamVal(location.href, "skuPrice", skuPriceFrom + "_" + skuPriceTo, false);})$(".sort_a").click(function () { //添加、剔除desc $(this).toggleClass("desc"); //获取sort属性值并进行url跳转 let sort = $(this).attr("sort"); sort = $(this).hasClass("desc") ? sort + "_desc" : sort + "_asc"; location.href = replaceParamVal(location.href, "sort", sort, false); return false;});

3.6、 面包屑导航

MallSearchServiceImpl

// 6、构建面包屑导航List attrs1 = searchParam.getAttrs();if (attrs1 != null && attrs1.size() > 0) { List navVos = attrs1.stream().map(attr -> { String[] split = attr.split("_"); SearchResult.NavVo navVo = new SearchResult.NavVo(); //6.1 设置属性值 navVo.setNavValue(split[1]); //6.2 查询并设置属性名 try { R r = productFeignService.info(Long.parseLong(split[0])); if (r.getCode() == 0) { AttrResponseVo attrResponseVo = JSON.parseObject(JSON.toJSONString(r.get("attr")), new TypeReference() { }); navVo.setNavName(attrResponseVo.getAttrName()); } } catch (Exception e) { log.error(REMOTEL_QUERY_PROPERTY_FAIL, e); } //6.3 设置面包屑跳转链接(当点击该链接时剔除点击属性) String queryString = searchParam.get_queryString(); String encodeAattr = null; try { encodeAattr = URLEncoder.encode(attr, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } String replace = queryString.replace("&attrs=" + encodeAattr, "").replace("attrs=" + encodeAattr + "&", "").replace("attrs=" + encodeAattr, ""); navVo.setlink("http://search.fire.flymall.com/list.html" + (replace.isEmpty() ? "" : "?" + replace)); return navVo; }).collect(Collectors.toList()); searchResult.setNavs(navVos);}

AttrResponseVo

package com.firefly.fireflymall.elasticsearch.vo;import com.baomidou.mybatisplus.annotation.TableId;import lombok.Data;@Datapublic class AttrResponseVo { @TableId private Long attrId; private String attrName; private Integer searchType; private String icon; private String valueSelect; private Integer attrType; private Long enable; private Long catelogId; private Integer showDesc; private Integer valueType; private Long attrGroupId; private String catelogName; private String attrGroupName; private Long[] catelogPath;}

渲染面包屑页面

"JD_ipone"> "JD_ipone_bar"> "JD_ipone_one a"> th:href="${nav.link}" th:each="nav:${result.navs}">: x "/search/image/right-@1x.png" alt="">

3.7、 条件筛选联动

就是将品牌和分类也封装进面包屑数据中,并且在页面进行th:if的判断,当url有该属性的查询条件时就不进行显示了。

3.8、异步和线程池

上一章:day07-商城业务
下一章:day09-商城详情

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。