文章目录
- 一,175-商城业务-检索服务-检索查询参数模型分析抽取
- 二,176-商城业务-检索服务-检索返回结果模型分析抽取
- 三,177-商城业务-检索服务-检索DSL测试-查询部分
- 四,178-商城业务-检索服务-检索DSL测试-聚合部分
- 问题记录
- 解决方案
搜索页面搭建完成之后,点击搜索按钮,发送参数给后台服务,后台服务根据参数从Elasticsearch中查询符合条件的数据,返回给前端。
一,175-商城业务-检索服务-检索查询参数模型分析抽取
根据前端的交互设计,将前端发送的请求参数解析、封装检索查询请求对象。
这一步骤在实际工作中非常重要,开发人员在开发详细设计阶段完成,并输出文档,后续依据文档完成开发。
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;
}
二,176-商城业务-检索服务-检索返回结果模型分析抽取
这一节的主要内容是分析搜索响应的数据结构,根据实际业务和前端需求,将要返回给前端的内容分为如下几部分:
- 检索到的产品信息
- 分页信息
- 汇总的产品的所有属性信息集合
- 汇总的产品的品牌信息集合
- 分类信息
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;
}
}
以上是返回给前端的所有信息。
三,177-商城业务-检索服务-检索DSL测试-查询部分
这一节的主要内容是结合前端交互,编写后端的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难度并不大。
四,178-商城业务-检索服务-检索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