商城检索-检索条件分析
• 1、全文检索:skuTitle — keyword
• 2、排序:saleCount(销量)、hotScore(热度分)、skuPrice(价格)
• 3、过滤:hasStock、skuPrice区间、brandId、catalog3Id、attrs
• 4、聚合:attrs

商城检索- 完整查询参数

keyword=小米&sort=saleCount_desc/asc&hasStock=0/1&skuPrice=400_1900&brandId=1&catalog3Id=1&attrs=1_3G:4G:5G&attrs=2_骁龙845&attrs=4_高清屏

controller

@GetMapping("/list.html")public String listPage(SearchParam param, Model model){SearchResult result =  mallSearchService.search(param);model.addAttribute("result",result);return  "list";}

SearchParam

/*** @Description 封装页面所有可能传递过来的查询条件*/
@Data
public class SearchParam {/*** 页面传递的关键字*/private String keyword;/*** 三类分级Id*/private Long catalog3Id;/*** 排序条件*/private String sort;/*** 是否有货 hasStock0/1 0无库存 1有库存*/private Integer hasStock;/*** 价格区间  skuPrice1_100*/private String skuPrice;/*** 品牌*/private List<Long> brandId;/*** 属性*/private List<String> attrs;/*** 页码*/private Integer pageNum;}

MallSearchServiceImpl

@Service
public class MallSearchServiceImpl implements MallSearchService {@AutowiredRestHighLevelClient restHighLevelClient;@Overridepublic SearchResult search(SearchParam param) {//动态构建查询DSL语句SearchResult result = null;//准备检索请求SearchRequest searchRequest = buildSearchRequest(param);try {//执行检索请求SearchResponse searchResponse = restHighLevelClient.search(searchRequest, EsConfig.COMMON_OPTIONS);//分析响应数据封装成我们所需要的格式result = buildSearchResult(searchResponse, param);} catch (IOException e) {e.printStackTrace();}return result;}/*** 准备检索请求* 模糊匹配 、过滤、(按照属性、分类、品牌、价格区间、库存)、排序、分页、高亮、聚合分析** @return*/private SearchRequest buildSearchRequest(SearchParam param) {SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();/*** 模糊匹配 、过滤、(按照属性、分类、品牌、价格区间、库存)*/BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();if (StringUtils.isNotBlank(param.getKeyword()))boolQuery.must(QueryBuilders.matchQuery("skuTitle", param.getKeyword()));if (param.getCatalog3Id() != null)boolQuery.filter(QueryBuilders.termQuery("catalogId", param.getCatalog3Id()));if (param.getBrandId() != null && param.getBrandId().size() > 0)boolQuery.filter(QueryBuilders.termsQuery("brandId", param.getBrandId()));if (param.getHasStock() != null)boolQuery.filter(QueryBuilders.termQuery("hasStock", param.getHasStock() == 1));if (StringUtils.isNotBlank(param.getSkuPrice())) {RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("skuPrice");String[] s = param.getSkuPrice().split("_");if (s.length == 2) {rangeQuery.gte(s[0]).lte(s[1]);} else if (s.length == 1) {if (param.getSkuPrice().startsWith("_"))rangeQuery.lte(s[1]);if (param.getSkuPrice().endsWith("_"))rangeQuery.gte(s[0]);}boolQuery.filter(rangeQuery);}if (param.getAttrs() != null && param.getAttrs().size() > 0) {//attrs=1_5寸:8寸&attrs2_16G:8Gfor (String attr : param.getAttrs()) {String[] s = attr.split("_");String attrId = s[0];//检索的属性idString[] attrValues = s[1].split(":");BoolQueryBuilder nestedBoolQuery = QueryBuilders.boolQuery();nestedBoolQuery.must(QueryBuilders.termQuery("attrs.attrId", attrId));nestedBoolQuery.must(QueryBuilders.termsQuery("attrs.attrValue", attrValues));//每一个都得生成一个nested查询NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery("attrs", nestedBoolQuery, ScoreMode.None);boolQuery.filter(nestedQuery);}}//所有条件进行封装sourceBuilder.query(boolQuery);/*** 排序、分页、高亮*/if (StringUtils.isNotBlank(param.getSort())) {String sort = param.getSkuPrice();String[] s = sort.split("_");SortOrder sortOrder = s[1].equalsIgnoreCase("asc") ? SortOrder.ASC : SortOrder.DESC;sourceBuilder.sort(s[0], sortOrder);}System.out.println("PageNum" + param.getPageNum());if (param.getPageNum() == null) {//sourceBuilder.from((50 - 1) * EsConstant.PRODUCT_PAGESIZE);} else {sourceBuilder.from((param.getPageNum() - 1) * EsConstant.PRODUCT_PAGESIZE);}sourceBuilder.size(EsConstant.PRODUCT_PAGESIZE);if (StringUtils.isNotBlank(param.getKeyword())) {HighlightBuilder builder = new HighlightBuilder();builder.field("skuTitle");builder.preTags("<b style='color:red'>");builder.postTags("</b>");sourceBuilder.highlighter(builder);}/*** 聚合分析*///品牌聚合TermsAggregationBuilder brand_agg = AggregationBuilders.terms("brand_agg").field("brandId").size(50);//品牌聚合的子聚合brand_agg.subAggregation(AggregationBuilders.terms("brand_name_agg").field("brandName").size(1));brand_agg.subAggregation(AggregationBuilders.terms("brand_img_agg").field("brandImg").size(1));sourceBuilder.aggregation(brand_agg);//分类聚合TermsAggregationBuilder catalog_agg = AggregationBuilders.terms("catalog_agg").field("catalogId").size(50);sourceBuilder.aggregation(catalog_agg);//分类子聚合catalog_agg.subAggregation(AggregationBuilders.terms("catalog_name_agg").field("catalogName").size(1));//属性聚合NestedAggregationBuilder attr_agg = AggregationBuilders.nested("attr_agg", "attrs");TermsAggregationBuilder attr_id_agg = AggregationBuilders.terms("attr_id_agg").field("attrs.attrId");attr_id_agg.subAggregation(AggregationBuilders.terms("attr_name_agg").field("attrs.attrName").size(1));attr_id_agg.subAggregation(AggregationBuilders.terms("attr_value_agg").field("attrs.attrValue").size(1));attr_agg.subAggregation(attr_id_agg);//聚合attrsourceBuilder.aggregation(attr_agg);System.out.println("检索请求" + sourceBuilder.toString());SearchRequest searchRequest = new SearchRequest(new String[]{EsConstant.PRODUCT_INDEX}, sourceBuilder);return searchRequest;}/*** 构建结果数据* 模糊匹配,过滤(按照属性、分类、品牌,价格区间,库存),完成排序、分页、高亮,聚合分析功能* @param response* @return*/private SearchResult buildSearchResult(SearchResponse response,SearchParam param) {SearchResult result = new SearchResult();//1、返回的所有查询到的商品SearchHits hits = response.getHits();List<SkuEsModel> esModels = new ArrayList<>();//遍历所有商品信息if (hits.getHits() != null && hits.getHits().length > 0) {for (SearchHit hit : hits.getHits()) {String sourceAsString = hit.getSourceAsString();SkuEsModel esModel = JSON.parseObject(sourceAsString, SkuEsModel.class);//判断是否按关键字检索,若是就显示高亮,否则不显示if (!StringUtils.isEmpty(param.getKeyword())) {//拿到高亮信息显示标题HighlightField skuTitle = hit.getHighlightFields().get("skuTitle");String skuTitleValue = skuTitle.getFragments()[0].string();esModel.setSkuTitle(skuTitleValue);}esModels.add(esModel);}}result.setProducts(esModels);//2、当前商品涉及到的所有属性信息List<SearchResult.AttrVo> attrVos = new ArrayList<>();//获取属性信息的聚合ParsedNested attrsAgg = response.getAggregations().get("attr_agg");ParsedLongTerms attrIdAgg = attrsAgg.getAggregations().get("attr_id_agg");for (Terms.Bucket bucket : attrIdAgg.getBuckets()) {SearchResult.AttrVo attrVo = new SearchResult.AttrVo();//1、得到属性的idlong attrId = bucket.getKeyAsNumber().longValue();attrVo.setAttrId(attrId);//2、得到属性的名字ParsedStringTerms attrNameAgg = bucket.getAggregations().get("attr_name_agg");String attrName = attrNameAgg.getBuckets().get(0).getKeyAsString();attrVo.setAttrName(attrName);//3、得到属性的所有值ParsedStringTerms attrValueAgg = bucket.getAggregations().get("attr_value_agg");List<String> attrValues = attrValueAgg.getBuckets().stream().map(item -> item.getKeyAsString()).collect(Collectors.toList());attrVo.setAttrValue(attrValues);attrVos.add(attrVo);}result.setAttrs(attrVos);//3、当前商品涉及到的所有品牌信息List<SearchResult.BrandVo> brandVos = new ArrayList<>();//获取到品牌的聚合ParsedLongTerms brandAgg = response.getAggregations().get("brand_agg");for (Terms.Bucket bucket : brandAgg.getBuckets()) {SearchResult.BrandVo brandVo = new SearchResult.BrandVo();//1、得到品牌的idlong brandId = bucket.getKeyAsNumber().longValue();brandVo.setBrandId(brandId);//2、得到品牌的名字ParsedStringTerms brandNameAgg = bucket.getAggregations().get("brand_name_agg");String brandName = brandNameAgg.getBuckets().get(0).getKeyAsString();brandVo.setBrandName(brandName);//3、得到品牌的图片ParsedStringTerms brandImgAgg = bucket.getAggregations().get("brand_img_agg");String brandImg = brandImgAgg.getBuckets().get(0).getKeyAsString();brandVo.setBrandImg(brandImg);brandVos.add(brandVo);}result.setBrands(brandVos);//4、当前商品涉及到的所有分类信息//获取到分类的聚合List<SearchResult.CatalogVo> catalogVos = new ArrayList<>();ParsedLongTerms catalogAgg = response.getAggregations().get("catalog_agg");for (Terms.Bucket bucket : catalogAgg.getBuckets()) {SearchResult.CatalogVo catalogVo = new SearchResult.CatalogVo();//得到分类idString keyAsString = bucket.getKeyAsString();catalogVo.setCatalogId(Long.parseLong(keyAsString));//得到分类名ParsedStringTerms catalogNameAgg = bucket.getAggregations().get("catalog_name_agg");String catalogName = catalogNameAgg.getBuckets().get(0).getKeyAsString();catalogVo.setCatalogName(catalogName);catalogVos.add(catalogVo);}result.setCatalogs(catalogVos);//===============以上可以从聚合信息中获取====================////5、分页信息-页码result.setPageNum(param.getPageNum());//5、1分页信息、总记录数long total = hits.getTotalHits().value;result.setTotal(total);//5、2分页信息-总页码-计算int totalPages = (int)total % EsConstant.PRODUCT_PAGESIZE == 0 ?(int)total / EsConstant.PRODUCT_PAGESIZE : ((int)total / EsConstant.PRODUCT_PAGESIZE + 1);result.setTotalPages(totalPages);return result;}}

这时查询会报错 大概意思是Elasticsearch索引只读

[FORBIDDEN/12/index read-only / allow delete (api)];

解决:
在虚拟机上执行

curl -XPUT -H "Content-Type: application/json" http://localhost:9200/_all/_settings -d '{"index.blocks.read_only_allow_delete": null}'

或kibana执行

PUT _settings{"index": {"blocks": {"read_only_allow_delete": "false"}}}

还有一个查询错误是之前的数据格式问题,新建一个索引(主要是type为keyword)

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

然后把旧数据迁移到新索引

#数据迁移
POST _reindex
{"source": {"index": "product" //旧索引},"dest": {"index": "mall_product" //新索引}
}

效果

谷粒商城微服务分布式高级篇十一———商城检索相关推荐

  1. 谷粒商城微服务分布式高级篇ElasticSearch二——重要概念及原理

    文章目录 面向文档 索引 分布式特性 分布式集群 集群健康 添加索引 增加故障转移 横向扩展 继续扩展 应对故障 数据结构 什么是文档? 文档元数据 _index _type _id 其他元数据 _s ...

  2. 谷粒商城微服务分布式高级篇ElasticSearch三——Dcoker安装ES及ES检索语法

    文章目录 Docker安装ES&kibban Elasticsearch安装 kibban安装 IK分词器安装 Nginx安装 检索 1.查看es中有哪些索引 2.增加一个索引(库) 3.删除 ...

  3. 谷粒商城微服务分布式基础篇二—— Spring Cloud Alibaba、Nacos注册与发现

    文章目录 Spring Cloud Alibaba--微服务开发 Spring Cloud Alibaba是什么?  主要功能  组件 为什么不使用Spring Cloud 使用 Nacos Disc ...

  4. 谷粒商城 - 微服务分布式电商项目

    谷粒商城 1.项目背景 谷粒商城项目是尚硅谷研究院最新推出的完整大型分布式架构电商平台,技术全面.业务深入,全网无出其右.技术涵盖:微服务架构 + 分布式 + 全栈 + 集群 + 部署 + 自动化运维 ...

  5. 谷粒商城项目篇8_分布式高级篇_商城首页、性能压测、优化(Nginx动静分离)

    目录 商城首页 整合thymeleaf springmvc的WebMvcAutoConfiguration 首页三级分类渲染 Nginx代理 Nginx代理会丢掉host信息 压力测试 性能检测 性能 ...

  6. SpringCloud 微服务分布式 笔记(二)

    SpringCloud 微服务分布式 本篇是结合上一篇代码进行修改学习 点击

  7. 谷粒商城-分布式高级篇[商城业务-秒杀服务]

    谷粒商城-分布式基础篇[环境准备] 谷粒商城-分布式基础[业务编写] 谷粒商城-分布式高级篇[业务编写]持续更新 谷粒商城-分布式高级篇-ElasticSearch 谷粒商城-分布式高级篇-分布式锁与 ...

  8. 谷粒商城-分布式高级篇[商城业务-检索服务]

    谷粒商城-分布式基础篇[环境准备] 谷粒商城-分布式基础[业务编写] 谷粒商城-分布式高级篇[业务编写]持续更新 谷粒商城-分布式高级篇-ElasticSearch 谷粒商城-分布式高级篇-分布式锁与 ...

  9. 谷粒商城分布式高级篇(中)

    谷粒商城分布式基础篇 谷粒商城分布式高级篇(上) 谷粒商城分布式高级篇(中) 谷粒商城分布式高级篇(下) 文章目录 商城业务 异步 异步复习 线程池详解 CompletableFuture Compl ...

  10. 谷粒商城-分布式高级篇【业务编写】

    谷粒商城-分布式基础篇[环境准备] 谷粒商城-分布式基础[业务编写] 谷粒商城-分布式高级篇[业务编写]持续更新 谷粒商城-分布式高级篇-ElasticSearch 谷粒商城-分布式高级篇-分布式锁与 ...

最新文章

  1. sql 相加_SQL-多表查询
  2. 每日一皮:程序猿的读书历程,最后一本​必备​!
  3. 关闭 定时开启_【话说定时器系列】之四:STM32定时器更新事件及案例分享
  4. BZOJ3522 [Poi2014]Hotel 【树形dp】
  5. Ajax+Node.js前后端交互最佳入门实践(05)
  6. centos7设置成文件服务器,CentOS7服务器架设ftp过程
  7. Oracle 更新Opatch、打补丁
  8. Python 3.x中reduce()函数完整用法
  9. golang mysql条件查询_mysql – 将变量传递给GoLang查询
  10. 拍摄人像最难的是哪个方面?
  11. python的类中包含什么_Python中的类(中)
  12. EMNLP 2021 投稿FAQ
  13. OSGEARTH三维地形开源项目
  14. 【PMP】工作分解结构WBS详解
  15. 希捷硬盘固件修复工具_希捷3.5寸500G台式机硬盘磁头损坏后的数据恢复
  16. 坑人的青旅乐山峨眉两日游
  17. Unity 打开摄像头
  18. 前端面试八股文(详细版)—上
  19. matlab repeat until,汇编语言用.REPEAT和.WHILE伪指令实现循环
  20. eacharts和eacharts-gl、3d饼图、3d柱状图加折线图、下载gl报错解决

热门文章

  1. postman请求404
  2. java 自动生成密码_java 自动生成密码
  3. 物联网的媒介——java usb串口通信
  4. 微分方程中解、特解、通解的区别
  5. 二级Office知识点整合
  6. bitbake 编译错误集
  7. Hive-获取本月的第一天,本月的最后一天,本月的天数
  8. 大量数据表的优化方案
  9. python 苹果电脑 怎么安装_mac怎么安装python2.7(python苹果电脑如何安装教程)
  10. QCC3040---earbudUi module