|  | @@ -58,27 +58,37 @@ public abstract class AbstractRegionRecallStrategy implements RecallStrategy {
 | 
	
		
			
				|  |  |          // recordKey: 每小时生成一个召回源,用来决定用哪个召回源
 | 
	
		
			
				|  |  |          // poolKey: 召回源的key
 | 
	
		
			
				|  |  |          // lastVideoLKey: 上次返回的最后一个视频
 | 
	
		
			
				|  |  | +        /**
 | 
	
		
			
				|  |  | +         * 1、如果当前小时数据已生成,那么召回源用当前小时数据
 | 
	
		
			
				|  |  | +         * 2、如果当前小时数据未生成,那么召回源用前一小时数据
 | 
	
		
			
				|  |  | +         *
 | 
	
		
			
				|  |  | +         * 1、如果recordKey是当前小时数据,用lastVideo作为cursor
 | 
	
		
			
				|  |  | +         * 2、如果recordKey是前一小时数据,重置lastVideo
 | 
	
		
			
				|  |  | +         *
 | 
	
		
			
				|  |  | +         *
 | 
	
		
			
				|  |  | +         */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          String record = redisTemplate.opsForValue().get(recordKey);
 | 
	
		
			
				|  |  |          if (StringUtils.isNotBlank(record)) {
 | 
	
		
			
				|  |  |              Map<String, String> recordMap = JSONUtils.fromJson(record, new TypeToken<Map<String, String>>() {
 | 
	
		
			
				|  |  |              }, Collections.emptyMap());
 | 
	
		
			
				|  |  |              if (MapUtils.isNotEmpty(recordMap)) {
 | 
	
		
			
				|  |  |                  String record_dt = recordMap.get("date");
 | 
	
		
			
				|  |  | -                String record_h = recordMap.get("h");
 | 
	
		
			
				|  |  | +                int record_h = NumberUtils.toInt(recordMap.get("h"), 0);
 | 
	
		
			
				|  |  |                  String now_dt = DateUtils.getCurrentDateStr("yyyyMMdd");
 | 
	
		
			
				|  |  |                  int h = DateUtils.getCurrentHour();
 | 
	
		
			
				|  |  | -                if (record_dt.equals(now_dt) && Integer.parseInt(record_h) == h) {
 | 
	
		
			
				|  |  | -                    poolKey = poolKey(param, now_dt, h);
 | 
	
		
			
				|  |  | +                if (record_dt.equals(now_dt) && record_h == h) {
 | 
	
		
			
				|  |  | +                    poolKey = poolKey(param, record_dt, record_h);
 | 
	
		
			
				|  |  |                      idx = getIdx(lastVideoKey, poolKey);
 | 
	
		
			
				|  |  | -                } else if ((record_dt.equals(now_dt) && h - Integer.parseInt(record_h) == 1)
 | 
	
		
			
				|  |  | -                        || (h == 0 && Integer.parseInt(record_h) == 23)) {
 | 
	
		
			
				|  |  | +                } else if ((record_dt.equals(now_dt) && h - record_h == 1)
 | 
	
		
			
				|  |  | +                        || (h == 0 && record_h == 23)) {
 | 
	
		
			
				|  |  |                      poolKey = poolKey(param, now_dt, h);
 | 
	
		
			
				|  |  |                      if (redisTemplate.hasKey(poolKey)) {
 | 
	
		
			
				|  |  |                          redisTemplate.opsForValue().set(recordKey, String.format(recordKeyFormat, now_dt,
 | 
	
		
			
				|  |  |                                  h), 2, TimeUnit.HOURS);
 | 
	
		
			
				|  |  |                          redisTemplate.delete(lastVideoKey);
 | 
	
		
			
				|  |  |                      } else {
 | 
	
		
			
				|  |  | -                        poolKey = poolKey(param, record_dt, Integer.parseInt(record_h));
 | 
	
		
			
				|  |  | +                        poolKey = poolKey(param, record_dt, record_h);
 | 
	
		
			
				|  |  |                          idx = getIdx(lastVideoKey, poolKey);
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |                  } else {
 | 
	
	
		
			
				|  | @@ -134,9 +144,11 @@ public abstract class AbstractRegionRecallStrategy implements RecallStrategy {
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        // 如果不限制返回size个数据,可以迁移到排序阶段
 | 
	
		
			
				|  |  | +        // Collections.sort(results, Comparator.comparingDouble(o -> -o.getRovScore()));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        Collections.sort(results, Comparator.comparingDouble(o -> -o.getRovScore()));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +        // 这里是一个优化:如果所有数据都被过滤,说明下一次召回可以直接从lastVideo开始
 | 
	
		
			
				|  |  | +        // TODO 可以优化成异步更新
 | 
	
		
			
				|  |  |          if (StringUtils.isNotBlank(lastVideoId)
 | 
	
		
			
				|  |  |                  && CollectionUtils.isEmpty(results)
 | 
	
		
			
				|  |  |                  && StringUtils.isNotBlank(param.getMid())) {
 | 
	
	
		
			
				|  | @@ -144,7 +156,8 @@ public abstract class AbstractRegionRecallStrategy implements RecallStrategy {
 | 
	
		
			
				|  |  |              redisTemplate.opsForValue().set(lastVideoKey, lastVideoId, 2, TimeUnit.HOURS);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        return results.subList(0, results.size() < param.getSize() ? results.size() : param.getSize());
 | 
	
		
			
				|  |  | +        // return results.subList(0, results.size() < param.getSize() ? results.size() : param.getSize());
 | 
	
		
			
				|  |  | +        return results;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      private int getIdx(String lastVideoKey, String poolKey) {
 | 
	
	
		
			
				|  | @@ -160,7 +173,6 @@ public abstract class AbstractRegionRecallStrategy implements RecallStrategy {
 | 
	
		
			
				|  |  |          return idx;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    // TODO 和 推荐排序后的lastVideo更新有什么区别?
 | 
	
		
			
				|  |  |      private String updateLastVideoRecord(String recordKey, RecallParam param) {
 | 
	
		
			
				|  |  |          String currentDateStr = DateUtils.getCurrentDateStr("yyyyMMdd");
 | 
	
		
			
				|  |  |          int h = DateUtils.getCurrentHour();
 |