Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >用 Redis 散列实现短网址生成器|文末福利

用 Redis 散列实现短网址生成器|文末福利

作者头像
每天晒白牙
发布于 2020-08-21 07:30:26
发布于 2020-08-21 07:30:26
1K00
代码可运行
举报
文章被收录于专栏:每天晒白牙每天晒白牙
运行总次数:0
代码可运行

散列简介

Redis 的散列键会将一个键和一个散列在数据库里关联起来,用户可以在散列中为任意多个字段(field)设置值。与字符串键一样,散列的字段和值既可以是文本数据,也可以是二进制数据。

通过使用散列键,用户可以把相关联的多项数据存储到同一个散列里面,以便对这些数据进行管理,或者针对它们执行批量操作。比如图 3-2 就展示了一个使用散列存储文章数据的例子,在这个例子中,散列的键为article::10086,而这个键对应的散列则包含了 4 个字段,其中:

"title" 字段存储文章的标题 "greeting"。 "content" 字段存储文章的内容 "hello world"。 "author" 字段存储文章的作者名字 "peter"。 "create_at" 字段存储文章的创建时间 "1442744762.631885"。

使用散列存储文章数据

与之前使用字符串键存储文章数据的做法相比,使用散列存储文章数据只需要在数据库里面创建一个键,并且因为散列的字段名不需要添加任何前缀,所以它们可以直接反映字段值存储的是什么数据。

Redis 为散列键提供了一系列操作命令,通过使用这些命令,用户可以:

为散列的字段设置值,或者只在字段不存在的情况下为它设置值。 从散列里面获取给定字段的值。 对存储着数字值的字段执行加法操作或者减法操作。 检查给定字段是否存在于散列当中。 从散列中删除指定字段。 查看散列包含的字段数量。 一次为散列的多个字段设置值,或者一次从散列中获取多个字段的值。 获取散列包含的所有字段、所有值或者所有字段和值。

本章接下来将对以上提到的散列操作进行介绍,说明如何使用这些操作去构建各种有用的应用程序,并在最后详细地说明散列键与字符串键之间的区别。

HSET:为字段设置值

用户可以通过执行 HSET 命令为散列中的指定字段设置值:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
HSET hash field value

根据给定的字段是否已经存在于散列中,HSET 命令的行为也会有所不同:

如果给定字段并不存在于散列当中,那么这次设置就是一次创建操作,命令将在散列里面关联起给定的字段和值,然后返回 1。 如果给定的字段原本已经存在于散列里面,那么这次设置就是一次更新操作,命令将使用用户给定的新值去覆盖字段原有的旧值,然后返回 0。

举个例子,通过执行以下 HSET 命令,我们可以创建出一个包含了 4 个字段的散列,这 4 个字段分别存储了文章的标题、内容、作者以及创建日期:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
redis> HSET article::10086 title "greeting"
(integer) 1
redis> HSET article::10086 content "hello world"
(integer) 1
redis> HSET article::10086 author "peter"
(integer) 1
redis> HSET article::10086 created_at "1442744762.631885"
(integer) 1

图 3-3 展示了以上 HSET 命令对散列 article::10086 进行设置的整个过程。

HSET前

HSET后

提示:散列包含的字段就像数据库包含的键一样,在实际中都是以无序方式进行排列的,不过本书为了展示方便,一般都会把新字段添加到散列的末尾,排在所有已有字段的后面。

使用新值覆盖旧值

正如之前所说,如果用户在调用 HSET 命令时给定的字段已经存在于散列当中,那么 HSET 命令将使用用户给定的新值去覆盖字段已有的旧值,并返回 0 表示这是一次更新操作。

比如,以下代码就展示了如何使用 HSET 命令去更新 article::10086 散列的 title 字段以及 content 字段:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
redis> HSET article::10086 title "Redis Tutorial" 
(integer) 0
redis> HSET article::10086 content "Redis is a data structure store, ..."
(integer) 0

图 3-4 展示了被更新之后的 article::10086 散列。

更新后的散列

其他信息

复杂度:O (1)。

版本要求:HSET 命令从 Redis 2.0.0 版本开始可用。

HSETNX:只在字段不存在的情况下为它设置值

HSETNX 命令的作用和 HSET 命令的作用非常相似,它们之间的区别在于,HSETNX 命令只会在指定字段不存在的情况下执行设置操作:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
HSETNX hash field value

HSETNX 命令在字段不存在并且成功为它设置值时返回 1,在字段已经存在并导致设置操作未能成功执行时返回0。

举个例子,对于图 3-5 所示的 article::10086 散列来说,执行以下 HSETNX 命令将不会对散列产生任何影响,因为 HSETNX 命令想要设置的 title 字段已经存在:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
redis> HSETNX article::10086 title "Redis Performance Test"
(integer) 0   -- 设置失败

HSETNX前

相反,如果我们使用 HSETNX 命令去对尚未存在的 view_count 字段进行设置,那么这个命令将会顺利执行,并将 view_count 字段的值设置为 100:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
redis> HSETNX article::10086 view_count 100
(integer) 1   -- 设置成功

图 3-6 展示了 HSETNX 命令成功执行之后的 article::10086 散列。

HSETNX命令后

其他信息

复杂度:O (1)。

版本要求:HSETNX 命令从 Redis 2.0.0 版本开始可用。

HGET:获取字段的值

HGET 命令可以根据用户给定的字段,从散列中获取该字段的值:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
HGET hash field

例如,对于图 3-7 所示的两个散列键来说,执行以下命令可以从 article::10086 散列中获取 author 字段的值:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
redis> HGET article::10086 author
"peter"

而执行以下命令则可以从 article::10086 散列中获取 created_at 字段的值:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
redis> HGET article::10086 created_at
"1442744762.631885"

两个散列

再例如,如果我们想要从 account::54321 散列中获取 email 字段的值,那么可以执行以下命令:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
redis> HGET account::54321 email
"peter1984@spam_mail.com"

处理不存在的字段或者不存在的散列

如果用户给定的字段并不存在于散列当中,那么 HGET 命令将返回一个空值。

举个例子,在以下代码中,我们尝试从 account::54321 散列里面获取 location 字段的值,但由于 location 字段并不存在于 account::54321 散列当中,所以 HGET 命令将返回一个空值:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
redis> HGET account::54321 location
(nil)

尝试从一个不存在的散列里面获取一个不存在的字段值,得到的结果也是一样的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
redis> HGET not-exists-hash not-exists-field
(nil)

其他信息

复杂度:O (1)。

版本要求:HGET 命令从 Redis 2.0.0 版本开始可用。

示例:实现短网址生成程序

为了给用户提供更多发言空间,并记录用户在网站上的链接点击行为,大部分社交网站都会将用户输入的网址转换为相应的短网址。比如,如果我们在新浪微博中发言时输入网址 http://redisdoc.com/geo/index.html,那么微博将把这个网址转换为相应的短网址 http://t.cn/RqRRZ8n,当用户访问这个短网址时,微博在后台就会对这次点击进行一些数据统计,然后再引导用户的浏览器跳转到 http://redisdoc.com/geo/index.html上面。

创建短网址本质上就是要创建出短网址 ID 与目标网址之间的映射,并在用户访问短网址时,根据短网址的 ID 从映射记录中找出与之相对应的目标网址。比如在前面的例子中,微博的短网址程序就将短网址 http://t.cn/RqRRZ8n 中的 ID 值 RqRRZ8n 映射到了 http://redisdoc.com/geo/index.html 这个网址上面,当用户访问短网址 http://t.cn/RqRRZ8n 时,程序就会根据这个短网址的 ID 值 RqRRZ8n 找出与之对应的目标网址 http://redisdoc.com/geo/index.html,并将用户引导至目标网址上面去。

作为示例,图 3-8 展示了几个微博短网址 ID 与目标网址之间的映射关系。

映射关系

因为 Redis 的散列非常适合用来存储短网址 ID 与目标网址之间的映射,所以我们可以基于 Redis 的散列实现一个短网址程序,代码清单 3-1 展示了一个这样的例子。

代码清单 3-1 使用散列实现的短网址程序:/hash/shorty_url.py

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from base36 import base10_to_base36

ID_COUNTER = "ShortyUrl::id_counter"
URL_HASH = "ShortyUrl::url_hash"

class ShortyUrl:
  def __init__(self, client):
    self.client = client

  def shorten(self, target_url):
    """
    为目标网址创建并存储相应的短网址ID
    """
    # 为目标网址创建新的数字ID
    new_id = self.client.incr(ID_COUNTER)
    # 通过将十进制数字转换为三十六进制数字来创建短网址ID,
    # 比如,十进制数字10086将被转换为三十六进制数字7S6
    short_id = base10_to_base36(new_id)
    # 把短网址ID用作字段,目标网址用作值,将它们之间的映射关系存储到散列里面
    self.client.hset(URL_HASH, short_id, target_url)
    return short_id

  def restore(self, short_id):
    """
    根据给定的短网址ID,返回与之对应的目标网址
    """
    return self.client.hget(URL_HASH, short_id)

ShortyUrl 类的 shorten() 方法负责为输入的网址生成短网址 ID,它的工作包括以下 4 个步骤:

1)为每个给定的网址创建一个十进制数字 ID。 2)将十进制数字ID转换为三十六进制,并将这个三十六进制数字用作给定网址的短网址 ID,这种方法在数字 ID 长度较大时可以有效地缩短数字 ID 的长度。代码清单 3-2 展示了将数字从十进制转换成三十六进制的 base10_to_base36 函数的具体实现。 3)将短网址 ID 和目标网址之间的映射关系存储到散列中。 4)向调用者返回刚刚生成的短网址 ID。

代码清单 3-2 将十进制数字转换成三十六进制数字的程序:/hash/base36.py

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def base10_to_base36(number):
  alphabets = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  result = ""

  while number != 0 :
    number, i = divmod(number, 36)
    result = (alphabets[i] + result)
return result or alphabets[0]

restore() 方法要做的事情和 shorten() 方法正好相反,它会从存储着映射关系的散列里面取出与给定短网址ID相对应的目标网址,然后将其返回给调用者。

以下代码简单地展示了使用 ShortyUrl 程序创建短网址 ID 的方法,以及根据短网址 ID 获取目标网址的方法:

>>> from redis import Redis >>> from shorty_url import ShortyUrl >>> client = Redis(decode_responses=True) >>> shorty_url = ShortyUrl(client) >>> shorty_url.shorten("RedisGuide.com") # 创建短网址 ID '1' >>> shorty_url.shorten("RedisBook.com") '2' >>> shorty_url.shorten("RedisDoc.com") '3' >>> shorty_url.restore("1") # 根据短网址 ID 查找目标网址 'RedisGuide.com' >>> shorty_url.restore("2") 'RedisBook.com'

图 3-9 展示了上面这段代码在数据库中创建的散列结构。

散列结构

HINCRBY:对字段存储的整数值执行加法或减法操作

与字符串键的 INCRBY 命令一样,如果散列的字段里面存储着能够被 Redis 解释为整数的数字,那么用户就可以使用 HINCRBY 命令为该字段的值加上指定的整数增量:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
HINCRBY hash field increment

HINCRBY 命令在成功执行加法操作之后将返回字段当前的值作为命令的结果。

比如,对于图 3-10 所示的 article::10086 散列,我们可以通过执行以下命令为 view_count 字段的值加上 1:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
redis> HINCRBY article::10086 view_count 1
(integer) 101

也可以通过执行以下命令,为 view_count 字段的值加上 30:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
redis> HINCRBY article::10086 view_count 30
(integer) 131

存储文章数量的散列

本文摘选自《Redis 使用手册》

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-11-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 每天晒白牙 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
redis命令之操作hash散列
Redis hash 是一个string类型的field和value的映射表,可以让用户将多个键值对存储到一个reids键里面,hash特别适合用于存储对象。从功能上来说,Redis为hash散列提供了一些与字符串值相同的特性,使得散列非常适用于将一些相关的数据存储在一起。我们可以把这种数据聚集看作是关系数据库中的行,或者文档数据库中的文档。
OECOM
2020/07/01
1.6K0
Redis 学习笔记 3.3 散列类型
散列类型适合存储对象,使用对象类别和ID构成键名,使用字段表示对象的属性,而字段值则存储属性值。
twowinter
2020/04/17
4420
实例讲解redis的hash散列类型
hash散列类型简介 image.png 命令 行为 HDEL key field [field ...] 删除key 中的一个或多个指定域 HEXISTS key field 查看key 中,给定域
章鱼喵
2018/06/27
1.5K0
Redis散列与有序集合
前面文章我们介绍了列表与集合中的基本命令,本文我们来看看Redis中的散列与有序集合。
江南一点雨
2018/07/31
7370
Redis学习笔记(散列类型)
介绍 散列类型(hash)的键值也是一种字典结构,其存储了字段(field)和字段值的映射,但字段值只能是字符串,不支持其他数据类型 常用命令 1. 赋值 HSET key field value 2. 取值 HGET key field 3. 多个字段赋值 HMSET key fidle [field value ...] 4. 多个字段取值 HMGET key field [field ...] 5. 判断字段是否存在,如果存在则返回1,否则返回0(如果键不存在也会返回0) HEXISTS
编程随想曲
2022/04/21
2500
【Redis实战】散列类型(Hash)
  HSET命令的方便之处在于不区分插入和更新操作,这意味着修改数据时不用事先判断字段是否存在,来决定要执行的是插入操作(update)还是更新操作(insert)。当执行的是插入操作时(即之前字段不存在)HSET命令会返回1,当执行的是更新操作时(即之前的字段已经存在)HSET命令会返回0。更进一步,当键本身不存在时,HSET命令还会自动建立它。
程序员云帆哥
2022/05/12
3640
Redis:09---Hash对象
hsetnx:它们的关系就像set和setnx命令一样,只不过作用域由键变为field
用户3479834
2021/02/03
1K0
Redis:09---Hash对象
redis简单使用
Redis是一个主要由Salvatore Sanfilippo(Antirez)开发的开源内存数据结构存储器,经常用作数据库、缓存以及消息代理等。
墨紫羽墨
2022/10/09
2K0
4.Python操作Redis:哈希(H
Redis 数据库hash数据类型是一个string类型的key和value的映射表,适用于存储对象。Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)。 Python的redis模块实现了Redis哈希(Hash)命令行操作的几乎全部命令,包括HDEL、HEXISTS、HGET、HGETALL、HINCRBY、HKEYS、HLEN 、HMGET 、HMSET 、HSET 、HSETNX 、HVALS 。但是无法支持HINCRBYFLOAT 、HSCAN 等命令。
py3study
2020/01/03
4.4K0
Redis之hash类型解读
Hash类型对应的数据结构是两种: ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable (Map<String,Map<Object,Obje ct>>)
一个风轻云淡
2023/10/15
4600
Redis中的hash类型解读
Hash类型对应的数据结构是两种: ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable (Map<String,Map<Object,Obje ct>>)
一个风轻云淡
2023/09/22
3820
Redis实战之Redis命令
  Redis可以存储键与5种不同数据结构类型之间的映射,这5种数据结构类型分别为string(字符串),list(列表),set(集合),hash(散列),zset(有序集合),下面将分别对这5种数据类型的控制命令进行总结,熟话说好记性不如烂笔头,方便以后查看。
全栈程序员站长
2021/12/31
8460
Redis实战之Redis命令
Redis教程(3)
Redis hash是一个string类型的field和value的映射表.它的添加、删除操作都是O(1)(平均)。hash特别适合用于存储对象。相较于将对象的每个字段存成单个string类型。将一个对象存储在hash类型中会占用更少的内存,并且可以更方便的存取整个对象。省内存的原因是新建一个hash对象时开始是用zipmap(又称为small hash)来存储的。这个zipmap其实并不是hash table,但是zipmap相比正常的hash实现可以节省不少hash本身需要的一些元数据存储开销。尽管zipmap的添加,删除,查找都是O(n),但是由于一般对象的field数量都不太多。所以使用zipmap也是很快的,也就是说添加删除平均还是O(1)。如果field或者value的大小超出一定限制后,Redis会在内部自动将zipmap替换成正常的hash实现. 这个限制可以在配置文件中指定
py3study
2020/01/09
5800
Redis 系列(3) —— Hash
Redis 的散列会将一个键和一个散列在数据库里关联起来,用户可以在散列中为任意多个字段设置值。与字符串键一样,散列的字段和值既可以是文本数据,也可以是二进制数据。
求和小熊猫
2021/09/10
4870
Redis字符串命令和Redis 哈希命令分析
Redis字符串命令 编号 命令 描述 1 SET key value 此命令设置指定键的值。 2 GET key 获取指定键的值。 3 GETRANGE key start end 获取存储在键上的字符串的子字符串。 4 GETSET key value 设置键的字符串值并返回其旧值。 5 APPEND key value 将指定值附加到键 6 MGET key1 [key2..] 获取所有给定键的值 7 SETBIT key offset value 存储在键上的字符串值中设置或清除偏移处的位 8 SE
用户1503405
2021/10/07
2960
redis妙用-hash类型
hash类型,又叫作散列类型,它类似hashmap,通过一定的hash算法得到对应的索引位置,然后将数据保存在该索引所在的地方。本章讲述的东西,重点不在于应用场景,因为hash能做的事情,string也都能做。所以本章分享的是,试图揣测redis官方推出hash的意义,以及实现原理。
并发笔记
2020/10/21
1.7K0
redis妙用-hash类型
Redis 哈希
{key:{field1:value1,field2:value2,...fieldN:valueN}}
三产
2021/01/12
3810
2024 RedisAnd Mysql基础与进阶操作系列(15-2)作者——LJS[你个小黑子这都还学不会嘛?你是真爱粉嘛?真是的 ~;以后请别侮辱我家鸽鸽]
Hash命令语法格式及说明表一 命令原型 时间复杂 度 命令描述返回值 HSET key field value O(1)
盛透侧视攻城狮
2024/10/22
930
redis 学习(3)-- 哈希类型
可以看出:哈希键值包括 key,field,value 这三部分,即键,属性,值这三部分。可以这样来表示:
希希里之海
2019/05/31
7770
Redis~Hash命令初识
Hash命令 上次我们说了redis中的String命令,这次来简单的介绍下Hash命令。Hash命令可以存储多个键值对之间的映射,和字符串类似,散列存储的值既可以是字符串也可以是数值。并且我们也可以对散列存储的数字执行自增操作或者自减操作。 操作命令 hset: 将哈希表中的key 中的域值 设置为 value ; 如果key filed 都不存在 ,设置的时候就是新建立的过程。存在就是将value 修改为新值。 时间复杂度为O(1);hset key field value; hge
用户2196435
2018/07/19
5300
相关推荐
redis命令之操作hash散列
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验