使用Python+Redis实现文章投票网站后端功能
1.实现投票功能,2.创建文章数据,3.对文章进行排序。
实现投票功能
实现投票功能,要注重文章的时效性与投票的公平性,所以需要给投票功能加上一些约束条件:
- 文章发布满一个星期后,不再允许用户对该文章投票
- 一个用户对一篇文章只能投一次票
所以我们需要使用:
- 一个有序集合
time,存储文章的发布时间 - 一个集合
voted:*,存储已投票用户名单- 其中
*是被投票文章的ID
- 其中
- 一个有序集合
score,存储文章的得票数
ONE_WEEK_IN_SECONDS = 7 * 24 * 60 * 60def article_vote(r, user_id, article_id):# 使用 time.time() 获取当前时间# 减去一周的秒数,从而获取一周前的Unix时间cutoff = time.time() - ONE_WEEK_IN_SECONDSif r.zscore('time', article_id) < cutoff:returnif r.sadd('voted:' + article_id, user_id):r.zincrby('score', article_id, 1)
当用户尝试投票时,使用 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两个有序集合中
def post_article(r, user, title, link):# 创建新的文章ID,使用一个整数计数器对 article 键执行自增# 如果该键不存在,article 的值会先被初始化为 0# 然后再执行自增命令article_id = str(r.incr('article'))voted = 'voted:' + article_idr.sadd(voted, user)r.expire(voted, ONE_WEEK_IN_SECONDS)now = time.time()article = 'article:' + article_idr.hmset(article, {'title': title,'link': link,'poster': user,})r.zadd('score', article_id, 1)r.zadd('time', article_id, now)return article_id
将文章作者加入已投票用户名单中和之前一样,这里不再赘述,但在这里我们需要为这个已投票用户名单设置一个过期时间,让它在一周后(到期后)自动删除,减少 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 命令来实现:
r.zadd(key, member, score)
key:有序集合的键名member:要加入有序集合的成员score:该成员的分值
这里需要注意的是,因为该篇文章的作者已经被加入到该文章已投票用户名单中,为了保持数据一致性,我们需要将文章的初始投票数设为 1。
对文章进行排序
实现了文章投票和创建文章功能,接下来我们就需要将评分最高的文章和最新发布的文章从 Redis 中取出了。
-
首先我们要根据排序方式的不同:
- 按评分排序,则从
score有序集合中取出一定量的文章ID(score有序集合存放文章ID和对应的投票数) - 按时间排序,则从
time有序集合中取出一定量的文章ID(time有序集合存放文章ID和对应的发布时间)
- 按评分排序,则从
-
构成一个有序文章信息列表,每个元素都:
- 使用
HGETALL命令,取出每篇文章的全部信息
- 使用
def get_articles(r, start, end, order='score'):ids = r.zrevrange(order, start, end)articles = []for id in ids:article_data = r.hgetall(id)article_data['id'] = idarticles.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()函数中:- 该方法作用是:对文章投票
- 参数说明:
r:Redis 客户端
-
user_id:投票用户 -
article_id:被投票文章- 已提供一周前
Unix时间戳,存放在变量cutoff - 当满足以下条件时,为文章投一票:
- 该文章发布不超过一周
- 已提供一周前
-
该用户没有为该文章投过票
-
在
post_article()函数中:- 该方法作用是:创建文章
- 参数说明:
r:Redis 客户端
-
user:发布用户 -
title:文章标题 -
link:文章链接- 已提供:
article_id,新文章ID
- 已提供:
-
voted,新文章已投票用户名单存储键名 -
article,新文章详细信息存储键名 -
now,文章创建时间- 按照
ID递增的顺序依次创建文章 - 保证发布文章的用户不能给自己的文章投票
- 文章在发布一周后删除已投票用户名单
- 存储文章详细信息到
Redis中,包括字段:- 文章标题
- 按照
-
文章链接
-
发布用户
- 存储文章的发布时间和初始投票数
- 初始投票数为
1
- 初始投票数为
- 存储文章的发布时间和初始投票数
-
在
get_articles()函数中:- 该方法作用是:对文章进行排序
- 参数说明:
r:Redis 客户端start:从排序为start的文章开始获取
-
end:到排序为end的文章结束获取 -
order:排序方式,分为两种:time:按时间排序score:按投票数排序
-
已提供文章信息空列表,
articles -
实现按时间/投票数排序
-
将排序后的文章及其全部信息组成一个列表:
- 按照不同排序规则取出排序在参数提供的区间范围内的文章
- 及每篇文章的全部信息,包括文章
ID#!/usr/bin/env python #-*- coding:utf-8 -*- import time ONE_WEEK_IN_SECONDS = 7 * 24 * 60 * 60 def 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# 请在下面完成要求的功能#********* Begin *********#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)#********* End *********#return article_id def get_articles(r, start, end, order='score'):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
相关文章:
使用Python+Redis实现文章投票网站后端功能
1.实现投票功能,2.创建文章数据,3.对文章进行排序。 实现投票功能 实现投票功能,要注重文章的时效性与投票的公平性,所以需要给投票功能加上一些约束条件: 文章发布满一个星期后&…...
SpringBoot 环境使用 Redis + AOP + 自定义注解实现接口幂等性
目录 一、前言二、主流实现方案介绍2.1、前端按钮做加载状态限制(必备)2.2、客户端使用唯一标识符2.3、服务端通过检测请求参数进行幂等校验(本文使用) 三、代码实现3.1、POM3.2、application.yml3.3、Redis配置类3.4、自定义注解…...
Leetcode—18.四数之和【中等】
2023每日刷题(四十一) Leetcode—18.四数之和 实现代码 class Solution { public:vector<vector<int>> fourSum(vector<int>& nums, int target) {vector<vector<int>> ans;sort(nums.begin(), nums.end());int n …...
springsecurity6配置二
一、springsecurity6自定义认证异常处理器 1.1 AuthenticationEntryPointImpl.java package com.school.information.core.security.handler;import com.alibaba.fastjson.JSON; import com.school.information.enums.result.ResultStatusEnum; import com.school.informatio…...
php如何对比浮点数大小(bccomp函数)
第一部分,常规例子: 例1:左边比右边小,结果:-1 //示例,左边比右边小返回值:-1 $price1 2.14; $price2 3.14; $result bccomp($price1, $price2, 2); echo 对比结果:.$result;//…...
服务号和订阅号哪个好
服务号和订阅号有什么区别?服务号转为订阅号有哪些作用?在推送频率上来看,服务号每月能推送四条消息,而订阅号可以每天(24小时)推送一条消息。如果企业开通公众号的目的是提供服务,例如售前资讯…...
面试问题--智能指针
什么是智能指针? 当你在编写程序时,可能需要在运行时动态分配内存来存储数据。在传统的C中,你可能会使用 new 和 delete 操作符来手动管理内存。但是这样容易出现一些问题,比如忘记释放内存导致内存泄漏,或者释放了之…...
向量机SVM原理理解和实战
目录 概念场景导入 点到超平面的距离公式 最大间隔的优化模型 硬间隔、软间隔和非线性 SVM 用 SVM 如何解决多分类问题 1. 一对多法 2. 一对一法 SVM主要原理和特点 原理 优点 缺点 支持向量机模型分类 SVM实战如何进行乳腺癌检测 数据集 字段含义 代码实现 参…...
什么是 Node.js?
在 Node.js 出现之前,最常见的 JavaScript 运行时环境是浏览器,也叫做 JavaScript 的宿主环境。浏览器为 JavaScript 提供了 DOM API,能够让 JavaScript 操作浏览器环境(JS 环境)。 2009 年初 Node.js 出现了…...
系列九、声明式事务(xml方式)
一、概述 声明式事务(declarative transaction management)是Spring提供的对程序事务管理的一种方式,Spring的声明式事务顾名思义就是采用声明的方式来处理事务。这里所说的声明,是指在配置文件中声明,用在Spring配置文件中声明式的处理事务来…...
c盘清理——常用方法和工具整理
背景 最近c盘满了,只剩下1-2G,周末有空清理一下。对这块不太熟悉,下面只是把今天网上看到的比较好用的工具整理一下。 使用工具 磁盘大小查看工具——TreeSize(收费) 之前都是右键一个个看每个文件的大小࿰…...
【React】打包体积分析 source-map-explorer
通过分析打包体积,才能知道项目中的哪部分内容体积过大,方便知道哪些包需要进一步优化。 使用步骤 安装分析打包体积的包:npm i source-map-explorer在 package.json 中的 scripts 标签中,添加分析打包体积的命令对项目打包&…...
Zookeeper(一):在WSL单机搭建Zookeeper伪集群
目录 Zookeeper1 启动单个Zookeeper实例1.1 下载Zookeeper安装包并解压1.2 添加环境变量1.3 修改默认配置1.4 新建数据存储目录和日志目录1.5 启动Zookeeper1.6 停止Zookeeper 2 搭建Zookeeper集群2.1 新建集群目录2.2 配置环境变量2.3 创建节点目录2.4 修改配置2.5 创建节点ID…...
Go语法的特殊之处
上文我们讲了GO模块引入指令Go Mod,本文讲述Go语法的特殊之处 : 单变量 : hello:“hello” Go 语言中新增了一个特殊的运算符:,这个运算符可以使变量在不声明的情况下直接被赋值使用。其使用方法和带值声明变量类似,只是少了var关键字&…...
浏览器v8垃圾回收机制和内存泄漏分析-初级
借鉴:一文搞懂V8引擎的垃圾回收 - 掘金 (juejin.cn) 聊聊V8引擎的垃圾回收 - 掘金 (juejin.cn) 内存泄漏方向: 1、全局变量 未手动清除 2、定时器 未手动清除 3、闭包中使用了匿名函数 未手动清除 4、dom被赋值使用后 未手动清除 其他解决方式 1、…...
hdlbits系列verilog解答(7420 chip)-49
文章目录 一、问题描述二、verilog源码三、仿真结果一、问题描述 本次将实现7420逻辑芯片,它内部有2个4输入的与非门电路,外部有8个输入和2个输出管脚,功能框图如下所示: 二、verilog源码 module top_module ( input p1a, p1b, p1c, p1d,output p1y,input p2a, p2b, p2c…...
Sentinel核心类解读:Entry
默认情况下,Sentinel会将controller中的方法作为被保护资源,Sentinel中的资源用Entry来表示。 Sentinel中Entry可以理解为每次进入资源的一个凭证,如果调用SphO.entry()或者SphU.entry()能获取Entry对象,代表获取了凭证ÿ…...
YOLOv8改进 | SAConv可切换空洞卷积(附修改后的C2f+Bottleneck)
论文地址:官方论文地址 代码地址:官方代码地址 一、本文介绍 本文给大家带来的改进机制是可切换的空洞卷积(Switchable Atrous Convolution, SAC)是一种创新的卷积网络机制,专为增强物体检测和分割任务中的特征提取而…...
可以ping通IP但是无法远程连接-‘telnet‘ 不是内部或外部命令,也不是可运行的程序或批处理文件
起因 一开始远程连接IP,报错,怀疑是自己网络原因,但是同事依旧无法连接 怀疑是自己防火墙的原因,查看关闭依旧无法连接 问题 两个地址可以ping通排除防火墙缘故 怀疑端口,测试端口 然 解决方案 winR 输入control…...
使用VC++设计程序:实现常见的三种图像插值算法:最近邻插值,双线性插值,立方卷积插值
图像放大的三种插值算法 获取源工程可访问gitee可在此工程的基础上进行学习。 该工程的其他文章: 01- 一元熵值、二维熵值 02- 图像平移变换,图像缩放、图像裁剪、图像对角线镜像以及图像的旋转 03-邻域平均平滑算法、中值滤波算法、K近邻均值滤波器 04-…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障
关键领域软件测试的"安全密码":Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力,从金融交易到交通管控,这些关乎国计民生的关键领域…...
使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...
TCP/IP 网络编程 | 服务端 客户端的封装
设计模式 文章目录 设计模式一、socket.h 接口(interface)二、socket.cpp 实现(implementation)三、server.cpp 使用封装(main 函数)四、client.cpp 使用封装(main 函数)五、退出方法…...
