spring redis 实现排行榜

2 篇文章 0 订阅
1 篇文章 0 订阅

https://docs.spring.io/spring-data/redis/docs/current/api/
org.springframework.data.redis.core.SetOperations 核心方法解析

add(K key, V... values)

Add given values to set at key. 插入数据

	// 不存在则添加,存在则添加失败
	@Nullable
    Boolean addIfAbsent(K key, V value, double score);


randomMember(K key)
Get random element from set at key. 获取set 中一个随机值

public static final String SCORE_RANK = "score_rank";

    public void testTank(){
        Set<ZSetOperations.TypedTuple<String>> tuples = new HashSet<>(16384);

        long start = System.currentTimeMillis();

        for (int i = 0; i < 10000; i++) {
            DefaultTypedTuple<String> tuple = new DefaultTypedTuple<>("ZHANG SAN" + i,  1D + i);
            tuples.add(tuple);
        }
        long loopEnd = System.currentTimeMillis();
        log.info("loop time:{}", loopEnd - start);
        Long num = stringRedisTemplate.opsForZSet().add(SCORE_RANK, tuples);
        log.info("add time:{}", System.currentTimeMillis() - loopEnd);
        log.info("default num:{}", num);

        // 获取前十名:
        Set<String> set = stringRedisTemplate.opsForZSet().reverseRange(SCORE_RANK, 0, 10);
        log.info("top 10:{}", set);

        Set<ZSetOperations.TypedTuple<String>> rangeWithScores = stringRedisTemplate.opsForZSet().reverseRangeWithScores(SCORE_RANK, 0, 6);
        log.info("reverseRangeWithScores:{}", rangeWithScores);

        Set<String> rangeByScores = stringRedisTemplate.opsForZSet().reverseRangeByScore(SCORE_RANK, 9990D, 10000D);
        log.info("reverseRangeByScore:{}", rangeByScores);

    }

import com.alibaba.fastjson.JSONObject;
import com.wm.learn.demoone.redis.RankingList;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.Set;

@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = DemoOneApplication.class)
class DemoOneApplicationTests {

    @Autowired
    RankingList rankingList;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Test
    void contextLoads() {
        rankingList.testTank();
    }

    /**
     * 如果不存在则添加,存在则添加失败
     */
    @Test
    void addIfAbsent() {
        String zhangsanV = "ZHANG SAN-11";
        Boolean zhangsan1 = stringRedisTemplate.opsForZSet()
                .addIfAbsent(RankingList.SCORE_RANK, zhangsanV, 100d);
        log.info("1zhangsan1:{}", zhangsan1);
        zhangsan1 = stringRedisTemplate.opsForZSet()
                .addIfAbsent(RankingList.SCORE_RANK, zhangsanV, 100d);
        log.info("2zhangsan1:{}", zhangsan1);
        // 1zhang_san1:true
        // 2zhang_san1:false
    }
    /**
     * 1、根据value 添加值
     * 2、删除值
     * 3、
     */
    @Test
    void incrementScore() {
        String zhangsanV1 = "ZHANG SAN-11";
        String zhangsanV2 = "ZHANG SAN-12";
        // 原来100 加上 100 = 200
        Double zhangsanScore = stringRedisTemplate.opsForZSet()
                .incrementScore(RankingList.SCORE_RANK, zhangsanV1, 100d);
        log.info("zhangsanScore:{}", zhangsanScore);
        // removeNum 删除成功结果,只有一个是存在,所以删除成功1个
        Long removeNum = stringRedisTemplate.opsForZSet()
                .remove(RankingList.SCORE_RANK, zhangsanV1, zhangsanV2);
        log.info("zhangsan remove num:{}", removeNum);
        // zhangsanScore:200.0
        // zhangsan remove num:1
    }

    /**
     * randomMember(K key)
     * Get random element from set at key.
     */
    @Test
    public void randomMember(){
        String randomMember = stringRedisTemplate.opsForZSet().randomMember(RankingList.SCORE_RANK);
        log.info("randomMember:{}", randomMember);
    }

    /**
     * 获取值
     */
    @Test
    public void get(){
        String obj = "ZHANG SAN1";
        // 个人分数
        Long rankListNum = stringRedisTemplate.opsForZSet().reverseRank(RankingList.SCORE_RANK, obj);
        log.info("{} reverseRank:{}", obj, rankListNum);
        // 个人分数
        Double score = stringRedisTemplate.opsForZSet().score(RankingList.SCORE_RANK, obj);
        log.info("{} score:{}", obj, score);
        // 逆序,从大到小,通过排名区间获取列表值和分数集合
        Set<ZSetOperations.TypedTuple<String>> reverseTuples = stringRedisTemplate.opsForZSet().reverseRangeWithScores(RankingList.SCORE_RANK, 0, 1);
        log.info("reverseRangeWithScores:{}", JSONObject.toJSONString(reverseTuples));
        // 正序,从小到大,通过排名区间获取列表值和分数集合
        Set<ZSetOperations.TypedTuple<String>> tuples = stringRedisTemplate.opsForZSet().rangeWithScores(RankingList.SCORE_RANK, 0, 1);
        log.info("rangeWithScores:{}", JSONObject.toJSONString(tuples));
        // 获取score为0-5的人,正序
        Set<String> rankSet = stringRedisTemplate.opsForZSet().rangeByScore(RankingList.SCORE_RANK, 0, 5);
        log.info("rangeByScore:{}", rankSet);
        // 获取score为0-5的人,逆序
        Set<String> reverseRankSet = stringRedisTemplate.opsForZSet().reverseRangeByScore(RankingList.SCORE_RANK, 0, 5);
        log.info("reverseRangeByScore:{}", reverseRankSet);

        // ZHANG SAN1 reverseRank:9998
        // ZHANG SAN1 score:2.0
        // reverseRangeWithScores:[{"score":99980.0,"value":"ZHANG SAN9997"},{"score":10000.0,"value":"ZHANG SAN9999"}]
        // rangeWithScores:[{"score":1.0,"value":"ZHANG SAN0"},{"score":2.0,"value":"ZHANG SAN1"}]
        // rangeByScore:[ZHANG SAN0, ZHANG SAN1, ZHANG SAN2, ZHANG SAN3, ZHANG SAN4]
        // reverseRangeByScore:[ZHANG SAN4, ZHANG SAN3, ZHANG SAN2, ZHANG SAN1, ZHANG SAN0]
    }

    @Test
    public void count(){
        // key min最小score, max 最大score, 统计分数之间有多少人
        Long count = stringRedisTemplate.opsForZSet().count(RankingList.SCORE_RANK, 10D, 20D);
        log.info("count:{}", count);
        // 统计集合总数
        Long allNum = stringRedisTemplate.opsForZSet().zCard(RankingList.SCORE_RANK);
        log.info("zCard:{}", allNum);
        // count:11
        // zCard:10000
    }

    @Test
    public void remove(){
        Set<ZSetOperations.TypedTuple<String>> tuples = stringRedisTemplate.opsForZSet().rangeByScoreWithScores(RankingList.SCORE_RANK, 0, 10);
        log.info("rangeByScoreWithScores.before:{}", JSONObject.toJSONString(tuples));
        // 删除某个值
        Long removeNum = stringRedisTemplate.opsForZSet().remove(RankingList.SCORE_RANK, "ZHANG SAN1");
        log.info("remove:{}", removeNum);
        // 正序,删除某个排序范围数据
        Long removeRangeNum = stringRedisTemplate.opsForZSet().removeRange(RankingList.SCORE_RANK, 0, 1);
        log.info("removeRange:{}", removeRangeNum);
        // 删除某个分数范围数据
        Long removeRangeByScoreNum = stringRedisTemplate.opsForZSet().removeRangeByScore(RankingList.SCORE_RANK, 2, 3);
        log.info("removeRangeByScore:{}", removeRangeByScoreNum);
        Set<ZSetOperations.TypedTuple<String>> tuplesNext = stringRedisTemplate.opsForZSet().rangeByScoreWithScores(RankingList.SCORE_RANK, 0, 10);
        log.info("rangeByScoreWithScores.tuplesNext:{}", JSONObject.toJSONString(tuplesNext));

//        rangeByScoreWithScores.before:[{"score":1.0,"value":"ZHANG SAN0"},{"score":2.0,"value":"ZHANG SAN1"},{"score":3.0,"value":"ZHANG SAN2"},{"score":4.0,"value":"ZHANG SAN3"},{"score":5.0,"value":"ZHANG SAN4"},{"score":6.0,"value":"ZHANG SAN5"},{"score":7.0,"value":"ZHANG SAN6"},{"score":8.0,"value":"ZHANG SAN7"},{"score":9.0,"value":"ZHANG SAN8"},{"score":10.0,"value":"ZHANG SAN9"}]
//        remove:1
//        removeRange:2
//        removeRangeByScore:0
//        rangeByScoreWithScores.tuplesNext:[{"score":4.0,"value":"ZHANG SAN3"},{"score":5.0,"value":"ZHANG SAN4"},{"score":6.0,"value":"ZHANG SAN5"},{"score":7.0,"value":"ZHANG SAN6"},{"score":8.0,"value":"ZHANG SAN7"},{"score":9.0,"value":"ZHANG SAN8"},{"score":10.0,"value":"ZHANG SAN9"}]

    }
    
}

实际使用场景中score 的生成方式需要多加考虑,如:同一个score 的排序问题

但凡所书,皆为来日留以回忆,反思

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值