|
@@ -1704,15 +1704,14 @@ POST album_info/_search
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 站内条件检索专辑接口
|
|
|
- *
|
|
|
+ * 站内搜索
|
|
|
* @param albumIndexQuery
|
|
|
* @return
|
|
|
*/
|
|
|
-@Operation(summary = "站内条件检索专辑接口")
|
|
|
+@Operation(summary = "站内搜索")
|
|
|
@PostMapping("/albumInfo")
|
|
|
-public Result<AlbumSearchResponseVo> search(@RequestBody AlbumIndexQuery albumIndexQuery) {
|
|
|
- AlbumSearchResponseVo vo = searchService.search(albumIndexQuery);
|
|
|
+public Result<AlbumSearchResponseVo> search(@RequestBody AlbumIndexQuery albumIndexQuery){
|
|
|
+ AlbumSearchResponseVo vo = searchService.search(albumIndexQuery);
|
|
|
return Result.ok(vo);
|
|
|
}
|
|
|
```
|
|
@@ -1721,27 +1720,26 @@ public Result<AlbumSearchResponseVo> search(@RequestBody AlbumIndexQuery albumIn
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 根据条件检索ElasticSearch专辑索引库
|
|
|
- * @param albumIndexQuery 查询条件
|
|
|
+ * 站内搜索
|
|
|
+ * @param albumIndexQuery
|
|
|
* @return
|
|
|
*/
|
|
|
AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery);
|
|
|
|
|
|
-
|
|
|
/**
|
|
|
- * 基于检索条件对象封装检索请求对象(封装完整DSL语句)
|
|
|
- * @param albumIndexQuery
|
|
|
+ * 基于查询条件封装ES检索DSL语句
|
|
|
+ * @param albumIndexQuery 查询条件
|
|
|
* @return
|
|
|
*/
|
|
|
SearchRequest buildDSL(AlbumIndexQuery albumIndexQuery);
|
|
|
|
|
|
/**
|
|
|
- * 解析ES检索结果
|
|
|
+ * 解析ES响应结果
|
|
|
* @param searchResponse
|
|
|
* @param albumIndexQuery
|
|
|
* @return
|
|
|
*/
|
|
|
-AlbumSearchResponseVo parseSearchResult(SearchResponse<AlbumInfoIndex> searchResponse, AlbumIndexQuery albumIndexQuery);
|
|
|
+AlbumSearchResponseVo parseResult(SearchResponse<AlbumInfoIndex> searchResponse, AlbumIndexQuery albumIndexQuery);
|
|
|
```
|
|
|
|
|
|
**SearchServiceImpl实现类**:
|
|
@@ -1751,29 +1749,26 @@ AlbumSearchResponseVo parseSearchResult(SearchResponse<AlbumInfoIndex> searchRes
|
|
|
private ElasticsearchClient elasticsearchClient;
|
|
|
|
|
|
|
|
|
-//专辑索引库名称
|
|
|
-private static final String INDE_NAME = "album_info";
|
|
|
-
|
|
|
/**
|
|
|
- * 整体采用传统写法,局部采用Lambda表达方式
|
|
|
- * 根据条件检索ElasticSearch专辑索引库
|
|
|
+ * 站内搜索
|
|
|
*
|
|
|
- * @param albumIndexQuery 查询条件
|
|
|
+ * @param albumIndexQuery
|
|
|
* @return
|
|
|
*/
|
|
|
@Override
|
|
|
public AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery) {
|
|
|
try {
|
|
|
- //1.基于查询条件封装检索请求对象
|
|
|
+ //一、构建完整检索请求对象:包含完整DSL语句请求体参数
|
|
|
SearchRequest searchRequest = this.buildDSL(albumIndexQuery);
|
|
|
System.err.println("本次检索DSL:");
|
|
|
- System.err.println(searchRequest);
|
|
|
- //2.执行索引库检索
|
|
|
+ System.out.println(searchRequest);
|
|
|
+ //二、执行检索
|
|
|
SearchResponse<AlbumInfoIndex> searchResponse = elasticsearchClient.search(searchRequest, AlbumInfoIndex.class);
|
|
|
- //3.解析解析ES检索结果
|
|
|
- return this.parseSearchResult(searchResponse, albumIndexQuery);
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("[检索服务]站内搜索异常:{}", e);
|
|
|
+
|
|
|
+ //三、解析ES响应结果
|
|
|
+ return this.parseResult(searchResponse, albumIndexQuery);
|
|
|
+ } catch (IOException e) {
|
|
|
+ log.error("执行检索失败", e);
|
|
|
throw new RuntimeException(e);
|
|
|
}
|
|
|
}
|
|
@@ -1782,94 +1777,111 @@ public AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery) {
|
|
|
**封装站内专辑检索DSL请求**
|
|
|
|
|
|
```java
|
|
|
+private static final String INDEX_NAME = "albuminfo";
|
|
|
+
|
|
|
/**
|
|
|
- * 基于检索条件对象封装检索请求对象(封装完整DSL语句)
|
|
|
+ * 整体看采用传统方式,局部采用Lambda简化开发
|
|
|
+ * 基于查询条件封装ES检索DSL语句
|
|
|
*
|
|
|
- * @param albumIndexQuery
|
|
|
+ * @param albumIndexQuery 查询条件
|
|
|
* @return
|
|
|
*/
|
|
|
@Override
|
|
|
public SearchRequest buildDSL(AlbumIndexQuery albumIndexQuery) {
|
|
|
- //1.创建检索请求构建器对象
|
|
|
+ //1.创建检索构建器对象 封装 请求地址中:index 索引库名称
|
|
|
SearchRequest.Builder builder = new SearchRequest.Builder();
|
|
|
- //2.设置DSL中各项请求体参数信息:分页、高亮、排序、条件、过滤
|
|
|
- //2.1 设置请求路径中检索:索引库名称
|
|
|
- builder.index(INDE_NAME);
|
|
|
- //2.2 设置请求体参数中"query"查询条件
|
|
|
+ builder.index(INDEX_NAME);
|
|
|
+ //2.设置查询条件:请求体参数query
|
|
|
String keyword = albumIndexQuery.getKeyword();
|
|
|
- //2.2.1 创建组合三大查询条件bool查询对象
|
|
|
+ //2.0 创建bool查询条件:用于封装所有查询条件
|
|
|
BoolQuery.Builder allConditionBoolQueryBuilder = new BoolQuery.Builder();
|
|
|
- //2.2.2 设置查询条件-关键字(全文查询专辑标题)
|
|
|
+ //2.1 条件1:关键字 采用must 有算分机制按相关性返回
|
|
|
if (StringUtils.isNotBlank(keyword)) {
|
|
|
- allConditionBoolQueryBuilder.must(m->m.match(m1 -> m1.field("albumTitle").query(keyword)));
|
|
|
+ allConditionBoolQueryBuilder.must(m -> m.match(m1 -> m1.field("albumTitle").query(keyword)));
|
|
|
}
|
|
|
- //2.2.3 设置过滤条件-分类
|
|
|
+ //2.2 条件2:一二三级分类ID 采用filter 有缓存机制
|
|
|
+ //2.2.1. 封装1级分类ID查询条件
|
|
|
Long category1Id = albumIndexQuery.getCategory1Id();
|
|
|
if (category1Id != null) {
|
|
|
allConditionBoolQueryBuilder.filter(f -> f.term(t -> t.field("category1Id").value(category1Id)));
|
|
|
}
|
|
|
+ //2.2.2. 封装2级分类ID查询条件
|
|
|
Long category2Id = albumIndexQuery.getCategory2Id();
|
|
|
if (category2Id != null) {
|
|
|
allConditionBoolQueryBuilder.filter(f -> f.term(t -> t.field("category2Id").value(category2Id)));
|
|
|
}
|
|
|
+ //2.2.3. 封装3级分类ID查询条件
|
|
|
Long category3Id = albumIndexQuery.getCategory3Id();
|
|
|
if (category3Id != null) {
|
|
|
allConditionBoolQueryBuilder.filter(f -> f.term(t -> t.field("category3Id").value(category3Id)));
|
|
|
}
|
|
|
- //2.2.4 设置过滤条件-标签 可能提交多组标签过滤条件 一组标签条件形式=标签ID:标签值ID
|
|
|
+ //2.3 条件3:多组标签List集合 每组标签形式=标签ID:标签值ID
|
|
|
List<String> attributeList = albumIndexQuery.getAttributeList();
|
|
|
- if (CollectionUtil.isNotEmpty(attributeList)) {
|
|
|
- for (String attribute : attributeList) {
|
|
|
- //2.2.4.1 每循环一次设置一组标签过滤条件 标签ID:标签值ID
|
|
|
- String[] split = attribute.split(":");
|
|
|
+ //2.4 每遍历一组标签过滤条件,设置一个Nested查询
|
|
|
+ if (CollUtil.isNotEmpty(attributeList)) {
|
|
|
+ for (String s : attributeList) {
|
|
|
+ String[] split = s.split(":");
|
|
|
if (split != null && split.length == 2) {
|
|
|
- allConditionBoolQueryBuilder.filter(f -> f.nested(
|
|
|
- n -> n.path("attributeValueIndexList")
|
|
|
- .query(q -> q.bool(
|
|
|
- b -> b.must(m -> m.term(t -> t.field("attributeValueIndexList.attributeId").value(split[0])))
|
|
|
+ allConditionBoolQueryBuilder
|
|
|
+ .filter(f -> f.nested(
|
|
|
+ n -> n.path("attributeValueIndexList")
|
|
|
+ .query(q -> q.bool(b -> b.must(m -> m.term(t -> t.field("attributeValueIndexList.attributeId").value(split[0])))
|
|
|
.must(m -> m.term(t -> t.field("attributeValueIndexList.valueId").value(split[1])))
|
|
|
- ))
|
|
|
- ));
|
|
|
+ ))
|
|
|
+ ));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
builder.query(allConditionBoolQueryBuilder.build()._toQuery());
|
|
|
- //2.3 设置请求体参数中"from,size"分页信息
|
|
|
- int from = (albumIndexQuery.getPageNo() - 1) * albumIndexQuery.getPageSize();
|
|
|
- builder.from(from).size(albumIndexQuery.getPageSize());
|
|
|
- //2.4 设置请求体参数中"sort"排序
|
|
|
+ //builder.query();
|
|
|
+ //3.设置分页:请求体参数from size
|
|
|
+ Integer pageNo = albumIndexQuery.getPageNo();
|
|
|
+ Integer pageSize = albumIndexQuery.getPageSize();
|
|
|
+ int from = (pageNo - 1) * pageSize;
|
|
|
+ builder.from(from).size(pageSize);
|
|
|
+
|
|
|
+ //4.设置排序:请求体参数sort
|
|
|
+ //4.1 前后端约定 如果需要排序提交参数order值=排序字段(1,2,3):排序方式(asc,desc)
|
|
|
String order = albumIndexQuery.getOrder();
|
|
|
- //2.4.1 获取前端提交排序参数取值 形式=1:desc
|
|
|
if (StringUtils.isNotBlank(order)) {
|
|
|
+ //4.2 获取排序字段以及排序方式
|
|
|
String[] split = order.split(":");
|
|
|
if (split != null && split.length == 2) {
|
|
|
- //2.4.2 获取排序字段
|
|
|
- String orderField = "";
|
|
|
+ String sortField = "";
|
|
|
switch (split[0]) {
|
|
|
case "1":
|
|
|
- orderField = "hotScore";
|
|
|
+ sortField = "hotScore";
|
|
|
break;
|
|
|
case "2":
|
|
|
- orderField = "playStatNum";
|
|
|
+ sortField = "playStatNum";
|
|
|
break;
|
|
|
case "3":
|
|
|
- orderField = "createTime";
|
|
|
+ sortField = "createTime";
|
|
|
break;
|
|
|
}
|
|
|
- //2.4.3 获取排序方式
|
|
|
- String orderDes = split[1];
|
|
|
- String finalOrderField = orderField;
|
|
|
- builder.sort(s -> s.field(f -> f.field(finalOrderField).order("asc".equals(orderDes) ? SortOrder.Asc : SortOrder.Desc)));
|
|
|
+ String direction = split[1];
|
|
|
+ //4.3 动态设置排序
|
|
|
+ SortOrder sortOrder = "asc".equals(direction) ? SortOrder.Asc : SortOrder.Desc;
|
|
|
+ String finalSortField = sortField;
|
|
|
+ builder.sort(s -> s.field(f -> f.field(finalSortField).order(sortOrder)));
|
|
|
}
|
|
|
}
|
|
|
- //2.5 设置请求体参数中"highlight"高亮
|
|
|
+
|
|
|
+ //5.设置高亮:请求体参数highlight 前提条件:用户采用关键字全文查询text字段
|
|
|
if (StringUtils.isNotBlank(keyword)) {
|
|
|
builder.highlight(h -> h.fields("albumTitle", f -> f.preTags("<font style='color:red'>").postTags("</font>")));
|
|
|
}
|
|
|
- //2.6 设置请求体参数中"_source"指定查询字段
|
|
|
- builder.source(s -> s.filter(f -> f.includes("id", "albumTitle", "albumIntro", "coverUrl", "includeTrackCount", "playStatNum", "createTime", "payType")));
|
|
|
|
|
|
- //3.基于构建器对象返回检索请求对象
|
|
|
+ //6.设置响应字段:请求体参数_source
|
|
|
+ builder.source(s -> s.filter(f -> f.excludes("attributeValueIndexList",
|
|
|
+ "hotScore",
|
|
|
+ "commentStatNum",
|
|
|
+ "buyStatNum",
|
|
|
+ "subscribeStatNum",
|
|
|
+ "announcerName")));
|
|
|
+
|
|
|
+ //7.基于构建器对象返回实际检索对象
|
|
|
return builder.build();
|
|
|
}
|
|
|
```
|
|
@@ -1878,47 +1890,49 @@ public SearchRequest buildDSL(AlbumIndexQuery albumIndexQuery) {
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 解析ES检索结果
|
|
|
+ * 解析ES响应结果
|
|
|
*
|
|
|
- * @param searchResponse
|
|
|
- * @param albumIndexQuery
|
|
|
+ * @param searchResponse ES响应对象
|
|
|
+ * @param albumIndexQuery 查询条件
|
|
|
* @return
|
|
|
*/
|
|
|
@Override
|
|
|
-public AlbumSearchResponseVo parseSearchResult(SearchResponse<AlbumInfoIndex> searchResponse, AlbumIndexQuery albumIndexQuery) {
|
|
|
- //1.创建响应VO对象
|
|
|
+public AlbumSearchResponseVo parseResult(SearchResponse<AlbumInfoIndex> searchResponse, AlbumIndexQuery albumIndexQuery) {
|
|
|
+ //1.创建响应结果对象
|
|
|
AlbumSearchResponseVo vo = new AlbumSearchResponseVo();
|
|
|
-
|
|
|
- //2.封装VO中四个分页相关信息
|
|
|
+ //2.封装VO中分页四项信息
|
|
|
Integer pageNo = albumIndexQuery.getPageNo();
|
|
|
Integer pageSize = albumIndexQuery.getPageSize();
|
|
|
+ //2.1 获取ES结果中总记录数
|
|
|
+ HitsMetadata<AlbumInfoIndex> hits = searchResponse.hits();
|
|
|
+ long total = hits.total().value();
|
|
|
+ //2.2 计算总页数 页大小=10 总计:101
|
|
|
+ long totalPages = total % pageSize == 0 ? total / pageSize : total / pageSize + 1;
|
|
|
vo.setPageNo(pageNo);
|
|
|
vo.setPageSize(pageSize);
|
|
|
- //2.1 解析ES获取命中记录数
|
|
|
- long total = searchResponse.hits().total().value();
|
|
|
vo.setTotal(total);
|
|
|
- //2.2 根据总记录数及页大小计算总页码
|
|
|
- long totalPages = total % pageSize == 0 ? total / pageSize : total / pageSize + 1;
|
|
|
vo.setTotalPages(totalPages);
|
|
|
|
|
|
- //3.封装Vo中检索到文档数据(记得处理高亮)
|
|
|
- List<Hit<AlbumInfoIndex>> hitList = searchResponse.hits().hits();
|
|
|
- if (CollectionUtil.isNotEmpty(hitList)) {
|
|
|
- //3.1 遍历命中记录对象得到Hit对象中中_source(专辑对象)
|
|
|
- List<AlbumInfoIndexVo> list = hitList.stream()
|
|
|
+ //3.封装Vo中专辑列表
|
|
|
+ List<Hit<AlbumInfoIndex>> hitsList = hits.hits();
|
|
|
+ if (CollUtil.isNotEmpty(hitsList)) {
|
|
|
+ List<AlbumInfoIndexVo> infoIndexVoList = hitsList
|
|
|
+ .stream()
|
|
|
.map(hit -> {
|
|
|
+ //3.1 获取命中文档原数据
|
|
|
AlbumInfoIndex albumInfoIndex = hit.source();
|
|
|
- //3.2 处理高亮
|
|
|
- Map<String, List<String>> highlightMap = hit.highlight();
|
|
|
- if (CollectionUtil.isNotEmpty(highlightMap)) {
|
|
|
- String highlightText = highlightMap.get("albumTitle").get(0);
|
|
|
- albumInfoIndex.setAlbumTitle(highlightText);
|
|
|
+ //3.2 处理高亮片段
|
|
|
+ Map<String, List<String>> highlight = hit.highlight();
|
|
|
+ if (CollUtil.isNotEmpty(highlight)) {
|
|
|
+ String albumTitleHightLight = highlight.get("albumTitle").get(0);
|
|
|
+ albumInfoIndex.setAlbumTitle(albumTitleHightLight);
|
|
|
}
|
|
|
+ //3.3响应VO
|
|
|
return BeanUtil.copyProperties(albumInfoIndex, AlbumInfoIndexVo.class);
|
|
|
}).collect(Collectors.toList());
|
|
|
- vo.setList(list);
|
|
|
+ vo.setList(infoIndexVoList);
|
|
|
}
|
|
|
- //4.响应VO
|
|
|
+ //x.响应结果VO对象
|
|
|
return vo;
|
|
|
}
|
|
|
```
|
|
@@ -1943,14 +1957,14 @@ public AlbumSearchResponseVo parseSearchResult(SearchResponse<AlbumInfoIndex> se
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 根据1级分类ID查询置顶3级分类列表
|
|
|
+ * 根据一级分类Id查询置顶7个三级分类列表
|
|
|
* @param category1Id
|
|
|
* @return
|
|
|
*/
|
|
|
-@Operation(summary = "根据1级分类ID查询置顶3级分类列表")
|
|
|
+@Operation(summary = "根据一级分类Id查询置顶7个三级分类列表")
|
|
|
@GetMapping("/category/findTopBaseCategory3/{category1Id}")
|
|
|
-public Result<List<BaseCategory3>> getTopBaseCategory3(@PathVariable Long category1Id){
|
|
|
- List<BaseCategory3> list = baseCategoryService.getTopBaseCategory3(category1Id);
|
|
|
+public Result<List<BaseCategory3>> findTopBaseCategory3(@PathVariable Long category1Id) {
|
|
|
+ List<BaseCategory3> list = baseCategoryService.findTopBaseCategory3(category1Id);
|
|
|
return Result.ok(list);
|
|
|
}
|
|
|
```
|
|
@@ -1959,47 +1973,42 @@ public Result<List<BaseCategory3>> getTopBaseCategory3(@PathVariable Long catego
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 根据1级分类ID查询置顶3级分类列表
|
|
|
+ * 根据一级分类Id查询置顶7个三级分类列表
|
|
|
* @param category1Id
|
|
|
* @return
|
|
|
*/
|
|
|
-List<BaseCategory3> getTopBaseCategory3(Long category1Id);
|
|
|
+List<BaseCategory3> findTopBaseCategory3(Long category1Id);
|
|
|
```
|
|
|
|
|
|
**BaseCategoryServiceImpl实现类**
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 根据1级分类ID查询置顶3级分类列表
|
|
|
+ * 根据一级分类Id查询置顶7个三级分类列表
|
|
|
*
|
|
|
* @param category1Id
|
|
|
* @return
|
|
|
*/
|
|
|
@Override
|
|
|
-public List<BaseCategory3> getTopBaseCategory3(Long category1Id) {
|
|
|
- //1.根据1级分类ID得到二级分类列表(获取二级分类ID列表)
|
|
|
- LambdaQueryWrapper<BaseCategory2> category2LambdaQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
- category2LambdaQueryWrapper.eq(BaseCategory2::getCategory1Id, category1Id);
|
|
|
- category2LambdaQueryWrapper.select(BaseCategory2::getId);
|
|
|
- List<BaseCategory2> baseCategory2List = baseCategory2Mapper.selectList(category2LambdaQueryWrapper);
|
|
|
- if (CollectionUtil.isNotEmpty(baseCategory2List)) {
|
|
|
- //2.根据二级分类ID列表得到置顶三级分类
|
|
|
- //2.1 获取所有2级分类ID
|
|
|
- List<Long> category2IdList = baseCategory2List
|
|
|
- .stream()
|
|
|
- .map(BaseCategory2::getId)
|
|
|
- .collect(Collectors.toList());
|
|
|
- //2.2 构建查询三级分类条件
|
|
|
- LambdaQueryWrapper<BaseCategory3> baseCategory3LambdaQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
- baseCategory3LambdaQueryWrapper.eq(BaseCategory3::getIsTop, 1);
|
|
|
- baseCategory3LambdaQueryWrapper.in(BaseCategory3::getCategory2Id, category2IdList);
|
|
|
- baseCategory3LambdaQueryWrapper.orderByAsc(BaseCategory3::getOrderNum);
|
|
|
- baseCategory3LambdaQueryWrapper.last("LIMIT 7");
|
|
|
- baseCategory3LambdaQueryWrapper.select(BaseCategory3::getId, BaseCategory3::getName, BaseCategory3::getCategory2Id);
|
|
|
- //2.3 查询得到7个置顶三级分类
|
|
|
- List<BaseCategory3> list = baseCategory3Mapper.selectList(baseCategory3LambdaQueryWrapper);
|
|
|
- return list;
|
|
|
+public List<BaseCategory3> findTopBaseCategory3(Long category1Id) {
|
|
|
+ //1.根据1级分类ID查询该1级分类下二级分类ID列表
|
|
|
+ List<BaseCategory2> baseCategory2List = baseCategory2Mapper.selectList(
|
|
|
+ new LambdaQueryWrapper<BaseCategory2>()
|
|
|
+ .eq(BaseCategory2::getCategory1Id, category1Id)
|
|
|
+ .select(BaseCategory2::getId)
|
|
|
+ );
|
|
|
+ if (CollUtil.isNotEmpty(baseCategory2List)) {
|
|
|
+ List<Long> category2IdList = baseCategory2List.stream()
|
|
|
+ .map(BaseCategory2::getId).collect(Collectors.toList());
|
|
|
+ //2.根据二级分类ID列表查询置顶前7个个三级分类列表
|
|
|
+ LambdaQueryWrapper<BaseCategory3> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.in(BaseCategory3::getCategory2Id, category2IdList);
|
|
|
+ queryWrapper.eq(BaseCategory3::getIsTop, 1);
|
|
|
+ queryWrapper.orderByAsc(BaseCategory3::getOrderNum);
|
|
|
+ queryWrapper.last("limit 7");
|
|
|
+ return baseCategory3Mapper.selectList(queryWrapper);
|
|
|
}
|
|
|
+
|
|
|
return null;
|
|
|
}
|
|
|
```
|
|
@@ -2016,13 +2025,13 @@ public List<BaseCategory3> getTopBaseCategory3(Long category1Id) {
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 查询当前1级分类下包含子分类(二三级分类)
|
|
|
+ * 查询1级分类下包含所有二级以及三级分类
|
|
|
* @param category1Id
|
|
|
- * @return {"categoryId":1,"categoryName":"音乐",categoryChild:[{"categoryId":101,"categoryName":"音乐音效",categoryChild:[{..}]}]}
|
|
|
+ * @return
|
|
|
*/
|
|
|
-@Operation(summary = "查询当前1级分类下包含子分类(二三级分类)")
|
|
|
+@Operation(summary = "查询1级分类下包含所有二级以及三级分类")
|
|
|
@GetMapping("/category/getBaseCategoryList/{category1Id}")
|
|
|
-public Result<JSONObject> getBaseCategoryListByCategory1Id(@PathVariable Long category1Id){
|
|
|
+public Result<JSONObject> getBaseCategoryListByCategory1Id(@PathVariable Long category1Id) {
|
|
|
JSONObject jsonObject = baseCategoryService.getBaseCategoryListByCategory1Id(category1Id);
|
|
|
return Result.ok(jsonObject);
|
|
|
}
|
|
@@ -2032,9 +2041,9 @@ public Result<JSONObject> getBaseCategoryListByCategory1Id(@PathVariable Long ca
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 查询当前1级分类下包含子分类(二三级分类)
|
|
|
+ * 查询1级分类下包含所有二级以及三级分类
|
|
|
* @param category1Id
|
|
|
- * @return {"categoryId":1,"categoryName":"音乐",categoryChild:[{"categoryId":101,"categoryName":"音乐音效",categoryChild:[{..}]}]}
|
|
|
+ * @return 一级分类对象
|
|
|
*/
|
|
|
JSONObject getBaseCategoryListByCategory1Id(Long category1Id);
|
|
|
```
|
|
@@ -2043,49 +2052,63 @@ JSONObject getBaseCategoryListByCategory1Id(Long category1Id);
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 查询当前1级分类下包含子分类(二三级分类)
|
|
|
+ * 查询1级分类下包含所有二级以及三级分类
|
|
|
*
|
|
|
* @param category1Id
|
|
|
- * @return {"categoryId":1,"categoryName":"音乐",categoryChild:[{"categoryId":101,"categoryName":"音乐音效",categoryChild:[{..}]}]}
|
|
|
+ * @return 一级分类对象
|
|
|
*/
|
|
|
@Override
|
|
|
public JSONObject getBaseCategoryListByCategory1Id(Long category1Id) {
|
|
|
- //1.根据1级分类ID查询分类视图得到“1级”分类列表 封装1级分类对象
|
|
|
- LambdaQueryWrapper<BaseCategoryView> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
- queryWrapper.eq(BaseCategoryView::getCategory1Id, category1Id);
|
|
|
- List<BaseCategoryView> category1List = baseCategoryViewMapper.selectList(queryWrapper);
|
|
|
- if (CollectionUtil.isNotEmpty(category1List)) {
|
|
|
- String category1Name = category1List.get(0).getCategory1Name();
|
|
|
- //1.1 封装1级分类对象
|
|
|
+ //1.处理1级分类
|
|
|
+ //1.1 根据1级分类ID查询分类视图得到所有"1级分类"列表
|
|
|
+ List<BaseCategoryView> baseCategory1List = baseCategoryViewMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<BaseCategoryView>()
|
|
|
+ .eq(BaseCategoryView::getCategory1Id, category1Id)
|
|
|
+ );
|
|
|
+ if (CollUtil.isNotEmpty(baseCategory1List)) {
|
|
|
+ BaseCategoryView baseCategoryView = baseCategory1List.get(0);
|
|
|
+ //1.2 创建1级分类JSON对象
|
|
|
JSONObject jsonObject1 = new JSONObject();
|
|
|
- jsonObject1.put("categoryId", category1Id);
|
|
|
- jsonObject1.put("categoryName", category1Name);
|
|
|
- //2.处理二级分类
|
|
|
- List<JSONObject> jsonObject2List = new ArrayList<>();
|
|
|
- //2.1 对"1级"分类列表进行按2级分类ID分组
|
|
|
- Map<Long, List<BaseCategoryView>> map2 = category1List
|
|
|
+ //1.2.1 封装1级分类ID
|
|
|
+ jsonObject1.put("categoryId", baseCategoryView.getCategory1Id());
|
|
|
+ //1.2.2 封装1级分类名称
|
|
|
+ jsonObject1.put("categoryName", baseCategoryView.getCategory1Name());
|
|
|
+
|
|
|
+ //2.处理2级分类
|
|
|
+ //2.1 对"1级分类列表"按二级分类ID进行分组,得到Map
|
|
|
+ Map<Long, List<BaseCategoryView>> map2 = baseCategory1List
|
|
|
.stream()
|
|
|
.collect(Collectors.groupingBy(BaseCategoryView::getCategory2Id));
|
|
|
- //2.2 遍历"2级"分类Map
|
|
|
+
|
|
|
+ //2.2 遍历Map,创建二级分类JSON对象集合
|
|
|
+ List<JSONObject> jsonObject2List = new ArrayList<>();
|
|
|
for (Map.Entry<Long, List<BaseCategoryView>> entry2 : map2.entrySet()) {
|
|
|
+ //2.2.1 创建二级分类JSON对象
|
|
|
+ JSONObject jsonObject2 = new JSONObject();
|
|
|
+ //2.2.2 封装二级分类ID
|
|
|
Long category2Id = entry2.getKey();
|
|
|
+ //2.2.3 封装二级分类名称
|
|
|
String category2Name = entry2.getValue().get(0).getCategory2Name();
|
|
|
- //2.3 封装2级分类JSON对象
|
|
|
- JSONObject jsonObject2 = new JSONObject();
|
|
|
- jsonObject2.put("categoryId", category2Id);
|
|
|
+ jsonObject2.put("categoryId", category1Id);
|
|
|
jsonObject2.put("categoryName", category2Name);
|
|
|
- //3.处理三级分类
|
|
|
+ //3.处理3级分类
|
|
|
+ //3.1 创建3级分类JSON对象集合
|
|
|
List<JSONObject> jsonObject3List = new ArrayList<>();
|
|
|
- for (BaseCategoryView baseCategoryView : entry2.getValue()) {
|
|
|
+ //3.2 遍历"2级分类列表",封装三级分类对象
|
|
|
+ for (BaseCategoryView categoryView : entry2.getValue()) {
|
|
|
+ //3.2.1 创建3级分类JSON对象
|
|
|
JSONObject jsonObject3 = new JSONObject();
|
|
|
- jsonObject3.put("categoryId", baseCategoryView.getCategory3Id());
|
|
|
- jsonObject3.put("categoryName", baseCategoryView.getCategory3Name());
|
|
|
+ //3.2.2 封装3级分类ID
|
|
|
+ jsonObject3.put("categoryId", categoryView.getCategory3Id());
|
|
|
+ //3.2.3 封装3级分类名称
|
|
|
+ jsonObject3.put("categoryName", categoryView.getCategory3Name());
|
|
|
jsonObject3List.add(jsonObject3);
|
|
|
}
|
|
|
+ //2.3 将三级分类集合加入到二级分类对象"categoryChild"中
|
|
|
jsonObject2.put("categoryChild", jsonObject3List);
|
|
|
jsonObject2List.add(jsonObject2);
|
|
|
}
|
|
|
- //2.4 将2级分类集合存入1级分类categoryChild中
|
|
|
+ //2.3 将三级分类集合加入到二级分类对象"categoryChild"中
|
|
|
jsonObject1.put("categoryChild", jsonObject2List);
|
|
|
return jsonObject1;
|
|
|
}
|
|
@@ -2207,20 +2230,20 @@ POST album_info/_search
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 根据1级分类ID查询置顶3级分类列表
|
|
|
+ * 根据一级分类Id查询置顶7个三级分类列表
|
|
|
* @param category1Id
|
|
|
* @return
|
|
|
*/
|
|
|
@GetMapping("/category/findTopBaseCategory3/{category1Id}")
|
|
|
-public Result<List<BaseCategory3>> getTopBaseCategory3(@PathVariable Long category1Id);
|
|
|
+public Result<List<BaseCategory3>> findTopBaseCategory3(@PathVariable Long category1Id);
|
|
|
```
|
|
|
|
|
|
**AlbumDegradeFeignClient服务降级类**
|
|
|
|
|
|
```java
|
|
|
@Override
|
|
|
-public Result<List<BaseCategory3>> getTopBaseCategory3(Long category1Id) {
|
|
|
- log.error("[专辑服务]远程调用getTopBaseCategory3执行服务降级");
|
|
|
+public Result<List<BaseCategory3>> findTopBaseCategory3(Long category1Id) {
|
|
|
+ log.error("[专辑服务]远程调用findTopBaseCategory3执行服务降级");
|
|
|
return null;
|
|
|
}
|
|
|
```
|
|
@@ -2231,14 +2254,14 @@ public Result<List<BaseCategory3>> getTopBaseCategory3(Long category1Id) {
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 查询置顶3级分类下热度TOP6专辑列表
|
|
|
+ * 查询1级分类下置顶3级分类热度TOP6专辑
|
|
|
* @param category1Id
|
|
|
- * @return
|
|
|
+ * @return [{"baseCategory3":{三级分类对象},list:[专辑列表]},,{其他6个置顶分类热门专辑Map}]
|
|
|
*/
|
|
|
-@Operation(summary = "查询置顶3级分类下热度TOP6专辑列表")
|
|
|
+@Operation(summary = "查询1级分类下置顶3级分类热度TOP6专辑")
|
|
|
@GetMapping("/albumInfo/channel/{category1Id}")
|
|
|
-public Result<List<Map<String, Object>>> searchTopCategoryHotAlbum(@PathVariable Long category1Id){
|
|
|
- List<Map<String, Object>> list = searchService.searchTopCategoryHotAlbum(category1Id);
|
|
|
+public Result<List<Map<String, Object>>> channel(@PathVariable Long category1Id) {
|
|
|
+ List<Map<String, Object>> list = searchService.channel(category1Id);
|
|
|
return Result.ok(list);
|
|
|
}
|
|
|
```
|
|
@@ -2247,89 +2270,95 @@ public Result<List<Map<String, Object>>> searchTopCategoryHotAlbum(@PathVariable
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 查询置顶3级分类下热度TOP6专辑列表
|
|
|
+ * 查询1级分类下置顶3级分类热度TOP6专辑
|
|
|
* @param category1Id
|
|
|
- * @return
|
|
|
+ * @return [{"baseCategory3":{三级分类对象},list:[专辑列表]},,{其他6个置顶分类热门专辑Map}]
|
|
|
*/
|
|
|
-List<Map<String, Object>> searchTopCategoryHotAlbum(Long category1Id);
|
|
|
+List<Map<String, Object>> channel(Long category1Id);
|
|
|
```
|
|
|
|
|
|
**SearchServiceImpl**实现类:
|
|
|
|
|
|
```java
|
|
|
/**
|
|
|
- * 查询置顶3级分类下热度TOP6专辑列表
|
|
|
+ * 查询1级分类下置顶3级分类热度TOP6专辑
|
|
|
*
|
|
|
* @param category1Id
|
|
|
- * @return
|
|
|
+ * @return [{"baseCategory3":{三级分类对象},list:[专辑列表]},,{其他6个置顶分类热门专辑Map}]
|
|
|
*/
|
|
|
@Override
|
|
|
-public List<Map<String, Object>> searchTopCategoryHotAlbum(Long category1Id) {
|
|
|
+public List<Map<String, Object>> channel(Long category1Id) {
|
|
|
try {
|
|
|
- //1.根据1级分类ID远程调用专辑服务获取6个置顶三级分类 用于检索ES条件,及封装Map中分类对象
|
|
|
- List<BaseCategory3> category3List = albumFeignClient.getTopBaseCategory3(category1Id).getData();
|
|
|
- Assert.notNull(category3List, "未查询到{}置顶分类", category1Id);
|
|
|
- //1.1 检索多关键字精确查询查询条件FiledValue类型 将集合泛型从BaseCategory3转为FiledValue(封装3级分类ID)
|
|
|
- List<FieldValue> fieldValueList = category3List
|
|
|
+ //1.根据1级分类ID获取置顶三级分类ID
|
|
|
+ //1.1 远程调用远程调用专辑微服务获取置顶3级分类
|
|
|
+ List<BaseCategory3> baseCategory3List = albumFeignClient.findTopBaseCategory3(category1Id).getData();
|
|
|
+ Assert.notNull(baseCategory3List, "一级分类{}置顶三级分类不存在", category1Id);
|
|
|
+
|
|
|
+ //1.2 获取置顶三级分类ID列表
|
|
|
+ List<FieldValue> fieldValueList = baseCategory3List
|
|
|
.stream()
|
|
|
- .map(category3 -> FieldValue.of(category3.getId()))
|
|
|
+ .map(c3 -> FieldValue.of(c3.getId()))
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
|
- //1.2 将三级分类List转为Map<Long, BaseCategory3> Map中key:三级分类ID Value:三级分类对象
|
|
|
- Map<Long, BaseCategory3> category3Map = category3List
|
|
|
+ //1.3 为了封装结果Map中分类对象,将三级分类List转为Map<3级分类ID,3级分类对象>
|
|
|
+ Map<Long, BaseCategory3> category3Map = baseCategory3List
|
|
|
.stream()
|
|
|
- .collect(Collectors.toMap(BaseCategory3::getId, c3 -> c3));
|
|
|
+ .collect(Collectors.toMap(BaseCategory3::getId, baseCategory3 -> baseCategory3));
|
|
|
|
|
|
-
|
|
|
- //2.根据查询条件:7个三级分类ID 聚合:根据三级分类ID聚合(子聚合:按照热度进行排序)检索ES
|
|
|
+ //2. 调用ES进行检索:置顶分类热门专辑
|
|
|
SearchResponse<AlbumInfoIndex> searchResponse = elasticsearchClient.search(
|
|
|
- s -> s.index(INDE_NAME)
|
|
|
+ s -> s.index(INDEX_NAME)
|
|
|
+ .size(0)
|
|
|
.query(q -> q.terms(t -> t.field("category3Id").terms(t1 -> t1.value(fieldValueList))))
|
|
|
- .aggregations("category3_agg",
|
|
|
- a -> a.terms(t -> t.field("category3Id").size(10))
|
|
|
- .aggregations("top6", a1 -> a1.topHits(t -> t.size(6).sort(
|
|
|
- sort -> sort.field(f -> f.field("hotScore").order(SortOrder.Desc))
|
|
|
- )))
|
|
|
+ .aggregations(
|
|
|
+ "c3_agg", a -> a.terms(t -> t.field("category3Id").size(7))
|
|
|
+ .aggregations("top6", a1 -> a1.topHits(
|
|
|
+ t -> t.size(6)
|
|
|
+ .sort(s1 -> s1.field(f -> f.field("hotScore").order(SortOrder.Desc)))
|
|
|
+ .source(s1 -> s1.filter(f -> f.excludes("attributeValueIndexList",
|
|
|
+ "hotScore",
|
|
|
+ "commentStatNum",
|
|
|
+ "buyStatNum",
|
|
|
+ "subscribeStatNum",
|
|
|
+ "announcerName")))
|
|
|
+ ))
|
|
|
)
|
|
|
- .size(0),
|
|
|
- AlbumInfoIndex.class);
|
|
|
-
|
|
|
- //2.解析ES检索结果封装置顶分类热门专辑Map对象
|
|
|
- //2.1 根据分类ID聚合名称从ES检索响应对象获取聚合结果
|
|
|
- LongTermsAggregate category3Agg = searchResponse.aggregations().get("category3_agg").lterms();
|
|
|
- //2.2 遍历三级分类桶(Bucket)数组,每遍历一个Bucket封装置顶分类热门专辑Map对象
|
|
|
- List<LongTermsBucket> bucketList = category3Agg.buckets().array();
|
|
|
- if (CollectionUtil.isNotEmpty(bucketList)) {
|
|
|
- List<Map<String, Object>> list = bucketList
|
|
|
+ , AlbumInfoIndex.class);
|
|
|
+
|
|
|
+ //3.解析聚合结果,获取置顶分类包含热度TOP6专辑列表 将7个置顶分类热门专辑Map封装到List集合中
|
|
|
+ List<LongTermsBucket> longTermsBuckets = searchResponse.aggregations().get("c3_agg").lterms().buckets().array();
|
|
|
+ //3.1 遍历三级分类聚合结果,每遍历一次就封装一个置顶分类热门专辑Map对象
|
|
|
+ if (CollUtil.isNotEmpty(longTermsBuckets)) {
|
|
|
+ List<Map<String, Object>> topCategory3MapList = longTermsBuckets
|
|
|
.stream()
|
|
|
- .map(c3Bucket -> {
|
|
|
- //2.2.1 获取外层聚合结果中key(三级分类ID)
|
|
|
- long category3Id = c3Bucket.key();
|
|
|
- //2.2.2 获取当前聚合内包含子聚合(按照组内专辑热度排序)
|
|
|
- TopHitsAggregate top6Aggregate = c3Bucket.aggregations().get("top6").topHits();
|
|
|
- //2.2.3 遍历子聚合Bucket得到热度TOP6专辑列表
|
|
|
- List<Hit<JsonData>> hitsList = top6Aggregate.hits().hits();
|
|
|
- if (CollectionUtil.isNotEmpty(hitsList)) {
|
|
|
- List<AlbumInfoIndex> top6List = hitsList.stream().map(hit -> {
|
|
|
- //获取热门专辑JSON字符串
|
|
|
- String sourceStr = hit.source().toString();
|
|
|
- //将JSON转为专辑文档对象
|
|
|
- AlbumInfoIndex albumInfoIndex = JSON.parseObject(sourceStr, AlbumInfoIndex.class);
|
|
|
- return albumInfoIndex;
|
|
|
- }).collect(Collectors.toList());
|
|
|
- //2.3 封装当前置顶分类热门专辑Map对象
|
|
|
- Map<String, Object> map = new HashMap<>();
|
|
|
- map.put("baseCategory3", category3Map.get(category3Id));
|
|
|
- map.put("list", top6List);
|
|
|
- return map;
|
|
|
+ .map(bucket -> {
|
|
|
+ //3.1.1 创建Map封装置顶分类热门专辑
|
|
|
+ Map<String, Object> map = new HashMap<>();
|
|
|
+ //3.1.2 获取聚合结果中三级分类ID
|
|
|
+ long topCategory3Id = bucket.key();
|
|
|
+ //3.1.3 获取top6专辑列表
|
|
|
+ //获取三级分类聚合内子聚合"top6"
|
|
|
+ List<Hit<JsonData>> top6HitsList = bucket.aggregations().get("top6")
|
|
|
+ .topHits().hits().hits();
|
|
|
+ if (CollUtil.isNotEmpty(top6HitsList)) {
|
|
|
+ //遍历Hit集合 将集合泛型从Hit转为AlbumInfoIndex类型
|
|
|
+ List<AlbumInfoIndex> topAlbumList = top6HitsList.stream()
|
|
|
+ .map(hit -> {
|
|
|
+ //获取专辑JSON字符串
|
|
|
+ String albumInfoIndexJSONStr = hit.source().toString();
|
|
|
+ //将专辑JSON字符串转为AlbumInfoIndex对象
|
|
|
+ AlbumInfoIndex albumInfoIndex = JSON.parseObject(albumInfoIndexJSONStr, AlbumInfoIndex.class);
|
|
|
+ return albumInfoIndex;
|
|
|
+ }).collect(Collectors.toList());
|
|
|
+ //3.2 封装置顶分类热门专辑Map
|
|
|
+ map.put("baseCategory3", category3Map.get(topCategory3Id));
|
|
|
+ map.put("list", topAlbumList);
|
|
|
}
|
|
|
- return null;
|
|
|
+ return map;
|
|
|
}).collect(Collectors.toList());
|
|
|
- //3.返回检索结果集合对象
|
|
|
- return list;
|
|
|
+ return topCategory3MapList;
|
|
|
}
|
|
|
} catch (IOException e) {
|
|
|
- log.error("[检索服务]检索置顶分类热门专辑异常:{}", e);
|
|
|
throw new RuntimeException(e);
|
|
|
}
|
|
|
return null;
|