Commit 402709b6 authored by 张辰's avatar 张辰

重写 主题列表 /api/theme/list

parent 3453c70f
......@@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.List;
@Data
public class ThemeListReq {
......@@ -12,20 +13,21 @@ public class ThemeListReq {
@NotNull(message = "主题类型不能为空")
@ApiModelProperty(value = "类型,1:推荐 2:关注 3:话题-热门 4:话题-最新")
private Integer type;
public Integer type;
@ApiModelProperty(value = "话题Id")
private String topicId;
public String topicId;
@ApiModelProperty(value = "当前浏览的最后一个themeId,可以为空")
private String lastId="";
public String lastId="";
@NotNull(message = "pageNumber不能为空")
@ApiModelProperty(value = "页面起始")
public Integer pageNumber;
@NotNull(message = "PageSize不能为空")
@ApiModelProperty(value = "页面大小")
private Integer pageSize;
public Integer pageSize;
public List<String> excludeIds;
}
package com.tanpu.community.api.beans.resp;
import com.tanpu.community.api.beans.qo.ThemeQo;
import lombok.Data;
import java.util.List;
@Data
public class ThemeListResp {
public List<ThemeQo> list;
public List<String> excludeIds;
}
......@@ -22,7 +22,6 @@ public class MetricsController {
@ApiOperation("浏览话题")
@GetMapping("/view/topic")
public CommonResp pageViewTopic(@RequestParam String topicId){
visitSummaryManager.addTopicPageView(topicId);
return CommonResp.success();
}
......@@ -30,7 +29,6 @@ public class MetricsController {
@ApiOperation("浏览主题")
@GetMapping("/view/theme")
public CommonResp pageViewTheme(@RequestParam String themeId){
visitSummaryManager.addFollowThemeView(themeId);
return CommonResp.success();
}
......@@ -38,7 +36,6 @@ public class MetricsController {
@ApiOperation("浏览关注主题")
@GetMapping("/view/follow")
public CommonResp pageViewTheme(){
visitSummaryManager.addFollowThemeView();
return CommonResp.success();
}
......
......@@ -7,6 +7,7 @@ import com.tanpu.common.auth.UserHolder;
import com.tanpu.community.api.beans.qo.ThemeQo;
import com.tanpu.community.api.beans.req.theme.*;
import com.tanpu.community.api.beans.resp.CreateThemeResp;
import com.tanpu.community.api.beans.resp.ThemeListResp;
import com.tanpu.community.cache.RedisCache;
import com.tanpu.community.manager.ThemeManager;
import io.swagger.annotations.ApiOperation;
......@@ -43,9 +44,9 @@ public class ThemeController {
@ApiOperation("主题列表-推荐/关注/热门/最新")
@PostMapping(value = "/list")
@ResponseBody
public CommonResp<List<ThemeQo>> selectInterestList(@Validated @RequestBody ThemeListReq req) {
public CommonResp<ThemeListResp> selectInterestList(@Validated @RequestBody ThemeListReq req) {
String userId = userHolder.getUserId();
List<ThemeQo> result = themeManager.queryThemes(req, userId);
ThemeListResp result = themeManager.queryThemes(req, userId);
return CommonResp.success(result);
}
......
......@@ -12,6 +12,7 @@ import com.tanpu.community.api.beans.req.homepage.QueryRecordThemeReq;
import com.tanpu.community.api.beans.req.theme.*;
import com.tanpu.community.api.beans.resp.CreateThemeResp;
import com.tanpu.community.api.beans.resp.ThemeFullSearchResp;
import com.tanpu.community.api.beans.resp.ThemeListResp;
import com.tanpu.community.api.beans.vo.feign.fatools.UserInfoNew;
import com.tanpu.community.api.enums.*;
import com.tanpu.community.cache.RedisCache;
......@@ -178,40 +179,58 @@ public class ThemeManager {
}
/**
* 推荐:由最热,最新和python推荐三个部分组成,比例为6,3,1
*/
// 查询主题列表:推荐/关注/热门/最新
public List<ThemeQo> queryThemes(ThemeListReq req, String userId) {
List<ThemeEntity> themeEntities = new ArrayList<>();
public ThemeListResp queryThemes(ThemeListReq req, String userId) {
Integer pageStart = (req.pageNumber - 1) * req.pageSize;
Integer realSize = req.pageSize * 2;
List<ThemeEntity> themes = new ArrayList<>();
if (ThemeListTypeEnum.RECOMMEND.getCode().equals(req.getType())) {
//推荐
List<String> recmdIds = recommendService.getRecommendThemes(pageStart, realSize, userId);
//去重已看过(查看正文)
recmdIds = visitSummaryService.filterUserNotVisited(userId, recmdIds);
List<String> recommendThemeIds = recommendService.getRecommendThemes(req.getLastId(), req.getPageSize(), userId);
themeEntities = themeService.queryByThemeIds(recommendThemeIds);
themeEntities = RankUtils.sortThemeEntityByIds(themeEntities, recommendThemeIds);
themes = themeService.queryByThemeIds(recmdIds);
themes = RankUtils.sortThemeEntityByIds(themes, recmdIds);
} else if (ThemeListTypeEnum.FOLLOW.getCode().equals(req.getType())) {
//关注
if (StringUtils.isEmpty(req.getLastId())) {
visitSummaryService.addPageView(userId, userId, VisitTypeEnum.FOLLOW_THEME_VIEW);
}
//根据关注列表查询
List<String> fansList = followRelService.queryFansByFollowerId(userId);
themeEntities = themeService.queryByUserIds(fansList, req.getLastId(), req.getPageSize());
themes = themeService.queryByUserIds(fansList, req.getLastId(), req.getPageSize());
} else if (ThemeListTypeEnum.TOPIC_HOT.getCode().equals(req.getType())) {
//根据话题查询热门
if (StringUtils.isEmpty(req.getTopicId())) throw new BizException("TopicId为空");
List<String> rankThemeIds = rankService.getRankThemeListByTopic(req.getTopicId());
themeEntities = themeService.queryByThemeIdsExcludeUser(rankThemeIds, null, req.getLastId(), req.getPageSize());
themeEntities = RankUtils.sortThemeEntityByIds(themeEntities, rankThemeIds);
if (StringUtils.isEmpty(req.getTopicId())) {
throw new BizException("TopicId为空");
}
List<String> rankThemeIds = rankService.getRankThemeListByTopic(req.getTopicId()).subList(pageStart, realSize);
themes = themeService.queryByThemeIds(rankThemeIds);
themes = RankUtils.sortThemeEntityByIds(themes, rankThemeIds);
} else if (ThemeListTypeEnum.TOPIC_LATEST.getCode().equals(req.getType())) {
//根据话题查询最新
if (StringUtils.isEmpty(req.getTopicId())) throw new BizException("TopicId为空");
themeEntities = themeService.queryByTopic(req.getTopicId(), req.getLastId(), req.getPageSize());
if (StringUtils.isEmpty(req.getTopicId())) {
throw new BizException("TopicId为空");
}
themes = themeService.queryNewestByTopic(req.topicId, req.pageNumber, realSize);
}
// filter用户自己的
themes = themes.stream().filter(t -> {
return !userId.equals(t.getAuthorId()) && !req.excludeIds.contains(t.getThemeId());
}).collect(Collectors.toList()).subList(0, req.pageSize);
ThemeListResp resp = new ThemeListResp();
resp.excludeIds = req.excludeIds;
resp.excludeIds.addAll(themes.stream().map(ThemeEntity::getThemeId).collect(Collectors.toList()));
resp.list = convertEntityToQo(themes, userId);
//组装详情
return convertEntityToQo(themeEntities, userId);
return resp;
}
//主题Entity转QO,组装所有信息
......@@ -290,8 +309,6 @@ public class ThemeManager {
//查询正文
public ThemeQo getThemeDetail(String themeId, String userId) {
//进入详情
visitSummaryService.addPageView(userId, themeId, VisitTypeEnum.THEME_PAGE_VIEW);
//查询详情
ThemeQo themeQo = redisCache.getObject(StringUtils.joinWith("_", CACHE_THEME_ID, themeId), 60,
() -> this.getDetailCommon(themeId), ThemeQo.class);
......
......@@ -52,8 +52,6 @@ public class TopicManager {
// 话题详情页
public TopicRankQo getDetail(String topicId) {
//话题详情
visitSummaryService.addPageView(userHolder.getUserId(), topicId, VisitTypeEnum.TOPIC_PAGE_VIEW);
return rankService.getTopicDetail(topicId);
}
......
......@@ -39,20 +39,4 @@ public class VisitSummaryManager {
VisitSummaryEntity vs = ConvertUtil.convertFromKafka(msg);
visitSummaryService.insertOrUpdateDur(vs);
}
public void addTopicPageView(String topicId) {
String userId = userHolder.getUserId();
visitSummaryService.addPageView(userId, topicId, VisitTypeEnum.TOPIC_PAGE_VIEW);
}
public void addFollowThemeView(String themeId) {
String userId = userHolder.getUserId();
visitSummaryService.addPageView(userId, themeId, VisitTypeEnum.THEME_PAGE_VIEW);
}
public void addFollowThemeView() {
String userId = userHolder.getUserId();
visitSummaryService.addPageView(userId, userId, VisitTypeEnum.FOLLOW_THEME_VIEW);
}
}
......@@ -49,7 +49,6 @@ public class RankService {
//最热
private List<ThemeAnalysDO> hotestThemes = new ArrayList<>();
private List<TopicRankQo> rankTopicList = new ArrayList<>();
private List<TopicRankQo> rankTopicListTop4 = new ArrayList<>();
......@@ -147,16 +146,16 @@ public class RankService {
* @param newCount
* @return
*/
public List<String> getHotAndNewThemes(Integer hotCount, Integer newCount, String userId) {
Set<String> hotThemeIds = this.hotestThemes.stream().limit(hotCount)
.filter(o -> !userId.equals(o.getAuthorId()))
.map(ThemeAnalysDO::getThemeId)
.collect(Collectors.toSet());
Set<String> newThemeIds = themeService.selectExcludeUser(null, null, newCount)
.stream().map(ThemeEntity::getThemeId).collect(Collectors.toSet());
hotThemeIds.addAll(newThemeIds);
return new ArrayList<>(hotThemeIds);
}
// public List<String> getHotAndNewThemes(Integer hotCount, Integer newCount, String userId) {
// Set<String> hotThemeIds = this.hotestThemes.stream().limit(hotCount)
// .filter(o -> !userId.equals(o.getAuthorId()))
// .map(ThemeAnalysDO::getThemeId)
// .collect(Collectors.toSet());
// Set<String> newThemeIds = themeService.selectExcludeUser(null, null, newCount)
// .stream().map(ThemeEntity::getThemeId).collect(Collectors.toSet());
// hotThemeIds.addAll(newThemeIds);
// return new ArrayList<>(hotThemeIds);
// }
/**
* 话题详情
......
......@@ -4,8 +4,10 @@ import com.tanpu.common.util.JsonUtil;
import com.tanpu.community.api.beans.qo.ThemeAnalysDO;
import com.tanpu.community.api.beans.resp.PythonResponse;
import com.tanpu.community.dao.entity.community.ThemeEntity;
import com.tanpu.community.util.BizUtils;
import com.tanpu.community.util.ConvertUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
......@@ -46,52 +48,36 @@ public class RecommendService {
private List<ThemeAnalysDO> recentThemeList = new ArrayList<>();
// 推荐
private Map<String, List<String>> recommondList = new HashMap<>();
// 用户已经看过的
private Map<String, Set<String>> returnedIdsMap = new HashMap<>();
public List<String> getRecommendThemes(String lastId, Integer pageSize, String userId) {
public List<String> getRecommendThemes(Integer pageStart, Integer pageSize, String userId) {
//最热话题,剔除当前用户的主题
// todo pageNo , pageSize
List<String> hotThemeIds = rankService.getHotestThemes().stream()
.filter(o -> !userId.equals(o.getAuthorId()))
.map(ThemeAnalysDO::getThemeId)
.collect(Collectors.toList());
//最新话题,剔除当前用户的主题
List<String> newThemeIds = this.getRecentThemeList().stream()
.filter(o -> !userId.equals(o.getAuthorId()))
List<String> newThemeIds = getNewestThemes().stream()
.map(ThemeAnalysDO::getThemeId)
.collect(Collectors.toList());
//推荐话题
List<String> recThemeIds = getPythonRecommendList(userId);
// 混合 如果重新搜索,则刷新返回id
Set<String> returnedIds = (StringUtils.isEmpty(lastId)) || !returnedIdsMap.containsKey(userId)
|| returnedIdsMap.get(userId) == null ?
new HashSet<>() : returnedIdsMap.get(userId);
List<String> result = new ArrayList<>();
getResultList(hotThemeIds, 0, newThemeIds, 0, recThemeIds, 0, returnedIds, result, pageSize, userId);
List<String> result = mergeRecommend(hotThemeIds, newThemeIds, recThemeIds);
result = result.stream().limit(pageSize).collect(Collectors.toList());
//记录已返回主题id
if (StringUtils.isEmpty(lastId)) {
returnedIdsMap.put(userId, new HashSet<>(result));
} else {
HashSet<String> newSet = new HashSet<>();
newSet.addAll(returnedIdsMap.get(userId));
newSet.addAll(result);
returnedIdsMap.put(userId, newSet);
}
return result;
}
public List<ThemeAnalysDO> getRecentThemeList() {
// 获取最新话题
public List<ThemeAnalysDO> getNewestThemes() {
if (recentThemeList.size() == 0) {
refreshNewestThemes();
}
return recentThemeList;
}
//从数据库查询最新主题
// 从数据库查询最新主题
public void refreshNewestThemes() {
List<ThemeEntity> themeEntities = themeService.queryLatestThemes(100);
this.recentThemeList = ConvertUtil.themeEntityToAnalysDOs(themeEntities);
......@@ -106,7 +92,7 @@ public class RecommendService {
}
}
//HTTP查询python推荐主题
//HTTP查询python推荐主题 python返回最多50个
public List<String> refreshPythonRecommendList(String userId) {
if (!"true".equals(enablePython)) {
return Collections.emptyList();
......@@ -160,53 +146,25 @@ public class RecommendService {
return result;
}
private void getResultList(List<String> hotThemeIds, Integer hotTag, List<String> newThemeIds, Integer newTag, List<String> recThemeIds, Integer recTag, Set<String> returnedIds, List<String> result, Integer pageSize, String userId) {
if (hotThemeIds.size() <= hotTag && newThemeIds.size() <= newTag && recThemeIds.size() <= recTag) {
//所有列表已循环结束,返回
return;
}
while (result.size() < pageSize * 1.5) {
int hotTimes = hotRatio;
int newTimes = newRatio;
int recTimes = pythonRatio;
String id;
while (hotTimes > 0 && hotThemeIds.size() > hotTag) {
id = hotThemeIds.get(hotTag);
if (!returnedIds.contains(id)) {
result.add(id);
returnedIds.add(id);
}
hotTag++;
hotTimes--;
}
while (newTimes > 0 && newThemeIds.size() > newTag) {
id = newThemeIds.get(newTag);
if (!returnedIds.contains(id)) {
result.add(id);
returnedIds.add(id);
}
newTag++;
newTimes--;
// 按照 6,3,1的比例
private List<String> mergeRecommend(List<String> hotIds, List<String> newestIds, List<String> recmdIds) {
List<String> retList = new ArrayList<>();
int round = 0;
while (true) {
int hotStart = round * 6;
int newestStart = round * 3;
int recmdStart = round;
if (hotStart >= hotIds.size() && newestStart >= newestIds.size() && recmdStart >= recmdIds.size()) {
break;
}
while (recTimes > 0 && recThemeIds.size() > recTag) {
id = recThemeIds.get(recTag);
if (!returnedIds.contains(id)) {
result.add(id);
returnedIds.add(id);
}
recTag++;
recTimes--;
}
}
//去重已看过(查看正文)
result = visitSummaryService.filterUserNotVisited(userId, result);
retList.addAll(BizUtils.subList(hotIds, hotStart, hotStart + 6));
retList.addAll(BizUtils.subList(newestIds, newestStart, newestStart + 3));
retList.addAll(BizUtils.subList(recmdIds, recmdStart, recmdStart + 1));
if (result.size() < pageSize) {
getResultList(hotThemeIds, hotTag, newThemeIds, newTag, recThemeIds, recTag, returnedIds, result, pageSize, userId);
round++;
}
return retList;
}
......
......@@ -202,23 +202,15 @@ public class ThemeService {
* 根据话题查询最新主题(可分页)
*
* @param topidId 话题Id
* @param lastId 查询此主题Id之前的主题
* @param pageSize 查询数量
* @return
*/
public List<ThemeEntity> queryByTopic(String topidId, String lastId, Integer pageSize) {
public List<ThemeEntity> queryNewestByTopic(String topidId, Integer pageNo, Integer pageSize) {
LambdaQueryWrapper<ThemeEntity> queryWrapper = new LambdaQueryWrapper<ThemeEntity>()
.eq(ThemeEntity::getTopicId, topidId);
if (StringUtils.isNotEmpty(lastId)) {
ThemeEntity lastEntity = queryByThemeId(lastId);
if (lastEntity == null) throw new BizException("主题未找到,id:" + lastId);
queryWrapper.lt(ThemeEntity::getUpdateTime, lastEntity.getCreateTime());
}
if (pageSize != null) {
queryWrapper.last("limit " + pageSize);
}
queryWrapper.orderByDesc(ThemeEntity::getCreateTime);
queryWrapper.eq(ThemeEntity::getDeleteTag, DeleteTagEnum.NOT_DELETED.getCode());
.eq(ThemeEntity::getTopicId, topidId)
.last("limit " + pageNo + ", " + pageSize)
.orderByDesc(ThemeEntity::getCreateTime)
.eq(ThemeEntity::getDeleteTag, DeleteTagEnum.NOT_DELETED.getCode());
return themeMapper.selectList(queryWrapper);
}
......
......@@ -25,6 +25,7 @@ public class VisitSummaryService {
@Resource
private VisitSummaryMapper visitSummaryMapper;
// 从refIds中去掉用户已经访问过的
public List<String> filterUserNotVisited(String userId, List<String> refIds) {
if (refIds.isEmpty()) {
return refIds;
......@@ -45,16 +46,6 @@ public class VisitSummaryService {
}
}
@Transactional
public void addPageView(String userId, String targetId, VisitTypeEnum type) {
visitSummaryMapper.insert(VisitSummaryEntity.builder()
.visitorId(userId)
.refId(targetId)
.refType(type.getCode())
.duration(0)
.build());
}
// 查询话题 详细页面 浏览量
public Integer queryTopicDetailVisit(String topicId) {
return visitSummaryMapper.selectCount(new LambdaQueryWrapper<VisitSummaryEntity>()
......
package com.tanpu.community.util;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
public class BizUtils {
public static <T> List<T> subList(List<T> list, int start, int size) {
if (list.isEmpty() || start >= list.size() || start < 0) {
return new ArrayList<>();
}
int realEnd = Math.min(start + size, list.size());
return list.subList(start, realEnd);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment