在上一篇《Golang 操作 Redis:Hash 哈希数据类型操作用法 - go-redis 使用指南》文章中,我们介绍了如何使用 go-redis 操作 Redis 的 Hash 类型。这一篇文章将带领大家了解 Redis 的 Set 集合数据类型,并展示如何在 Golang 中使用 go-redis 进行相关操作。

👉 点击查看《go-redis使用指南》系列文章目录

在《go-redis使用指南》系列文章中,我们将详细介绍如何在 Golang 项目中使用 redis/go-redis 库与 Redis 进行交互。以下是该系列文章的全部内容:

  1. Golang 操作 Redis:快速上手 - go-redis 使用指南
  2. Golang 操作 Redis:连接设置与参数详解 - go-redis 使用指南
  3. Golang 操作 Redis:基础的字符串键值操作 - go-redis 使用指南
  4. Golang 操作 Redis:如何设置 key 的过期时间 - go-redis 使用指南
  5. Golang 操作 Redis:Hash 哈希数据类型操作用法 - go-redis 使用指南
  6. Golang 操作 Redis:Set 集合数据类型操作用法 - go-redis 使用指南
  7. Golang 操作 Redis:为 Hash 中的字段设置过期时间 - go-redis 使用指南
  8. Golang 操作 Redis:List 列表数据类型操作用法 - go-redis 使用指南
  9. Golang 操作 Redis:SortedSet 有序集合数据类型操作用法 - go-redis 使用指南
  10. Golang 操作 Redis:bitmap 数据类型操作用法 - go-redis 使用指南
  11. Golang 操作 Redis:事务处理操作用法 - go-redis 使用指南
  12. Golang 操作 Redis:地理空间数据类型操作用法 - go-redis 使用指南
  13. Golang 操作 Redis:HyperLogLog 操作用法 - go-redis 使用指南
  14. Golang 操作 Redis:Pipeline 操作用法 - go-redis 使用指南
  15. Golang 操作 Redis:PubSub发布订阅用法 - go-redis 使用指南
  16. Golang 操作 Redis:布隆过滤器(Bloom Filter)操作用法 - go-redis 使用指南
  17. Golang 操作 Redis:Cuckoo Filter操作用法 - go-redis 使用指南
  18. Golang 操作 Redis:Stream操作用法 - go-redis 使用指南
golang redis go-redis

Redis Set 集合介绍

Redis 的 Set 是一个无序的字符串集合。集合中的元素是唯一的,这意味着集合中不能有重复的数据。Sets 提供了一些强大而有用的操作,如求交集、并集和差集等。

使用场景如下:

  • 用户标签管理:可以用来存储用户的兴趣标签,方便快速查找共同兴趣的用户。
  • 唯一性保证:可以用来确保某个列表中不包含重复元素,如唯一的活动参与者。
  • 好友推荐:可以用来计算共同好友、推荐好友等社交场景。

在 Golang 中使用 go-redis 操作 Set 集合

下面我们将演示如何在 Golang 中操作 Redis 的 Set 集合。

初始化 go-redis 客户端

首先,我们需要初始化 go-redis 客户端:

package main

import (
    "context"
    "fmt"
    "github.com/redis/go-redis/v9"
)

var ctx = context.Background()

func main() {
    // 初始化 Redis 客户端
    rdb := redis.NewClient(&redis.Options{
        Addr: "localhost:6379", // Redis 服务器地址
        Password: "",           // 无密码
        DB: 0,                  // 使用默认数据库
    })

    // 在这里进行后续的操作
}

SAdd 添加元素 / SCard 获取元素数量

我们可以使用 SAdd 方法将元素添加到集合中,并使用 SCard 方法获取集合中的元素数量。

members := []interface{}{"hello", "world"}

rdb.SAdd(ctx, "myset", members...)
count, err := rdb.SCard(ctx, "myset").Result()
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println("The number of elements in set:", count)
}
  • SAdd 将 “hello” 和 “world” 添加到名为 “myset” 的集合中。
  • SCard 返回集合 “myset” 中元素的数量。

SMembers 获取集合中的所有成员

members, err := rdb.SMembers(ctx, "myset").Result()
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Members in set:", members)
}
  • SMembers 返回集合 “myset” 中的所有成员。

SUnion 计算并集 / SInter 计算交集

rdb.SAdd(ctx, "myset1", "a", "b", "c")
rdb.SAdd(ctx, "myset2", "b", "c", "d")

union, err := rdb.SUnion(ctx, "myset1", "myset2").Result()
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Union of sets:", union)
}

inter, err := rdb.SInter(ctx, "myset1", "myset2").Result()
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Intersection of sets:", inter)
}
  • SUnion 返回集合 “myset1” 和 “myset2” 的并集。
  • SInter 返回集合 “myset1” 和 “myset2” 的交集。

SDiff 计算集合的差集

diff, err := rdb.SDiff(ctx, "myset1", "myset2").Result()
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Difference of sets:", diff)
}
  • SDiff 返回集合 “myset1” 和 “myset2” 的差集,即 “myset1” 中存在但 “myset2” 中不存在的元素。

SIsMember 和 SMIsMember 检查一个或多个元素是否是集合的成员

isMember, err := rdb.SIsMember(ctx, "myset", "hello").Result()
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Is 'hello' a member of set:", isMember)
}

members := []interface{}{"hello", "world"}
isMembers, err := rdb.SMIsMember(ctx, "myset", members...).Result()
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Are 'hello' and 'world' members of set:", isMembers)
}
  • SIsMember 检查 “hello” 是否是集合 “myset” 的成员。
  • SMIsMember 检查 “hello” 和 “world” 是否是集合 “myset” 的成员。

SMove 将一个元素从一个集合移动到另一个集合

rdb.SAdd(ctx, "myset1", "hello")
rdb.SAdd(ctx, "myset2", "world")

moved, err := rdb.SMove(ctx, "myset1", "myset2", "hello").Result()
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Was 'hello' moved from myset1 to myset2:", moved)
}
  • SMove 将 “hello” 从集合 “myset1” 移动到集合 “myset2”。

SPop/SPopN 从集合中随机移除一个或多个元素

rdb.SAdd(ctx, "myset", "a", "b", "c")

pop, err := rdb.SPop(ctx, "myset").Result()
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Popped member:", pop)
}

pops, err := rdb.SPopN(ctx, "myset", 2).Result()
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Popped members:", pops)
}
  • SPop 从集合 “myset” 随机移除一个元素并返回该元素。
  • SPopN 从集合 “myset” 随机移除两个元素并返回这些元素。

SRandMember/SRandMemberN 从集合中随机获取一个或多个元素,但不移除它们

rdb.SAdd(ctx, "myset", "a", "b", "c")

randMember, err := rdb.SRandMember(ctx, "myset").Result()
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Random member:", randMember)
}

randMembers, err := rdb.SRandMemberN(ctx, "myset", 2).Result()
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Random members:", randMembers)
}
  • SRandMember 从集合 “myset” 中随机获取一个元素,但不移除它。
  • SRandMemberN 从集合 “myset” 中随机获取两个元素,但不移除它们。

SRem 从集合中移除一个或多个元素

rdb.SAdd(ctx, "myset", "a", "b", "c")

removed, err := rdb.SRem(ctx, "myset", "a").Result()
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Number of removed members:", removed)
}
  • SRem 从集合 “myset” 中移除元素 “a”。

SScan 增量迭代集合中的元素

在处理 Redis Set 集合数据类型时,有时候需要增量迭代集合中的元素以避免一次性获取所有元素带来的性能问题。增量迭代是一种高效的遍历数据集合的方法,特别适用于数据量较大的集合。与一次性获取所有数据不同,增量迭代可以分批次获取数据,降低内存和网络资源的消耗。

以下是使用 SScan 方法进行增量迭代,逐步获取集合中的元素的示例:

rdb.SAdd(ctx, "myset", "apple", "banana", "apricot", "blueberry", "grape")

var cursor uint64
// 循环迭代,直到游标值为 0
for {
    var members []string
    var err error
    members, cursor, err = rdb.SScan(ctx, "myset", cursor, "a*", 2).Result()
    if err != nil {
        fmt.Println("Error:", err)
        break
    }

    fmt.Println("Members:", members)

    // 如果游标值为 0,说明迭代结束
    if cursor == 0 {
        break
    }
}
  • SScan 增量迭代集合 “myset” 中的元素,每次返回一部分集合元素和一个新的游标。果游标值为 0,说明迭代结束,退出循环。
  • a* 设置 MATCH 参数,以匹配所有以 “a” 开头的元素。我们还设置 COUNT 为 2,表示每次扫描的数量为 2。

MATCH 参数允许你使用模式匹配来过滤集合中的元素。Redis 使用类似于 Unix shell 的通配符模式来匹配集合中的元素:

  • *:匹配任意数量的任意字符,包括空字符。
  • ?:匹配任何单个字符。
  • []:匹配括号内的任何单个字符。例如,[abc] 匹配字符 a、b 或 c。

SUnionStore / SInterStore 将多个集合的并集或交集存储到一个新的集合中

rdb.SAdd(ctx, "myset1", "a", "b")
rdb.SAdd(ctx, "myset2", "b", "c")

unionStore, err := rdb.SUnionStore(ctx, "unionset", "myset1", "myset2").Result()
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Number of members in union set:", unionStore)
}

interStore, err := rdb.SInterStore(ctx, "interset", "myset1", "myset2").Result()
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Number of members in intersection set:", interStore)
}
  • SUnionStore 将 “myset1” 和 “myset2” 的并集存储到新的集合 “unionset” 中。
  • SInterStore 将 “myset1” 和 “myset2” 的交集存储到新的集合 “interset” 中。

go-redis 设置 Set 集合的过期时间

Redis 的过期时间是为整个键设置的,包括键中的所有数据。因此,设置 Set 集合的过期时间实际上是设置整个集合键的过期时间。以下是如何使用 go-redis 设置集合的过期时间的代码示例:

package main

import (
    "context"
    "fmt"
    "github.com/redis/go-redis/v9"
    "time"
)

var ctx = context.Background()

func main() {
    rdb := redis.NewClient(&redis.Options{
        Addr: "localhost:6379",
    })

    // 测试连接
    _, err := rdb.Ping(ctx).Result()
    if err != nil {
        panic(err)
    }

    // 添加集合成员
    err = rdb.SAdd(ctx, "myset", "member1", "member2", "member3").Err()
    if err != nil {
        panic(err)
    }
    fmt.Println("Members added to set")

    // 设置集合的过期时间
    err = rdb.Expire(ctx, "myset", 10*time.Minute).Err()
    if err != nil {
        panic(err)
    }
    fmt.Println("Set expiration time for key myset to 10 minutes")

    // 检查集合的过期时间
    ttl, err := rdb.TTL(ctx, "myset").Result()
    if err != nil {
        panic(err)
    }
    fmt.Printf("Time to live for key myset is %v\n", ttl)
}

结论

在本文中,我们介绍了 Redis Set 集合的基本概念和常见操作,并展示了如何使用 go-redis 在 Golang 中进行这些操作。掌握这些知识可以帮助你在实际开发中更高效地使用 Redis 进行数据存储和处理。

希望这篇文章对你有所帮助!点击 go-redis 使用指南 可查看更多相关教程!


也可以看看