Redis 五种数据结构类型

redis的数据类型

key,value格式的数据,其中key都是字符串,value有5种不同的数据结构,如下所示

1) 字符串类型 string
2) 哈希类型 hash : map格式  
3) 列表类型 list : linkedlist格式。支持重复元素
4) 集合类型 set  : 不允许重复元素
5) 有序集合类型 set:不允许重复元素,且元素有顺序

String类型

string类型是Redis基本的数据类型,一个键大能存储512MB。
string 数据结构是简单的key-value类型,value其不仅是string,也可以是数字,是包含很多种类型的特殊类型,

string类型是二进制安全的。意思是redis的string可以包含任何数据。 比如序列化的对象进行存储,比如一张图片进 行二进制存储,比如一个简单的字符串,数值等等。

String命令

赋值语法:

SET KEY_NAME VALUE: (说明:多次设置name会覆盖) (SET命令用于设置给定key的值。如果 key已经存储值,SET就覆写旧值,且无视类型)

SETNX key1 value:(not exist)
如果key1不存在,则设值并返回1
。如果key1存在,则不设值并返回0;(解决分 布式锁 方案之一,只有在 key 不存在时设置 key 的值。Setnx(SET if Not eXists) 命令在指定的 key 不存在 时,为 key 设置指定的值)------通常用来做分布式锁

SETEX key1 10 lx :(expired)设置key1的值为lx,过期时间为10秒,10秒后key1清除(key也清除)

SETRANGE string range value: 替换字符串

取值语法:

GET KEY_NAME :Redis GET命令用于获取指定 key 的值。如果 key 不存在,返回 nil 。如果key 储存的值不是字 符串类型,返回一个错误。

GETRANGE key start end :用于获取存储在指定 key 中字符串的子字符串。字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)

GETBIT key offset :对 key 所储存的字符串值,获取指定偏移量上的位(bit)

GETSET语法: GETSET KEY_NAME VALUE :Getset 命令用于设置指定 key 的值,并返回 key 的旧值,当 key 不存在时,返回 nil

STRLEN key :返回 key 所储存的字符串值的长度

删值语法:

DEL KEY_Name:删除指定的KEY,如果存在,返回值数字类型。

批量写:MSET k1 v1 k2 v2 … 一次性写入多个值

批量读:MGET k1 k2 k3

GETSET name value :一次性设值和读取(返回旧值,写上新值)

自增/自减:

INCR KEY_Name :Incr 命令将 key 中储存的数字值增1。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然 后再执行 INCR 操作

自增:INCRBY KEY_Name :增量值 Incrby 命令将 key 中储存的数字加上指定的增量值
自减:DECR KEY_NAME 或 DECYBY KEY_NAME 减值 :DECR 命令将 key 中储存的数字减1
:(注意这些 key 对应的必须是数字类型字符串,否则会出错,)

字符串拼接:APPEND KEY_NAME VALUE
:Append 命令用于为指定的 key 追加至未尾,如果不存在,为其赋值

字符串长度 :STRLEN key

应用场景

  1. String通常用于保存单个字符串或JSON字符串数据
  2. 因String是二进制安全的,所以你完全可以把一个图片文件的内容作为字符串来存储
  3. 计数器(常规key-value缓存应用。常规计数: 微博数, 粉丝数)

INCR等指令本身就具有原子操作的特性,所以我们完全可以利用redis的INCR、INCRBY、DECR、DECRBY等 指令来实现原子计数的效果。假如,在某种场景下有3个客户端同时读取了mynum的值(值为2),然后对其 同时进行了加1的操作,那么,后mynum的值一定是5。 不少网站都利用redis的这个特性来实现业务上的统 计计数需求。

Hash类型

Hash类型是String类型的field和value的映射表,或者说是一个String集合。hash特别适合用于存储对象,相比较而言,将一个对象类型存储在Hash类型比要存储在String类型里占用更少的内存空间,并对整个对象的存取。
可以看成具有KEY和VALUE的MAP容器,该类型非常适合于存储值对象的信息, 如:uname,upass,age等。该类型的数据仅占用很少的磁盘空间(相比于JSON).Redis 中每个 hash 可以存储 2的32次方- 1键值对(40多亿)

Hash命令

赋值语法:

HSET KEY FIELD VALUE :为指定的KEY,设定FILD/VALUE

HMSET KEY FIELD VALUE [FIELD1,VALUE1]…… :同时将多个 field-value (域-值)对设置到哈希表 key 中。

取值语法:

HGET KEY FIELD :获取存储在HASH中的值,根据FIELD得到VALUE

HMGET KEY field[field1] :获取key所有给定字段的值

HGETALL KEY :返回HASH表中所有的字段和值

HKEYS KEY :获取所有哈希表中的字段

HLEN KEY :获取哈希表中字段的数量

删除语法:

HDEL KEY field1[field2] :删除一个或多个HASH表字段

其它语法

HSETNX key field value :只有在字段 field 不存在时,设置哈希表字段的值

HINCRBY key field increment :为哈希表key中的指定字段的整数值加上增量 increment

HINCRBYFLOAT key field increment :为哈希key中的指定字段的浮点数值加上增量increment 。

HEXISTS key field :查看哈希表 key 中,指定的字段是否存在

应用场景

  1. 常用于存储一个对象
  2. 为什么不用string存储一个对象

hash是接近关系数据库结构的数据类型,可以将数据库一条记录或程序中一个对象转换成hashmap存放在redis 中。

用户ID为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,如果用普通的key/value结构来存储,主要有 以下2种存储方式:

第一种方式将用户ID作为查找key,把其他信息封装成一个对象以序列化的方式存储,这种方式的缺点是,增加了序列 化/反序列化的开销,并且在需要修改其中一项信息时,需要把整个对象取回,并且修改操作需要对并发进行保护,引入CAS 等复杂问题。

第二种方法是这个用户信息对象有多少成员就存成多少个key-value对儿,用用户ID+对应属性的名称作为唯一标识来 取得对应属性的值,虽然省去了序列化开销和并发问题,但是用户ID为重复存储,如果存在大量这样的数据,内存浪费还是 非常可观的。

总结: Redis提供的Hash很好的解决了这个问题,Redis的Hash实际是内部存储的Value为一个HashMap, 并提供了直接存取这个Map成员的接口

List类型

List类型是一个链表结构的集合,其主要功能有push、pop、获取元素等。更详细的说,List类型是一个双端链表的节后,我们可以通过相关的操作进行集合的头部或者尾部添加和删除元素,List的设计非常简单精巧,即可以作为栈,又可以作为队列,满足绝大多数的需求。

按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素) 类似JAVA中的LinkedList

常用命令

赋值语法

LPUSH key value1 [value2] :将一个或多个值插入到列表头部(从左侧添加)

RPUSH key value1 [value2] :在列表中添加一个或多个值(从右侧添加)

LPUSHX key value :将一个值插入到已存在的列表头部。如果列表不在,操作无效

RPUSHX key value :一个值插入已存在的列表尾部(最右边)。如果列表不在,操作无效。

取值语法

LLEN key :获取列表长度

LINDEX key index :通过索引获取列表中的元素

LRANGE key start stop :获取列表指定范围内的元素

描述: 返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定。

其中 0 表示列表的第一个元素, 1 表示列表的第二个元素,以此类推。

使用负数下标

-1 表示列表的最后一个元素

-2 表示列表的倒数第二个元素,以此类推。

start: 页大小(页数-1)
stop : (页大小页数)-1

# 当前是第1页, 每页显示3条数据 
start :0  stop:2 
start :3  stop:5 
start :6  stop: 8

删除语法

LPOP key 移出并获取列表的第一个元素(从左侧删除)

RPOP key 移除列表的最后一个元素,返回值为移除的元素(从右侧删除)

BLPOP key1 [key2 ] timeout 移出并获取列表的第一个元素,如果列表没有元素会阻塞列表直到等待超时或发 现可弹出元素为止。

redis 127.0.0.1:6379> BLPOP list1 100

在以上实例中,操作会被阻塞,如果指定的列表 key list1 存在数据则会返回第一个元素,否则在等待100秒后会返回 nil

BRPOP key1 [key2 ] timeout :移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或 发现可弹出元素为止。

LTRIM key start stop :对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区 间之内的元素都将被删除。

修改语法

LSET key index value :通过索引设置列表元素的值

LINSERT key BEFORE|AFTER world value :在列表的元素前或者后插入元素 描述:将值 value 插入到列表 key 当中,位于值 world 之前或之后。

高级语法

RPOPLPUSH source destination :移除列表的最后一个元素,并将该元素添加到另一个列表并返回

示例描述:
RPOPLPUSH a1 a2 :a1的最后元素移到a2的左侧

RPOPLPUSH a1 a1 :循环列表,将最后元素移到最左侧

BRPOPLPUSH source destination timeout :从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返 回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

应用场景

项目常应用于:1、对数据量大的集合数据删减 2、任务队列

1、对数据量大的集合数据删减

列表数据显示、关注列表、粉丝列表、留言评价等…分页、热点新闻(Top5)等 利用 LRANGE还可以很方便的实现分页的功能,在博客系统中,每片博文的评论也可以存入一个单独的list中。

2、任务队列

list通常用来实现一个消息队列,而且可以确保先后顺序,不必像MySQL那样还需要通过ORDER BY来 进行排序

任务队列介绍(生产者和消费者模式):

在处理Web客户端发送的命令请求时,某些操作的执行时间可能会比我们预期的更长一些,通过将待执行任务的相关信 息放入队列里面,并在之后对队列进行处理,用户可以推迟执行那些需要一段时间才能能完成的操作,这种将工作交给任务 处理器来执行的做法被称为任务队列(task queue)。

RPOPLPUSH source destination 移除列表的最后一个元素,并将该元素添加到另一个列表并返回

代码案例

案例一

比如:获取最新5条首页新闻,获取最新的评论列表,获取最后登录10个用户,获取最近7天的活跃用户数等或做为队列来使 用。

需求: 获取最新5条首页新闻。

案例二

1:用户系统登录注册短信实名认证等

2:订单系统的下单流程等

set类型

Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。 Redis 中集合 是通过哈希表实现的,set是通过hashtable实现的 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40 多亿个成员)。 类似于JAVA中的 Hashtable集合

常用命令

赋值语法

SADD key member1 [member2] :向集合添加一个或多个成员

取值语法

SCARD key :获取集合的成员数

SMEMBERS key :返回集合中的所有成员

SISMEMBER key member :判断member元素是否是集合key的成员(开发中:验证是否存在判断)

SRANDMEMBER key [count] :返回集合中一个或多个随机数

删除语法

SREM key member1 [member2] :移除集合中一个或多个成员

SPOP key [count] :移除并返回集合中的一个随机元素

SMOVE source destination member :将 member 元素从 source 集合移动到 destination 集合

差集语法

SDIFF key1 [key2] :返回给定所有集合的差集(左侧)

SDIFFSTORE destination key1 [key2] :返回给定所有集合的差集并存储在 destination 中

交集语法

SINTER key1 [key2] :返回给定所有集合的交集(共有数据)

SINTERSTORE destination key1 [key2] :返回给定所有集合的交集并存储在 destination 中

并集语法

SUNION key1 [key2] :返回所有给定集合的并集

SUNIONSTORE destination key1 [key2] :所有给定集合的并集存储在 destination 集合中

应用场景

常应用于:对两个集合间的数据[计算]进行交集、并集、差集运算

1、利用集合操作,可以取不同兴趣圈子的交集,以非常方便的实现如共同关注、共同喜好、二度好友等功能。对上面 的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存储到一个新的集合中。

2、利用唯一性,可以统计访问网站的所有独立 IP、存取当天[或某天]的活跃用户列表。

代码案例

判断用户名是否存在

抽奖活动。 现有员工10个。1等奖1名。2等奖2名。3等奖3名。 用Redis实现

有两组数据,求两组数据的 交集、差集、并集

zset类型

1.Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。

2、不同的是每个元素都会关联一
个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

3、有序集合的成员是唯一的,但 分数(score)却可以重复。

4、集合是通过哈希表实现的。 集合中最大的成员数为 2次方32 - 1 (4294967295, 每个集 合可存储40多亿个成员)。Redis的ZSet是有序、且不重复 (很多时候,我们都将redis中的有序集合叫做zsets,这是因 为在redis中,有序集合相关的操作指令都是以z开头的)

常用命令

赋值语法

ZADD key score1 member1 [score2 member2] :向有序集合添加一个或多个成员,或者更新已存在成员的分 数

取值语法

ZCARD key :获取有序集合的成员数

ZCOUNT key min max :计算在有序集合中指定区间分数的成员数

ZRANK key member :返回有序集合中指定成员的索引

ZRANGE key start stop [WITHSCORES] :通过索引区间返回有序集合成指定区间内的成员(低到高)

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT] :通过分数返回有序集合指定区间内的成员

ZREVRANGE key start stop [WITHSCORES] :返回有序集中指定区间内的成员,通过索引,分数从高到底

ZREVRANGEBYSCORE key max min [WITHSCORES] :返回有序集中指定分数区间内的成员,分数从高到低排序

删除语法

DEL key :移除集合

ZREM key member [member …] :移除有序集合中的一个或多个成员

ZREMRANGEBYRANK key start stop :移除有序集合中给定的排名区间的所有成员(第一名是0)(低到高排序)

ZREMRANGEBYSCORE key min max :移除有序集合中给定的分数区间的所有成员

ZINCRBY key increment member
:增加memeber元素的分数increment,返回值是更改后的分数

应用场景

常应用于:排行榜

销量排名,积分排名等

1比如twitter 的public
timeline可以以发表时间作为score来存储,这样获取时就是自动按时间排好序的。

2比如一个存储全班同学成绩的Sorted Set,其集合value可以是同学的学号,而score就可以是其考试得分,这 样在数据插入集合的时候,就已经进行了天然的排序。

3还可以用Sorted Set来做带权重的队列,比如普通消息的score为1,重要消息的score为2,然后工作线程可以 选择按score的倒序来获取工作任务。让重要的任务优先执行。

代码案例

积分、成绩、等等排行榜

需求1:在zset中插入10名同学成绩

需求2:按成绩由高到低,查出前3名同学成绩信息

需求3:查询成绩在60- 80分之间 的同学成绩信息

HyperLogLog

Redis 在 2.8.9 版本添加了 HyperLogLog 结构。

Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时, 计算基数所需的空间总是固定的、并且是很小的。

在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计 算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那 样,返回输入的各个元素。

小知识: 什么是基数?

比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。

为什么需要HyperLoglog

如果要统计1亿个数据的基数值,大约需要内存100000000/8/1024/1024 ≈ 12M,内存减少占用的效果显著。

然而统计一个对象的基数值需要12M,如果统计10000个对象,就需要将近120G,同样不能广泛用于大数据场景。

常用命令

PFADD key element [element …] :添加指定元素到 HyperLogLog 中

PFCOUNT key [key …] :返回给定 HyperLogLog 的基数估算值

PFMERGE destkey sourcekey [sourcekey …] :将多个 HyperLogLog 合并为一个 HyperLogLog

应用场景

基数不大,数据量不大就用不上,会有点大材小用浪费空间 有局限性,就是只能统计基数数量,而没办法去知道具 体的内容是什么

统计注册 IP 数

统计每日访问 IP 数

统计页面实时 UV 数

统计在线用户数

统计用户每天搜索不同词条的个数

统计真实文章阅读数

总结

HyperLogLog是一种算法,并非redis独有 目的是做基数统计,故不是集合,不会保存元数据,只记录数量而不是数值。 耗空间极小,支持输入非常体积的数据量

核心是基数估算算法,主要表现为计算时内存的使用和数据合并的处理。最终数值存在一定误差 redis中每个hyperloglog key占用了12K的内存用于标记基数(官方文档) pfadd命令并不会一次性分配12k内存,而是随着基数的增加而逐渐增加内存分配;而pfmerge操作则会将sourcekey合并 后存储在12k大小的key中,这由hyperloglog合并操作的原理(两个hyperloglog合并时需要单独比较每个桶的值)可以 很容易理解。

误差说明:基数估计的结果是一个带有 0.81% 标准错误(standard error)的近似值。是可接受的范围 Redis 对 HyperLogLog 的存储进行了优化,在计数比较小时,它的存储空间采用稀疏矩阵存储,空间占用很小,仅仅在 计数慢慢变大,稀疏矩阵占用空间渐渐超过了阈值时才会一次性转变成稠密矩阵,才会占用 12k 的空间

发布了240 篇原创文章 · 获赞 435 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/fjxcsdn/article/details/104065772