Răsfoiți Sursa

feat: 商品推荐支持空维度返回全量推荐

Xiaogang Liao 1 lună în urmă
părinte
comite
d3bb91a737

+ 31 - 13
cfc-backend/src/main/java/com/etotem/cfc/service/ProductRecommendationService.java

@@ -60,11 +60,12 @@ public class ProductRecommendationService {
         List<Product> candidates = new ArrayList<>();
 
         // 从 mapping 表获取关联商品
-        List<ProductDimensionMapping> mappings = dimensionMappingMapper.selectList(
-                new LambdaQueryWrapper<ProductDimensionMapping>()
-                        .eq(ProductDimensionMapping::getDimensionCode, dimensionCode)
-                        .eq(ProductDimensionMapping::getEnabled, 1)
-        );
+        LambdaQueryWrapper<ProductDimensionMapping> mappingQw = new LambdaQueryWrapper<ProductDimensionMapping>()
+                .eq(ProductDimensionMapping::getEnabled, 1);
+        if (dimensionCode != null && !dimensionCode.isEmpty()) {
+            mappingQw.eq(ProductDimensionMapping::getDimensionCode, dimensionCode);
+        }
+        List<ProductDimensionMapping> mappings = dimensionMappingMapper.selectList(mappingQw);
 
         if (mappings != null && !mappings.isEmpty()) {
             List<Long> mappedProductIds = mappings.stream()
@@ -106,14 +107,17 @@ public class ProductRecommendationService {
 
         // fallback: 从 Product.domain 匹配
         if (candidates.isEmpty()) {
-            List<Product> domainMatched = productMapper.selectList(
-                    new LambdaQueryWrapper<Product>()
-                            .eq(Product::getDomain, dimensionCode)
-                            .eq(Product::getStatus, "上架")
-                            .gt(Product::getStock, 0)
-                            .notIn(!purchasedIds.isEmpty(), Product::getId, purchasedIds)
-                            .orderByAsc(Product::getSortOrder)
-            );
+            LambdaQueryWrapper<Product> domainQw = new LambdaQueryWrapper<Product>()
+                    .eq(Product::getStatus, "上架")
+                    .gt(Product::getStock, 0)
+                    .orderByAsc(Product::getSortOrder);
+            if (dimensionCode != null && !dimensionCode.isEmpty()) {
+                domainQw.eq(Product::getDomain, dimensionCode);
+            }
+            if (!purchasedIds.isEmpty()) {
+                domainQw.notIn(Product::getId, purchasedIds);
+            }
+            List<Product> domainMatched = productMapper.selectList(domainQw);
             candidates.addAll(domainMatched);
         }
 
@@ -256,6 +260,9 @@ public class ProductRecommendationService {
      * 对低得分维度加权 boost
      */
     private double applyDimensionBoost(int baseScore, String dimensionCode, Map<String, Integer> memberScores) {
+        if (dimensionCode == null || dimensionCode.isEmpty()) {
+            return baseScore;
+        }
         Integer score = memberScores.get(dimensionCode);
         if (score == null || score >= 70) {
             return baseScore;
@@ -271,6 +278,14 @@ public class ProductRecommendationService {
      */
     private double calculateMatchScore(Product product, String dimensionCode, Map<String, Integer> memberScores) {
         int base = 70;
+        if (dimensionCode == null || dimensionCode.isEmpty()) {
+            Integer minScore = memberScores.values().stream().min(Integer::compareTo).orElse(null);
+            if (minScore != null) {
+                if (minScore < 50) base = 90;
+                else if (minScore < 70) base = 80;
+            }
+            return base;
+        }
         Integer myScore = memberScores.get(dimensionCode);
         if (myScore != null) {
             if (myScore < 50) base = 90;
@@ -284,6 +299,9 @@ public class ProductRecommendationService {
      * 构建推荐理由
      */
     private String buildRecommendationReason(Product product, String dimensionCode, Map<String, Integer> memberScores) {
+        if (dimensionCode == null || dimensionCode.isEmpty()) {
+            return "为您推荐的好物";
+        }
         Integer score = memberScores.get(dimensionCode);
         if (score == null) {
             return "根据您的维度匹配为您推荐";