Sfoglia il codice sorgente

Merge branch 'feature-20240423-sunxy-appTypeVideoStatus1' of algorithm/recommend-server into master

sunxiaoyi 1 anno fa
parent
commit
c3197cee09

+ 63 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/config/VideoRedisTemplateConfig.java

@@ -0,0 +1,63 @@
+package com.tzld.piaoquan.recommend.server.config;
+
+import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
+import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+@Configuration
+public class VideoRedisTemplateConfig {
+
+    @Bean("videoRedisPool")
+    @ConfigurationProperties(prefix = "spring.video-redis.lettuce.pool")
+    public GenericObjectPoolConfig<LettucePoolingClientConfiguration> videoRedisPool() {
+        return new GenericObjectPoolConfig<>();
+    }
+
+    @Bean("videoRedisConfig")
+    @ConfigurationProperties(prefix = "spring.video-redis")
+    public RedisStandaloneConfiguration videoRedisConfig() {
+        return new RedisStandaloneConfiguration();
+    }
+
+    @Bean("videoRedisFactory")
+    @Primary
+    public LettuceConnectionFactory factory(@Qualifier("videoRedisPool") GenericObjectPoolConfig<LettucePoolingClientConfiguration> videoRedisPool,
+                                            @Qualifier("videoRedisConfig") RedisStandaloneConfiguration videoRedisConfig) {
+        LettuceClientConfiguration lettuceClientConfiguration =
+                LettucePoolingClientConfiguration.builder().poolConfig(videoRedisPool).build();
+        return new LettuceConnectionFactory(videoRedisConfig, lettuceClientConfiguration);
+    }
+
+    @Bean(name = "videoRedisTemplate")
+    public RedisTemplate<String, String> getRedisTemplate(@Qualifier("videoRedisFactory") RedisConnectionFactory factory) {
+        return buildRedisTemplateByString(factory);
+    }
+
+    /**
+     * 构建redisTemplate 使用string序列化
+     *
+     * @param factory
+     * @return
+     */
+    private RedisTemplate<String, String> buildRedisTemplateByString(RedisConnectionFactory factory) {
+        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
+        redisTemplate.setConnectionFactory(factory);
+        // key的序列化类型 保证可读性
+        redisTemplate.setKeySerializer(new StringRedisSerializer());
+        redisTemplate.setValueSerializer(new StringRedisSerializer());
+        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
+        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
+        return redisTemplate;
+    }
+
+}

+ 94 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/repository/VideoAppTypeStatus.java

@@ -0,0 +1,94 @@
+package com.tzld.piaoquan.recommend.server.repository;
+
+import lombok.Data;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * This class was generated by MyBatis Generator.
+ * This class corresponds to the database table video_app_type_status
+ */
+@Data
+@Entity
+@Table(name = "video_app_type_status")
+public class VideoAppTypeStatus implements Serializable {
+
+    /**
+     * This field was generated by MyBatis Generator.
+     * This field corresponds to the database column video_app_type_status.id
+     *
+     * @mbg.generated
+     */
+    @Id
+    private Long id;
+
+    /**
+     * Database Column Remarks:
+     * 视频ID,Wx_video表的主键
+     * <p>
+     * This field was generated by MyBatis Generator.
+     * This field corresponds to the database column video_app_type_status.video_id
+     *
+     * @mbg.generated
+     */
+    private Long videoId;
+
+    /**
+     * Database Column Remarks:
+     * 应用类型
+     * <p>
+     * This field was generated by MyBatis Generator.
+     * This field corresponds to the database column video_app_type_status.app_type
+     *
+     * @mbg.generated
+     */
+    private Integer appType;
+
+    /**
+     * Database Column Remarks:
+     * 视频状态 1 上架 0 下架
+     * <p>
+     * This field was generated by MyBatis Generator.
+     * This field corresponds to the database column video_app_type_status.video_status
+     *
+     * @mbg.generated
+     */
+    private Integer videoStatus;
+
+    /**
+     * Database Column Remarks:
+     * 最后更新人
+     * <p>
+     * This field was generated by MyBatis Generator.
+     * This field corresponds to the database column video_app_type_status.last_update_by
+     *
+     * @mbg.generated
+     */
+    private String lastUpdateBy;
+
+    /**
+     * Database Column Remarks:
+     * 创建时间
+     * <p>
+     * This field was generated by MyBatis Generator.
+     * This field corresponds to the database column video_app_type_status.create_time
+     *
+     * @mbg.generated
+     */
+    private Date createTime;
+
+    /**
+     * Database Column Remarks:
+     * 视频的发布时间戳
+     * <p>
+     * This field was generated by MyBatis Generator.
+     * This field corresponds to the database column video_app_type_status.update_time
+     *
+     * @mbg.generated
+     */
+    private Date updateTime;
+}

+ 14 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/repository/VideoAppTypeStatusRepository.java

@@ -0,0 +1,14 @@
+package com.tzld.piaoquan.recommend.server.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * @Author sunxy
+ */
+@Repository
+public interface VideoAppTypeStatusRepository extends JpaRepository<VideoAppTypeStatus, Long> {
+    List<VideoAppTypeStatus> findAllByVideoIdInAndAppType(List<Long> videoIdList, Integer appType);
+}

+ 1 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/filter/AbstractFilterService.java

@@ -270,6 +270,7 @@ public abstract class AbstractFilterService {
         strategies.add(ServiceBeanFactory.getBean(ViewedStrategy.class));
         strategies.add(ServiceBeanFactory.getBean(RecommendStatusStrategy.class));
         strategies.add(ServiceBeanFactory.getBean(SupplyExpStrategy.class));
+        strategies.add(ServiceBeanFactory.getBean(AppletVideoStatusStrategy.class));
         switch (param.getAppType()) {
             case 0:
             case 4:

+ 123 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/filter/strategy/AppletVideoStatusStrategy.java

@@ -0,0 +1,123 @@
+package com.tzld.piaoquan.recommend.server.service.filter.strategy;
+
+import com.tzld.piaoquan.recommend.server.common.ThreadPoolFactory;
+import com.tzld.piaoquan.recommend.server.repository.VideoAppTypeStatus;
+import com.tzld.piaoquan.recommend.server.repository.VideoAppTypeStatusRepository;
+import com.tzld.piaoquan.recommend.server.service.filter.FilterParam;
+import com.tzld.piaoquan.recommend.server.service.filter.FilterStrategy;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.RandomUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.dao.DataAccessException;
+import org.springframework.data.redis.core.RedisOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.SessionCallback;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * @author dyp
+ */
+@Component
+@Slf4j
+public class AppletVideoStatusStrategy implements FilterStrategy {
+    @Autowired
+    @Qualifier("videoRedisTemplate")
+    private RedisTemplate<String, String> videoRedisTemplate;
+
+    @Autowired
+    private VideoAppTypeStatusRepository videoAppTypeStatusRepository;
+
+
+    private final String videoAppTypeStatusKeyFormat = "video:active:status:%s:%s";
+
+
+    @Override
+    public List<Long> filter(FilterParam param) {
+        if (param == null
+                || CollectionUtils.isEmpty(param.getVideoIds())) {
+            return Collections.emptyList();
+        }
+        return filterActiveStatusVideoId(param.getVideoIds(), param.getAppType());
+    }
+
+    /**
+     * 过滤上下架状态
+     * <p>
+     * 紧急需求上线
+     * 性能待优化
+     *
+     * @param idList  videoId列表
+     * @param appType appType
+     */
+    private List<Long> filterActiveStatusVideoId(List<Long> idList, Integer appType) {
+        if (CollectionUtils.isEmpty(idList)) {
+            return idList;
+        }
+        List<String> keys = idList.stream()
+                .map(id -> String.format(videoAppTypeStatusKeyFormat, appType, id))
+                .collect(Collectors.toList());
+        List<String> activeStatusList = videoRedisTemplate.opsForValue().multiGet(keys);
+        if (activeStatusList == null) {
+            activeStatusList = new ArrayList<>();
+        }
+
+        List<Long> cacheMissVideoIds = new ArrayList<>();
+        Map<String, String> updateRedisStatus = new HashMap<>();
+        Map<Long, Integer> activeStatusMap = new HashMap<>();
+        for (int i = 0; i < idList.size(); i++) {
+            String value = activeStatusList.get(i);
+            if (StringUtils.isBlank(value)) {
+                cacheMissVideoIds.add(idList.get(i));
+            } else {
+                activeStatusMap.put(idList.get(i), NumberUtils.toInt(value));
+            }
+        }
+
+        if (CollectionUtils.isNotEmpty(cacheMissVideoIds)) {
+            List<VideoAppTypeStatus> videoAppTypeStatusList = videoAppTypeStatusRepository.findAllByVideoIdInAndAppType(cacheMissVideoIds, appType);
+            Set<Long> cacheMissVideoIdSet = new HashSet<>(cacheMissVideoIds);
+            if (CollectionUtils.isNotEmpty(videoAppTypeStatusList)) {
+                // 数据库有数据
+                for (VideoAppTypeStatus videoAppTypeStatus : videoAppTypeStatusList) {
+                    activeStatusMap.put(videoAppTypeStatus.getVideoId(), videoAppTypeStatus.getVideoStatus());
+                    updateRedisStatus.put(String.format(videoAppTypeStatusKeyFormat, appType, videoAppTypeStatus.getVideoId()), "1");
+                    cacheMissVideoIdSet.remove(videoAppTypeStatus.getVideoId());
+                }
+            }
+            // 数据库无数据的videoId
+            if (CollectionUtils.isNotEmpty(cacheMissVideoIdSet)) {
+                for (Long videoId : cacheMissVideoIdSet) {
+                    // 设置默认值
+                    updateRedisStatus.put(String.format(videoAppTypeStatusKeyFormat, appType, videoId), "1");
+                    activeStatusMap.put(videoId, 1);
+                }
+            }
+        }
+
+        // 异步更新缓存
+        ThreadPoolFactory.defaultPool().execute(() -> videoRedisTemplate.executePipelined(new SessionCallback<String>() {
+            @Override
+            public <A, B> String execute(RedisOperations<A, B> redisOperations) throws DataAccessException {
+                ValueOperations<String, String> operations = (ValueOperations<String, String>) redisOperations.opsForValue();
+                updateRedisStatus.forEach((key, value) -> operations.set(key, value, RandomUtils.nextInt(10, 15),
+                        TimeUnit.DAYS));
+                return null;
+            }
+        }));
+
+        return idList.stream()
+                .filter(id -> activeStatusMap.containsKey(id) && activeStatusMap.get(id) == 1)
+                .collect(Collectors.toList());
+
+    }
+
+}

+ 3 - 1
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/filter/strategy/RecommendStatusStrategy.java

@@ -36,7 +36,7 @@ public class RecommendStatusStrategy implements FilterStrategy {
     @Autowired
     private WxVideoStatusRepository wxVideoStatusRepository;
 
-    private String keyFormat = "video:recommend:status:%s";
+    private final String keyFormat = "video:recommend:status:%s";
 
     private static final int RECOMMEND_STATUS = -6;
 
@@ -90,9 +90,11 @@ public class RecommendStatusStrategy implements FilterStrategy {
             }
         }
 
+
         return param.getVideoIds().stream()
                 .filter(id -> recommendStatusMap.containsKey(id) && recommendStatusMap.get(id) == RECOMMEND_STATUS)
                 .collect(Collectors.toList());
+
     }
 
 }

+ 11 - 0
recommend-server-service/src/main/resources/application-dev.yml

@@ -57,6 +57,17 @@ spring:
         max-wait: -1
         max-idle: 8
         min-idle: 0
+  video-redis:
+    hostName: r-bp1ps6my7lzg8rdhwx682.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    timeout: 1000
+    lettuce:
+      pool:
+        max-active: 8
+        max-wait: -1
+        max-idle: 8
+        min-idle: 0
   data:
     mongodb:
       clusterHost: dds-bp1de4fc73029b241978.mongodb.rds.aliyuncs.com

+ 11 - 0
recommend-server-service/src/main/resources/application-pre.yml

@@ -57,6 +57,17 @@ spring:
         max-wait: -1
         max-idle: 8
         min-idle: 0
+  video-redis:
+    hostName: r-bp1f3341ec15a634301.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    timeout: 1000
+    lettuce:
+      pool:
+        max-active: 8
+        max-wait: -1
+        max-idle: 8
+        min-idle: 0
   data:
     mongodb:
       clusterHost: s-bp14ce206f81b754.mongodb.rds.aliyuncs.com

+ 11 - 0
recommend-server-service/src/main/resources/application-prod.yml

@@ -57,6 +57,17 @@ spring:
         max-wait: -1
         max-idle: 8
         min-idle: 0
+  video-redis:
+    hostName: r-bp1f3341ec15a634301.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    timeout: 1000
+    lettuce:
+      pool:
+        max-active: 8
+        max-wait: -1
+        max-idle: 8
+        min-idle: 0
   data:
     mongodb:
       clusterHost: s-bp14ce206f81b754.mongodb.rds.aliyuncs.com

+ 11 - 0
recommend-server-service/src/main/resources/application-test.yml

@@ -57,6 +57,17 @@ spring:
         max-wait: -1
         max-idle: 8
         min-idle: 0
+  video-redis:
+    hostName: r-bp1ps6my7lzg8rdhwx682.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    timeout: 1000
+    lettuce:
+      pool:
+        max-active: 8
+        max-wait: -1
+        max-idle: 8
+        min-idle: 0
   data:
     mongodb:
       clusterHost: dds-bp1de4fc73029b241978.mongodb.rds.aliyuncs.com