redis key set (Data Structure Part)

Collection (set)

Storing a plurality of different elements.
Redis set disorderly way of storing a plurality of different elements.
The user can quickly ㏿ added to the collection element, the collection or remove elements from the inside may be set to a plurality of set of arithmetic operations such as calculation of union, intersection, and difference.
Here Insert Picture Description

Operating elements

Add elements, remove elements, check element exists, returns the size of the collection, and so on.

Adding elements

SADD key element [element ...]
to add one or more elements to which a given set, already present in the elements of the set are automatically ignored, command returns the number of elements newly added to the collection.

redis> SADD friends "peter"
(integer) 1
redis> SADD friends "jack" "tom" "john"
(integer) 3
redis> SADD friends "may" "tom"
(integer) 1

Command is the complexity of O (N), N is the number of elements added successfully.
Here Insert Picture Description

Remove elements

SREM key element [element ...]
removing one or more elements of the collection, not present in the elements of the collection are automatically ignored, command returns the number of elements is present and is removed.
redis> SREM friends "peter"

(integer) 1
redis> SREM friends "tom" "john"
(integer) 2

Command is the complexity of O (N), N is the number of elements to be removed.
Here Insert Picture Description

Checks if the given element exists in the set

SISMEMBER key element
checks whether the given element is present in the collection, a return exists; if the element is not present, or a given bond is absent, 0 is returned.

redis> SISMEMBER friends "peter"
(integer) 1
redis> SISMEMBER friends "li lei"
(integer) 0
redis> SISMEMBER NOT-EXISTS-KEY "element"
(integer) 0

Command is the complexity of O (1).
Here Insert Picture Description

Returns the size of the collection

SCARD key
returns the number of elements contained set (that is, the cardinality of the set).

redis> SCARD friends
(integer) 6
redis> SREM friends "peter" "jack" "tom"
(integer) 3
redis> SCARD friends
(integer) 3

Because Redis stores the set length, the complexity of the command is O (1).
Here Insert Picture Description

Returns all elements in the collection contained

SMEMBERS key
returns all elements in the collection contains.

redis> SMEMBERS friends
1) "jack"
2) "peter"
3) "may"
4) "tom"
5) "john"
6) "ben"

命令的复杂度为 O(N) ,N 为集合的大小。
当集合的基数比较大时,执行这个命令有可能会造成服务器阻塞,将来会介绍更好的方式来迭代集合中的元素。
Here Insert Picture Description

集合的无序性质
redis> SADD friends "peter" "jack" "tom" "john" 
"may" "ben"
(integer) 6
redis> SMEMBERS friends
1) "jack"
2) "peter"
3) "may"
4) "tom"
5) "john"
6) "ben"
redis> SADD another-friends "ben" "may" "john" 
"tom" "jack" "peter"
(integer) 6
redis> SMEMBERS another-friends
1) "may"
2) "ben"
3) "john"
4) "tom"
5) "jack"
6) "peter"

对于相同的一集元素,同一个集合命令可能会返回不同的 结果。
结论:不要使用集合来储存有序的数据。如果想要储存有序且重复的值,可以使用列表;如果想要储存有序且无重复的值,可以使用之后介绍的有序集合。

示例:赞、喜欢、Like、签到……

Here Insert Picture Description
除了微博的赞之外,网上还有很多作用类似的功能,比如豆瓣的 “喜欢”、Facebook 的“Like”、以及一些网站上的“签到”等等。
这些功能实际上都是一种投票功能,比如 “赞”就是投一票,而“取消赞”就是撤销自己的投票。
通过使用 Redis 的集合,我们也可以实现类似的投票功能。

投票功能的 API 及其实现

Here Insert Picture Description
这个投票程序的实现源码可以在 vote.py 看到。

vote.py
# encoding: utf-8

class Vote:

    def __init__(self, key, client):
        self.key = key
        self.client = client

    def cast(self, user):
        # 因为 SADD 命令会自动忽略已存在的元素
        # 所以我们无须在投票之前检查用户是否已经投票
        self.client.sadd(self.key, user)

    def undo(self, user):
        self.client.srem(self.key, user)

    def is_voted(self, user):
        if self.client.sismember(self.key, user):
            return True
        else:
            return False

    def voted_members(self):
        return self.client.smembers(self.key)
投票功能的使用示例
like = Vote('weibo::10086::like', client) # 记录 ID 为 10086 的微博的“赞”
like.cast('peter') # 'peter' 赞了这条微博
like.cast('john') # 'john' 赞了这条微博
like.cast('tom') # 'tom' 因为误操作而赞了这条微博
like.undo('tom') # 然后它通过“取消”按钮撤消了“赞”操作
like.is_voted('peter') # 返回 True ,因为 peter 已经赞过了
like.voted_members() # 返回 {'peter', 'john'} 
like.voted_count() # 返回 2
示例:打标签功能

Here Insert Picture Description
豆瓣允许你在标记一本书的同时,为 这本书添加标签,比如“Linux”、“系统 编程”、“计算机”、“C”、“编程”,等等。使用 Redis 的集合也可以实现这样的加标签功能。

打标签功能的 API 及其实现

Here Insert Picture Description
这个打标签程序的实现代码可以在 tag.py 看到。

tag.py
# encoding: utf-8

class Tag:

    def __init__(self, key, client):
        self.key = key
        self.client = client

    def add(self, *tags):
        self.client.sadd(self.key, *tags)

    def remove(self, *tags):
        self.client.srem(self.key, *tags)

    def is_include(self, tag):
        return self.client.sismember(self.key, tag)

    def get_all(self):
        return self.client.smembers(self.key)

    def count(self):
        return self.client.scard(self.key)
打标签功能的使用示例
# 创建一个集合键来保存书本的标签
book_tag = Tag('Linux System Programming :: Tag', client)
# 给书本打标签
book_tag.add('linux', 'system programming', 'c', 'windows')
# 获取书本的所有标签
book_tag. get_all()
# 移除指定的标签
book_tag.remove('windows')

Here Insert Picture Description

从集合里面随机地弹出一个元素

SPOP key
随机地从集合中移除并返回一个元素,复杂度为 O(1) 。

redis> SADD friends "peter" "jack" "tom" "john" "may" "ben"
(integer) 6
redis> SPOP friends
"may"
redis> SMEMBERS friends
1) "tom"
2) "john"
3) "jack"
4) "peter"
5) "ben"
从集合里面随机地返回元素

SRANDMEMBER key [count]
如果没有给定可选的 count 参数,那么命令随机地返回集合中的一个元素。
如果给定了 count 参数,那么:
• 当 count 为正数,并且少于集合基数 时,命令返回一个包含 count 个元素的数组,数组中的每个元素各不相同。如果 count 大于或等于集合基数,那么命令返回整个集合。
• 当 count 为负数时,命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为count 的绝对值。 和 SPOP 不同, SRANDMEMBER 不会移除被返回的元素。
命令的复杂度为 O(N),N 为被返回元素的数量。

SRANDMEMBER 的使用示例
redis> SADD friends "peter" "jack" "tom" "john" "may" "ben"
(integer) 1
redis> SRANDMEMBER friends # 随机地返回一个元素
"ben"
redis> SRANDMEMBER friends 3 # 随机地返回三个无重复的元素
1) "john"
2) "jack"
3) "peter"
redis> SRANDMEMBER friends -3 # 随机地返回三个可能有重复的元素
1) "may"
2) "peter"
3) "may"
示例:抽奖系统

Here Insert Picture Description
微博上的转发抽奖活动:每个参与者只需要进行转发,就有机会获得奖品。通过将参与抽奖的所有人都添加到一个集合里面,并使用SRANDMEMBER 命令来抽取获奖得主,我们也可以构建一个类似的抽奖功能。

抽奖程序的 API 及其实现

Here Insert Picture Description
这个抽象程序的实现代码可以在 loterry.py 找到。

lottery.py
# encoding: utf-8

class Lottery:

    def __init__(self, key, client):
        self.key = key
        self.client = client

    def add_player(self, *users):
        self.client.sadd(self.key, *users)

    def get_all_players(self):
        return self.client.smembers(self.key)

    def player_count(self):
        return self.client.scard(self.key)

    def draw(self, n):
        return self.client.srandmember(self.key, n)
抽奖程序的使用示例
# 创建一个赠送 Redis 书的抽奖活动
book_loterry('loterry::redis_book', client) 
# 不断地添加参与者
book_loterry.add_player('peter', 'jack', 'tom', 'may', ..., 'ben')
# 抽出三名幸运的获奖者
book_loterry.draw(3)

集合运算操作

计算并集、交集和差集。

差集运算

Here Insert Picture Description

交集运算

Here Insert Picture Description

并集运算

Here Insert Picture Description

示例:使用集合实现共同关注功能

Here Insert Picture Description
新浪微博的共同关注功能:当用 户访问另一个用户时,该功能会显示出两个用户关注了哪些相同的用户。如果我们把每个用户的关注对象都分别放到一个集合里面的话,那么我们可以使用 SINTER 或者 SINTERSTORE 命令来实现这个共同关注功能。
例如:
peter = {‘john’, ‘jack’, ‘may’}
ben = {‘john’, ‘jack’, ‘tom’}
那么 peter 和 ben 的共同关注为:
SINTER peter ben = {‘john’, ‘jack’}
还可以使用 SINTERSTORE 来避免重复计算。

示例:构建商品筛选功能

Here Insert Picture Description
京东上的一个手机筛选系统,用户可以根据品牌、价格、网 络、屏幕尺寸等条件,对商品进 行筛选。 对于每个条件的每个选项,我们可以使用一个集合来保存 该选项对应的所有商品,并通过在多个选项之间进行交集计算,从而达到筛选的目的。

示例:构建商品筛选功能

对于品牌条件,我们可以创建这样的集合,比如 apple = { ‘iPhone 5c’, ‘iPhons 5s’, …} ,而 samsung = {‘Galaxy S5’, ‘Galaxy S4’, …} ,诸如此类。 而对于价格条件,我们可以创建这样的集合,比如 price_2900_to_4099 = { ‘Galaxy S5’, ‘Galaxy S4’, …} ,以及 price_uppon_4100 = { ‘iPhone 5c’, ‘iPhone 5S’, …} ,诸如此类。
每当用户添加一个过滤选项时,我们就计算出所有被选中选项的交集,而交集的计算结果就是符合筛 选条件的商品。

示例:构建商品筛选功能

Here Insert Picture Description
ZINTER apple price_uppon_5200 unicom_wcdma'iPhone 5s 32G 'Of course, each filter should be calculated once the intersection, then ㏿ degree too slow, so we can pre-calculated, then the results are stored in a fixed place, such as:
ZINTERSTORE
the Apple & price_uppon_5200 & unicom_wcdma
the Apple unicom_wcdma price_uppon_5200
SMEMBER
the Apple & price_uppon_5200 & unicom_wcdma

Goods filter function to achieve its API

Here Insert Picture Description
This product screening function implementation code can be seen in item_filter.py.

#item_filter.py
# encoding: utf-8

class ItemFilter:

    def __init__(self, client):
        self.client = client
        self.options = set()

    def add_option(self, item_set):
        self.options.add(item_set)

    def result(self):
        return self.client.sinter(*self.options)

    def store_result(self, key):
        return self.client.sinterstore(key, *self.options)
Examples of the use of commodity filtering feature
# 创建一个筛选器
filter = ItemFilter(client)
# 只保留 Apple 公司的产品
filter.add_option(apple_product_set)
filter.result()
# 只保留 Apple 公司生产,并且售价 5200 块以上的商品
filter.add_option(price_uppon_5200_product_set)
filter.result()
# 储存起 Apple 公司生产的、售价 5200 块以上并且支持联通 WCDMA 网络的商品
filter.add_option(unicom_wcdma_product_set)
filter.store_result('apple&price_uppon_5200&unicom_wcdma')

review

Set may be stored in a disorderly manner in a plurality of different elements, and may perform additional element, deleting an element, all elements get operation and the like, as well as intersection, union, difference set operation and the like.
Here Insert Picture Description

Published 252 original articles · won praise 151 · views 10000 +

Guess you like

Origin blog.csdn.net/qq_39885372/article/details/104243520