|
|
@@ -2025,7 +2025,7 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 搜索:在当前入口的 demand 白名单(prior+posterior 池,rov>=0.02)内对向量召回结果做交集 + 排序。
|
|
|
+ * 搜索:在当前入口的 demand 白名单(prior+posterior 池,rov>=0.02)内做 title LIKE 关键字命中 + 向量召回,并集去重后统一排序。
|
|
|
* 门控:
|
|
|
* - 用户身份 type ∈ {2 自营, 3 代理},否则返回空
|
|
|
* - 渠道 ∈ {小程序投流-稳定, 公众号投流-稳定},否则返回空
|
|
|
@@ -2033,10 +2033,10 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
|
|
|
* 流程:
|
|
|
* 1. demand 白名单(channel + crowdSegment/channelLevel3 + demand_strategy IN (人群需求,优质相似) + rov>=0.02)
|
|
|
* 2. 同 video_id 取 sceneSumRov 最大的代表行
|
|
|
- * 3. 向量召回 topN=500
|
|
|
- * 4. 交集:仅保留向量召回中出现在白名单的 video_id
|
|
|
- * 5. 排序:向量 score DESC,缺失/相同时 sceneSumRov DESC
|
|
|
- * 6. 一次性全量返回(不分页;白名单+召回交集量级小)
|
|
|
+ * 3. Pass1: 池内 title.toLowerCase().contains(query) 关键字命中,score=null
|
|
|
+ * 4. Pass2: 向量召回 topN=500,池内交集;同 video_id 已被关键字命中则用向量 score 升级
|
|
|
+ * 5. 排序:score DESC(向量 score 优先),缺失/相同时 sceneSumRov DESC
|
|
|
+ * 6. 一次性算好全量,按 pageNum/pageSize 切片返回(翻页不再调向量服务)
|
|
|
*/
|
|
|
private Page<VideoContentItemVO> searchByTitleInDemandPool(VideoContentListParam param, ContentPlatformAccount user) {
|
|
|
Page<VideoContentItemVO> empty = new Page<>(param.getPageNum(), param.getPageSize());
|
|
|
@@ -2075,26 +2075,45 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- JSONObject vectorData = managerApiService.recallVideoWithScore(param.getTitle(), SEARCH_VECTOR_TOP_N);
|
|
|
- if (vectorData == null) return empty;
|
|
|
- JSONArray items = vectorData.getJSONArray("items");
|
|
|
- if (items == null || items.isEmpty()) return empty;
|
|
|
-
|
|
|
- // 交集:按向量召回顺序遍历,留下 whitelist 命中的 video_id;同 video_id 去重
|
|
|
- List<VideoContentItemVO> hits = new ArrayList<>();
|
|
|
- Set<Long> seen = new HashSet<>();
|
|
|
- for (int i = 0; i < items.size(); i++) {
|
|
|
- JSONObject item = items.getJSONObject(i);
|
|
|
- Long videoId = item.getLong("videoId");
|
|
|
- if (videoId == null || !bestPerVideo.containsKey(videoId) || !seen.add(videoId)) continue;
|
|
|
- ContentPlatformDemandVideo demand = bestPerVideo.get(videoId);
|
|
|
+ // Pass 1: title LIKE 关键字命中(池内 substring,大小写不敏感),score=null 兜底 sceneSumRov
|
|
|
+ String kw = param.getTitle().toLowerCase();
|
|
|
+ Map<Long, VideoContentItemVO> byVid = new LinkedHashMap<>();
|
|
|
+ for (ContentPlatformDemandVideo demand : bestPerVideo.values()) {
|
|
|
+ if (demand.getTitle() == null) continue;
|
|
|
+ if (!demand.getTitle().toLowerCase().contains(kw)) continue;
|
|
|
VideoContentItemVO vo = buildDemandVideoContentItemVOList(Collections.singletonList(demand)).get(0);
|
|
|
- vo.setSearchSource("vector");
|
|
|
- vo.setScore(item.getDouble("score")); // 用向量 score 覆盖 demand.score,主排序键
|
|
|
- hits.add(vo);
|
|
|
+ vo.setSearchSource("keyword");
|
|
|
+ vo.setScore(null);
|
|
|
+ byVid.put(demand.getVideoId(), vo);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Pass 2: 向量召回,池内交集;若已被 title 命中,用向量 score 升级以提升排序
|
|
|
+ JSONObject vectorData = managerApiService.recallVideoWithScore(param.getTitle(), SEARCH_VECTOR_TOP_N);
|
|
|
+ JSONArray items = vectorData == null ? null : vectorData.getJSONArray("items");
|
|
|
+ if (items != null) {
|
|
|
+ for (int i = 0; i < items.size(); i++) {
|
|
|
+ JSONObject item = items.getJSONObject(i);
|
|
|
+ Long videoId = item.getLong("videoId");
|
|
|
+ if (videoId == null || !bestPerVideo.containsKey(videoId)) continue;
|
|
|
+ Double vScore = item.getDouble("score");
|
|
|
+ VideoContentItemVO existing = byVid.get(videoId);
|
|
|
+ if (existing != null) {
|
|
|
+ existing.setSearchSource("both");
|
|
|
+ existing.setScore(vScore);
|
|
|
+ } else {
|
|
|
+ ContentPlatformDemandVideo demand = bestPerVideo.get(videoId);
|
|
|
+ VideoContentItemVO vo = buildDemandVideoContentItemVOList(Collections.singletonList(demand)).get(0);
|
|
|
+ vo.setSearchSource("vector");
|
|
|
+ vo.setScore(vScore);
|
|
|
+ byVid.put(videoId, vo);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- // 排序:向量 score DESC,缺失/相同时 sceneSumRov DESC
|
|
|
+ if (byVid.isEmpty()) return empty;
|
|
|
+ List<VideoContentItemVO> hits = new ArrayList<>(byVid.values());
|
|
|
+
|
|
|
+ // 排序:score DESC(向量 score 优先),缺失/相同时 sceneSumRov DESC
|
|
|
hits.sort((a, b) -> {
|
|
|
double sa = a.getScore() == null ? 0d : a.getScore();
|
|
|
double sb = b.getScore() == null ? 0d : b.getScore();
|