赞
踩
搜索页面搭建完成之后,点击搜索按钮,发送参数给后台服务,后台服务根据参数从Elasticsearch中查询符合条件的数据,返回给前端。
根据前端的交互设计,将前端发送的请求参数解析、封装检索查询请求对象。
这一步骤在实际工作中非常重要,开发人员在开发详细设计阶段完成,并输出文档,后续依据文档完成开发。
package com.atguigu.gulimall.search.vo; import lombok.Data; import java.util.List; @Data public class SearchParam { /** * 页面传递过来的全文匹配关键字 */ private String keyword; /** * 品牌id,可以多选 */ private List<Long> brandId; /** * 三级分类id */ private Long catalog3Id; /** * 排序条件:sort=price/salecount/hotscore_desc/asc */ private String sort; /** * 是否显示有货 */ private Integer hasStock; /** * 价格区间查询 */ private String skuPrice; /** * 按照属性进行筛选 */ private List<String> attrs; /** * 页码 */ private Integer pageNum = 1; /** * 原生的所有查询条件 */ private String _queryString; }
这一节的主要内容是分析搜索响应的数据结构,根据实际业务和前端需求,将要返回给前端的内容分为如下几部分:
package com.atguigu.gulimall.search.vo; import com.atguigu.common.es.SkuEsModel; import lombok.Data; import java.util.List; @Data public class SearchResult { /** * 查询到的所有商品信息 */ private List<SkuEsModel> product; /** * 当前页码 */ private Integer pageNum; /** * 总记录数 */ private Long total; /** * 总页码 */ private Integer totalPages; private List<Integer> pageNavs; /** * 当前查询到的结果,所有涉及到的品牌 */ private List<BrandVo> brands; /** * 当前查询到的结果,所有涉及到的所有属性 */ private List<AttrVo> attrs; /** * 当前查询到的结果,所有涉及到的所有分类 */ private List<CatalogVo> catalogs; @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<String> attrValue; } @Data public static class CatalogVo { private Long catalogId; private String catalogName; } }
以上是返回给前端的所有信息。
这一节的主要内容是结合前端交互,编写后端的Elasticsearch的DSL语句。
涉及到Elasticsearch查询的开发,最佳的开发方式是先把DSL查询出来,然后转化为Java代码。
在编写ES查询DSL时,需要全文匹配的使用match query
,其余的使用filter
,因为全文匹配会有评分,精确匹配不需要评分,所以用filter
,以提高查询性能。
GET gulimall_product/_search { "query": { "bool": { "must": [ { "match": { "skuTitle": "华为" } } ], "filter": [ { "term": { "catalogId": "225" } }, { "terms": { "brandId": [ 1, 2, 9 ] } }, { "nested": { "path": "attrs", "query": { "bool": { "must": [ { "term": { "attrs.attrId": { "value": "15" } } }, { "terms": { "attrs.attrValue": [ "海思(Hisilicon)", "以官网信息为准" ] } } ] } } } }, { "term": { "hasStock": true } }, { "range": { "skuPrice": { "gte": 5000, "lte": 7000 } } } ] } }, "sort": [ { "skuPrice": { "order": "desc" } } ], "from": 0, "size": 4, "highlight": { "pre_tags": ["<b style='color:red'>"], "post_tags": ["</b>"], "fields": {"skuTitle":{}} } }
如果对DSL的语法比较熟悉,编写DSL难度并不大。
在搜索界面,点击搜索后,会展示如下的属性信息,以供用户进行点击查询,这些信息是在查询时根据产品信息汇总得到的,是实时的。
也就是说,我们还要在es查询结果基础上对数据进行汇总分析,可以使用ES提供的聚合分析完成这个需求。
GET gulimall_product/_search { "query": { "match_all": {} }, "aggs": { "brand_agg": { "terms": { "field": "brandId" }, "aggs": { "brand_name_agg": { "terms": { "field": "brandName", "size": 10 } }, "brand_img_agg": { "terms": { "field": "brandImg", "size": 10 } } } }, "catelog_agg": { "terms": { "field": "catalogId" }, "aggs": { "catelog_name_agg": { "terms": { "field": "catalogName", "size": 10 } } } }, "attr_agg":{ "nested": { "path": "attrs" }, "aggs": { "attr_id_agg": { "terms": { "field": "attrs.attrId", "size": 10 }, "aggs": { "attr_name_agg": { "terms": { "field": "attrs.attrName", "size": 10 } }, "attr_value_agg": { "terms": { "field": "attrs.attrValue", "size": 10 } } } } } } }, "size": 0 }
在kibana上执行搜索请求时,后台服务报错,报错信息如下。
{ "error" : { "root_cause" : [ { "type" : "query_shard_exception", "reason" : "failed to create query: Cannot invoke \"org.wltea.analyzer.dic.DictSegment.match(char[], int, int)\" because \"org.wltea.analyzer.dic.Dictionary.singleton._StopWords\" is null", "index_uuid" : "2y1rV0AxTEO-0b3NW_7vyA", "index" : "gulimall_product" } ], "type" : "search_phase_execution_exception", "reason" : "all shards failed", "phase" : "query", "grouped" : true, "failed_shards" : [ { "shard" : 0, "index" : "gulimall_product", "node" : "xUhfiZFBQlC5T8RerthrhQ", "reason" : { "type" : "query_shard_exception", "reason" : "failed to create query: Cannot invoke \"org.wltea.analyzer.dic.DictSegment.match(char[], int, int)\" because \"org.wltea.analyzer.dic.Dictionary.singleton._StopWords\" is null", "index_uuid" : "2y1rV0AxTEO-0b3NW_7vyA", "index" : "gulimall_product", "caused_by" : { "type" : "null_pointer_exception", "reason" : "Cannot invoke \"org.wltea.analyzer.dic.DictSegment.match(char[], int, int)\" because \"org.wltea.analyzer.dic.Dictionary.singleton._StopWords\" is null" } } } ] }, "status" : 400 }
原因是安装的IK分词器不能正常工作。
之前是使用命令进行自动安装。
bin/elasticsearch-plugin install https://get.infini.cloud/elasticsearch/analysis-ik/7.13.0
这种安装方式是有缺陷的,缺失配置文件相关。
应该手动安装。
①
在/mydata/elasticsearch/plugins
目录下创建ik
目录,cd
到ik
目录下。
②
下载IK分词器。
wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.13.0/elasticsearch-analysis-ik-7.13.0.zip
③
解压压缩包。
unzip elasticsearch-analysis-ik-7.13.0.zip
④
重启Elasticsearch容器。
docker restart elasticsearch
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。