分布式数据库NoSQL(十)——初识Redis

目录

Redis下载

第1关:6-1-1Redis中的数据结构

Redis与其他数据库的对比

Redis的特性

快速安装 Redis 与 Python(可跳过)

Redis数据结构简介

启动方式

Redis中的字符串

Redis中的列表

Redis中的集合

Redis中的哈希

Redis中的有序集合

编程要求

第2关:6-1-2 使用 Python 与 Redis 交互

第3关:6-1-3 使用Python+Redis实现文章投票网站后端功能

实现投票功能

创建文章数据

对文章进行排序

编程要求


Redis下载

链接:https://pan.baidu.com/s/1WGFRMALrVCS5eDreaOxVfw 
提取码:1234 

解压文件安装,一路next,记得改路径。

或者从 https://redis.io/download 下载最新的稳定版本 Redis 源码

第1关:6-1-1Redis中的数据结构

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 能够解决更为广泛的问题,而且既能作为主数据库使用,也可以作为辅助数据库使用。

我们通过一张表来对比常用的数据库与缓存服务器:

名称类型数据存储选项查询类型附加功能
Redis基于内存的非关系型数据库字符串、列表、集合、哈希、有序集合针对数据类型有专属命令,另有批量操作和不完全的事务支持发布与订阅、复制、持久化、脚本扩展
memcached基于内存的键值缓存键值映射创建、读取、更新、删除等多线程支持
MySQL关系型数据库数据表、视图等查询、插入、更新、删除、内置函数、自定义存储过程等支持 ACID 性质、复制等
MongoDB基于硬盘的非关系型文档存储数据库无 schema 的 BSON 文档创建、读取、更新、删除、条件查询等复制、分片、空间索引等

Redis的特性

由于Redis是内存型数据库,在使用之前就要考虑当服务器被关闭时,服务器存储的数据是否能保留。Redis 拥有两种不同形式的持久化方法,都可以用紧凑的格式将数据写入硬盘:

  • RDB 持久化
    • 在指定的时间间隔内生成数据集的时间点快照
  • AOF 持久化
    • 记录服务器执行的所有写操作命令
    • 新命令会被追加到文件的末尾
    • 在服务器启动时,通过重新执行这些命令还原数据集

除此之外,为了扩展Redis的读性能,并为Redis提供故障转移支持,Redis实现了主从复制特性:

  • 执行复制的从服务器连接主服务器
    • 接收主服务器发送的初始副本
    • 接收主服务器执行的所有写命令
  • 在从服务器上执行所有写命令,实时更新数据库
  • 读命令可以向任意一个从服务器发送

快速安装 Redis 与 Python(可跳过)

为了避免安装到旧版 Redis 的问题,我们直接使用源码编译安装 Redis,首先你需要获取并安装 make 等一系列构建工具:

$ sudo apt-get update
$ sudo apt-get install make gcc python-dev

构建工具安装完毕后,你需要执行以下操作:

从 https://redis.io/download 下载最新的稳定版本 Redis 源码
//也可以根据开头百度网盘的链接下载
解压源码,编译、安装并启动 Redis 
下载并安装 Python 语言的 Redis 客户端库

其中,安装 Redis 的过程如下:

~:$ wget -q http://download.redis.io/releases/redis-5.0.0.tar.gz
~:$ tar -xzf redis-5.0.0.tar.gz
~:$ cd redis-5.0.0
# 注意观察编译消息,最后不应该产生任何错误(`Error`)
~/redis-5.0.0:$ make
# 注意观察安装消息,最后不应该产生任何错误(`Error`)
~/redis-5.0.0:$ sudo make install
# 启动 Redis 服务器,注意通过日志确认 Redis 顺利启动
~/redis-5.0.0:$ redis-server redis.conf

除了上述的启动 Redis 服务器方式,你还可以通过 Redis 默认的配置在后台启动它(常用启动方式):

$ redis-server &

因为近几年发布的 UbuntuDebian 都预装了 Python 2.6Python 2.7,所以你不再需要花时间去安装 Python。你可以通过一个名为 setuptools 的辅助包更方便的下载和安装 Redis 客户端:

~:$ sudo python -m easy_install redis hiredis

这里的 redis 包为 Python 提供了连接 Redis 的接口,hiredis 包则是可选的,它是一个使用 C 语言编写的高性能 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中的集合

集合和列表的区别就在于:列表可以存储多个相同的字符串,而集合通过散列表来保证存储的字符串都是各不相同的(这些散列表只有键,而没有对应的值)。

  • 由于集合是无序的,所以我们只能通过统一的 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,有一系列命令对哈希进行插入、获取、删除:

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

root@evassh-13781135:~# redis-cli
127.0.0.1:6379> set hello redis
OK
127.0.0.1:6379> lpush educoder-list hello
(integer) 1
(0.84s)
127.0.0.1:6379> rpush educoder-list educoder
(integer) 2
127.0.0.1:6379> rpush educoder-list bye
(integer) 3
127.0.0.1:6379> rpop educoder-list
"bye"
127.0.0.1:6379> sadd educoder-set c
(integer) 1
127.0.0.1:6379> sadd educoder-set python
(integer) 1
127.0.0.1:6379> sadd educoder-set redis
(integer) 1
127.0.0.1:6379> srem educoder-set c
(integer) 1
127.0.0.1:6379> hset educoder-hash python language
(integer) 1
127.0.0.1:6379> hset educoder-hash ruby language
(integer) 1
127.0.0.1:6379> hset educoder-hash redis database
(integer) 1
127.0.0.1:6379> hdel educoder-hash ruby
(integer) 1
127.0.0.1:6379> zadd educoder-zset 200 jack
(integer) 1
127.0.0.1:6379> zadd educoder-zset 400 rose
(integer) 1
127.0.0.1:6379> zadd educoder-zset 100 lee
(integer) 1

 

第2关:6-1-2 使用 Python 与 Redis 交互

如果你在上一关中已经使用 easy_install 包安装了 redis 包,那么你现在连接 Redis 就很简单了,可以使用以下两种方法:

方法1

# 导入 redis 模块
import redis

# 创建 redis 客户端
conn = redis.Redis()

...
# 使用完资源之后删除客户端 conn
del conn

方法2

# 导入 redis 模块
import redis

# 创建连接池
pool = redis.ConnectionPool(host='127.0.0.1', port=6379, decode_responses=True)

# 创建客户端并连接到 Redis
r = redis.Redis(connection_pool=pool)

两种方法的对比如下:

  • 方法 1需要在使用完该客户端后手动删除客户端,以避免创建多个连接
  • 方法 2
    • 使用了连接池总揽多个客户端与服务端的连接
    • 不需要手动删除客户端
    • 同时有效的减少多个客户端连接的损耗

所以我们在实际开发中使用第二种方法较多。

在创建了客户端之后,你就可以使用 coonr 这个客户端来进行 Redis 操作了。

通过客户端对 Redis 的数据进行操作

通过客户端对 Redis 的数据进行操作和第一关直接在 Redis 中的操作命令基本相同。只是在客户端中操作如下,要在命令前加上客户端的名字和.(假设使用方法2创建客户端r):

# 使用 SET 命令设置一个字符串键
r.set("test", "hello")
# 显示字符串键 test 的值
print(r.get("test"))

编程要求

根据提示,在右侧Begin-End区域补充代码,实现使用 Python 编写程序与 Redis 交互:

  • 使用方法2创建客户端r1连接到 Redis 
  • 设置下表中的两个字符串键:
test1hello
test2Redis
#!/usr/bin/env python
#-*- coding:utf-8 -*-

def write_redis():
    #********* Begin *********#
    import redis
    pool = redis.ConnectionPool(host='127.0.0.1',port=6379,decode_responses=True)
    r = redis.Redis(connection_pool=pool)
    r.set("test1","hello")
    r.set("test2","Redis")
    #********* End *********#

 

第3关:6-1-3 使用Python+Redis实现文章投票网站后端功能

本关任务:编写一个简化版文章投票网站的后端处理逻辑。

相关知识

第一关中,我们对 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

if 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 命令来为文章的投票数加 1zincrby 函数语法如下:

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_id
r.sadd(voted, user)
r.expire(voted, ONE_WEEK_IN_SECONDS)

now = time.time()
article = 'article:' + article_id
r.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 函数设置进去就行。

最后,将初始投票数和创建时间设置到 scoretime 中都可以通过 ZADD 命令来实现:

r.zadd(key, member, score)

  • key :有序集合的键名
  • member :要加入有序集合的成员
  • score :该成员的分值

这里需要注意的是,因为该篇文章的作者已经被加入到该文章已投票用户名单中,为了保持数据一致性,我们需要将文章的初始投票数设为 1

对文章进行排序

实现了文章投票和创建文章功能,接下来我们就需要将评分最高的文章最新发布的文章Redis 中取出了。

  • 首先我们要根据排序方式的不同:

    • 按评分排序,则从 score 有序集合中取出一定量的文章 IDscore有序集合存放文章ID和对应的投票数)
    • 按时间排序,则从 time 有序集合中取出一定量的文章 IDtime有序集合存放文章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'] = id
articles.append(article_data)

return articles

这里因为需要对有序集合进行排序,所以我们在取出文章 ID 时需要使用到 ZREVRANGE 命令,以分值从大到小的排序方式取出文章 IDZREVRANGE 命令的语法是:

r.zrevrange(key, start, stop)

  • key :有序集合的键名
  • start :开始的数组下标
  • stop :结束的数组下标

得到多个文章 ID 后,我们还需要根据每一个文章 ID 获取文章的全部信息,这时就需要使用到 HGETALL 命令,它的语法如下:

r.hgetall(key)

  • key :哈希的键名

我们取出文章的全部信息后,还为文章信息添加了一个字段 id。这是因为文章 IDRedis 中是作为键名存储的,不在值当中,所以我们需要附加这个字段到文章信息中。

实现这些方法后,我们大体实现了一个文章投票的后端处理逻辑,能够为文章投票并能根据投票结果改变文章的排序情况。

编程要求

根据提示,在右侧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:
        return

    if 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_id
    now = 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'] = id
        articles.append(article_data)

    #********* End *********#

    return articles

世界地图矢量数据可以通过多种网站进行下载。以下是一些提供免费下载世界地图矢量数据的网站: 1. Open Street Map (https://www.openstreetmap.org/): 这个网站可以根据输入的经纬度或手动选定范围来导出目标区域的矢量图。导出的数据格式为osm格式,但只支持矩形范围的地图下载。 2. Geofabrik (http://download.geofabrik.de/): Geofabrik提供按洲际和国家快速下载全国范围的地图数据数据格式支持shape文件格式,包含多个独立图层,如道路、建筑、水域、交通、土地利用分类、自然景观等。数据每天更新一次。 3. bbbike (https://download.bbbike.org/osm/): bbbike提供全球主要的200多个城市的地图数据下载,也可以按照bbox进行下载。该网站还提供全球数据数据格式种类齐全,包括geojson、shp等。 4. GADM (https://gadm.org/index.html): GADM提供按国家或全球下载地图数据的服务。该网站提供多种格式的数据下载。 5. L7 AntV (https://l7.antv.antgroup.com/custom/tools/worldmap): L7 AntV是一个提供标准世界地图矢量数据免费下载的网站。支持多种数据格式下载,包括GeoJSON、KML、JSON、TopJSON、CSV和高清SVG格式等。可以下载中国省、市、县的矢量边界和世界各个国家的矢量边界数据。 以上这些网站都提供了世界地图矢量数据免费下载服务,你可以根据自己的需求选择合适的网站进行下载
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值