wangyunpeng 2 дней назад
Родитель
Сommit
14c183fd69

+ 9 - 0
core/src/main/java/com/tzld/videoVector/dao/mapper/pgVector/ext/VideoDeconstructResultMapperExt.java

@@ -50,4 +50,13 @@ public interface VideoDeconstructResultMapperExt {
      */
     List<VideoDeconstructResult> selectResultsByVideoIds(@Param("source") String source,
                                                         @Param("videoIds") List<Long> videoIds);
+
+    /**
+     * 批量查询 videoId 列表的解构结果(不限来源,每个 videoId 取最新一条)
+     * 用于替代 Redis 缓存读取,按 id DESC 取最新记录
+     *
+     * @param videoIds 视频ID列表
+     * @return 解构结果列表(每个 videoId 最多一条)
+     */
+    List<VideoDeconstructResult> selectLatestByVideoIds(@Param("videoIds") List<Long> videoIds);
 }

+ 17 - 30
core/src/main/java/com/tzld/videoVector/job/VideoVectorJob.java

@@ -635,8 +635,7 @@ public class VideoVectorJob {
                         if (dataContent == null) {
                             continue;
                         }
-                        // 尝试缓存 decode 结果
-                        tryCacheDecodeResult(videoId, dataContent);
+                        tryCacheDecodeResult(videoId);
 
                         try {
                             inFlightLimiter.acquire();
@@ -842,7 +841,6 @@ public class VideoVectorJob {
 
                 if (!notPassedIds.isEmpty()) {
                     vectorStoreService.deleteBatch(configCode, notPassedIds);
-                    // 同步删除 decode 缓存
                     deleteDecodeCacheBatch(notPassedIds);
                     totalRemoved += notPassedIds.size();
                     log.info("配置 {} 移除审核不通过的视频 {} 个: {}", configCode, notPassedIds.size(), notPassedIds);
@@ -1422,48 +1420,37 @@ public class VideoVectorJob {
     // ========================== Decode 缓存相关方法 ==========================
 
     /**
-     * 尝试将解构结果解析并缓存到 Redis (JSONObject 版本)
-     * 仅在本次 Job 运行中未缓存过时执行
+     * 尝试从 video_deconstruct_result 表查询解构结果并写入 Redis 缓存
+     * 缓存 key: recall:vid_decode:{videoId}
      */
-    private void tryCacheDecodeResult(Long videoId, JSONObject rawJson) {
-        if (videoId == null || rawJson == null) {
-            return;
-        }
-        if (decodeCachedInThisRun.contains(videoId)) {
-            return;
-        }
+    private void tryCacheDecodeResult(Long videoId) {
+        if (videoId == null) return;
+        if (decodeCachedInThisRun.contains(videoId)) return;
         try {
-            JSONObject decoded = videoSearchService.parseDecodeResult(rawJson);
-            if (!isValidDecodeResult(decoded)) {
+            List<VideoDeconstructResult> dbResults = videoDeconstructResultMapperExt
+                    .selectLatestByVideoIds(Collections.singletonList(videoId));
+            if (CollectionUtils.isEmpty(dbResults) || !StringUtils.hasText(dbResults.get(0).getResult())) {
                 return;
             }
+            JSONObject rawJson = JSON.parseObject(dbResults.get(0).getResult());
+            JSONObject decoded = videoSearchService.parseDecodeResult(rawJson);
+            if (!isValidDecodeResult(decoded)) return;
             String redisKey = VectorConstants.VID_DECODE_KEY_PREFIX + videoId;
             redisUtils.addVal(redisKey, decoded.toJSONString());
-            // 记录到追踪 SET
             redisUtils.sAdd(VectorConstants.VID_DECODE_IDS_SET_KEY, String.valueOf(videoId));
             decodeCachedInThisRun.add(videoId);
-            log.info("decode 缓存写入成功,videoId={}", videoId);
         } catch (Exception e) {
-            log.warn("tryCacheDecodeResult 失败,videoId={}, error={}", videoId, e.getMessage());
+            log.error("tryCacheDecodeResult 失败, videoId={}: {}", videoId, e.getMessage(), e);
         }
     }
 
     /**
-     * 批量删除 decode 缓存
+     * 批量删除 Redis 解构缓存
      */
     private void deleteDecodeCacheBatch(Set<Long> videoIds) {
-        if (videoIds == null || videoIds.isEmpty()) {
-            return;
-        }
-        try {
-            for (Long videoId : videoIds) {
-                String redisKey = VectorConstants.VID_DECODE_KEY_PREFIX + videoId;
-                redisUtils.del(redisKey);
-                redisUtils.sRemove(VectorConstants.VID_DECODE_IDS_SET_KEY, String.valueOf(videoId));
-            }
-            log.info("删除 decode 缓存 {} 个", videoIds.size());
-        } catch (Exception e) {
-            log.error("删除 decode 缓存失败: {}", e.getMessage(), e);
+        for (Long videoId : videoIds) {
+            redisUtils.del(VectorConstants.VID_DECODE_KEY_PREFIX + videoId);
+            redisUtils.sRemove(VectorConstants.VID_DECODE_IDS_SET_KEY, String.valueOf(videoId));
         }
     }
 

+ 23 - 12
core/src/main/java/com/tzld/videoVector/service/impl/VideoSearchServiceImpl.java

@@ -8,14 +8,11 @@ import com.tzld.videoVector.dao.mapper.pgVector.ChannelDemandMatchResultMapper;
 import com.tzld.videoVector.dao.mapper.pgVector.DeconstructContentMapper;
 import com.tzld.videoVector.dao.mapper.pgVector.DeconstructVectorConfigMapper;
 import com.tzld.videoVector.dao.mapper.pgVector.ext.ContentVectorMapperExt;
+import com.tzld.videoVector.dao.mapper.pgVector.ext.VideoDeconstructResultMapperExt;
 import com.tzld.videoVector.model.entity.DeconstructResult;
 import com.tzld.videoVector.model.entity.VideoDetail;
 import com.tzld.videoVector.model.entity.VideoMatch;
-import com.tzld.videoVector.model.param.ChannelDemandMatchQueryParam;
-import com.tzld.videoVector.model.param.DeconstructParam;
-import com.tzld.videoVector.model.param.GetDeconstructParam;
-import com.tzld.videoVector.model.param.MatchTopNVideoParam;
-import com.tzld.videoVector.model.param.RecallVideoScoreParam;
+import com.tzld.videoVector.model.param.*;
 import com.tzld.videoVector.model.po.pgVector.*;
 import com.tzld.videoVector.model.vo.ChannelDemandMatchVO;
 import com.tzld.videoVector.model.vo.RecallVideoScoreVO;
@@ -65,6 +62,9 @@ public class VideoSearchServiceImpl implements VideoSearchService {
     @Resource
     private DeconstructVectorConfigMapper deconstructVectorConfigMapper;
 
+    @Resource
+    private VideoDeconstructResultMapperExt videoDeconstructResultMapperExt;
+
     @Resource
     private RedisUtils redisUtils;
 
@@ -1076,7 +1076,7 @@ public class VideoSearchServiceImpl implements VideoSearchService {
      *     "目的点": [...], "目的点-实质": [...]
      *   }
      *
-     * 数据来源:script/sync_decode_to_redis.py 同步,Key: recall:vid_decode:{videoId}
+     * 数据来源:Redis recall:vid_decode:{videoId}
      */
     private void enrichDeconstruct(List<VideoMatchResult> results) {
         if (results == null || results.isEmpty()) {
@@ -1084,15 +1084,27 @@ public class VideoSearchServiceImpl implements VideoSearchService {
         }
 
         try {
-            List<String> keys = results.stream()
-                    .map(r -> VectorConstants.VID_DECODE_KEY_PREFIX + r.getVideoId())
+            List<Long> videoIds = results.stream()
+                    .map(VideoMatchResult::getVideoId)
+                    .filter(Objects::nonNull)
                     .collect(Collectors.toList());
+            if (videoIds.isEmpty()) {
+                return;
+            }
 
+            // 从 Redis 批量获取解构缓存
+            List<String> keys = videoIds.stream()
+                    .map(id -> VectorConstants.VID_DECODE_KEY_PREFIX + id)
+                    .collect(Collectors.toList());
             List<String> values = redisUtils.mGet(keys);
+            if (values == null) {
+                return;
+            }
 
             for (int i = 0; i < results.size(); i++) {
-                String json = values.get(i);
-                if (json == null) {
+                VideoMatchResult r = results.get(i);
+                String json = (i < values.size()) ? values.get(i) : null;
+                if (!StringUtils.hasText(json)) {
                     continue;
                 }
                 try {
@@ -1100,7 +1112,6 @@ public class VideoSearchServiceImpl implements VideoSearchService {
                     if (deconstructFlat == null || deconstructFlat.isEmpty()) {
                         continue;
                     }
-                    VideoMatchResult r = results.get(i);
                     Map<String, Object> detail = r.getVideoDetail();
                     if (detail == null) {
                         detail = new HashMap<>();
@@ -1108,7 +1119,7 @@ public class VideoSearchServiceImpl implements VideoSearchService {
                     }
                     detail.put("deconstruct", deconstructFlat);
                 } catch (Exception e) {
-                    log.error("解析视频解构失败,videoId={}: {}", results.get(i).getVideoId(), e.getMessage());
+                    log.error("解析视频解构失败,videoId={}: {}", r.getVideoId(), e.getMessage());
                 }
             }
         } catch (Exception e) {

+ 11 - 15
core/src/main/java/com/tzld/videoVector/service/recall/impl/VectorRecallTestServiceImpl.java

@@ -7,6 +7,7 @@ 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.videoVector.deconstruct.MysqlDeconstructContentMapper;
+import com.tzld.videoVector.dao.mapper.pgVector.ext.VideoDeconstructResultMapperExt;
 import com.tzld.videoVector.model.entity.VideoDetail;
 import com.tzld.videoVector.model.param.MatchTopNVideoParam;
 import com.tzld.videoVector.model.param.recall.MatchByTextParam;
@@ -56,6 +57,9 @@ public class VectorRecallTestServiceImpl implements VectorRecallTestService {
     @Autowired
     private MysqlDeconstructContentMapper mysqlDeconstructContentMapper;
 
+    @Autowired
+    private VideoDeconstructResultMapperExt videoDeconstructResultMapperExt;
+
     @Autowired(required = false)
     private StringRedisTemplate stringRedisTemplate;
 
@@ -137,26 +141,18 @@ public class VectorRecallTestServiceImpl implements VectorRecallTestService {
             return null;
         }
         if (stringRedisTemplate == null) {
-            log.warn("getDeconstructPoints: stringRedisTemplate 未注入");
-            return null;
-        }
-        String vid = String.valueOf(videoId);
-        String key = REDIS_KEY_DECODE_PREFIX + vid;
-        String json;
-        try {
-            json = stringRedisTemplate.opsForValue().get(key);
-        } catch (Exception e) {
-            log.error("getDeconstructPoints: read redis fail, vid={}, err={}", vid, e.getMessage(), e);
-            return null;
-        }
-        if (!StringUtils.hasText(json)) {
-            log.info("getDeconstructPoints: Redis 无 vid={} 的解构记录(脚本未同步或非视频内容)", vid);
+            log.info("getDeconstructPoints: redisTemplate not available, returning null. vid={}", videoId);
             return null;
         }
         try {
+            String json = stringRedisTemplate.opsForValue().get(REDIS_KEY_DECODE_PREFIX + videoId);
+            if (!StringUtils.hasText(json)) {
+                log.info("getDeconstructPoints: Redis 无 vid={} 的解构缓存", videoId);
+                return null;
+            }
             return JSON.parseObject(json, DeconstructPointsVO.class);
         } catch (Exception e) {
-            log.error("getDeconstructPoints: parse redis value fail, vid={}, err={}", vid, e.getMessage(), e);
+            log.error("getDeconstructPoints: Redis 读取/解析失败, vid={}, err={}", videoId, e.getMessage(), e);
             return null;
         }
     }

+ 11 - 0
core/src/main/resources/mapper/pgVector/ext/VideoDeconstructResultMapperExt.xml

@@ -52,4 +52,15 @@
     </foreach>
   </select>
 
+  <!-- 批量查询 videoId 的解构结果(不限来源,每个 videoId 取最新一条) -->
+  <select id="selectLatestByVideoIds" resultMap="BaseResultMap">
+    SELECT DISTINCT ON (video_id) video_id, source, result, create_time, update_time
+    FROM video_deconstruct_result
+    WHERE video_id IN
+    <foreach collection="videoIds" item="id" open="(" separator="," close=")">
+      #{id}
+    </foreach>
+    ORDER BY video_id, id DESC
+  </select>
+
 </mapper>