Redis有序集合詳解
有序集合和集合類似,只是說它是有序的,和無序集合的主要區別在於每一個元素除了值之外,它還會多一個分數。分數是一個浮點數,在 Java 中是使用雙精度表示的,根據分數,Redis 就可以支援對分數從小到大或者從大到小的排序。
這裡和無序集合一樣,對於每一個元素都是唯一的,但是對於不同元素而言,它的分數可以一樣。元素也是 String 資料型別,也是一種基於 hash 的儲存結構。
集合是通過雜湊表實現的,所以新增、刪除、查詢的複雜度都是 0(1)。集合中最大的成員數為 2 的 32 次方減 1(40 多億個成員),有序集合的資料結構如圖所示。
有序集合是依賴 key 標示它是屬於哪個集合,依賴分數進行排序,所以值和分數是必須的,而實際上不僅可以對分數進行排序,在滿足一定的條件下,也可以對值進行排序。
Redis基礎命令
有序集合和無序集合的命令是接近的,只是在這些命令的基礎上,會增加對於排序的操作,這些是我們在使用的時候需要注意的細節。
下面講解這些常用的有序集合的部分命令。有些時候 Redis 藉助資料區間的表示方法來表示包含或者不包含,比如在數學的區間表示中,[2,5] 表示包含 2,但是不包含 5 的區間。
Redis有序集合的部分命令
在對有序集合、下標、區間的表示方法進行操作的時候,需要十分小心命令,注意它是操作分數還是值,稍有不慎就會出現問題。
這裡命令比較多,也有些命令比較難使用,在使用的時候,務必要小心,不過好在我們使用 zset 的頻率並不是太高,下面是測試結果——有序集合命令展示。
spring-data-redis對有序集合的封裝
在 Spring 中使用 Redis 的有序集合,需要注意的是 Spring 對 Redis 有序集合的元素的值和分數的範圍(Range)和限制(Limit)進行了封裝,在演示如何使用 Spring 操作有序集合前要進一步瞭解它的封裝。
先介紹一個主要的介面——TypedTuple,它不是一個普通的介面,而一個內部介面,它是 org.springframework.data.redis.core.ZSetOperations 介面的內部介面,它定義了兩個方法,程式碼如下所示。
public interface ZSetOperations<K,V>{
......
public interface TypedTuple<V> extends Comparable<TypedTuple<V>< {
V getValue();
Double getScore();
}
......
}
這裡的 getValue() 是獲取值,而 getScore() 是獲取分數,但是它只是一個介面,而不是一個實現類。spring-data-redis 提供了一個預設的實現類—— DefaultTypedTuple,同樣它會實現 TypedTuple 介面,在預設的情況下 Spring 就會把帶有分數的有序集合的值和分數封裝到這個類中,這樣就可以通過這個類物件讀取對應的值和分數了。
Spring 不僅對有序集合元素封裝,而且對範圍也進行了封裝,方便使用。它是使用介面 org.springframework.data.redis.connection.RedisZSetCommands 下的內部類 Range 進行封裝的,它有一個靜態的 range() 方法,使用它就可以生成一個 Range 物件了,只是要清楚 Range 物件的幾個方法才行,為此我們來看看下面的虛擬碼。
//設定大於等於min
public Range gte(Object min)
//設定大於min
public Range gt(Object min)
//設定小於等於max
public Range lte(Object max)
//設定小於max
public Range lt(Object max)
這 4 個方法就是最常用的範圍方法。下面討論一下限制,它是介面 org.springframework.data.redis.connection.RedisZSetCommands 下的內部類,它是一個簡單的 POJO,它存在兩個屬性,它們的 getter 和 setter 方法,如下面的程式碼所示。
// ......
public interface RedisZSetCommands {
// ......
public class Limit {
int offset;
int count;
//setter和getter方法
}
//......
}
通過屬性的名稱很容易知道:offset 代表從第幾個開始擷取,而 count 代表限制返回的總數量。
通過 Spring 操作有序集合
我們討論了 spring-data-redis 專案對有序集合的封裝。在測試程式碼前,要把 RedisTemplate 的 keySerializer 和 valueSerializer 屬性都修改為字串序列化器 StringRedisSerializer,測試程式碼如下所示。
public static void testZset() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"applicationContext.xml");
RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);
// Spring提供介面 TypedTuple操作有序集合
Set<TypedTuple> set1 = new HashSet<TypedTuple>();
Set<TypedTuple> set2 = new HashSet<TypedTuple>();
int j = 9;
for (int i = 1; i <= 9; i++) {
j--;
// 計算分數和值
Double score1 = Double.valueOf(i);
String value1 = "x" + i;
Double score2 = Double.valueOf(j);
String value2 = j % 2 == 1 ? "y" + j : "x" + j;
// 使用 Spring 提供的預設 TypedTuple--DefaultTypedTuple
TypedTuple typedTuple1 = new DefaultTypedTuple(value1, score1);
set1.add(typedTuple1);
TypedTuple typedTuple2 = new DefaultTypedTuple(value2, score2);
set2.add(typedTuple2);
}
// 將元素插入有序集合zset1
redisTemplate.opsForZSet().add("zset1", set1);
redisTemplate.opsForZSet().add("zset2", set2);
// 統計總數
Long size = null;
size = redisTemplate.opsForZSet().zCard("set1");
// 計分數為score,那麼下面的方法就是求 3<=score<=6的元素
size = redisTemplate.opsForZSet().count("zset1", 3, 6);
Set set = null;
// 從下標一開始擷取5個元素,但是不返回分數,每一個元索是String
set = redisTemplate.opsForZSet().range("zset1", 1, 5);
printSet(set);
// 擷取集合所有元素,並且對集合按分數排序,並返回分數,每一個元素是TypedTuple
set = redisTemplate.opsForZSet().rangeWithScores("zset1", 0, -1);
printTypedTuple(set);
// 將zset1和zset2兩個集合的交集放入集合inter_zset
size = redisTemplate.opsForZSet().intersectAndStore("zset1", "zset2","inter_zset");
// 區間
Range range = Range.range();
range.lt("x8");// 小於
range.gt("x1"); // 大於
set = redisTemplate.opsForZSet().rangeByLex("zset1", range);
printSet(set);
range.lte("x8"); // 小於等於
range.gte("xl"); // 大於等於
set = redisTemplate.opsForZSet().rangeByLex("zset1", range);
printSet(set);
// 限制返回個數
Limit limit = Limit.limit();
// 限制返回個數
limit.count(4);
// 限制從第五個開始擷取
limit.offset(5);
// 求區間內的元素,並限制返回4條
set = redisTemplate.opsForZSet().rangeByLex("zset1", range, limit);
printSet(set);
// 求排行,排名第1返回0,第2返回1
Long rank = redisTemplate.opsForZSet().rank("zset1", "x4");
System.err.println("rank = " + rank);
// 刪除元素,返回刪除個數
size = redisTemplate.opsForZSet().remove("zset1", "x5", "x6");
System.err.println("delete = " + size);
// 按照排行刪除從0開始算起,這裡將刪除第排名第2和第3的元素
size = redisTemplate.opsForZSet().removeRange("zset2", 1, 2);
// 獲取所有集合的元素和分數,以-1代表全部元素
set = redisTemplate.opsForZSet().rangeWithScores("zset2", 0, -1);
printTypedTuple(set);
// 刪除指定的元素
size = redisTemplate.opsForZSet().remove("zset2", "y5", "y3");
System.err.println(size);
// 給集合中的一個元素的分數加上11
Double dbl = redisTemplate.opsForZSet().incrementScore("zset1", "x1",11);
redisTemplate.opsForZSet().removeRangeByScore("zset1", 1, 2);
set = redisTemplate.opsForZSet().reverseRangeWithScores("zset2", 1, 10);
printTypedTuple(set);
}
/**
* 列印TypedTuple集合
* @param set
* -- Set<TypedTuple>
*/
public static void printTypedTuple(Set<TypedTuple> set) {
if (set != null && set.isEmpty()) {
return;
}
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
TypedTuple val = (TypedTuple) iterator.next();
System.err.print("{value = " + val.getValue() + ", score = "
+ val.getScore() + "}\n");
}
}
/**
* 列印普通集合
* @param set普通集合
*/
public static void printSet(Set set) {
if (set != null && set.isEmpty()) {
return;
}
Iterator iterator = set.iterator();
while (iterator .hasNext()) {
Object val = iterator.next();
System. out.print (val +"\t");
}
System.out.println();
}
上面的程式碼演示了大部分 Spring 對有序集合的操作,並給出了比較清晰的註釋,大家認真思考之後就能熟悉如何通過 Spring 操作有序集合了。
相關文章
- Redis 有序集合(zset)命令詳解Redis
- redis有序集合Redis
- Redis有序集合原理Redis
- Redis有序集合物件Redis物件
- Redis有序集合操作Redis
- Redis有序集合命令Redis
- Redis有序集合學習Redis
- Redis物件——有序集合(ZSet)Redis物件
- Redis雜湊與有序集合Redis
- redis學習之有序集合Redis
- php操作redis,有序集合zsetPHPRedis
- redis 有序集合(sorted set)(redis學習七)Redis
- 《Redis實戰》筆記-Redis的有序集合Redis筆記
- 【Redis實戰】有序集合型別Redis型別
- Redis 入門指南九:Redis 有序集合(sorted set)Redis
- Python&Redis 無序集合set、有序集合zset操作PythonRedis
- redis有序集合實現實時排名Redis
- 《閒扯Redis十一》Redis 有序集合物件底層實現Redis物件
- [Redis 系列]redis 學習四,set 集合,hash 雜湊,zset 有序集合初步認知Redis
- 【Redis 系列】redis 學習四,set 集合,hash 雜湊,zset 有序集合初步認知Redis
- 使用Redis的有序集合實現排行榜功能Redis
- 使用 Redis 有序集合實現 IP 歸屬地查詢Redis
- Redis五大資料型別之 Zset(有序集合)Redis大資料資料型別
- Python–Redis實戰:第三章:Redis命令:第五節:有序集合PythonRedis
- redis之有序集合型別(Zset)——排行榜的實現Redis型別
- redis——集合,有序,慢查詢, pipline與事務, bitmap ,HyperLogLog geoRedis
- redis~有序集合處理ip範圍的查詢問題Redis
- Kotlin——集合詳解Kotlin
- (免費領取紅包封面)[Redis 系列]redis 學習四,set 集合,hash 雜湊,zset 有序集合初步認知Redis
- (免費領取紅包封面)【Redis 系列】redis 學習四,set 集合,hash 雜湊,zset 有序集合初步認知Redis
- Java集合詳解(二)Java
- Java集合詳解(三)Java
- Redis詳解Redis
- PHP+Redis 有序集合實現 24 小時排行榜實時更新PHPRedis
- 面試官:Redis中有序集合的內部實現方式是什麼?面試Redis
- Java集合詳解(一):全面理解Java集合Java
- Redis 設計與實現 10:五大資料型別之有序集合Redis大資料資料型別
- java基礎詳解-集合Java