|
|
@@ -9,10 +9,10 @@ import com.tzld.videoVector.api.VideoApiService;
|
|
|
import com.tzld.videoVector.common.constant.VectorConstants;
|
|
|
import com.tzld.videoVector.common.enums.Modality;
|
|
|
import com.tzld.videoVector.dao.mapper.pgVector.DeconstructVectorConfigMapper;
|
|
|
+import com.tzld.videoVector.dao.mapper.pgVector.ext.AdsMaterialTouliuAllChannelMapperExt;
|
|
|
import com.tzld.videoVector.dao.mapper.pgVector.ext.ArticleDeconstructResultMapperExt;
|
|
|
import com.tzld.videoVector.dao.mapper.pgVector.ext.ArticleQualityMapperExt;
|
|
|
import com.tzld.videoVector.dao.mapper.pgVector.ext.MaterialDeconstructResultMapperExt;
|
|
|
-import com.tzld.videoVector.dao.mapper.pgVector.ext.MaterialQualityMapperExt;
|
|
|
import com.tzld.videoVector.model.entity.ArticleMatch;
|
|
|
import com.tzld.videoVector.model.entity.MaterialMatch;
|
|
|
import com.tzld.videoVector.model.entity.VideoDetail;
|
|
|
@@ -27,8 +27,8 @@ import com.tzld.videoVector.model.po.pgVector.ArticleDeconstructResult;
|
|
|
import com.tzld.videoVector.model.po.pgVector.ArticleQuality;
|
|
|
import com.tzld.videoVector.model.po.pgVector.DeconstructVectorConfig;
|
|
|
import com.tzld.videoVector.model.po.pgVector.DeconstructVectorConfigExample;
|
|
|
+import com.tzld.videoVector.model.po.pgVector.AdsMaterialTouliuAllChannel;
|
|
|
import com.tzld.videoVector.model.po.pgVector.MaterialDeconstructResult;
|
|
|
-import com.tzld.videoVector.model.po.pgVector.MaterialQuality;
|
|
|
import com.tzld.videoVector.model.vo.VideoMatchResult;
|
|
|
import com.tzld.videoVector.model.vo.recall.AIUnderstandingVO;
|
|
|
import com.tzld.videoVector.model.vo.recall.ArticleBasicVO;
|
|
|
@@ -49,6 +49,7 @@ import com.tzld.videoVector.service.MaterialVectorStoreService;
|
|
|
import com.tzld.videoVector.service.VectorStoreService;
|
|
|
import com.tzld.videoVector.service.VideoSearchService;
|
|
|
import com.tzld.videoVector.service.recall.VectorRecallTestService;
|
|
|
+import com.tzld.videoVector.util.MaterialQualityCalculator;
|
|
|
import com.tzld.videoVector.util.Md5Util;
|
|
|
import com.tzld.videoVector.util.RedisUtils;
|
|
|
import com.tzld.videoVector.model.po.pgVector.ArticleVector;
|
|
|
@@ -63,6 +64,8 @@ import org.springframework.util.StringUtils;
|
|
|
|
|
|
import javax.annotation.PreDestroy;
|
|
|
import javax.annotation.Resource;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Collections;
|
|
|
import java.util.HashMap;
|
|
|
@@ -106,7 +109,7 @@ public class VectorRecallTestServiceImpl implements VectorRecallTestService {
|
|
|
private MaterialDeconstructResultMapperExt materialDeconstructResultMapperExt;
|
|
|
|
|
|
@Autowired
|
|
|
- private MaterialQualityMapperExt materialQualityMapperExt;
|
|
|
+ private AdsMaterialTouliuAllChannelMapperExt adsMaterialTouliuAllChannelMapperExt;
|
|
|
|
|
|
@Autowired
|
|
|
private ArticleVectorStoreService articleVectorStoreService;
|
|
|
@@ -257,10 +260,11 @@ public class VectorRecallTestServiceImpl implements VectorRecallTestService {
|
|
|
}, RECALL_EXECUTOR)
|
|
|
: CompletableFuture.completedFuture(Collections.emptyList());
|
|
|
|
|
|
+ int materialDays = param.getDays() != null ? param.getDays() : metricsDays;
|
|
|
CompletableFuture<List<VideoMatchEnrichedVO>> materialFuture = needMaterial
|
|
|
? CompletableFuture.supplyAsync(
|
|
|
() -> recallMaterialItems(param.getQueryText(), finalConfigCode, finalMaterialRecallK,
|
|
|
- toSourceType(param.getSourceLabels())),
|
|
|
+ toSourceType(param.getSourceLabels()), materialDays),
|
|
|
RECALL_EXECUTOR)
|
|
|
: CompletableFuture.completedFuture(Collections.emptyList());
|
|
|
|
|
|
@@ -429,25 +433,25 @@ public class VectorRecallTestServiceImpl implements VectorRecallTestService {
|
|
|
// 视频去重
|
|
|
List<VideoMatchResult> dedupedVideo = deduplicateRaw(allRawVideo,
|
|
|
VideoMatchResult::getVideoId, m -> m.getScore() != null ? m.getScore() : 0.0);
|
|
|
- // 素材去重 + 批量查 quality 做轻量预打分(不等 full enrich)
|
|
|
+ // 素材去重 + 批量查 touliu 做轻量预打分(不等 full enrich)
|
|
|
List<MaterialMatch> dedupedMaterial = deduplicateRaw(allRawMaterial,
|
|
|
MaterialMatch::getMaterialId, MaterialMatch::getScore);
|
|
|
List<String> matIds = dedupedMaterial.stream()
|
|
|
.map(MaterialMatch::getMaterialId).distinct().limit(enrichK * 2)
|
|
|
.collect(Collectors.toList());
|
|
|
- Map<String, MaterialQuality> qualitySnapshot = matIds.isEmpty()
|
|
|
- ? Collections.emptyMap() : loadMaterialQualityRows(matIds);
|
|
|
+ int preDays = param.getDays() != null ? param.getDays() : metricsDays;
|
|
|
+ Map<String, AdsMaterialTouliuAllChannel> statsSnapshot = matIds.isEmpty()
|
|
|
+ ? Collections.emptyMap() : loadMaterialTouliuStats(matIds, preDays);
|
|
|
// 文章去重
|
|
|
List<ArticleMatch> dedupedArticle = deduplicateRaw(allRawArticle,
|
|
|
ArticleMatch::getArticleId, ArticleMatch::getScore);
|
|
|
|
|
|
double preAlpha = RankingParams.defaults().getAlpha(); // 0.6
|
|
|
|
|
|
- // 素材预打分:sim + quality 轻量复合,有质量数据的获得加成
|
|
|
+ // 素材预打分:sim + quality 轻量复合
|
|
|
List<MaterialMatch> topMaterial = dedupedMaterial.stream()
|
|
|
.sorted(Comparator.comparingDouble((MaterialMatch m) -> {
|
|
|
- MaterialQuality mq = qualitySnapshot.get(m.getMaterialId());
|
|
|
- double qs = (mq != null && mq.getQualityScore() != null) ? mq.getQualityScore() : 0;
|
|
|
+ double qs = computeSimpleQualityScore(statsSnapshot.get(m.getMaterialId()));
|
|
|
return -(preAlpha * m.getScore() + (1 - preAlpha) * qs);
|
|
|
}))
|
|
|
.limit(enrichK).collect(Collectors.toList());
|
|
|
@@ -467,7 +471,9 @@ public class VectorRecallTestServiceImpl implements VectorRecallTestService {
|
|
|
String cc = topVideo.get(i).getConfigCode();
|
|
|
if (cc != null) videoItems.get(i).setConfigCode(cc);
|
|
|
}
|
|
|
- List<VideoMatchEnrichedVO> materialItems = enrichMaterialMatches(topMaterial, configCodes.get(0));
|
|
|
+ int matDays = param.getDays() != null ? param.getDays() : metricsDays;
|
|
|
+ System.out.println("=== matchByText matDays: param.getDays()=" + param.getDays() + " metricsDays=" + metricsDays + " matDays=" + matDays);
|
|
|
+ List<VideoMatchEnrichedVO> materialItems = enrichMaterialMatches(topMaterial, configCodes.get(0), matDays);
|
|
|
List<VideoMatchEnrichedVO> articleItems = enrichArticleMatches(topArticle, configCodes.get(0));
|
|
|
|
|
|
log.info("batchByText 阶段二 enrich 完成(含预打分): video={}/{}, material={}/{}, article={}/{}",
|
|
|
@@ -651,7 +657,7 @@ public class VectorRecallTestServiceImpl implements VectorRecallTestService {
|
|
|
* 素材文本召回:material_vectors → material_deconstruct_result
|
|
|
*/
|
|
|
private List<VideoMatchEnrichedVO> recallMaterialItems(String queryText, String configCode,
|
|
|
- int topN, Short sourceType) {
|
|
|
+ int topN, Short sourceType, int days) {
|
|
|
try {
|
|
|
int candidate = Math.max(topN * VectorConstants.MULTI_POINT_RECALL_CANDIDATE_FACTOR,
|
|
|
VectorConstants.MULTI_POINT_RECALL_MIN_CANDIDATES);
|
|
|
@@ -677,7 +683,7 @@ public class VectorRecallTestServiceImpl implements VectorRecallTestService {
|
|
|
}
|
|
|
log.info("素材召回(rawVector) 去重后({}条): {}, configCode={}",
|
|
|
matches.size(), matchSample, configCode);
|
|
|
- return limitEnrichedItemsByScore(enrichMaterialMatches(matches, configCode), topN);
|
|
|
+ return limitEnrichedItemsByScore(enrichMaterialMatches(matches, configCode, days), topN);
|
|
|
}
|
|
|
log.info("素材召回(rawVector) 无结果, configCode={}", configCode);
|
|
|
return Collections.emptyList();
|
|
|
@@ -700,7 +706,7 @@ public class VectorRecallTestServiceImpl implements VectorRecallTestService {
|
|
|
}
|
|
|
log.info("素材召回(parsed vector缓存) 去重后({}条): {}, configCode={}",
|
|
|
matches.size(), matchSample, configCode);
|
|
|
- return limitEnrichedItemsByScore(enrichMaterialMatches(matches, configCode), topN);
|
|
|
+ return limitEnrichedItemsByScore(enrichMaterialMatches(matches, configCode, days), topN);
|
|
|
}
|
|
|
log.info("素材召回(parsed vector缓存) 无结果, configCode={}", configCode);
|
|
|
return Collections.emptyList();
|
|
|
@@ -727,7 +733,7 @@ public class VectorRecallTestServiceImpl implements VectorRecallTestService {
|
|
|
matchSample.add(m.getMaterialId() + ":" + String.format("%.4f", m.getScore()));
|
|
|
}
|
|
|
log.info("素材召回(embedding API) 去重后({}条): {}, configCode={}", matches.size(), matchSample, configCode);
|
|
|
- return limitEnrichedItemsByScore(enrichMaterialMatches(matches, configCode), topN);
|
|
|
+ return limitEnrichedItemsByScore(enrichMaterialMatches(matches, configCode, days), topN);
|
|
|
} catch (Exception e) {
|
|
|
log.error("素材召回 material_vectors 异常: {}", e.getMessage(), e);
|
|
|
return Collections.emptyList();
|
|
|
@@ -901,7 +907,7 @@ public class VectorRecallTestServiceImpl implements VectorRecallTestService {
|
|
|
* - materialDetail.deconstruct:解析 dataContent 得到 topic + 灵感点/关键点/目的点
|
|
|
* - materialDetail.source:source_type → 中文标签
|
|
|
*/
|
|
|
- private List<VideoMatchEnrichedVO> enrichMaterialMatches(List<MaterialMatch> matches, String requestConfigCode) {
|
|
|
+ private List<VideoMatchEnrichedVO> enrichMaterialMatches(List<MaterialMatch> matches, String requestConfigCode, int days) {
|
|
|
if (CollectionUtils.isEmpty(matches)) {
|
|
|
return Collections.emptyList();
|
|
|
}
|
|
|
@@ -910,7 +916,7 @@ public class VectorRecallTestServiceImpl implements VectorRecallTestService {
|
|
|
.filter(java.util.Objects::nonNull)
|
|
|
.collect(Collectors.toList());
|
|
|
Map<String, MaterialDeconstructResult> rowByMaterialId = loadMaterialDeconstructRows(materialIds);
|
|
|
- Map<String, MaterialQuality> qualityByMaterialId = loadMaterialQualityRows(materialIds);
|
|
|
+ Map<String, AdsMaterialTouliuAllChannel> statsByMaterialId = loadMaterialTouliuStats(materialIds, days);
|
|
|
|
|
|
List<VideoMatchEnrichedVO> items = new ArrayList<>(matches.size());
|
|
|
for (MaterialMatch m : matches) {
|
|
|
@@ -941,9 +947,9 @@ public class VectorRecallTestServiceImpl implements VectorRecallTestService {
|
|
|
fillMaterialDetailImageCount(detail, vo.getImageList());
|
|
|
|
|
|
// 填充投放质量数据
|
|
|
- MaterialQuality mq = qualityByMaterialId.get(m.getMaterialId());
|
|
|
- if (mq != null) {
|
|
|
- detail.setQuality(buildQualityMap(mq));
|
|
|
+ AdsMaterialTouliuAllChannel stats = statsByMaterialId.get(m.getMaterialId());
|
|
|
+ if (stats != null) {
|
|
|
+ detail.setQuality(buildQualityMap(stats, days));
|
|
|
}
|
|
|
|
|
|
vo.setMaterialDetail(detail);
|
|
|
@@ -1294,75 +1300,86 @@ public class VectorRecallTestServiceImpl implements VectorRecallTestService {
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
- private Map<String, Object> buildQualityMap(MaterialQuality mq) {
|
|
|
+ private Map<String, Object> buildQualityMap(AdsMaterialTouliuAllChannel s, int days) {
|
|
|
+ System.out.println("=== buildQualityMap days=" + days + " materialId=" + s.getMaterialId());
|
|
|
Map<String, Object> map = new LinkedHashMap<>();
|
|
|
- map.put("dt", mq.getDt());
|
|
|
- map.put("qualityScore", mq.getQualityScore());
|
|
|
- map.put("confidence", mq.getConfidence());
|
|
|
- map.put("conversionEfficiencyScore", mq.getConversionEfficiencyScore());
|
|
|
- map.put("revenueScore", mq.getRevenueScore());
|
|
|
- map.put("viralScore", mq.getViralScore());
|
|
|
- map.put("engagementScore", mq.getEngagementScore());
|
|
|
- map.put("cost7d", mq.getCost7d());
|
|
|
- map.put("targetConversion7d", mq.getTargetConversion7d());
|
|
|
- map.put("totalConversion7d", mq.getTotalConversion7d());
|
|
|
- map.put("revenue7d", mq.getRevenue7d());
|
|
|
- map.put("t0ViralCount7d", mq.getT0ViralCount7d());
|
|
|
- map.put("t0ViralRate7d", mq.getT0ViralRate7d());
|
|
|
- map.put("miniProgramOpenRate7d", mq.getMiniProgramOpenRate7d());
|
|
|
- map.put("firstUv7d", mq.getFirstUv7d());
|
|
|
- map.put("shareCount7d", mq.getShareCount7d());
|
|
|
- map.put("cost30d", mq.getCost30d());
|
|
|
- map.put("targetConversion30d", mq.getTargetConversion30d());
|
|
|
- // 派生指标
|
|
|
- Long firstUv = mq.getFirstUv7d();
|
|
|
- Long totalConv = mq.getTotalConversion7d();
|
|
|
- Long viralCount = mq.getT0ViralCount7d();
|
|
|
- Double rev = mq.getRevenue7d();
|
|
|
-
|
|
|
- // 消耗优先7天,不足时用30天兜底
|
|
|
- Double cost = mq.getCost7d();
|
|
|
- boolean use30d = cost == null || cost < 50;
|
|
|
- if (use30d && mq.getCost30d() != null && mq.getCost30d() > 0) {
|
|
|
- cost = mq.getCost30d();
|
|
|
- }
|
|
|
- map.put("use30d", use30d);
|
|
|
- map.put("effectiveCost", cost); // 实际用于计算的消耗(7d 不足时兜底为 30d)
|
|
|
-
|
|
|
- // 打开率(CTR) = 首层uv / 总转化量
|
|
|
- if (firstUv != null && firstUv > 0 && totalConv != null && totalConv > 0) {
|
|
|
- map.put("ctr7d", Math.round((double) firstUv / totalConv * 10000.0) / 10000.0);
|
|
|
- }
|
|
|
- // 裂变率 = t0裂变数 / 首层uv
|
|
|
- if (viralCount != null && viralCount > 0 && firstUv != null && firstUv > 0) {
|
|
|
- map.put("viralRate7d", Math.round((double) viralCount / firstUv * 10000.0) / 10000.0);
|
|
|
- }
|
|
|
- // ROI = 收入 / effectiveCost
|
|
|
- if (cost != null && cost > 0 && rev != null && rev > 0) {
|
|
|
- map.put("roi7d", Math.round(rev / cost * 10000.0) / 10000.0);
|
|
|
- }
|
|
|
- map.put("adOptimizationGoal", mq.getAdOptimizationGoal());
|
|
|
- map.put("packageName", mq.getPackageName());
|
|
|
- map.put("adStatus", mq.getAdStatus());
|
|
|
- map.put("creativeStatus", mq.getCreativeStatus());
|
|
|
+ map.put("dt", String.valueOf(days));
|
|
|
+ map.put("impressions", s.getImpressions());
|
|
|
+ map.put("clicks", s.getClicks());
|
|
|
+ map.put("conversions", s.getConversions());
|
|
|
+ map.put("cost", s.getCost());
|
|
|
+ map.put("income", s.getIncome());
|
|
|
+ map.put("firstUv", s.getFirstUv());
|
|
|
+ map.put("fission0Uv", s.getFission0Uv());
|
|
|
+
|
|
|
+ // 效率指标
|
|
|
+ Double ctr = divide(s.getClicks(), s.getImpressions());
|
|
|
+ Double cvr = divide(s.getConversions(), s.getImpressions());
|
|
|
+ Double roi = divide(s.getIncome(), s.getCost());
|
|
|
+ Double openRate = divide(s.getFirstUv(), s.getConversions());
|
|
|
+ Double fissionRate = divide(s.getFission0Uv(), s.getFirstUv());
|
|
|
+ if (ctr != null) { map.put("ctr", round4(ctr)); map.put("ctrScore", round4(ctr)); }
|
|
|
+ if (cvr != null) { map.put("cvr", round4(cvr)); map.put("cvrScore", round4(cvr)); }
|
|
|
+ if (roi != null) { map.put("roi", round4(roi)); map.put("roiScore", round4(roi)); }
|
|
|
+ if (openRate != null) { map.put("openRate", round4(openRate)); map.put("openRateScore", round4(openRate)); }
|
|
|
+ if (fissionRate != null) { map.put("fissionRate", round4(fissionRate)); map.put("fissionRateScore", round4(fissionRate)); }
|
|
|
+
|
|
|
+ // 综合质量分(等权加权,测试路径无批内百分位排名,用原始比率近似)
|
|
|
+ double qs = computeSimpleQualityScore(s);
|
|
|
+ map.put("qualityScore", round4(qs));
|
|
|
+
|
|
|
return map;
|
|
|
}
|
|
|
|
|
|
- private Map<String, MaterialQuality> loadMaterialQualityRows(List<String> materialIds) {
|
|
|
+ /** a / b,任一方为 null 或 b==0 时返回 null */
|
|
|
+ private static Double divide(Number a, Number b) {
|
|
|
+ if (a == null || b == null) return null;
|
|
|
+ double bd = b.doubleValue();
|
|
|
+ if (bd == 0) return null;
|
|
|
+ return a.doubleValue() / bd;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static double round4(double v) {
|
|
|
+ return Math.round(v * 10000.0) / 10000.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 简单质量分:等权加权所有有数据的效率指标 */
|
|
|
+ private double computeSimpleQualityScore(AdsMaterialTouliuAllChannel s) {
|
|
|
+ if (s == null) return 0;
|
|
|
+ int count = 0;
|
|
|
+ double sum = 0;
|
|
|
+ Double ctr = divide(s.getClicks(), s.getImpressions());
|
|
|
+ Double cvr = divide(s.getConversions(), s.getImpressions());
|
|
|
+ Double roi = divide(s.getIncome(), s.getCost());
|
|
|
+ Double openRate = divide(s.getFirstUv(), s.getConversions());
|
|
|
+ Double fissionRate = divide(s.getFission0Uv(), s.getFirstUv());
|
|
|
+ if (ctr != null) { sum += ctr; count++; }
|
|
|
+ if (cvr != null) { sum += cvr; count++; }
|
|
|
+ if (roi != null) { sum += roi; count++; }
|
|
|
+ if (openRate != null) { sum += openRate; count++; }
|
|
|
+ if (fissionRate != null) { sum += fissionRate; count++; }
|
|
|
+ return count > 0 ? sum / count : 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, AdsMaterialTouliuAllChannel> loadMaterialTouliuStats(
|
|
|
+ List<String> materialIds, int days) {
|
|
|
if (CollectionUtils.isEmpty(materialIds)) {
|
|
|
return Collections.emptyMap();
|
|
|
}
|
|
|
- Map<String, MaterialQuality> result = new HashMap<>();
|
|
|
+ Map<String, AdsMaterialTouliuAllChannel> result = new HashMap<>();
|
|
|
try {
|
|
|
- List<MaterialQuality> rows = materialQualityMapperExt.selectByMaterialIds(materialIds);
|
|
|
+ String dtThreshold = LocalDate.now().minusDays(days)
|
|
|
+ .format(DateTimeFormatter.ofPattern("yyyyMMdd"));
|
|
|
+ List<AdsMaterialTouliuAllChannel> rows = adsMaterialTouliuAllChannelMapperExt
|
|
|
+ .aggregateByMaterialIds(materialIds, dtThreshold);
|
|
|
if (CollectionUtils.isEmpty(rows)) return result;
|
|
|
- for (MaterialQuality row : rows) {
|
|
|
+ for (AdsMaterialTouliuAllChannel row : rows) {
|
|
|
if (row != null && row.getMaterialId() != null) {
|
|
|
result.putIfAbsent(row.getMaterialId(), row);
|
|
|
}
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
- log.error("批量加载 material_quality 失败: {}", e.getMessage(), e);
|
|
|
+ log.error("批量加载 ads_material_touliu_all_channel 失败: {}", e.getMessage(), e);
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
@@ -1813,9 +1830,9 @@ public class VectorRecallTestServiceImpl implements VectorRecallTestService {
|
|
|
? vo.getMaterialDetail().getQuality() : null;
|
|
|
if (qualityMap != null && !qualityMap.isEmpty()) {
|
|
|
qs.setHasData(true);
|
|
|
- qs.setCtr(toDoubleOrNull(qualityMap.get("conversionEfficiencyScore")));
|
|
|
- qs.setViral(toDoubleOrNull(qualityMap.get("viralScore")));
|
|
|
- qs.setRoi(toDoubleOrNull(qualityMap.get("revenueScore")));
|
|
|
+ qs.setCtr(toDoubleOrNull(qualityMap.get("ctr")));
|
|
|
+ qs.setViral(toDoubleOrNull(qualityMap.get("fissionRate")));
|
|
|
+ qs.setRoi(toDoubleOrNull(qualityMap.get("roi")));
|
|
|
} else {
|
|
|
qs.setHasData(false);
|
|
|
}
|
|
|
@@ -1973,7 +1990,7 @@ public class VectorRecallTestServiceImpl implements VectorRecallTestService {
|
|
|
.collect(Collectors.toList());
|
|
|
List<MaterialMatch> deduped = deduplicateMaterialMatches(matches, tn);
|
|
|
if (!deduped.isEmpty()) {
|
|
|
- allResults.addAll(enrichMaterialMatches(deduped, cc));
|
|
|
+ allResults.addAll(enrichMaterialMatches(deduped, cc, metricsDays));
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
log.error("matchByMaterialId 素材搜索失败 configCode={}: {}", cc, e.getMessage(), e);
|
|
|
@@ -2363,7 +2380,7 @@ public class VectorRecallTestServiceImpl implements VectorRecallTestService {
|
|
|
List<MaterialMatch> matches = materialVectorStoreService.searchTopNByRawVector(cc, rawEmbedding, ctn);
|
|
|
List<MaterialMatch> deduped = deduplicateMaterialMatches(matches, tn);
|
|
|
if (!deduped.isEmpty()) {
|
|
|
- allResults.addAll(enrichMaterialMatches(deduped, cc));
|
|
|
+ allResults.addAll(enrichMaterialMatches(deduped, cc, metricsDays));
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
log.error("matchByArticleId 素材搜索失败 configCode={}: {}", cc, e.getMessage(), e);
|