|
@@ -112,49 +112,71 @@ public class RecommendService {
|
|
|
|
|
|
|
|
public RecommendResponse recommend(RecommendRequest request) {
|
|
public RecommendResponse recommend(RecommendRequest request) {
|
|
|
long start = System.currentTimeMillis();
|
|
long start = System.currentTimeMillis();
|
|
|
- RecommendParam param = genRecommendParam(request, SceneConstants.DEFAULT);
|
|
|
|
|
- log.info("genRecommendParam {}", JSONUtils.toJson(param));
|
|
|
|
|
- // 获取账号排序设置
|
|
|
|
|
- setStrategy(request, param);
|
|
|
|
|
|
|
|
|
|
- // 获取 video-article match 结果(仅配置中的账号,当日缓存)
|
|
|
|
|
- Map<String, String> sourceIdToExperimentId = videoArticleMatchAccountList.contains(request.getAccountName())
|
|
|
|
|
- ? fetchSourceIdToExperimentId(request.getAccountName())
|
|
|
|
|
- : Collections.emptyMap();
|
|
|
|
|
|
|
+ // 基于 planId + accountId 的分布式锁,防止并发重复执行
|
|
|
|
|
+ String lockKey = null;
|
|
|
|
|
+ String requestId = null;
|
|
|
|
|
+ if (StringUtils.hasText(request.getPlanId()) && StringUtils.hasText(request.getAccountId())) {
|
|
|
|
|
+ lockKey = "recommend-lock:" + request.getPlanId() + ":" + request.getAccountId();
|
|
|
|
|
+ requestId = UUID.randomUUID().toString();
|
|
|
|
|
+ if (!redisUtil.tryAcquireLock(lockKey, requestId, 600L)) {
|
|
|
|
|
+ log.info("recommend is already processing, skip. planId:{}, accountId:{}", request.getPlanId(), request.getAccountId());
|
|
|
|
|
+ RecommendResponse response = new RecommendResponse();
|
|
|
|
|
+ response.setCode(0);
|
|
|
|
|
+ response.setMsg("success");
|
|
|
|
|
+ return response;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- RecallResult recallResult = recallService.recall(convertToRecallParam(param));
|
|
|
|
|
|
|
+ try {
|
|
|
|
|
+ RecommendParam param = genRecommendParam(request, SceneConstants.DEFAULT);
|
|
|
|
|
+ log.info("genRecommendParam {}", JSONUtils.toJson(param));
|
|
|
|
|
+ // 获取账号排序设置
|
|
|
|
|
+ setStrategy(request, param);
|
|
|
|
|
|
|
|
- filterRecallBySourceId(recallResult, sourceIdToExperimentId);
|
|
|
|
|
|
|
+ // 获取 video-article match 结果(仅配置中的账号,当日缓存)
|
|
|
|
|
+ Map<String, String> sourceIdToExperimentId = videoArticleMatchAccountList.contains(request.getAccountName())
|
|
|
|
|
+ ? fetchSourceIdToExperimentId(request.getAccountName())
|
|
|
|
|
+ : Collections.emptyMap();
|
|
|
|
|
|
|
|
- if (CollectionUtils.isEmpty(recallResult.getData())) {
|
|
|
|
|
- RecommendResponse response = new RecommendResponse();
|
|
|
|
|
- response.setCode(0);
|
|
|
|
|
- response.setMsg("success");
|
|
|
|
|
- return response;
|
|
|
|
|
- }
|
|
|
|
|
- long t2 = System.currentTimeMillis();
|
|
|
|
|
- CostMonitor.logCost("Recommend", "Recall", t2 - start);
|
|
|
|
|
- RankResult rankResult = rankService.rank(convertToRankParam(param, recallResult));
|
|
|
|
|
- long t3 = System.currentTimeMillis();
|
|
|
|
|
- CostMonitor.logCost("Recommend", "Rank", t3 - t2);
|
|
|
|
|
- excludeArticleIndex(rankResult, request.getExcludeContentIndex());
|
|
|
|
|
- saveSortLog(param, rankResult);
|
|
|
|
|
|
|
+ RecallResult recallResult = recallService.recall(convertToRecallParam(param));
|
|
|
|
|
|
|
|
- RecommendResponse response = buildRecommendResponse(recallResult, rankResult, param.getPublishNum());
|
|
|
|
|
- // 设置每个 item 的 experimentId
|
|
|
|
|
- if (CollectionUtils.isNotEmpty(sourceIdToExperimentId.keySet())) {
|
|
|
|
|
- for (ArticleSortResponseDataItem item : response.getData().getRank_list()) {
|
|
|
|
|
- String expId = sourceIdToExperimentId.get(item.getSourceId());
|
|
|
|
|
- if (expId != null) {
|
|
|
|
|
- item.setExperimentId(expId);
|
|
|
|
|
|
|
+ filterRecallBySourceId(recallResult, sourceIdToExperimentId);
|
|
|
|
|
+
|
|
|
|
|
+ if (CollectionUtils.isEmpty(recallResult.getData())) {
|
|
|
|
|
+ RecommendResponse response = new RecommendResponse();
|
|
|
|
|
+ response.setCode(0);
|
|
|
|
|
+ response.setMsg("success");
|
|
|
|
|
+ return response;
|
|
|
|
|
+ }
|
|
|
|
|
+ long t2 = System.currentTimeMillis();
|
|
|
|
|
+ CostMonitor.logCost("Recommend", "Recall", t2 - start);
|
|
|
|
|
+ RankResult rankResult = rankService.rank(convertToRankParam(param, recallResult));
|
|
|
|
|
+ long t3 = System.currentTimeMillis();
|
|
|
|
|
+ CostMonitor.logCost("Recommend", "Rank", t3 - t2);
|
|
|
|
|
+ excludeArticleIndex(rankResult, request.getExcludeContentIndex());
|
|
|
|
|
+ saveSortLog(param, rankResult);
|
|
|
|
|
+
|
|
|
|
|
+ RecommendResponse response = buildRecommendResponse(recallResult, rankResult, param.getPublishNum());
|
|
|
|
|
+ // 设置每个 item 的 experimentId
|
|
|
|
|
+ if (CollectionUtils.isNotEmpty(sourceIdToExperimentId.keySet())) {
|
|
|
|
|
+ for (ArticleSortResponseDataItem item : response.getData().getRank_list()) {
|
|
|
|
|
+ String expId = sourceIdToExperimentId.get(item.getSourceId());
|
|
|
|
|
+ if (expId != null) {
|
|
|
|
|
+ item.setExperimentId(expId);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ long t4 = System.currentTimeMillis();
|
|
|
|
|
+ log.info("recommendCost param:{} total cost:{} recall:{} rank:{} response: {}", JSONObject.toJSONString(request),
|
|
|
|
|
+ t4 - start, t2 - start, t3 - t2, JSONObject.toJSONString(response));
|
|
|
|
|
+ CostMonitor.logCost("Recommend", "Total", t4 - start);
|
|
|
|
|
+ return response;
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ if (lockKey != null) {
|
|
|
|
|
+ redisUtil.releaseLock(lockKey, requestId);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- long t4 = System.currentTimeMillis();
|
|
|
|
|
- log.info("recommendCost param:{} total cost:{} recall:{} rank:{} response: {}", JSONObject.toJSONString(request),
|
|
|
|
|
- t4 - start, t2 - start, t3 - t2, JSONObject.toJSONString(response));
|
|
|
|
|
- CostMonitor.logCost("Recommend", "Total", t4 - start);
|
|
|
|
|
- return response;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|