Sorted Set 操作
Redis Sorted Set 是有序集合,每个成员关联一个分数(score)。集合根据分数进行排序。
ZAdd - 添加有序集合成员
添加带分数的成员
vb
oRedis.ZAdd "mysortedset", 100, "member1"
oRedis.ZAdd "mysortedset", 200, "member2"
oRedis.ZAdd "mysortedset", 150, "member3"注意:
- 分数可以是整数或浮点数
- 相同分数的成员按字典序排序
- 如果成员已存在,会更新其分数
ZRange - 获取范围内的成员
获取所有成员(按分数升序)
vb
Dim vMembers As Variant
vMembers = oRedis.ZRange("mysortedset", 0, -1)
If IsArray(vMembers) Then
Dim i As Long
For i = 0 To UBound(vMembers)
Debug.Print vMembers(i)
Next
End If获取带分数的成员
vb
vMembers = oRedis.ZRange("mysortedset", 0, -1, True)
If IsArray(vMembers) Then
For i = 0 To UBound(vMembers) Step 2
If i + 1 <= UBound(vMembers) Then
Debug.Print vMembers(i) & ": " & vMembers(i + 1)
End If
Next
End If获取前 N 名
vb
' 获取前 3 名(分数最低的 3 个)
vMembers = oRedis.ZRange("mysortedset", 0, 2)获取最后 N 名
vb
' 获取最后 3 名(分数最高的 3 个)
vMembers = oRedis.ZRange("mysortedset", -3, -1)ZRem - 删除有序集合成员
vb
' 删除单个成员
oRedis.ZRem "mysortedset", "member1"
' 删除多个成员
oRedis.ZRem "mysortedset", "member2", "member3"ZCard - 获取有序集合成员数量
vb
Dim lCount As Long
lCount = oRedis.ZCard("mysortedset")
Debug.Print "有序集合成员数: " & lCount应用场景
1. 排行榜
vb
Sub Leaderboard()
Dim oRedis As New cRedisClient
If Not oRedis.Connect() Then Exit Sub
Dim sLeaderboard As String
sLeaderboard = "leaderboard"
' 添加玩家分数
oRedis.ZAdd sLeaderboard, 1000, "玩家A"
oRedis.ZAdd sLeaderboard, 1500, "玩家B"
oRedis.ZAdd sLeaderboard, 800, "玩家C"
oRedis.ZAdd sLeaderboard, 2000, "玩家D"
oRedis.ZAdd sLeaderboard, 1200, "玩家E"
' 获取排行榜(按分数升序)
Dim vRanking As Variant
vRanking = oRedis.ZRange(sLeaderboard, 0, -1)
Debug.Print "排行榜(升序):"
Dim i As Long
If IsArray(vRanking) Then
For i = 0 To UBound(vRanking)
Debug.Print " " & (i + 1) & ". " & vRanking(i)
Next
End If
' 获取排行榜(带分数)
vRanking = oRedis.ZRange(sLeaderboard, 0, -1, True)
Debug.Print vbCrLf & "排行榜(带分数):"
If IsArray(vRanking) Then
For i = 0 To UBound(vRanking) Step 2
If i + 1 <= UBound(vRanking) Then
Debug.Print " " & vRanking(i) & ": " & vRanking(i + 1) & " 分"
End If
Next
End If
' 获取前 3 名
vRanking = oRedis.ZRange(sLeaderboard, 0, 2, True)
Debug.Print vbCrLf & "前 3 名:"
If IsArray(vRanking) Then
For i = 0 To UBound(vRanking) Step 2
If i + 1 <= UBound(vRanking) Then
Debug.Print " 第 " & (i / 2 + 1) & " 名: " & vRanking(i) & " (" & vRanking(i + 1) & " 分)"
End If
Next
End If
' 更新玩家分数
oRedis.ZAdd sLeaderboard, 2500, "玩家A"
Debug.Print vbCrLf & "更新玩家A分数后:"
vRanking = oRedis.ZRange(sLeaderboard, -1, -1, True)
If IsArray(vRanking) Then
Debug.Print " 第一名: " & vRanking(0) & " (" & vRanking(1) & " 分)"
End If
oRedis.DisConnect
End Sub2. 时间轴
vb
Sub Timeline()
Dim oRedis As New cRedisClient
If Not oRedis.Connect() Then Exit Sub
Dim sTimeline As String
sTimeline = "timeline:events"
' 添加事件(使用时间戳作为分数)
oRedis.ZAdd sTimeline, 1640995200, "事件1: 项目启动"
oRedis.ZAdd sTimeline, 1640995800, "事件2: 需求分析"
oRedis.ZAdd sTimeline, 1640996400, "事件3: 设计完成"
oRedis.ZAdd sTimeline, 1640997000, "事件4: 开始开发"
oRedis.ZAdd sTimeline, 1640997600, "事件5: 测试阶段"
' 获取按时间排序的事件
Dim vEvents As Variant
vEvents = oRedis.ZRange(sTimeline, 0, -1, True)
Debug.Print "时间轴:"
Dim i As Long
If IsArray(vEvents) Then
For i = 0 To UBound(vEvents) Step 2
If i + 1 <= UBound(vEvents) Then
Dim lTimestamp As Long
lTimestamp = CLng(vEvents(i + 1))
Debug.Print " " & FormatDateTime(lTimestamp) & " - " & vEvents(i)
End If
Next
End If
oRedis.DisConnect
End Sub
Function FormatDateTime(ByVal lTimestamp As Long) As String
' 将 Unix 时间戳转换为日期时间字符串
Dim dtDate As Date
dtDate = DateAdd("s", lTimestamp, #1/1/1970#)
FormatDateTime = Format(dtDate, "yyyy-mm-dd hh:nn:ss")
End Function3. 延迟队列
vb
Sub DelayedQueue()
Dim oRedis As New cRedisClient
If Not oRedis.Connect() Then Exit Sub
Dim sQueue As String
sQueue = "queue:delayed"
' 添加任务(使用执行时间作为分数)
Dim lNow As Long
lNow = Timer ' 当前秒数(简化)
oRedis.ZAdd sQueue, lNow + 60, "任务1: 1分钟后执行"
oRedis.ZAdd sQueue, lNow + 120, "任务2: 2分钟后执行"
oRedis.ZAdd sQueue, lNow + 30, "任务3: 30秒后执行"
' 模拟时间流逝
Dim i As Long
For i = 1 To 5
lNow = Timer
' 获取到期的任务
Dim vTasks As Variant
vTasks = oRedis.ZRange(sQueue, 0, 0, True)
If IsArray(vTasks) And UBound(vTasks) >= 1 Then
Dim lTaskTime As Long
lTaskTime = CLng(vTasks(1))
If lTaskTime <= lNow Then
Debug.Print "执行任务: " & vTasks(0)
oRedis.ZRem sQueue, vTasks(0)
End If
End If
' 等待一秒
Application.Wait (Now + TimeValue("0:00:01"))
Next
oRedis.DisConnect
End Sub4. 热度排行
vb
Sub HotArticles()
Dim oRedis As New cRedisClient
If Not oRedis.Connect() Then Exit Sub
Dim sHotKey As String
sHotKey = "hot:articles"
' 模拟文章浏览量
oRedis.ZAdd sHotKey, 1000, "article:1"
oRedis.ZAdd sHotKey, 2500, "article:2"
oRedis.ZAdd sHotKey, 800, "article:3"
oRedis.ZAdd sHotKey, 3000, "article:4"
oRedis.ZAdd sHotKey, 1500, "article:5"
' 获取热门文章 TOP 10
Dim vHotArticles As Variant
vHotArticles = oRedis.ZRange(sHotKey, -10, -1, True)
Debug.Print "热门文章 TOP 10:"
Dim i As Long, lIndex As Long
lIndex = 1
If IsArray(vHotArticles) Then
For i = UBound(vHotArticles) To 0 Step -2
If i - 1 >= 0 Then
Debug.Print " " & lIndex & ". " & vHotArticles(i - 1) & " (" & vHotArticles(i) & " 浏览)"
lIndex = lIndex + 1
End If
Next
End If
' 文章被浏览,增加热度
Dim sArticle As String
sArticle = "article:1"
' 获取当前分数
Dim lCurrentScore As Long
lCurrentScore = CLng(oRedis.Get_(sArticle))
lCurrentScore = lCurrentScore + 1
' 更新分数
oRedis.ZAdd sHotKey, lCurrentScore, sArticle
Debug.Print vbCrLf & "文章 " & sArticle & " 浏览后热度更新"
oRedis.DisConnect
End Sub5. 优先级队列
vb
Sub PriorityQueue()
Dim oRedis As New cRedisClient
If Not oRedis.Connect() Then Exit Sub
Dim sQueue As String
sQueue = "queue:priority"
' 添加任务(使用优先级作为分数,优先级越高分数越小)
oRedis.ZAdd sQueue, 1, "紧急任务: 修复生产环境bug"
oRedis.ZAdd sQueue, 3, "普通任务: 编写文档"
oRedis.ZAdd sQueue, 2, "重要任务: 代码审查"
oRedis.ZAdd sQueue, 1, "紧急任务: 数据库维护"
' 获取最高优先级任务
Dim vTask As Variant
vTask = oRedis.ZRange(sQueue, 0, 0)
If IsArray(vTask) Then
Debug.Print "最高优先级任务: " & vTask(0)
End If
' 处理任务
Debug.Print vbCrLf & "处理顺序:"
While oRedis.ZCard(sQueue) > 0
vTask = oRedis.ZRange(sQueue, 0, 0)
If IsArray(vTask) Then
Debug.Print " " & vTask(0)
oRedis.ZRem sQueue, vTask(0)
End If
Wend
oRedis.DisConnect
End Sub6. 评分系统
vb
Sub RatingSystem()
Dim oRedis As New cRedisClient
If Not oRedis.Connect() Then Exit Sub
Dim sProductId As String
sProductId = "product:1001"
' 用户评分
oRedis.ZAdd sProductId & ":ratings", 5, "user:1"
oRedis.ZAdd sProductId & ":ratings", 4, "user:2"
oRedis.ZAdd sProductId & ":ratings", 5, "user:3"
oRedis.ZAdd sProductId & ":ratings", 3, "user:4"
oRedis.ZAdd sProductId & ":ratings", 4, "user:5"
' 获取所有评分
Dim vRatings As Variant
vRatings = oRedis.ZRange(sProductId & ":ratings", 0, -1, True)
Debug.Print "所有评分:"
Dim i As Long
Dim dSum As Double
dSum = 0
If IsArray(vRatings) Then
For i = 0 To UBound(vRatings) Step 2
If i + 1 <= UBound(vRatings) Then
Dim lRating As Long
lRating = CLng(vRatings(i + 1))
Debug.Print " " & vRatings(i) & ": " & lRating & " 星"
dSum = dSum + lRating
End If
Next
End If
' 计算平均评分
Dim lCount As Long
lCount = oRedis.ZCard(sProductId & ":ratings")
Dim dAverage As Double
dAverage = dSum / lCount
Debug.Print vbCrLf & "平均评分: " & Format(dAverage, "0.00") & " 星 (" & lCount & " 人评分)"
oRedis.DisConnect
End Sub完整示例
vb
Sub Example_SortedSets()
Dim oRedis As New cRedisClient
If Not oRedis.Connect() Then
Debug.Print "连接失败: " & oRedis.LastError
Exit Sub
End If
' 使用 Sorted Set 存储排行榜
oRedis.ZAdd "leaderboard", 1000, "玩家A"
oRedis.ZAdd "leaderboard", 1500, "玩家B"
oRedis.ZAdd "leaderboard", 800, "玩家C"
oRedis.ZAdd "leaderboard", 2000, "玩家D"
Debug.Print "排行榜(按分数升序):"
Dim vPlayers As Variant
vPlayers = oRedis.ZRange("leaderboard", 0, -1)
Dim i As Long
If IsArray(vPlayers) Then
For i = 0 To UBound(vPlayers)
Debug.Print " " & (i + 1) & ". " & vPlayers(i)
Next
End If
Debug.Print vbCrLf & "排行榜(带分数):"
vPlayers = oRedis.ZRange("leaderboard", 0, -1, True)
If IsArray(vPlayers) Then
For i = 0 To UBound(vPlayers) Step 2
If i + 1 <= UBound(vPlayers) Then
Debug.Print " " & vPlayers(i) & ": " & vPlayers(i + 1) & " 分"
End If
Next
End If
' 获取有序集合成员数量
Debug.Print vbCrLf & "玩家数量: " & oRedis.ZCard("leaderboard")
oRedis.DisConnect
End SubSorted Set 特性
- 有序:根据分数自动排序
- 唯一:成员唯一,但分数可以相同
- 可更新:可以更新成员的分数
- 范围查询:支持按分数范围查询
- 高性能:插入和查询都是 O(log N) 复杂度
使用建议
- 排行榜:使用分数存储评分,
ZRange获取排名 - 时间线:使用时间戳作为分数
- 优先级队列:使用优先级作为分数
- 范围查询:可以查询分数在特定范围内的成员