Alice52 / database

ddf13ad8d4be76a80a336418b5cf5727bf6e3059
gitee.com
MIT License
0 stars 0 forks source link

[redis] multi sort #61

Closed Alice52 closed 3 years ago

Alice52 commented 3 years ago
  1. Alice52/database#62

redis zset multi column sort

  1. 分数降序+耗时升序: score type is int[32 bit], time is microseconds is also int type

    • ^: 与0异或值不变
    • 比如 64bit = 16bit[score desc] + 32bit[avg pk time asc] + 16bit[pk count asc]
    • score {desc-Y} + avg {asc-N-翻转} + count {asc-N-翻转}: 值大则分大
    • ^: 与0异或大小会被颠倒, 因此优先判断每个标准会被0异或几
  2. (score << 32) ^(INT.MAX_VALUE - microseconds)

    /**
     * There are 64 bit in Long. Here is a sample of rank score: <br>
     * 64bit = 16bit[score desc] + 32bit[avg pk time asc] + 16bit[pk count asc]
     *
     * @param score
     * @param attendCount
     * @param totalTime
     * @return
     */
    private static Long calculateRoundRankScore(Integer score, Integer attendCount, Integer totalTime) {
    
        long virtualScore = ((long)score) << 32;
        int countDesc = attendCount == 0 ? 0: (Integer.MAX_VALUE - totalTime / attendCount);
        return ((virtualScore ^ countDesc) << 16) ^ (1000 - attendCount);
    }
    
    public static void main(String[] args) {
    
        // 10   5  50   -- 5
        System.out.println(calculateRoundRankScore(10, 5, 50));
        // 100  5  50   -- 2
        System.out.println(calculateRoundRankScore(100, 5, 50));
        // 100  6  50   -- 1
        System.out.println(calculateRoundRankScore(100, 6, 50));
        // 100  5  60   -- 4
        System.out.println(calculateRoundRankScore(100, 5, 60));
        // 100  6  60   -- 3
        System.out.println(calculateRoundRankScore(100, 6, 60));
        // 1000 x  xx   -- -1
        System.out.println(calculateRoundRankScore(1000, 60, 6024));
    }
  3. redis zset 数据结构: zadd, zrevrange, zrevrank, zincrby

     # 1. 设置玩家分数: O(log(N))
     # zadd 排行榜名称 分数 玩家标识
     zadd lb 89 user1
     zadd lb 95 user2
     zadd lb 95 user3
    
     # 2. 查看玩家分数: O(1)
     # zscore 排行榜名称 玩家标识
     zscore lb user2
    
     # 3. 按名次查看排行榜: O(log(N)+M)
     # zrevrange 排行榜名称 起始位置 结束位置 [withscores]
     zrevrange lb 0 -1 withscores
    
     # 4. 查看玩家的排名: O(log(N))
     # zrevrank 排行榜名称 玩家标识
     zrevrank lb user3 #0
    
     # 5. 增减玩家分数: O(log(N)), 没有的话默认为0
     # zincrby 排行榜名称 分数增量 玩家标识
     zincrby lb 6 user4
    
     # 6. zrem: O(log(N))
     # zrem 排行榜名称 玩家标识
     zrem lb user4
    
     # 7. 删除排行榜
     del lb
  4. 遇到的问题

    • 分值计算公式 + redis 用量考虑
    • 离职员工不显示: 定时任务 + 提交时该组离职员工移除
    • 如果数据量超大[big key问题打满网卡+慢查询], 可以考虑对 key 进行 hash[将数据分开存放]
    • 遇到泛型擦除问题: Set 但是得到的是 Set 原因是我们项目中配置的 redisTemplate<string, Object> 会被redis 反序列化[Jackson2JsonRedisSerializer]是根据长度转换为 Integer 或者 Long
      if (len <= 9) {
          int i = this._textBuffer.contentsAsInt(this._numberNegative);
          this._numberInt = i;
          this._numTypesValid = 1;
      } else if (len <= 18) {     
          long l = this._textBuffer.contentsAsLong(this._numberNegative);   
          // ...
      } else {
          this._parseSlowInt(expType);
      }

redis maintain top N record

  1. zadd + ZREMRANGEBYRANK set 0 -51