使用Redis缓存热词信息【一眼就能看懂-简单】

在电商场景中,通过 Redis 缓存热门检索商品关键词可以显著提升搜索性能和用户体验。以下是基于 Redis 的完整实现方案:

简单的直接上代码-一眼就能看懂

    private RedisTemplate<String, Object> redisTemplate;

    public Boolean saveHotKeyword(String keyword) {
        String key = "hot_keywords";

        try {

            // 检查关键词在有序集合中的分数。
            if (redisTemplate.opsForZSet().score(key, keyword) != null) {

                // 如果关键词存在,则调用 incrementScore 方法将分数加1
                redisTemplate.opsForZSet().incrementScore(key, keyword, 1);
            } else {

            // 如果关键词不存在于集合中,则调用 add 方法将其添加到集合中,并设置初始分数为 1.0
                redisTemplate.opsForZSet().add(key, keyword, 1.0);
            }

            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

稍微复杂点-本质一样-考虑的较多较详细点

1. 数据结构选择

1.1 关键词热度存储

使用 Sorted Set(有序集合) 存储关键词及其搜索频次:

  • Keyhot_keywords:{category_id}(可按商品分类区分)

  • Member:关键词(如 手机连衣裙

  • Score:搜索次数(实时更新)

操作示例

# 每次搜索时增加关键词的分数(搜索次数)
ZINCRBY hot_keywords:electronics 1 "智能手机"
1.2 关键词元数据缓存

使用 Hash 存储关键词的附加信息(如关联商品数、更新时间):

  • Keykeyword_metadata:{keyword}

  • Fieldproduct_count(关联商品数)、update_time(最后更新时间)

HSET keyword_metadata:智能手机 product_count 150 update_time 1717123200

2. 核心实现步骤

2.1 实时热度统计

在用户搜索时,异步更新关键词的热度:

// 示例:Java + Spring Boot
public void logSearchKeyword(String keyword, String categoryId) {
    // 1. 更新 Sorted Set 中的搜索频次
    redisTemplate.opsForZSet().incrementScore(
        "hot_keywords:" + categoryId, 
        keyword, 
        1
    );
    
    // 2. 异步更新关键词元数据(如关联商品数)
    CompletableFuture.runAsync(() -> {
        int productCount = productService.countProductsByKeyword(keyword);
        redisTemplate.opsForHash().put(
            "keyword_metadata:" + keyword,
            "product_count",
            String.valueOf(productCount)
        );
    });
}
2.2 定时生成热门关键词列表

每日凌晨生成当前热门关键词(避免频繁计算):

// 定时任务(Cron:每天0点执行)
@Scheduled(cron = "0 0 0 * * ?")
public void generateDailyHotKeywords() {
    // 1. 按分类获取前100热门关键词(按Score倒序)
    Set<String> categories = getProductCategories();
    for (String categoryId : categories) {
        String hotKey = "hot_keywords:" + categoryId;
        Set<ZSetOperations.TypedTuple<String>> topKeywords = 
            redisTemplate.opsForZSet().reverseRangeWithScores(hotKey, 0, 99);
        
        // 2. 将结果缓存到新Key(避免更新影响当前查询)
        String dailyHotKey = "daily_hot_keywords:" + categoryId + ":" + LocalDate.now();
        redisTemplate.opsForZSet().add(dailyHotKey, topKeywords);
        
        // 3. 设置过期时间(保留7天历史数据)
        redisTemplate.expire(dailyHotKey, 7, TimeUnit.DAYS);
        
        // 4. 重置当前热度计数器(可选)
        redisTemplate.delete(hotKey);
    }
}
2.3 缓存淘汰策略
  • 冷门关键词自动淘汰
    对 Sorted Set 中的关键词按以下规则清理:

    • 每周清理一次过去7天内无搜索的关键词:

      # 使用ZREMRANGEBYSCORE删除分数(搜索次数)为0的成员
      ZREMRANGEBYSCORE hot_keywords:electronics 0 0

    • 限制每个分类下关键词数量(如最多保留500个):

      # 保留分数最高的500个关键词,删除其他 
      ZREMRANGEBYRANK hot_keywords:electronics 0 -501


3. 查询热门关键词

3.1 获取实时热门关键词
public List<String> getRealTimeHotKeywords(String categoryId, int topN) {
    String key = "hot_keywords:" + categoryId;
    return redisTemplate.opsForZSet()
        .reverseRange(key, 0, topN - 1);
}
3.2 获取每日缓存的热门关键词
public List<String> getDailyHotKeywords(String categoryId, LocalDate date) {
    String key = "daily_hot_keywords:" + categoryId + ":" + date;
    return redisTemplate.opsForZSet()
        .reverseRange(key, 0, 99);
}

4. 进阶优化

4.1 热度衰减机制

为避免历史热搜长期占据榜单,可引入 时间衰减因子

  • 每天对热度值进行衰减(如乘以系数0.9):

    // Lua脚本实现原子衰减操作
    String script = 
        "local keywords = redis.call('ZRANGE', KEYS[1], 0, -1); " +
        "for _, kw in ipairs(keywords) do " +
        "   local score = redis.call('ZSCORE', KEYS[1], kw); " +
        "   redis.call('ZADD', KEYS[1], tonumber(score) * 0.9, kw); " +
        "end";
    redisTemplate.execute(new DefaultRedisScript<>(script), List.of("hot_keywords:electronics"));

4.2 防刷机制

防止恶意刷搜索量:

  • 对同一用户(或IP)的重复搜索进行去重:

    // 使用HyperLogLog统计独立用户数
    String userKey = "kw_users:" + keyword;
    redisTemplate.opsForHyperLogLog().add(userKey, userId);
    Long uniqueUsers = redisTemplate.opsForHyperLogLog().size(userKey);
    
    // 只有独立用户数达到阈值时才增加热度
    if (uniqueUsers >= MIN_UNIQUE_USERS) {
        redisTemplate.opsForZSet().incrementScore(hotKey, keyword, 1);
    }

4.3 多级缓存
  • 本地缓存(Caffeine):在应用层缓存TOP 10热门关键词,减少Redis访问。

  • 布隆过滤器:快速过滤不存在于热门列表中的关键词,避免无效查询。


5. 数据持久化

  • 同步到数据库:每日将热门关键词持久化到 MySQL 或 Elasticsearch,用于数据分析。

  • 备份机制:启用 Redis RDB/AOF 持久化,确保缓存数据不丢失。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值