电子商务网站建设与管理期末考试,瑜伽 网站模板,商业设计网站有哪些,手游推广平台哪个好一、Redis中的数据结构 任务描述 本关任务#xff1a;启动 Redis 客户端并创建一些值。 相关知识 为了完成本关任务#xff0c;你需要掌握#xff1a;1#xff0e;Redis简介#xff0c;2#xff0e;快速安装Redis与Python#xff0c;3#xff0e;Redis数据结构简介。 R…一、Redis中的数据结构 任务描述 本关任务启动 Redis 客户端并创建一些值。 相关知识 为了完成本关任务你需要掌握1Redis简介2快速安装Redis与Python3Redis数据结构简介。 Redis简介 Redis 是一个速度非常快的非关系型数据库non-relational database它可以存储键key和五种不同类型的值value之间的映射mapping可基于内存存储亦可持久化到硬盘的日志型Key-Value 数据库。 Redis与其他数据库的对比 如果你使用过关系型数据库例如Mysql那么你肯定写过关联两张表数据的查询语句。而 Redis 属于 NoSQL它不使用表也不会预定义数据模式或强制用户对 Redis 的各种数据进行关联。 NoSQLNot Only SQL 意指“不仅仅是SQL”其泛指非关系型数据库主要分为四类键值Key-Value存储数据库列存储数据库文档型数据库图形Graph数据库。 Redis 也经常与高性能键值缓存服务器 memcached 做比较两者均可用于存储键值映射性能相差也甚少但 Redis 能存储除普通字符串值之外的四种数据结构而 memcached 只能存储普通的字符串值。这些不同使得 Redis 能够解决更为广泛的问题而且既能作为主数据库使用也可以作为辅助数据库使用。 0我们通过一张表来对比常用的数据库与缓存服务器 名称类型数据存储选项查询类型附加功能Redis基于内存的非关系型数据库字符串、列表、集合、哈希、有序集合针对数据类型有专属命令另有批量操作和不完全的事务支持发布与订阅、复制、持久化、脚本扩展memcached基于内存的键值缓存键值映射创建、读取、更新、删除等多线程支持MySQL关系型数据库数据表、视图等查询、插入、更新、删除、内置函数、自定义存储过程等支持 ACID 性质、复制等MongoDB基于硬盘的非关系型文档存储数据库无 schema 的 BSON 文档创建、读取、更新、删除、条件查询等复制、分片、空间索引等 Redis的特性 由于 Redis 是内存型数据库在使用之前就要考虑当服务器被关闭时服务器存储的数据是否能保留。Redis 拥有两种不同形式的持久化方法都可以用紧凑的格式将数据写入硬盘 RDB 持久化 在指定的时间间隔内生成数据集的时间点快照AOF 持久化 记录服务器执行的所有写操作命令新命令会被追加到文件的末尾在服务器启动时通过重新执行这些命令还原数据集 除此之外为了扩展 Redis 的读性能并为 Redis 提供故障转移支持Redis 实现了主从复制特性 执行复制的从服务器连接主服务器 接收主服务器发送的初始副本接收主服务器执行的所有写命令在从服务器上执行所有写命令实时更新数据库读命令可以向任意一个从服务器发送 快速安装 Redis docker-compose部署redis Redis数据结构简介 Redis 的五种数据结构分别是 字符串STRING列表LIST集合SET哈希HASH有序集合ZSET ZSET 可以说是 Redis 特有的数据结构我们会在之后的实训中详细介绍它在本实训中我们只简要介绍他们的功能和小部分命令。他们的存储的值如下 结构类型存储的值STRING字符串、整数或浮点数LIST一个链表上面的每个节点都是一个字符串SET包含若干个字符串的无序集合且集合中的元素都是唯一的HASH包含键值对的无序散列表ZSET成员中的字符串与分值的有序映射其排序由分值决定 在安装完 Redis 并启动了 redis-server 后我们可以使用 redis-cli 控制台与 Redis 进行交互其启动方式是在终端中输入 redis-cli 其会默认连接本机 6379 端口启动的 Redis 服务器接下俩你可以使用它来体验 Redis 各种数据结构和其命令的使用。 Redis中的字符串 STRING 拥有一些和其他键值存储相似的命令比如 GET获取值SET设置值DEL删除值等例如 $ redis-cli
redis-cli 127.0.0.1:6379 set hello redis
OK
redis-cli 127.0.0.1:6379 get hello
redis
redis-cli 127.0.0.1:6379 del hello
(integer) 1
redis-cli 127.0.0.1:6379 get hello
(nil) 其中 SET 命令的第一个参数是键Key第二个参数是值Value尝试获取不存在的键时会得到一个 nil Redis中的列表 就像前面所说的Redis 中的列表是一个“链表”这和大多数编程语言相似。所以他们的操作也十分相似 LPUSH 命令可用于将元素推入列表的左侧RPUSH 命令可将元素推入列表的右侧LPOP 和 RPOP 就分别从列表的左侧和右侧弹出元素LINDEX 可以获取指定位置上的元素LRANGE 可以获取指定范围的全部元素 我们通过 redis-cli 来亲自体验 redis 127.0.0.1:6379 rpush testlist item
(integer) 1
redis 127.0.0.1:6379 rpush testlist item2
(integer) 2
redis 127.0.0.1:6379 rpush testlist item
(integer) 3
redis 127.0.0.1:6379 lrange testlist 0 -1
1) item
2) item2
3) item
redis 127.0.0.1:6379 lindex testlist 1
item2
redis 127.0.0.1:6379 lpop testlist
item
redis 127.0.0.1:6379 lrange testlist 0 -1
1) item2
2) item 我们可以看出在列表中元素可以重复出现。在后续的实训中我们还会介绍更多列表命令现在我们先来了解以下 Redis 中的集合。 Redis中的集合 集合和列表的区别就在于列表可以存储多个相同的字符串而集合通过散列表来保证存储的字符串都是各不相同的这些散列表只有键而没有对应的值。 由于集合是无序的所以我们只能通过统一的 SADD 命令将元素添加到集合中SREM 命令将元素从集合中移除。你还可以通过 SMEMBERS 命令获取到集合中的所有元素SISMEMBER 命令来判断一个元素是否已存在在集合中 redis 127.0.0.1:6379 sadd testset item
(integer) 1
redis 127.0.0.1:6379 sadd testset item2
(integer) 1
redis 127.0.0.1:6379 sadd testset item
(integer) 0
redis 127.0.0.1:6379 smembers testset
1) item
2) item2
redis 127.0.0.1:6379 sismember testset item3
(integer) 0
redis 127.0.0.1:6379 sismember testset item
(integer) 1
redis 127.0.0.1:6379 srem testset item2
(integer) 1
redis 127.0.0.1:6379 srem testset item2
(integer) 0
redis 127.0.0.1:6379 smembers testset
1) item 上面示例的集合中包含的元素少所以执行 SMEMBERS 命令没有问题一旦集合中包含的元素非常多时SMEMBERS 命令的执行速度会很慢所以要谨慎的使用这个命令。 Redis中的哈希 哈希可以存储多个键值对之间的映射。和字符串一样哈希存储的值既可以是字符串又可以是数字值并且可以对数字值进行自增/自减操作。 哈希就像是一个缩小版的 Redis有一系列命令对哈希进行插入、获取、删除 HSET key field value设置哈希字段的值HGET key field获取哈希字段的值HDEL key field删除哈希字段HEXISTS key field检查哈希字段是否存在HKEYS key获取哈希的所有字段HVALS key获取哈希的所有值HGETALL key获取哈希的所有字段和值HLEN key获取哈希的字段数量HMSET key field1 value1 [field2 value2 ]设置多个哈希字段HMGET key field1 [field2]获取多个哈希字段的 redis 127.0.0.1:6379 hset testhash key1 value1
(integer) 1
redis 127.0.0.1:6379 hset testhash key2 value2
(integer) 1
redis 127.0.0.1:6379 hset testhash key1 newvalue
(integer) 0
redis 127.0.0.1:6379 hgetall testhash
1) key1
2) newvalue
3) key2
4) value2
redis 127.0.0.1:6379 hdel testhash key2
(integer) 1
redis 127.0.0.1:6379 hget testhash key1
newvalue
redis 127.0.0.1:6379 hgetall testhash
1) key1
2) newvalue 其中 hset 用于插入元素 第一个参数为该哈希的键名如果该哈希不存在则创建一个第二个参数为哈希中的域名 如果不存在则创建该域并与第三个参数的值进行映射如果存在则使用第三个参数更新该域的值 第三个参数为哈希中的值hgetall 会获取到该哈希的所有域-值对hget 用于获取哈希中的某一个域hdel 用户删除哈希中的某一个域 Redis中的有序集合 有序集合和哈希一样也是存储键值对。 只是有序集合的键被称为成员member每个成员都是唯一的有序集合的值则被称为分值score这个分值必须为浮点数。所以有序集合既可以通过成员访问元素也可以通过分值来排序元素。 我们可以通过 ZADD 命令将带有指定分值的成员添加到有序集合中ZRANGE 命令根据分值有序排列后的集合获取到指定范围的元素ZRANGEBYSCORE 命令获取指定分值范围内的元素ZREM 命令从有序集合中删除指定成员 redis 127.0.0.1:6379 zadd testzset 100 member1
(integer) 1
redis 127.0.0.1:6379 zadd testzset 200 member0
(integer) 1
redis 127.0.0.1:6379 zrange testzset 0 -1 withscores
1) member1
2) 100
3) member0
4) 200
redis 127.0.0.1:6379 zrangebyscore testzset 0 150 withscores
1) member1
2) 100
redis 127.0.0.1:6379 zrem testzset member1
(integer) 1
redis 127.0.0.1:6379 zrange testzset 0 -1 withscores
1) member0
2) 200 编程要求 根据提示打开命令行启动 Redis 客户端并创建一些值 使用默认配置后台启动 Redis 服务器启动 Redis 客户端 redis-cli设置字符串 键为 hello值为 redis设置列表键为 educoder-list 从列表左侧推入元素 hello从列表右侧推入元素 educoder从列表右侧推入元素 bye从列表右侧弹出一个元素设置集合键为 educoder-set 添加元素 c添加元素 python添加元素 redis删除元素 c设置哈希键为 educoder-hash 添加键python值为language添加键ruby值为language添加键: redis值为database删除键 ruby设置有序列表键为 educoder-zset 添加成员 jack分值为 200添加成员 rose分值为 400添加成员 lee分值为 100 redis-cli
set hello redis
LPUSH educoder-list hello
RPUSH educoder-list educoder
RPUSH educoder-list bye
RPOP educoder-list
sadd educoder-set c
sadd educoder-set python
sadd educoder-set redis
srem educoder-set c
hset educoder-hash python language
hset educoder-hash ruby language
hset educoder-hash redis database
hdel educoder-hash ruby
zadd educoder-zset 200 jack
zadd educoder-zset 400 rose
zadd educoder-zset 100 lee
二、使用 Python 与 Redis 交互 任务描述 本关任务使用 Python 编写程序与 Redis 交互。 相关知识 为了完成本关任务你需要掌握1如何使用 Python 连接 Redis2通过客户端对 Redis 的数据进行操作。 如何使用 Python 连接 Redis 如果你在上一关中已经使用 easy_install 包安装了 redis 包那么你现在连接 Redis 就很简单了可以使用以下两种方法 方法1 # 导入 redis 模块
import redis
# 创建 redis 客户端
conn redis.Redis()
...
# 使用完资源之后删除客户端 conn
del conn 方法2 # 导入 redis 模块
import redis
# 创建连接池
pool redis.ConnectionPool(host127.0.0.1, port6379, decode_responsesTrue)
# 创建客户端并连接到 Redis
r redis.Redis(connection_poolpool) 两种方法的对比如下 方法 1需要在使用完该客户端后手动删除客户端以避免创建多个连接方法 2 使用了连接池总揽多个客户端与服务端的连接不需要手动删除客户端同时有效的减少多个客户端连接的损耗 所以我们在实际开发中使用第二种方法较多。 在创建了客户端之后你就可以使用 coon 或 r 这个客户端来进行 Redis 操作了。 通过客户端对 Redis 的数据进行操作 通过客户端对 Redis 的数据进行操作和第一关直接在 Redis 中的操作命令基本相同。只是在客户端中操作如下要在命令前加上客户端的名字和.假设使用方法2创建客户端r # 使用 SET 命令设置一个字符串键
r.set(test, hello)
# 显示字符串键 test 的值
print(r.get(test)) 编程要求 根据提示在右侧Begin-End区域补充代码实现使用 Python 编写程序与 Redis 交互 使用方法2创建客户端r1连接到 Redis 设置下表中的两个字符串键 键值test1hellotest2Redis #!/usr/bin/env python
#-*- coding:utf-8 -*-
import redis
def write_redis():#********* Begin *********#r1 redis.Redis(hostlocalhost, port6379, db0)# 设置键值对r1.set(test1, hello)r1.set(test2, Redis)#********* End *********#三、使用PythonRedis实现文章投票网站后端功能 任务描述 本关任务编写一个简化版文章投票网站的后端处理逻辑。 相关知识 第一关中我们对 Redis 提供的五种数据结构有了基本的了解这一关我们学习如何使用这些数据结构来解决实际问题。 大多数网站都提供了对新闻、文章或者问答进行投票的功能并根据文章的发布时间/投票数量进行排序。本关卡中我们将使用 Redis 构建简单的文字投票及排序功能。 为了完成本关任务你需要掌握1实现投票功能2创建文章数据3对文章进行排序。 实现投票功能 实现投票功能要注重文章的时效性与投票的公平性所以需要给投票功能加上一些约束条件 文章发布满一个星期后不再允许用户对该文章投票一个用户对一篇文章只能投一次票 所以我们需要使用 一个有序集合 time存储文章的发布时间一个集合 voted:*存储已投票用户名单 其中 * 是被投票文章的 ID一个有序集合 score存储文章的得票数 # 定义一个常量表示一周的秒数
ONE_WEEK_IN_SECONDS 7 * 24 * 60 * 60# 定义一个函数处理用户对文章的投票
def article_vote(r, user_id, article_id):# 使用 time.time() 获取当前时间# 减去一周的秒数从而获取一周前的Unix时间cutoff time.time() - ONE_WEEK_IN_SECONDS# 检查文章的发布时间是否在一周前# 如果是那么不允许投票直接返回if r.zscore(time, article_id) cutoff:return# 尝试将用户添加到已经投票的用户集合中# 如果用户是第一次投票那么 sadd 方法会返回 1# 如果用户已经投过票那么 sadd 方法会返回 0if r.sadd(voted: article_id, user_id):# 如果用户是第一次投票那么增加文章的得分r.zincrby(score, article_id, 1) 在这段代码中我们使用了Redis的有序集合zset和集合set数据类型。zscore方法用于获取有序集合中元素的分数sadd方法用于向集合中添加元素zincrby方法用于增加有序集合中元素的分数 当用户尝试投票时使用 ZSCORE 命令读取 time 有序集合得到这篇文章的发布时间再判断文章的发布时间是否超过一周。ZSCORE 命令的语法如下 r.zscore(key, member) key 是有序集合的键名member 是有序集合中的某个成员 若未超过则使用 SADD 命令尝试将用户追加到这篇文章的已投票用户名单中如果添加成功则说明该用户未投过票。SADD 命令的语法是 r.sadd(key, member) key 是集合的键名member 是要添加进集合的元素 由于集合中的元素是唯一的所以sadd函数会根据member是否存在在集合中做出不同返回 若该元素不存在在集合中返回 True若该元素已存在在集合中返回 False 所以返回为 True 时使用 ZINCRBY 命令来为文章的投票数加 1。 zincrby 函数语法如下 r.zincrby(key, member, increment) key 是有序集合的键名member 是有序集合中要增加分值的成员increment 是要增加的分值 创建文章数据 现在系统中还缺少文章数据所以我们要提供一个创建文章的函数并把文章数据存储到 Redis 中。创建文章的步骤如下 创建新的文章 ID将文章作者加入到这篇文章的已投票用户名单中存储文章详细信息到 Redis 中将文章的发布时间和初始投票数加入到 time 和 score 两个有序集合中 r.expire(key, seconds) key 要设置过期时间的键名seconds 过期时间的长度单位秒 这里我们要设置的时间是一周所以我们可以使用上面定义好的全局变量 ONE_WEEK_IN_SECONDS。 在这段代码中我们使用了Redis的字符串string、集合set、哈希hash和有序集合zset数据类型。incr命令用于对字符串值进行自增操作sadd命令用于向集合中添加元素expire命令用于设置键的过期时间hmset命令用于向哈希中添加多个字段和值zadd命令用于向有序集合中添加元素。 将文章作者加入已投票用户名单中和之前一样这里不再赘述但在这里我们需要为这个已投票用户名单设置一个过期时间让它在一周后到期后自动删除减少 Redis 的内存消耗。为键设置过期时间的命令是 r.expire(key, seconds) key 要设置过期时间的键名seconds 过期时间的长度单位秒 这里我们要设置的时间是一周所以我们可以使用上面定义好的全局变量 ONE_WEEK_IN_SECONDS。 接下来要存储文章详细信息了前面介绍过 hset 可以执行单个字段域的设置这里我们使用 hmset 一次性设置多个字段域其语法如下 r.hmset(key, {field: value, [field: value ...]}) 我们可以使用 Python 的散列来一次性存储多个字段域到 Redis只需要将整个散列当作 key 对应的值通过 hmset 函数设置进去就行。 最后将初始投票数和创建时间设置到 score 和 time 中都可以通过 ZADD 命令来实现 我们可以使用 Python 的散列来一次性存储多个字段域到 Redis只需要将整个散列当作 key 对应的值通过 hmset 函数设置进去就行。 最后将初始投票数和创建时间设置到 score 和 time 中都可以通过 ZADD 命令来实现 r.zadd(key, member, score) key 有序集合的键名member 要加入有序集合的成员score 该成员的分值 这里需要注意的是因为该篇文章的作者已经被加入到该文章已投票用户名单中为了保持数据一致性我们需要将文章的初始投票数设为 1。 对文章进行排序 实现了文章投票和创建文章功能接下来我们就需要将评分最高的文章和最新发布的文章从 Redis 中取出了。 首先我们要根据排序方式的不同 按评分排序则从 score 有序集合中取出一定量的文章 IDscore有序集合存放文章ID和对应的投票数按时间排序则从 time 有序集合中取出一定量的文章 IDtime有序集合存放文章ID和对应的发布时间 构成一个有序文章信息列表每个元素都 使用 HGETALL 命令取出每篇文章的全部信息 def get_articles(r, start, end, orderscore):# 使用Redis的ZREVRANGE命令获取有序集合中的一系列元素。这些元素是按照分数从高到低排序的范围是从start到endids r.zrevrange(order, start, end)# 创建一个空列表用于存储获取到的文章articles []# 遍历获取到的元素IDfor id in ids:# 使用Redis的HGETALL命令获取哈希中的所有字段和值这些字段和值构成了文章的数据article_data r.hgetall(id)# 将元素ID添加到文章数据中article_data[id] id# 将文章数据添加到列表中articles.append(article_data)# 返回文章列表return articles 这里因为需要对有序集合进行排序所以我们在取出文章 ID 时需要使用到 ZREVRANGE 命令以分值从大到小的排序方式取出文章 ID。ZREVRANGE 命令的语法是 r.zrevrange(key, start, stop) key 有序集合的键名start 开始的数组下标stop 结束的数组下标 得到多个文章 ID 后我们还需要根据每一个文章 ID 获取文章的全部信息这时就需要使用到 HGETALL 命令它的语法如下 r.hgetall(key) key 哈希的键名 我们取出文章的全部信息后还为文章信息添加了一个字段 id。这是因为文章 ID 在 Redis 中是作为键名存储的不在值当中所以我们需要附加这个字段到文章信息中。 实现这些方法后我们大体实现了一个文章投票的后端处理逻辑能够为文章投票并能根据投票结果改变文章的排序情况。 编程要求 根据提示在右侧Begin-End区域补充代码完成简化版文章投票网站的后端处理逻辑 在 article_vote() 函数中 该方法作用是对文章投票参数说明 rRedis 客户端 user_id投票用户 article_id被投票文章 已提供一周前 Unix 时间戳存放在变量 cutoff当满足以下条件时为文章投一票 该文章发布不超过一周 该用户没有为该文章投过票 在 post_article() 函数中 该方法作用是创建文章参数说明 rRedis 客户端 user发布用户 title文章标题 link文章链接 已提供 article_id新文章 ID voted新文章已投票用户名单存储键名 article新文章详细信息存储键名 now文章创建时间 按照 ID 递增的顺序依次创建文章保证发布文章的用户不能给自己的文章投票文章在发布一周后删除已投票用户名单存储文章详细信息到 Redis 中包括字段 文章标题 文章链接 发布用户 存储文章的发布时间和初始投票数 初始投票数为 1 在 get_articles() 函数中 该方法作用是对文章进行排序参数说明 rRedis 客户端start从排序为 start 的文章开始获取 end到排序为 end 的文章结束获取 order排序方式分为两种 time按时间排序score按投票数排序 已提供文章信息空列表articles 实现按时间/投票数排序 将排序后的文章及其全部信息组成一个列表 按照不同排序规则取出排序在参数提供的区间范围内的文章及每篇文章的全部信息包括文章 ID #!/usr/bin/env python
#-*- coding:utf-8 -*-import timeONE_WEEK_IN_SECONDS 7 * 24 * 60 * 60def article_vote(r, user_id, article_id):cutoff time.time() - ONE_WEEK_IN_SECONDS# 请在下面完成要求的功能#********* Begin *********#if r.zscore(time, article_id) cutoff:returnif r.sadd(voted: article_id, user_id):r.zincrby(score, article_id, 1)#********* End *********#def post_article(r, user, title, link):article_id str(r.incr(article))voted voted: article_idnow time.time()article article: article_id# 将发布文章的用户添加到投票集合中并设置投票集合的过期时间为一周r.sadd(voted, user)r.expire(voted, ONE_WEEK_IN_SECONDS)# 将文章的标题、链接和发布者添加到哈希中并将文章添加到得分和时间有序集合中r.hmset(article, {title: title,link: link,poster: user,})r.zadd(score, article_id, 1)r.zadd(time, article_id, now)return article_iddef get_articles(r, start, end, orderscore):articles []# 请在下面完成要求的功能#********* Begin *********#ids r.zrevrange(order, start, end)for id in ids:article_data r.hgetall(id)article_data[id] idarticles.append(article_data)#********* End *********#return articles