一日一技:带过期时间的缓存、全文搜索、频率限制怎么做?

存储
walrus对redis-py进行了很好的二次封装,用起来非常顺手。除了上面我提到的三个功能外,它还可以实现几行代码生成布隆过滤器,实现自动补全功能,实现简易图数据库等等。

[[442671]]

在以前的文章里面,我给大家介绍了使用Python自带的LRU缓存实现带有过期时间的缓存:一日一技:实现有过期时间的LRU缓存。也讲过倒排索引:使用倒排索引极速提高字符串搜索效率。但这些代码对初学者来说比较难,写起来可能会出错。

实际上,这些功能其实都可以使用Redis来实现,而且每个功能只需要1分钟就能做出来。全文搜索功能在搜索英文的时候,甚至可以智能识别拼写错误的问题。

要实现这些功能,只需要做两件事:

安装Redis

Python安装第三方库:walrus

安装完成以后,我们来看看它有多简单:

带过期时间的缓存装饰器

我们想实现一个装饰器,它装饰一个函数。让我在1分钟内多次访问函数的时候,使用缓存的数据;超过1分钟以后才重新执行函数的内部代码:

  1. import time 
  2. import datetime 
  3. from walrus import Database 
  4.  
  5. db = Database() 
  6. cache = db.cache() 
  7.  
  8. @cache.cached(timeout=60) 
  9. def test(): 
  10.     print('函数真正运行起来'
  11.     now = datetime.datetime.now() 
  12.     return now 
  13.  
  14. now = test() 
  15. print('函数返回的数据是:', now) 
  16. time.sleep(10) # 等待10秒,此时会使用缓存 
  17. print('函数返回的数据是:', test()) 
  18. time.sleep(5) # 等待5秒,此时依然使用缓存 
  19. print('函数返回的数据是:', test()) 
  20.  
  21. time.sleep(50)  # 让时间超过缓存的时间 
  22. print('函数返回的数据是:', test()) 

运行效果如下图所示:

全文搜索

我们再来看看全文搜索功能,实现起来也很简单:

  1. from walrus import Database 
  2.  
  3. db = Database() 
  4. search = db.Index('xxx')  # 这个名字随便取 
  5. poem1 = 'Early in the day it was whispered that we should sail in a boat, only thou and I, and never a soul in the world would know of this our pilgrimage to no country and to no end.' 
  6. poem2 = 'Had I the heavens’ embroidered cloths,Enwrought with golden and silver light' 
  7. poem3 = 'to be or not to be, that is a question.' 
  8.  
  9. search.add('docid1', poem1) # 第一个参数不能重复 
  10. search.add('docid2', poem2) 
  11. search.add('docid3', poem3) 
  12.  
  13.  
  14. for doc in search.search('end'): 
  15.     print(doc['content']) 

运行效果如下图所示:

如果你想让他兼容拼写错误,那么可以把search = db.Index('xxx')改成search = db.Index('xxx’, metaphone=True),运行效果如下图所示:

不过遗憾的是,这个全文搜索功能只支持英文。

频率限制

我们有时候要限制调用某个函数的频率,或者网站的某个接口要限制IP的访问频率。这个时候,使用walrus也可以轻松实现:

  1. import time 
  2. from walrus import Database 
  3.  
  4. db = Database() 
  5. rate = db.rate_limit('xxx', limit=5, per=60) # 每分钟只能调用5次 
  6.  
  7. for _ in range(35): 
  8.     if rate.limit('xxx'): 
  9.         print('访问频率太高!'
  10.     else
  11.         print('还没有触发访问频率限制'
  12.     time.sleep(2) 

运行效果如下图所示:

其中参数limit表示能出现多少次,per表示在多长时间内。

rate.limit只要传入相同的参数,那么就会开始检查这个参数在设定的时间内出现的频率。

你可能觉得这个例子并不能说明什么问题,那么我们跟FastAPI结合一下,用来限制IP访问接口的频率。编写如下代码:

  1. from walrus import Database, RateLimitException 
  2. from fastapi import FastAPI, Request 
  3. from fastapi.responses import JSONResponse 
  4.  
  5. db = Database() 
  6. rate = db.rate_limit('xxx', limit=5, per=60) # 每分钟只能调用5次 
  7.  
  8. app = FastAPI() 
  9.  
  10.  
  11. @app.exception_handler(RateLimitException) 
  12. def parse_rate_litmit_exception(request: Request, exc: RateLimitException): 
  13.     msg = {'success'False'msg': f'请喝杯茶,休息一下,你的ip: {request.client.host}访问太快了!'
  14.     return JSONResponse(status_code=429, content=msg) 
  15.  
  16. @app.get('/'
  17. def index(): 
  18.     return {'success'True
  19.  
  20.  
  21. @app.get('/important_api'
  22. @rate.rate_limited(lambda request: request.client.host) 
  23. def query_important_data(request: Request): 
  24.     data = '重要数据' 
  25.     return {'success'True'data': data} 

上面代码定义了一个全局的异常拦截器:

  1. @app.exception_handler(RateLimitException) 
  2. def parse_rate_litmit_exception(request: Request, exc: RateLimitException): 
  3.     msg = {'success'False'msg': f'请喝杯茶,休息一下,你的ip: {request.client.host}访问太快了!'
  4.     return JSONResponse(status_code=429, content=msg) 

在整个代码的任何地方抛出了RateLimitException异常,就会进入这里的逻辑中。

使用装饰器@rate.rate_limited装饰一个路由函数,并且这个装饰器要更靠近函数。路由函数接收什么参数,它就接收什么参数。在上面的例子中,我们只接收了request参数,用于获取访问者的IP。发现这个IP的访问频率超过了限制,就抛出一个RateLimitException。于是前面定义好的全局拦截器就会拦截RateLimitException异常,拦截到以后返回我们定义好的报错信息。

在频率范围内访问页面,返回正常的JSON数据:

频率超过设定的值以后,访问页面就会报错,如下图所示:

总结

walrus对redis-py进行了很好的二次封装,用起来非常顺手。除了上面我提到的三个功能外,它还可以实现几行代码生成布隆过滤器,实现自动补全功能,实现简易图数据库等等。大家可以访问它的官方文档了解详细使用说明[1]。

参考文献

[1] 官方文档了解详细使用说明: https://walrus.readthedocs.io/en/latest/getting-started.html

本文转载自微信公众号「未闻Code」,可以通过以下二维码关注。转载本文请联系未闻Code公众号。

 

责任编辑:武晓燕 来源: 未闻Code
相关推荐

2021-07-26 21:15:10

LRU缓存MongoDB

2021-04-27 22:15:02

Selenium浏览器爬虫

2021-08-01 15:26:59

协程Asyncio并发数

2022-05-02 16:27:01

JavaScriptHTMLPython

2021-10-15 21:08:31

PandasExcel对象

2022-06-28 09:31:44

LinuxmacOS系统

2021-04-05 14:47:55

Python多线程事件监控

2024-11-13 09:18:09

2022-03-12 20:38:14

网页Python测试

2021-07-08 21:49:13

前端后端Cookies

2021-04-12 21:19:01

PythonMakefile项目

2021-03-18 23:28:45

Python反斜杠字符串

2023-10-28 12:14:35

爬虫JavaScriptObject

2021-09-13 20:38:47

Python链式调用

2024-07-30 08:16:18

Python代码工具

2021-03-12 21:19:15

Python链式调用

2021-04-19 23:29:44

MakefilemacOSLinux

2024-07-30 08:11:16

2021-07-27 21:32:57

Python 延迟调用

2024-11-11 00:38:13

Mypy静态类型
点赞
收藏

51CTO技术栈公众号