|
@@ -17,6 +17,7 @@ import com.tzld.longarticle.recommend.server.mapper.longArticle.LongArticleBaseM
|
|
|
import com.tzld.longarticle.recommend.server.model.cgi.VideoArticleMatchRecord;
|
|
import com.tzld.longarticle.recommend.server.model.cgi.VideoArticleMatchRecord;
|
|
|
import com.tzld.longarticle.recommend.server.model.cgi.VideoArticleMatchResponse;
|
|
import com.tzld.longarticle.recommend.server.model.cgi.VideoArticleMatchResponse;
|
|
|
import com.tzld.longarticle.recommend.server.model.dto.Content;
|
|
import com.tzld.longarticle.recommend.server.model.dto.Content;
|
|
|
|
|
+import com.tzld.longarticle.recommend.server.model.dto.DemandSearchArticleRelationDTO;
|
|
|
import com.tzld.longarticle.recommend.server.model.dto.UserGroupCountDTO;
|
|
import com.tzld.longarticle.recommend.server.model.dto.UserGroupCountDTO;
|
|
|
import com.tzld.longarticle.recommend.server.model.entity.crawler.AccountAvgInfo;
|
|
import com.tzld.longarticle.recommend.server.model.entity.crawler.AccountAvgInfo;
|
|
|
import com.tzld.longarticle.recommend.server.model.entity.crawler.PublishSortLog;
|
|
import com.tzld.longarticle.recommend.server.model.entity.crawler.PublishSortLog;
|
|
@@ -42,6 +43,7 @@ import com.tzld.longarticle.recommend.server.util.CommonCollectionUtils;
|
|
|
import com.tzld.longarticle.recommend.server.util.DateUtils;
|
|
import com.tzld.longarticle.recommend.server.util.DateUtils;
|
|
|
import com.tzld.longarticle.recommend.server.util.JSONUtils;
|
|
import com.tzld.longarticle.recommend.server.util.JSONUtils;
|
|
|
import com.tzld.longarticle.recommend.server.util.RedisUtil;
|
|
import com.tzld.longarticle.recommend.server.util.RedisUtil;
|
|
|
|
|
+import com.tzld.longarticle.recommend.server.util.TitleSimilarCheckUtil;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.collections4.CollectionUtils;
|
|
import org.apache.commons.collections4.CollectionUtils;
|
|
|
import org.springframework.beans.BeanUtils;
|
|
import org.springframework.beans.BeanUtils;
|
|
@@ -58,6 +60,7 @@ import java.util.*;
|
|
|
import java.util.concurrent.CompletableFuture;
|
|
import java.util.concurrent.CompletableFuture;
|
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
+import static com.tzld.longarticle.recommend.server.common.constant.SceneConstants.DEMAND_POOL;
|
|
|
import static com.tzld.longarticle.recommend.server.common.constant.SceneConstants.FWH_COLD_START;
|
|
import static com.tzld.longarticle.recommend.server.common.constant.SceneConstants.FWH_COLD_START;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -340,6 +343,339 @@ public class RecommendService {
|
|
|
new RecommendWithUserGroupResponse.RecommendWithUserGroupData(rankList, filterList));
|
|
new RecommendWithUserGroupResponse.RecommendWithUserGroupData(rankList, filterList));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ public RecommendResponse recommendDemandPool(RecommendRequest request) {
|
|
|
|
|
+ long start = System.currentTimeMillis();
|
|
|
|
|
+
|
|
|
|
|
+ RecommendParam param = genRecommendParam(request, DEMAND_POOL);
|
|
|
|
|
+ param.setStrategy(RankStrategyEnum.DEMAND_POOL_STRATEGY.getStrategy());
|
|
|
|
|
+ log.info("recommendDemandPool genRecommendParam {}", JSONUtils.toJson(param));
|
|
|
|
|
+
|
|
|
|
|
+ RecallResult recallResult = recallService.recall(convertToRecallParam(param));
|
|
|
|
|
+
|
|
|
|
|
+ if (CollectionUtils.isEmpty(recallResult.getData())) {
|
|
|
|
|
+ RecommendResponse response = new RecommendResponse();
|
|
|
|
|
+ response.setCode(0);
|
|
|
|
|
+ response.setMsg("success");
|
|
|
|
|
+ return response;
|
|
|
|
|
+ }
|
|
|
|
|
+ long t2 = System.currentTimeMillis();
|
|
|
|
|
+ CostMonitor.logCost("RecommendDemandPool", "Recall", t2 - start);
|
|
|
|
|
+
|
|
|
|
|
+ // 召回后检查内容池是否为空
|
|
|
|
|
+ String utilizePool = ContentPoolEnum.accountDemandPoolLevelUtilize.getContentPool();
|
|
|
|
|
+ String coldPool = ContentPoolEnum.accountDemandPoolLevelCold.getContentPool();
|
|
|
|
|
+ boolean hasUtilize = false;
|
|
|
|
|
+ boolean hasCold = false;
|
|
|
|
|
+ for (RecallResult.RecallData rd : recallResult.getData()) {
|
|
|
|
|
+ if (CollectionUtils.isNotEmpty(rd.getContents())) {
|
|
|
|
|
+ for (Content c : rd.getContents()) {
|
|
|
|
|
+ if (utilizePool.equals(c.getContentPoolType())) {
|
|
|
|
|
+ hasUtilize = true;
|
|
|
|
|
+ } else if (coldPool.equals(c.getContentPoolType())) {
|
|
|
|
|
+ hasCold = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (hasUtilize && hasCold) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ boolean needsFallback = !hasUtilize || !hasCold;
|
|
|
|
|
+
|
|
|
|
|
+ // 回填 experiment_id:需求池内容通过 account_id + sourceId 查 demand_produce_content_relation
|
|
|
|
|
+ enrichDemandExperimentId(recallResult, request.getAccountId());
|
|
|
|
|
+
|
|
|
|
|
+ if (needsFallback) {
|
|
|
|
|
+ log.info("recommendDemandPool pool empty utilize:{} cold:{}, running new rank and old recall+rank in parallel. accountName:{}",
|
|
|
|
|
+ hasUtilize, hasCold, request.getAccountName());
|
|
|
|
|
+
|
|
|
|
|
+ // 并行:新排序 + 老召排
|
|
|
|
|
+ CompletableFuture<RankResult> newRankFuture = CompletableFuture.supplyAsync(() -> {
|
|
|
|
|
+ long ft1 = System.currentTimeMillis();
|
|
|
|
|
+ RankResult result = rankService.rank(convertToRankParam(param, recallResult));
|
|
|
|
|
+ long ft2 = System.currentTimeMillis();
|
|
|
|
|
+ CostMonitor.logCost("RecommendDemandPool", "NewRank", ft2 - ft1);
|
|
|
|
|
+ return result;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ CompletableFuture<OldRecallRankResult> fallbackFuture = CompletableFuture.supplyAsync(() -> {
|
|
|
|
|
+ long ft1 = System.currentTimeMillis();
|
|
|
|
|
+ RecommendParam fallbackParam = genRecommendParam(request, SceneConstants.DEFAULT);
|
|
|
|
|
+ setStrategy(request, fallbackParam);
|
|
|
|
|
+ RecallResult fallbackRecallResult = recallService.recall(convertToRecallParam(fallbackParam));
|
|
|
|
|
+ long ft2 = System.currentTimeMillis();
|
|
|
|
|
+ CostMonitor.logCost("RecommendDemandPool", "FallbackRecall", ft2 - ft1);
|
|
|
|
|
+ if (CollectionUtils.isEmpty(fallbackRecallResult.getData())) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ RankResult fallbackRankResult = rankService.rank(convertToRankParam(fallbackParam, fallbackRecallResult));
|
|
|
|
|
+ long ft3 = System.currentTimeMillis();
|
|
|
|
|
+ CostMonitor.logCost("RecommendDemandPool", "FallbackRank", ft3 - ft2);
|
|
|
|
|
+ return new OldRecallRankResult(fallbackRecallResult, fallbackRankResult);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ RankResult newRankResult = newRankFuture.join();
|
|
|
|
|
+ OldRecallRankResult fallbackResult = fallbackFuture.join();
|
|
|
|
|
+
|
|
|
|
|
+ // 合并:非空池用新结果,空池用老结果兜底
|
|
|
|
|
+ List<Content> merged = mergeResults(newRankResult.getContents(),
|
|
|
|
|
+ fallbackResult != null ? fallbackResult.rankResult.getContents() : null,
|
|
|
|
|
+ hasUtilize, hasCold, utilizePool, coldPool, param.getPublishNum());
|
|
|
|
|
+
|
|
|
|
|
+ // 合并 filterContents
|
|
|
|
|
+ List<Content> mergedFilterContents = new ArrayList<>();
|
|
|
|
|
+ addFilterContents(mergedFilterContents, recallResult);
|
|
|
|
|
+ addFilterContents(mergedFilterContents, fallbackResult != null ? fallbackResult.recallResult : null);
|
|
|
|
|
+
|
|
|
|
|
+ RankResult mergedRankResult = new RankResult(merged);
|
|
|
|
|
+ excludeArticleIndex(mergedRankResult, request.getExcludeContentIndex());
|
|
|
|
|
+ saveSortLog(param, mergedRankResult);
|
|
|
|
|
+
|
|
|
|
|
+ // 构建响应时使用合并后的 filterContents
|
|
|
|
|
+ RecommendResponse response = buildRecommendResponseWithFilters(mergedRankResult, mergedFilterContents, param.getPublishNum());
|
|
|
|
|
+ long t4 = System.currentTimeMillis();
|
|
|
|
|
+ log.info("recommendDemandPool merged resultSize:{} total:{}", merged.size(), t4 - start);
|
|
|
|
|
+ CostMonitor.logCost("RecommendDemandPool", "Total", t4 - start);
|
|
|
|
|
+ return response;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 池子都非空,正常新排序
|
|
|
|
|
+ RankResult rankResult = rankService.rank(convertToRankParam(param, recallResult));
|
|
|
|
|
+ long t3 = System.currentTimeMillis();
|
|
|
|
|
+ CostMonitor.logCost("RecommendDemandPool", "Rank", t3 - t2);
|
|
|
|
|
+
|
|
|
|
|
+ excludeArticleIndex(rankResult, request.getExcludeContentIndex());
|
|
|
|
|
+ saveSortLog(param, rankResult);
|
|
|
|
|
+
|
|
|
|
|
+ RecommendResponse response = buildRecommendResponse(recallResult, rankResult, param.getPublishNum());
|
|
|
|
|
+ long t4 = System.currentTimeMillis();
|
|
|
|
|
+ log.info("recommendDemandPool cost param:{} total:{} recall:{} rank:{}",
|
|
|
|
|
+ JSONObject.toJSONString(request), t4 - start, t2 - start, t3 - t2);
|
|
|
|
|
+ CostMonitor.logCost("RecommendDemandPool", "Total", t4 - start);
|
|
|
|
|
+ return response;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 合并新排序结果和老排序结果,空池位置用老结果兜底
|
|
|
|
|
+ */
|
|
|
|
|
+ private List<Content> mergeResults(List<Content> newContents, List<Content> oldContents,
|
|
|
|
|
+ boolean hasUtilize, boolean hasCold,
|
|
|
|
|
+ String utilizePool, String coldPool, int size) {
|
|
|
|
|
+ List<Content> merged = new ArrayList<>();
|
|
|
|
|
+ List<String> usedTitles = new ArrayList<>();
|
|
|
|
|
+
|
|
|
|
|
+ // 拆分新结果
|
|
|
|
|
+ List<Content> newUtilize = new ArrayList<>();
|
|
|
|
|
+ List<Content> newCold = new ArrayList<>();
|
|
|
|
|
+ if (CollectionUtils.isNotEmpty(newContents)) {
|
|
|
|
|
+ for (Content c : newContents) {
|
|
|
|
|
+ if (utilizePool.equals(c.getContentPoolType())) {
|
|
|
|
|
+ newUtilize.add(c);
|
|
|
|
|
+ } else if (coldPool.equals(c.getContentPoolType())) {
|
|
|
|
|
+ newCold.add(c);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ List<Content> oldList = oldContents != null ? oldContents : new ArrayList<>();
|
|
|
|
|
+
|
|
|
|
|
+ // 位置 1-2:利用池内容
|
|
|
|
|
+ if (hasUtilize) {
|
|
|
|
|
+ for (Content c : newUtilize) {
|
|
|
|
|
+ if (merged.size() >= 2) break;
|
|
|
|
|
+ if (!TitleSimilarCheckUtil.isDuplicateContent(c.getTitle(), usedTitles, TitleSimilarCheckUtil.SIMILARITY_THRESHOLD)) {
|
|
|
|
|
+ merged.add(c);
|
|
|
|
|
+ usedTitles.add(c.getTitle());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // 利用池为空,从老结果取兜底
|
|
|
|
|
+ if (!hasUtilize) {
|
|
|
|
|
+ for (Content c : oldList) {
|
|
|
|
|
+ if (merged.size() >= 2) break;
|
|
|
|
|
+ if (!TitleSimilarCheckUtil.isDuplicateContent(c.getTitle(), usedTitles, TitleSimilarCheckUtil.SIMILARITY_THRESHOLD)) {
|
|
|
|
|
+ merged.add(c);
|
|
|
|
|
+ usedTitles.add(c.getTitle());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 位置 3-8:冷启池内容
|
|
|
|
|
+ if (hasCold) {
|
|
|
|
|
+ for (Content c : newCold) {
|
|
|
|
|
+ if (merged.size() >= size) break;
|
|
|
|
|
+ if (!TitleSimilarCheckUtil.isDuplicateContent(c.getTitle(), usedTitles, TitleSimilarCheckUtil.SIMILARITY_THRESHOLD)) {
|
|
|
|
|
+ merged.add(c);
|
|
|
|
|
+ usedTitles.add(c.getTitle());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // 冷启池为空,从老结果取兜底
|
|
|
|
|
+ if (!hasCold) {
|
|
|
|
|
+ for (Content c : oldList) {
|
|
|
|
|
+ if (merged.size() >= size) break;
|
|
|
|
|
+ if (!TitleSimilarCheckUtil.isDuplicateContent(c.getTitle(), usedTitles, TitleSimilarCheckUtil.SIMILARITY_THRESHOLD)) {
|
|
|
|
|
+ // 跳过已经被利用池使用的
|
|
|
|
|
+ boolean alreadyUsed = false;
|
|
|
|
|
+ for (Content existing : merged) {
|
|
|
|
|
+ if (Objects.equals(existing.getId(), c.getId())) {
|
|
|
|
|
+ alreadyUsed = true;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!alreadyUsed) {
|
|
|
|
|
+ if (!TitleSimilarCheckUtil.isDuplicateContent(c.getTitle(), usedTitles, TitleSimilarCheckUtil.SIMILARITY_THRESHOLD)) {
|
|
|
|
|
+ merged.add(c);
|
|
|
|
|
+ usedTitles.add(c.getTitle());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return merged;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void addFilterContents(List<Content> target, RecallResult recallResult) {
|
|
|
|
|
+ if (recallResult == null || CollectionUtils.isEmpty(recallResult.getData())) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ for (RecallResult.RecallData data : recallResult.getData()) {
|
|
|
|
|
+ if (CollectionUtils.isNotEmpty(data.getFilterContents())) {
|
|
|
|
|
+ target.addAll(data.getFilterContents());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private RecommendResponse buildRecommendResponseWithFilters(RankResult rankResult,
|
|
|
|
|
+ List<Content> filterContents, Integer publishNum) {
|
|
|
|
|
+ List<Content> contentList = rankResult.getContents();
|
|
|
|
|
+ List<ArticleSortResponseDataItem> rankList = new ArrayList<>();
|
|
|
|
|
+ List<ArticleSortResponseDataItem> filterContentList = new ArrayList<>();
|
|
|
|
|
+ if (CollectionUtils.isNotEmpty(filterContents)) {
|
|
|
|
|
+ for (Content filterContent : filterContents) {
|
|
|
|
|
+ ArticleSortResponseDataItem item = new ArticleSortResponseDataItem();
|
|
|
|
|
+ BeanUtils.copyProperties(filterContent, item);
|
|
|
|
|
+ filterContentList.add(item);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ArticleSortResponseData data = new ArticleSortResponseData();
|
|
|
|
|
+ if (CollectionUtils.isNotEmpty(contentList)) {
|
|
|
|
|
+ for (Content content : contentList) {
|
|
|
|
|
+ ArticleSortResponseDataItem item = new ArticleSortResponseDataItem();
|
|
|
|
|
+ BeanUtils.copyProperties(content, item);
|
|
|
|
|
+ rankList.add(item);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ data.setRank_list(rankList.subList(0, Math.min(rankList.size(), publishNum)));
|
|
|
|
|
+ data.setFilter_list(filterContentList);
|
|
|
|
|
+
|
|
|
|
|
+ CompletableFuture.runAsync(() -> updateWaitingContentFilter(filterContentList));
|
|
|
|
|
+
|
|
|
|
|
+ RecommendResponse response = new RecommendResponse();
|
|
|
|
|
+ response.setCode(0);
|
|
|
|
|
+ response.setMsg("success");
|
|
|
|
|
+ response.setData(data);
|
|
|
|
|
+ return response;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static class OldRecallRankResult {
|
|
|
|
|
+ final RecallResult recallResult;
|
|
|
|
|
+ final RankResult rankResult;
|
|
|
|
|
+
|
|
|
|
|
+ OldRecallRankResult(RecallResult recallResult, RankResult rankResult) {
|
|
|
|
|
+ this.recallResult = recallResult;
|
|
|
|
|
+ this.rankResult = rankResult;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 从 demand_search_article_relation 表回填 experiment_id 到召回结果
|
|
|
|
|
+ */
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 回填 experiment_id 到召回结果
|
|
|
|
|
+ * - accountDemandPoolLevelCold / accountDemandPoolLevelUtilize → demand_produce_content_relation (by account_id + sourceId)
|
|
|
|
|
+ * - 其他内容 → demand_search_article_relation (by channel_content_id)
|
|
|
|
|
+ */
|
|
|
|
|
+ private void enrichDemandExperimentId(RecallResult recallResult, String accountId) {
|
|
|
|
|
+ if (recallResult == null || CollectionUtils.isEmpty(recallResult.getData())) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ String coldPool = ContentPoolEnum.accountDemandPoolLevelCold.getContentPool();
|
|
|
|
|
+ String utilizePool = ContentPoolEnum.accountDemandPoolLevelUtilize.getContentPool();
|
|
|
|
|
+ Set<String> demandPoolSourceIds = new HashSet<>();
|
|
|
|
|
+ Set<String> otherChannelContentIds = new HashSet<>();
|
|
|
|
|
+
|
|
|
|
|
+ for (RecallResult.RecallData rd : recallResult.getData()) {
|
|
|
|
|
+ if (CollectionUtils.isNotEmpty(rd.getContents())) {
|
|
|
|
|
+ for (Content c : rd.getContents()) {
|
|
|
|
|
+ if (coldPool.equals(c.getContentPoolType()) || utilizePool.equals(c.getContentPoolType())) {
|
|
|
|
|
+ if (StringUtils.hasText(c.getSourceId())) {
|
|
|
|
|
+ demandPoolSourceIds.add(c.getSourceId());
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (StringUtils.hasText(c.getCrawlerChannelContentId())) {
|
|
|
|
|
+ otherChannelContentIds.add(c.getCrawlerChannelContentId());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, String> contentIdToExperimentId = new HashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ // 需求池:通过 account_id + sourceId(=content_id) 查 demand_produce_content_relation
|
|
|
|
|
+ if (!demandPoolSourceIds.isEmpty() && StringUtils.hasText(accountId)) {
|
|
|
|
|
+ List<DemandSearchArticleRelationDTO> mappings = longArticleBaseMapper
|
|
|
|
|
+ .getDemandExperimentIdByContentIds(new ArrayList<>(demandPoolSourceIds), accountId);
|
|
|
|
|
+ if (CollectionUtils.isNotEmpty(mappings)) {
|
|
|
|
|
+ for (DemandSearchArticleRelationDTO m : mappings) {
|
|
|
|
|
+ if (StringUtils.hasText(m.getContentId()) && StringUtils.hasText(m.getExperimentId())) {
|
|
|
|
|
+ contentIdToExperimentId.put(m.getContentId(), m.getExperimentId());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 其他内容:查 demand_search_article_relation
|
|
|
|
|
+ if (!otherChannelContentIds.isEmpty()) {
|
|
|
|
|
+ List<DemandSearchArticleRelationDTO> mappings = longArticleBaseMapper
|
|
|
|
|
+ .getDemandExperimentIdByChannelContentIds(new ArrayList<>(otherChannelContentIds));
|
|
|
|
|
+ if (CollectionUtils.isNotEmpty(mappings)) {
|
|
|
|
|
+ for (DemandSearchArticleRelationDTO m : mappings) {
|
|
|
|
|
+ if (StringUtils.hasText(m.getChannelContentId()) && StringUtils.hasText(m.getExperimentId())) {
|
|
|
|
|
+ contentIdToExperimentId.put(m.getChannelContentId(), m.getExperimentId());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (contentIdToExperimentId.isEmpty()) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 回填到 Content:需求池按 sourceId 匹配,其他按 crawlerChannelContentId
|
|
|
|
|
+ for (RecallResult.RecallData rd : recallResult.getData()) {
|
|
|
|
|
+ if (CollectionUtils.isNotEmpty(rd.getContents())) {
|
|
|
|
|
+ for (Content c : rd.getContents()) {
|
|
|
|
|
+ if (coldPool.equals(c.getContentPoolType()) || utilizePool.equals(c.getContentPoolType())) {
|
|
|
|
|
+ String expId = contentIdToExperimentId.get(c.getSourceId());
|
|
|
|
|
+ if (expId != null) {
|
|
|
|
|
+ c.setExperimentId(expId);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ String expId = contentIdToExperimentId.get(c.getCrawlerChannelContentId());
|
|
|
|
|
+ if (expId != null) {
|
|
|
|
|
+ c.setExperimentId(expId);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("enrichDemandExperimentId enriched {} experimentIds (demandPool={}, other={})",
|
|
|
|
|
+ contentIdToExperimentId.size(), demandPoolSourceIds.size(), otherChannelContentIds.size());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private RecommendResponse buildRecommendResponse(RecallResult recallResult, RankResult rankResult, Integer publishNum) {
|
|
private RecommendResponse buildRecommendResponse(RecallResult recallResult, RankResult rankResult, Integer publishNum) {
|
|
|
List<Content> contentList = rankResult.getContents();
|
|
List<Content> contentList = rankResult.getContents();
|
|
|
List<ArticleSortResponseDataItem> rankList = new ArrayList<>();
|
|
List<ArticleSortResponseDataItem> rankList = new ArrayList<>();
|