物流网站查询,阅读的网站建设需要多少钱,我市精神文明建设的门户网站是,线上商城介绍商城检索服务 1.检索页面的搭建 商品检索页面我们放在search服务中处理#xff0c;首页我们需要在mall-search服务中支持Thymeleaf。添加对应的依赖 !-- 添加Thymeleaf的依赖 --dependencygroupIdorg.springframework.boot/groupIdartifa…商城检索服务 1.检索页面的搭建 商品检索页面我们放在search服务中处理首页我们需要在mall-search服务中支持Thymeleaf。添加对应的依赖 !-- 添加Thymeleaf的依赖 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-thymeleaf/artifactId/dependency然后我们拷贝模板文件到template目录下然后不要忘记添加Thymeleaf的名称空间 需要把相关的静态资源文件拷贝到Nginx服务中。目录结构是/mydata/nginx/html/static/search/ 我们需要修改index.html页面中的资源的路径 然后我们要通过 msb.search.com 来访问我们的检索服务那么就需要设置对应的host文件 然后我们就需要修改Nginx的配置 这时我需要在修改网关的服务根据我们的域名访问那么需要网关路由到我们的检索服务中 然后我们就可以重启相关的服务 来测试了 2.检索服务
2.1 创建对应VO 我们需要检索数据库中的相关的商品信息那么我们就需要提交相关的检索条件为了统一的管理提交的数据我们需要创建一个VO来封装信息。
/*** 封装页面所有可能提交的查询条件*/
Data
public class SearchParam {private String keyword; // 页面传递的查询全文匹配的关键字private Long catalog3Id;// 需要根据分类查询的编号/*** sortsalaCount_asc/desc* sortskuPrice_asc/desc* sorthotScore_asc/desc*/private String sort; // 排序条件// 查询的筛选条件 hasStock0/1;private Integer hasStock ; // 是否只显示有货// brandId1brandId2private ListLong brandId; // 按照品牌来查询可以多选// skuPrice200_300// skuPrice_300// skuPrice200_private String skuPrice; // 价格区间查询// 不同的属性 attrs:1_苹果:6.5寸private ListString attrs; // 按照属性信息进行筛选private Integer pageNum; // 页码}然后就是检索后的数据我们需要封装的VO对象定义如下
package com.msb.mall.mallsearch.vo;import com.msb.common.dto.es.SkuESModel;
import lombok.Data;import java.util.List;/*** 封装检索后的响应信息*/
Data
public class SearchResult {private ListSkuESModel products; // 查询到的所有的商品信息 满足条件// 分页信息private Integer pageNum; // 当前页private Long total; // 总的记录数private Integer totalPages; // 总页数// 当前查询的所有的商品涉及到的所有的品牌信息private ListBrandVO brands;// 当前查询的所有的商品涉及到的所有的属性信息private ListAttrVo attrs;// 当前查询的所有商品涉及到的所有的类别信息private ListCatalogVO catalogs;Datapublic static class CatalogVO{private Long catalogId;private String catalogName;}/*** 品牌的相关信息*/Datapublic static class BrandVO{private Long brandId; // 品牌的编号private String brandName; // 品牌的名称private String brandImg; // 品牌的图片}Datapublic static class AttrVo{private Long attrId; // 属性的编号private String attrName; // 属性的名称private ListString attrValue; // 属性的值}}
2.2 构建查询DSL语句 我们需要根据基本的检索条件来封装对应的DSL语句
查询关键字 模糊匹配过滤(分类品牌属性价格区间库存…)排序分页高亮
GET /product/_search
{query: {bool: {must: [{match: {subTitle: 华为}}],filter: [{term: {catalogId: 225}},{terms: {brandId: [13,16,14]}},{range: {skuPrice: {gte: 10,lte: 12000}}},{nested: {path: attrs,query: {bool: {must: [{term: {attrs.attrId: {value: 9}}},{terms: {attrs.attrValue: [12,08,11]}}]}}}}]}},sort: [{skuPrice: {order: desc}}],from: 0,size: 20,highlight: {fields: {subTitle: {}},pre_tags: b stylecolor:red,post_tags: b}
}2.3 构建SearchRequest对象 根据客户端提交的检索的信息我们需要封装为对应的SearchRequest对象然后通过ES的API来检索数据。 /*** 构建检索的请求* 模糊匹配关键字匹配* 过滤(类别品牌属性价格区间库存)* 排序* 分页* 高亮* 聚合分析* param param* return*/private SearchRequest buildSearchRequest(SearchParam param) {SearchRequest searchRequest new SearchRequest();searchRequest.indices(ESConstant.PRODUCT_INDEX);SearchSourceBuilder sourceBuilder new SearchSourceBuilder();// 构建具体的检索的条件// 1.构建bool查询BoolQueryBuilder boolQuery QueryBuilders.boolQuery();// 1.1 关键字的条件if(!StringUtils.isEmpty(param.getKeyword())){boolQuery.must(QueryBuilders.matchQuery(subTitle,param.getKeyword()));}// 1.2 类别的检索条件if(param.getCatalog3Id() ! null){boolQuery.filter(QueryBuilders.termQuery(catalogId,param.getCatalog3Id()));}// 1.3 品牌的检索条件if(param.getBrandId() ! null param.getBrandId().size() 0){boolQuery.filter(QueryBuilders.termsQuery(brandId,param.getBrandId()));}// 1.4 是否有库存if(param.getHasStock() ! null){boolQuery.filter(QueryBuilders.termQuery(hasStock,param.getHasStock() 1));}// 1.5 根据价格区间来检索if(!StringUtils.isEmpty(param.getSkuPrice())){String[] msg param.getSkuPrice().split(_);RangeQueryBuilder skuPrice QueryBuilders.rangeQuery(skuPrice);if(msg.length 2){// 说明是 200_300skuPrice.gte(msg[0]);skuPrice.lte(msg[1]);}else if(msg.length 1){// 说明是 _300 200_if(param.getSkuPrice().endsWith(_)){// 说明是 200_skuPrice.gte(msg[0]);}if(param.getSkuPrice().startsWith(_)){// 说明是 _300skuPrice.lte(msg[0]);}}boolQuery.filter(skuPrice);}// 1.6 属性的检索条件 attrs20_8英寸:10英寸attrs19_64GB:32GBif(param.getAttrs() ! null param.getAttrs().size() 0){for (String attrStr : param.getAttrs()) {BoolQueryBuilder boolNestedQuery QueryBuilders.boolQuery();// attrs19_64GB:32GB 我们首先需要根据 _ 做分割String[] attrStrArray attrStr.split(_);// 属性的编号String attrId attrStrArray[0];// 64GB:32GB 获取属性的值String[] values attrStrArray[1].split(:);// 拼接组合条件boolNestedQuery.must(QueryBuilders.termQuery(attrs.attrId,attrId));boolNestedQuery.must(QueryBuilders.termsQuery(attrs.attrValue,values));NestedQueryBuilder nestedQuery QueryBuilders.nestedQuery(attrs, boolNestedQuery, ScoreMode.None);boolQuery.filter(nestedQuery);}}sourceBuilder.query(boolQuery);// 2.排序if(!StringUtils.isEmpty(param.getSort())){// sortsalaCount_asc/descString[] s param.getSort().split(_);SortOrder order s[1].equalsIgnoreCase(asc)?SortOrder.ASC:SortOrder.DESC;sourceBuilder.sort(s[0], order);}// 3.处理分页// Integer pageNum; // 页码if(param.getPageNum() ! null){// 需要做分页处理 pageSize 5// pageNum:1 from:0 [0,1,2,3,4]// pageNum:2 from:5 [5,6,7,8,9]// from ( pageNum - 1 ) * pageSizesourceBuilder.from( (param.getPageNum() - 1 ) * ESConstant.PRODUCT_PAGESIZE);sourceBuilder.size(ESConstant.PRODUCT_PAGESIZE);}// 4. 设置高亮if(!StringUtils.isEmpty(param.getKeyword())){// 如果有根据关键字查询那么我们才需要高亮设置HighlightBuilder highlightBuilder new HighlightBuilder();highlightBuilder.field(subTitle);highlightBuilder.preTags(b stylecolor:red);highlightBuilder.postTags(/b);sourceBuilder.highlighter(highlightBuilder);}// 5.聚合运算// 5.1 品牌的聚合TermsAggregationBuilder brand_agg AggregationBuilders.terms(brand_agg);brand_agg.field(brandId);brand_agg.size(50);// 品牌的子聚合brand_agg.subAggregation(AggregationBuilders.terms(brand_name_agg).field(brandName).size(10));brand_agg.subAggregation(AggregationBuilders.terms(brand_img_agg).field(brandImg).size(10));sourceBuilder.aggregation(brand_agg);// 5.2 类别的聚合TermsAggregationBuilder catalog_agg AggregationBuilders.terms(catalog_agg);catalog_agg.field(catalogId);catalog_agg.size(10);// 类别的子聚合catalog_agg.subAggregation(AggregationBuilders.terms(catalog_name_agg).field(catalogName).size(10));sourceBuilder.aggregation(catalog_agg);// 5.3 属性的聚合NestedAggregationBuilder attr_agg AggregationBuilders.nested(attr_agg, attrs);// 属性id聚合TermsAggregationBuilder attr_id_agg AggregationBuilders.terms(attr_id_agg);attr_id_agg.field(attrs.attrId);attr_id_agg.size(10);// 属性id下的子聚合 属性名称和属性值attr_id_agg.subAggregation(AggregationBuilders.terms(attr_name_agg).field(attrs.attrName).size(10));attr_id_agg.subAggregation(AggregationBuilders.terms(attr_value_agg).field(attrs.attrValue).size(10));attr_agg.subAggregation(attr_id_agg);sourceBuilder.aggregation(attr_agg);System.out.println(sourceBuilder.toString());searchRequest.source(sourceBuilder);return searchRequest;}2.4 构建SearchResult对象 当我们通过封装的SearchRequest对象从ES中检索出了相关的信息后我们需要将返回的SearchResponse对象封装为前端接收的SearchResult对象。
所有的满足条件的商品分页相关的信息当前商品涉及的品牌信息当前商品涉及的类别信息当前商品涉及的属性信息 /*** 根据检索的结果解析封装为SearchResult对象* param response* return*/private SearchResult buildSearchResult(SearchResponse response,SearchParam param){SearchResult result new SearchResult();SearchHits hits response.getHits();// 1.检索的所有商品信息SearchHit[] products hits.getHits();ListSkuESModel esModels new ArrayList();if(products ! null products.length 0){for (SearchHit product : products) {String sourceAsString product.getSourceAsString();// 把json格式的字符串通过fastjson转换为SkuESModel对象SkuESModel model JSON.parseObject(sourceAsString, SkuESModel.class);if(!StringUtils.isEmpty(param.getKeyword())){// 我们需要设置高亮HighlightField subTitle product.getHighlightFields().get(subTitle);String subTitleHighlight subTitle.getFragments()[0].string();model.setSubTitle(subTitleHighlight); // 设置高亮}esModels.add(model);}}result.setProducts(esModels);Aggregations aggregations response.getAggregations();// 2.当前商品所涉及到的所有的品牌ParsedLongTerms brand_agg aggregations.get(brand_agg);List? extends Terms.Bucket buckets brand_agg.getBuckets();// 存储所有品牌的容器ListSearchResult.BrandVO brandVOS new ArrayList();if(buckets!null buckets.size() 0){for (Terms.Bucket bucket : buckets) {SearchResult.BrandVO brandVO new SearchResult.BrandVO();// 获取品牌的keyString keyAsString bucket.getKeyAsString();brandVO.setBrandId(Long.parseLong(keyAsString)); // 设置品牌的编号// 然后我们需要获取品牌的名称和图片的地址ParsedStringTerms brand_img_agg bucket.getAggregations().get(brand_img_agg);List? extends Terms.Bucket bucketsImg brand_img_agg.getBuckets();if(bucketsImg ! null bucketsImg.size() 0){String img bucketsImg.get(0).getKeyAsString();brandVO.setBrandImg(img);}// 获取品牌名称的信息ParsedStringTerms brand_name_agg bucket.getAggregations().get(brand_name_agg);String breadName brand_name_agg.getBuckets().get(0).getKeyAsString();brandVO.setBrandName(breadName);brandVOS.add(brandVO);}}result.setBrands(brandVOS);// 3.当前商品涉及到的所有的类别信息ParsedLongTerms catalog_agg aggregations.get(catalog_agg);List? extends Terms.Bucket bucketsCatalogs catalog_agg.getBuckets();// 创建一个保存所有类别的容器ListSearchResult.CatalogVO catalogVOS new ArrayList();if(bucketsCatalogs ! null bucketsCatalogs.size() 0){for (Terms.Bucket bucket : bucketsCatalogs) {SearchResult.CatalogVO catalogVO new SearchResult.CatalogVO();String keyAsString bucket.getKeyAsString(); // 获取类别的编号catalogVO.setCatalogId(Long.parseLong(keyAsString));// 获取类别的名称ParsedStringTerms catalog_name_agg bucket.getAggregations().get(catalog_name_agg);String catalogName catalog_name_agg.getBuckets().get(0).getKeyAsString();catalogVO.setCatalogName(catalogName);catalogVOS.add(catalogVO);}}result.setCatalogs(catalogVOS);// 4.当前商品涉及到的所有的属性信息ParsedNested attr_agg aggregations.get(attr_agg);ParsedLongTerms attr_id_agg attr_agg.getAggregations().get(attr_id_agg);List? extends Terms.Bucket bucketsAttr attr_id_agg.getBuckets();ListSearchResult.AttrVo attrVos new ArrayList();if(bucketsAttr ! null bucketsAttr.size() 0){for (Terms.Bucket bucket : bucketsAttr) {SearchResult.AttrVo attrVo new SearchResult.AttrVo();// 获取属性的编号String keyAsString bucket.getKeyAsString();attrVo.setAttrId(Long.parseLong(keyAsString));// 又得分别获取 属性的名称 和 属性的值ParsedStringTerms attr_name_agg bucket.getAggregations().get(attr_name_agg);String attrName attr_name_agg.getBuckets().get(0).getKeyAsString(); // 属性的名称attrVo.setAttrName(attrName);ParsedStringTerms attr_value_agg bucket.getAggregations().get(attr_value_agg);if(attr_value_agg.getBuckets() ! null attr_value_agg.getBuckets().size() 0 ){ListString values attr_value_agg.getBuckets().stream().map(item - {String keyAsString1 item.getKeyAsString();return keyAsString1;}).collect(Collectors.toList());attrVo.setAttrValue(values);}attrVos.add(attrVo);}}result.setAttrs(attrVos);// 5. 分页信息 当前页 总的记录数 总页数long total hits.getTotalHits().value;result.setTotal(total);// 设置总记录数 6 /5 11result.setPageNum(param.getPageNum()); // 设置当前页long totalPage total % ESConstant.PRODUCT_PAGESIZE 0 ? total / ESConstant.PRODUCT_PAGESIZE : (total / ESConstant.PRODUCT_PAGESIZE 1);result.setTotalPages((int)totalPage); // 设置总的页数return result;}