RAG项目Redis应用

用户所属组织标签缓存

  • 用户所属的标签是高频访问字段,所以在Redis中进行缓存
  • 使用List结构存储而不使用set,List底层是压缩列表+双向链表,内存紧凑读写快,set天然去重是要依赖哈希表的,计算哈希值解决哈希冲突效率不如List,而且Set存储是乱序的,List存储是按照存储的顺序的,是有一定的顺序的
  //标签分为所属组织标签和个人私有标签,其中组织所属标签是一对多的关系,也就是一个用户可以归属多个组织
  //所以数据结构采用List更加合适,因为有多个所以使用方法是rightPushAll(),orgTags是一个List.of,在这个转换成数组全部加入
  //rightPushAll有个问题是每次添加数据都是在追加,所以容易造成重复数据,所以在分配所属组织标签的时候要先删除key在添加数据
  redisTemplate.opsForList().rightPushAll(key, orgTags.toArray());

  //取值操作range从0到-1默认是取出从0索引到结尾的所有元素,Redis存储的是二进制数据,所以默认封装成Object对象,再通过map进行转换
  try {
            String key = USER_ORG_TAGS_KEY_PREFIX + username;
            List<Object> result = redisTemplate.opsForList().range(key, 0, -1);
            if (result != null && !result.isEmpty()) {
                return result.stream()
                        .map(obj -> (String) obj)
                        .toList();
            }
        } catch (Exception e) {
            logger.error("Failed to get organization tags for user: {}", username, e);
        }
        return null;

RedisCallback原生连接

  • 在 Redis 中,像 opsForValue/opsForHash 其实都是高级封装,Spring 帮忙把 java 对象转换 Redis 能识别的字节数组,但是会有少量的封装开销, 而且并不是所有的命令都有封装
  • RedisCallback 跳过 Spring 的封装直接拿到 RedisConnection 原生连接。RedisCallback 是一个函数式接口(只有一个抽象方法 doInRedis),必须实现这个唯一的抽象方法。直接显示重写 doInRedis 或者使用 Lambda 表达式都可以。
long uploadedCount = redisTemplate.execute(new RedisCallback<Long>() {
    @Override
    public Long doInRedis(RedisConnection connection) throws DataAccessException {
        // 统计 redisKey 对应位图中 1 的数量(已上传分片数)
        return connection.bitCount(redisKey.getBytes());
    }
});

// 等价于上面的 Hash 统计(Lambda 隐式实现)
Long hashFieldCount = redisTemplate.execute(connection -> {
    // 这里的代码就是 doInRedis 方法的逻辑,省略了方法声明和 @Override
    return connection.hLen("user:100".getBytes());
});

文件分片上传在 Redis 中缓存

  • Redis BitMap 是一个由二进制数组,每一位都是 0 和 1,分块的数对应偏移量下标, 1表示已上传, 0表示未上传
// 核心:查询 redisKey 对应位图中,下标为 chunkIndex 的位值(0=未上传,1=已上传)
boolean isUploaded = redisTemplate.opsForValue().getBit(redisKey, chunkIndex);

// 分片上传成功后,标记该分片为已上传(位值设为1)
redisTemplate.opsForValue().setBit(redisKey, chunkIndex, true);

//全部分片上传完成后,需要合并文件,此时用 bitCount 统计位图中 1 的数量,对比总分片数
long uploadedCount = redisTemplate.execute(new RedisCallback<Long>() {
    @Override
    public Long doInRedis(RedisConnection connection) throws DataAccessException {
        // 统计 redisKey 对应位图中 1 的数量(已上传分片数)
        return connection.bitCount(redisKey.getBytes());
    }
});
posted @ 2026-01-23 17:19  Huangyien  阅读(3)  评论(0)    收藏  举报