网站建设电商考试,社交系统开发,wordpress循环评论,旺道seo工具文章目录 1. set的基本介绍1.1. set底层结构之hash表的简单介绍1.2. 常用命令 2. 常见的业务场景2.1. 标签系统2.2. 社交网络好友关系 1. set的基本介绍
参考链接#xff1a;https://mp.weixin.qq.com/s/srkd73bS2n3mjIADLVg72A redis 的 set 数据结构是一个无序的集合#… 文章目录 1. set的基本介绍1.1. set底层结构之hash表的简单介绍1.2. 常用命令 2. 常见的业务场景2.1. 标签系统2.2. 社交网络好友关系 1. set的基本介绍
参考链接https://mp.weixin.qq.com/s/srkd73bS2n3mjIADLVg72A redis 的 set 数据结构是一个无序的集合可以存储不重复的元素。适合于多种应用场景尤其是在需要去重、快速查找和集合运算的场合。从上面的介绍可以看到set主要的特性为 无序性元素在set中没有特定的顺序 唯一性set中的元素是唯一的不能重复。 其中还有一个比较重要的特性就是高效性。因为redis 的 Set 数据结构是基于哈希表hash table实现的这也是为什么对元素的添加、删除和查找操作的时间复杂度都是 O(1) 的原因。
1.1. set底层结构之hash表的简单介绍
哈希函数哈希表使用哈希函数将元素映射到一个数组的索引中。通过这个索引我们可以快速定位到存储在该位置的元素。存储结构在 Redis 中Set 存储元素时会使用一个哈希表其键是元素的值值通常是一个指向该元素的指针。这样每个元素的插入、查找或删除操作都可以直接通过哈希表的索引进行。添加元素SADD当添加一个新元素时Redis 计算该元素的哈希值并根据这个哈希值找到相应的索引位置。如果该位置为空即没有相同的元素就将该元素插入数组中。这一过程的时间复杂度是 O(1)。删除元素SREM删除一个元素时Redis 同样计算该元素的哈希值并找到相应的索引位置。如果该元素存在就将其从哈希表中移除。这一过程也是 O(1)。查找元素SISMEMBER查找一个元素是否在集合中Redis 计算该元素的哈希值并通过该哈希值定位到对应的索引位置。如果该元素存在于该位置则返回 true如果不存在则返回 false。这一过程同样是 O(1)。 理论上的限制 尽管哈希表的平均时间复杂度是 O(1)在某些情况下哈希表可能会出现冲突即不同的元素计算出相同的哈希值。当发生冲突时多个元素可能会存储在同一个索引位置导致查找、插入和删除的性能下降。此时复杂度可能退化为 O(n)其中 n 是发生冲突的元素数量。然而Redis 使用了一些策略如动态扩容和链表/树结构来处理冲突来保持哈希表的性能使得在大多数情况下操作的时间复杂度仍然可以保持在 O(1)。
1.2. 常用命令
SADD key member [member ...]将一个或多个成员添加到集合中。
SREM key member [member ...]移除集合中的一个或多个成员。
SISMEMBER key member判断某个成员是否是集合中的成员。
SMEMBERS key返回集合中的所有成员。
SCARD key返回集合中成员的数量。
交集SINTER key1 [key2 ...]返回所有给定集合的交集。
并集SUNION key1 [key2 ...]返回所有给定集合的并集。
差集SDIFF key1 [key2 ...]返回第一个集合与其他集合的差集。SADD myset apple banana orange
SREM myset banana
SISMEMBER myset apple # 返回 1 (true)
SMEMBERS myset # 返回 [apple, orange]
SCARD myset # 返回 2SADD set1 a b c
SADD set2 b c d
SINTER set1 set2 # 返回 [b, c]
SUNION set1 set2 # 返回 [a, b, c, d]
SDIFF set1 set2 # 返回 [a]2. 常见的业务场景
一般业务场景的使用是会根据对应数据结构的特性来说明的
去重当需要存储一组唯一的用户 ID、标签或其他信息时可以使用 Set 来自动去重。例如存储用户的浏览历史确保每个用户的历史记录中没有重复的页面。【唯一性】社交网络在社交网络应用中可以使用 Set 来表示用户的好友关系。比如用户 A 的好友可以存储在 Set 中快速判断用户 B 是否是用户 A 的好友。【唯一性高效性】标签系统对于文章、商品等可以使用 Set 来存储相关标签方便进行标签查询和管理。【高效性】投票系统可以使用 Set 存储已经投票的用户 ID确保每个用户只能投一次票。【唯一性】实时分析在实时分析场景中可以使用 Set 来跟踪活跃用户、访问过的页面等。【高效性】
2.1. 标签系统
标签系统Set类型可用于存储和处理具有标签特性的数据如商品标签、文章分类标签等。 背景 在一个内容平台上用户可以给文章打上不同的标签系统需要根据标签过滤和推荐文章。 优势
快速查找使用Set可以快速判断一个元素是否属于某个集合。灵活的标签管理方便地添加和删除标签实现标签的灵活管理。集合运算通过集合运算如交集和并集可以轻松实现复杂的标签过滤逻辑。
代码实现
package mainimport (contextfmtgithub.com/go-redis/redis/v8
)var ctx context.Background()// Redis 客户端初始化
var rdb redis.NewClient(redis.Options{Addr: , // Redis 服务器地址Password: , // 密码DB: 0, // 使用默认 DB
})// 文章标签管理结构体
type ArticleTagManager struct{}// 给文章添加标签
func (atm *ArticleTagManager) AddTagToArticle(articleID string, tags []string) error {_, err : rdb.SAdd(ctx, article:articleID:tags, tags).Result()if err ! nil {return err}for _, tag : range tags {_, err : rdb.SAdd(ctx, global:tags:tag, article:articleID).Result()if err ! nil {return err}}log.Printf(Added tags %v to article %s\n, tags, articleID)return nil
}// 从文章中删除标签
func (atm *ArticleTagManager) RemoveTagFromArticle(articleID string, tag string) error {_, err : rdb.SRem(ctx, article:articleID:tags, tag).Result()if err ! nil {return err}log.Printf(Removed tag %s from article %s\n, tag, articleID)return nil
}// 获取文章的所有标签
func (atm *ArticleTagManager) GetTagsOfArticle(articleID string) ([]string, error) {tags, err : rdb.SMembers(ctx, article:articleID:tags).Result()if err ! nil {return nil, err}return tags, nil
}// 根据标签获取文章列表
func (atm *ArticleTagManager) GetArticlesByTag(tag string) ([]string, error) {articles, err : rdb.SMembers(ctx, global:tags:tag).Result()if err ! nil {return nil, err}return articles, nil
}// 获取文章的标签数量
func (atm *ArticleTagManager) GetTagCountOfArticle(articleID string) (int64, error) {count, err : rdb.SCard(ctx, article:articleID:tags).Result()if err ! nil {return 0, err}return count, nil
}// 获取某个标签的文章数量
func (atm *ArticleTagManager) GetArticleCountByTag(tag string) (int64, error) {count, err : rdb.SCard(ctx, global:tags:tag).Result()if err ! nil {return 0, err}return count, nil
}func main() {atm : ArticleTagManager{}// 为文章添加标签if err : atm.AddTagToArticle(1, []string{Golang, Redis}); err ! nil {log.Fatalf(Error adding tags: %v, err)}if err : atm.AddTagToArticle(2, []string{Python, Redis}); err ! nil {log.Fatalf(Error adding tags: %v, err)}if err : atm.AddTagToArticle(3, []string{Golang, Python}); err ! nil {log.Fatalf(Error adding tags: %v, err)}// 获取文章的所有标签if tags, err : atm.GetTagsOfArticle(1); err nil {fmt.Println(Tags for article 1:)for _, tag : range tags {fmt.Println(tag)}}// 根据标签获取文章列表if articles, err : atm.GetArticlesByTag(Golang); err nil {fmt.Println(Articles with tag Golang:)for _, article : range articles {fmt.Println(article)}}// 获取文章标签数量if count, err : atm.GetTagCountOfArticle(1); err nil {fmt.Printf(Article 1 has %d tags.\n, count)}// 获取某个标签的文章数量if count, err : atm.GetArticleCountByTag(Redis); err nil {fmt.Printf(Tag Redis has %d articles associated.\n, count)}// 测试完移除整个集合rdb.Del(ctx, article:1:tags)rdb.Del(ctx, article:2:tags)rdb.Del(ctx, article:3:tags)rdb.Del(ctx, global:tags:Golang)rdb.Del(ctx, global:tags:Redis)rdb.Del(ctx, global:tags:Python)
}运行结果
2.2. 社交网络好友关系
社交网络好友关系Set类型可以表示用户的好友列表支持快速好友关系测试和好友推荐。 背景 在一个社交网络应用中用户可以添加和删除好友系统需要管理用户的好友关系。 优势
唯一性保证好友列表中不会有重复的好友。快速关系测试快速判断两个用户是否互为好友。好友推荐利用集合运算如差集推荐可能认识的好友。
解决方案 使用Redis Set类型存储用户的好友集合实现好友关系的管理。 代码实现
package mainimport (contextfmtgithub.com/go-redis/redis/v8log
)var ctx context.Background()// Redis 客户端初始化
var rdb redis.NewClient(redis.Options{Addr: , // Redis 服务器地址Password: , // 密码DB: 0, // 使用默认 DB
})// 添加好友
func addFriend(userOneID string, userTwoID string) error {_, err : rdb.SAdd(ctx, user:userOneID:friends, userTwoID).Result()if err ! nil {return err}_, err rdb.SAdd(ctx, user:userTwoID:friends, userOneID).Result()return err
}// 判断是否是好友
func isFriend(userOneID string, userTwoID string) bool {return rdb.SIsMember(ctx, user:userOneID:friends, userTwoID).Val()
}// 获取用户的好友列表
func getFriendsOfUser(userID string) ([]string, error) {friends, err : rdb.SMembers(ctx, user:userID:friends).Result()return friends, err
}// 删除好友
func removeFriend(userOneID string, userTwoID string) error {_, err : rdb.SRem(ctx, user:userOneID:friends, userTwoID).Result()if err ! nil {return err}_, err rdb.SRem(ctx, user:userTwoID:friends, userOneID).Result()return err
}// 推荐可能认识的好友
func recommendFriends(userID string) ([]string, error) {// 获取用户的好友friends, err : getFriendsOfUser(userID)if err ! nil {return nil, err}// 如果没有好友则没有推荐if len(friends) 0 {return nil, nil}// 找到所有好友的好友以及去掉自己的好友和自己potentialFriends : make(map[string]struct{})for _, friendID : range friends {friendFriends, err : getFriendsOfUser(friendID)if err ! nil {return nil, err}for _, potentialFriend : range friendFriends {// 排除自己和直接好友if potentialFriend ! userID {potentialFriends[potentialFriend] struct{}{}}}}// 将推荐的好友转换为切片recommendations : []string{}for friend : range potentialFriends {// 确保不是已经存在的好友if !isFriend(userID, friend) {recommendations append(recommendations, friend)}}return recommendations, nil
}func main() {// 示例添加好友if err : addFriend(user1, user2); err ! nil {log.Fatalf(Error adding friend: %v, err)}// 示例检查好友关系if isFriend(user1, user2) {fmt.Println(user1 and user2 are friends.)}// 示例获取好友列表friends, err : getFriendsOfUser(user1)if err ! nil {log.Fatalf(Error getting friends: %v, err)}fmt.Println(Friends of user1:, friends)// 示例推荐可能认识的好友recommendations, err : recommendFriends(user1)if err ! nil {log.Fatalf(Error recommending friends: %v, err)}fmt.Println(Recommended friends for user1:, recommendations)// 示例删除好友if err : removeFriend(user1, user2); err ! nil {log.Fatalf(Error removing friend: %v, err)}
}注意事项
虽然Set是无序的但Redis会保持元素的插入顺序直到集合被重新排序。Set中的元素是唯一的任何尝试添加重复元素的操作都会无效。使用集合运算时需要注意结果集的大小因为它可能会影响性能。