NoSQL之Redis6基础(五大数据结构)

Redis6

1.NoSQL数据库

1.1概念

NoSQL(Not Only SQL),泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在处理web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,出现了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,特别是大数据应用难题。

NoSQL不依赖业务逻辑方式存储,而是以简单的key-value模式存储,因此大大增加了数据库的拓展能力。

  • 不遵循SQL标准
  • 不支持ACID
  • 远超于SQL的性能

1.2应用场景

  • 数据高并发读写
  • 大量数据读写
  • 对数据的高可拓展性

不适用于:

  • 需要事务支持
  • 基于sql的结构化存储查询,处理复杂的关系,需要即席查询
  • (用不着sql和用了sql也不行的情况,考虑使用NoSQL)

1.3 常见NoSQL数据库

  • Mencache

image-20210817140757562

  • Reids

    image-20210817140816253

  • MongoDB

image-20210817140902938

2.Redis概述

  • Redis是一个开源的key-value存储系统。

  • 和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。

  • 这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。

  • 在此基础上,Redis支持各种不同方式的排序。

  • 与memcached一样,为了保证效率,数据都是缓存在内存中。

  • 区别的是Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件。

  • 并且在此基础上实现了master-slave(主从)同步。

  • 默认16个数据库,下标从0开始,使用命令select 来切换数据库,所有库密码一样

  • 常用命令:

    • dbsiz,查看当前数据库key数量
    • flushdb清空当前数据库
    • flushall清空全部数据库

3.常用5大数据类型

  • string 字符串(可以为整形、浮点型和字符串,统称为元素)
  • list 列表(实现队列,元素不唯一,先入先出原则)
  • set 集合(各不相同的元素)
  • hash hash散列值(hash的key必须是唯一的)
  • sort set 有序集合

在了解五大数据类型时我们需要首先了解redis的key-value以及一些常用操作

Redis键(key)

keys *查看当前库所有key (匹配:keys *1)

exists key判断某个key是否存在

type key 查看你的key是什么类型

del key 删除指定的key数据

unlink key 根据value选择非阻塞删除,仅将keys从keyspace元数据中删除,真正的删除会在后续异步操作。

expire key 10 10秒钟:为给定的key设置过期时间

ttl key 查看还有多少秒过期,-1表示永不过期,-2表示已过期

select命令切换数据库

dbsize查看当前数据库的key的数量

flushdb清空当前库

flushall通杀全部库

3.1字符串(String)

3.1.1简介:

字符串是一种最基本的Redis值类型。Redis字符串是二进制安全的,这意味着一个Redis字符串能包含任意类型的数据,例如: 一张JPEG格式的图片或者一个序列化的Ruby对象。

一个字符串类型的值最多能存储512M字节的内容。

你可以用Redis字符串做许多有趣的事,例如你可以:

  • 利用INCR命令簇(INCR, DECR, INCRBY)来把字符串当作原子计数器使用。
  • 使用APPEND命令在字符串后添加内容。
  • 将字符串作为GETRANGESETRANGE的随机访问向量。
  • 在小空间里编码大量数据,或者使用 GETBITSETBIT创建一个Redis支持的Bloom过滤器。

查看所有可用的字符串命令获取更多信息, 或者进一步阅读 Redis数据类型介绍.

3.1.2常用操作

image-20210817233703961

在set后面添加拼接下面的字符达到的效果

*NX:当数据库中key不存在时,可以将key-value添加数据库

*XX:当数据库中key存在时,可以将key-value添加数据库,与NX参数互斥

*EX:key的超时秒数

*PX:key的超时毫秒数,与EX互斥

例如:image-20210817233908993

  • get 查询对应值
  • append 追加字符到原有的值末尾
  • strlen 获得值长度
  • incr 自增1,只能对数字值操作,如果为空,新增值为1
  • decr 自减,如果为空,新增值为-1
  • incrby /decrby key 步长 将 key 中储存的数字值增减。自定义步长。
  • mset 同时设置多个key-value对
  • getset 设置新值同时获得旧值
3.1.3数据接口

String类型数据结构在达到存储上限时可以自动扩容,类似于java的ArrayList,bufferstring等。

注意:等字符串小于1m每次扩容都是加倍当前的空间,如果超过1m则是每次追加1m空间。

3.2列表(List)

3.2.1简介

Redis列表是简单的字符串列表,按照插入顺序排序。 你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

LPUSH 命令插入一个新元素到列表头部,而RPUSH命令 插入一个新元素到列表的尾部。当 对一个空key执行其中某个命令时,将会创建一个新表。 类似的,如果一个操作要清空列表,那么key会从对应的key空间删除。这是个非常便利的语义, 因为如果使用一个不存在的key作为参数,所有的列表命令都会像在对一个空表操作一样。

一些列表操作及其结果:

LPUSH mylist a   # now the list is "a"
LPUSH mylist b   # now the list is "b","a"
RPUSH mylist c   # now the list is "b","a","c" (RPUSH was used this time)

一个列表最多可以包含232-1个元素(4294967295,每个表超过40亿个元素)。

从时间复杂度的角度来看,Redis列表主要的特性就是支持时间常数的 插入和靠近头尾部元素的删除,即使是需要插入上百万的条目。 访问列表两端的元素是非常快的,但如果你试着访问一个非常大 的列表的中间元素仍然是十分慢的,因为那是一个时间复杂度为 O(N) 的操作。

你可以用Redis列表做许多有趣的事,例如你可以:

  • 在社交网络中建立一个时间线模型,使用LPUSH去添加新的元素到用户时间线中,使用LRANGE去检索一些最近插入的条目。
  • 你可以同时使用LPUSHLTRIM去创建一个永远不会超过指定元素数目的列表并同时记住最后的N个元素。
  • 列表可以用来当作消息传递的基元(primitive),例如,众所周知的用来创建后台任务的Resque Ruby库。
  • 你可以使用列表做更多事,这个数据类型支持许多命令,包括像BLPOP这样的阻塞命令。请查看所有可用的列表操作命令获取更多的信息。
3.2.2常用操作
  • l/rpush 列表左/右边(头/尾部)插入
  • l/rpop 取出值,值全部取出时建就消失
  • rpoplpush key1 key2 key1右边取值到key2左边
  • lrange key start stop 按照索引下标获得元素(从左到右)
  • lindex key indes 按照索引下标获得元素(从左到右)
  • llen 获得列表长度
  • linsert key before value newvalue 在 value 的后面插入 newvalue 插入值
  • lrem key n value 从左边删除n个value(从左到右)
  • lset key index value 将列表key下标为index的值替换成value
3.2.3数据结构

List的数据结构为快速链表quickList。

首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也即是压缩列表。

它将所有的元素紧挨着一起存储,分配的是一块连续的内存。

当数据量比较多的时候才会改成quicklist。

因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是int类型的数据,结构上还需要两个额外的指针prev和next。

img

Redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。

3.3集合(Set)

3.3.1简介

Redis集合是一个无序的字符串合集。你可以以O(1) 的时间复杂度(无论集合中有多少元素时间复杂度都为常量)完成 添加,删除以及测试元素是否存在的操作。

Redis集合有着不允许相同成员存在的优秀特性。向集合中多次添加同一元素,在集合中最终只会存在一个此元素。实际上这就意味着,在添加元素前,你并不需要事先进行检验此元素是否已经存在的操作。

一个Redis列表十分有趣的事是,它们支持一些服务端的命令从现有的集合出发去进行集合运算。 所以你可以在很短的时间内完成合并(union),求交(intersection), 找出不同元素的操作。

一个集合最多可以包含232-1个元素(4294967295,每个集合超过40亿个元素)。

你可以用Redis集合做很多有趣的事,例如你可以:

  • 用集合跟踪一个独特的事。想要知道所有访问某个博客文章的独立IP?只要每次都用SADD来处理一个页面访问。那么你可以肯定重复的IP是不会插入的。
  • Redis集合能很好的表示关系。你可以创建一个tagging系统,然后用集合来代表单个tag。接下来你可以用SADD命令把所有拥有tag的对象的所有ID添加进集合,这样来表示这个特定的tag。如果你想要同时有3个不同tag的所有对象的所有ID,那么你需要使用SINTER.
  • 使用SPOP或者SRANDMEMBER命令随机地获取元素。
3.3.2常用操作
  • sadd key value1 value2 将一个或者多个添加到集合中
  • smembers key 取出所有的元素
  • sismembers key value 判断是否有对应的值
  • scard key 返回集合元素个数
  • srem … 删除集合中的某个元素。
  • spop ****随机从该集合中吐出一个值。****
  • srandmember 随机从该集合中取出n个值。不会从集合中删除 。
  • smove value把集合中一个值从一个集合移动到另一个集合
  • sinter 返回两个集合的交集元素。
  • sunion 返回两个集合的并集元素。
  • sdiff 返回两个集合的****差集****元素(key1中的,不包含key2中的)
3.3.3 数据结构

Set数据结构是dict字典,字典是用哈希表实现的。

Java中HashSet的内部实现使用的是HashMap,只不过所有的value都指向同一个对象。Redis的set结构也是一样,它的内部也使用hash结构,所有的value都指向同一个内部值。

3.4hash散列值(Hash)

3.4.1简介

Redis Hashes是字符串字段和字符串值之间的映射,所以它们是完美的表示对象(eg:一个有名,姓,年龄等属性的用户)的数据类型。

@cli
HMSET user:1000 username antirez password P1pp0 age 34
HGETALL user:1000
HSET user:1000 password 12345
HGETALL user:1000

一个拥有少量(100个左右)字段的hash需要很少的空间来存储,所有你可以在一个小型的 Redis实例中存储上百万的对象。

尽管Hashes主要用来表示对象,但它们也能够存储许多元素,所以你也可以用Hashes来完成许多其他的任务。

一个hash最多可以包含232-1 个key-value键值对(超过40亿)。

3.4.2 常用操作

hset 给集合中的 键赋值

hget 从集合取出 value

hmset … 批量设置hash的值

hexists查看哈希表 key 中,给定域 field 是否存在。

hkeys 列出该hash集合的所有field

hvals 列出该hash集合的所有value

hincrby 为哈希表 key 中的域 field 的值加上增量 1 -1

hsetnx 将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在 .

3.4.3数据结构

Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable。

3.5有序集合(Sorted sets)

3.5.1简介

Redis有序集合和Redis集合类似,是不包含 相同字符串的合集。它们的差别是,每个有序集合 的成员都关联着一个评分,这个评分用于把有序集 合中的成员按最低分到最高分排列。

使用有序集合,你可以非常快地(O(log(N)))完成添加,删除和更新元素的操作。 因为元素是在插入时就排好序的,所以很快地通过评分(score)或者 位次(position)获得一个范围的元素。 访问有序集合的中间元素同样也是非常快的,因此你可以使用有序集合作为一个没用重复成员的智能列表。 在这个列表中, 你可以轻易地访问任何你需要的东西: 有序的元素,快速的存在性测试,快速访问集合中间元素!

简而言之,使用有序集合你可以很好地完成 很多在其他数据库中难以实现的任务。

使用有序集合你可以:

  • 在一个巨型在线游戏中建立一个排行榜,每当有新的记录产生时,使用ZADD 来更新它。你可以用ZRANGE轻松地获取排名靠前的用户, 你也可以提供一个用户名,然后用ZRANK获取他在排行榜中的名次。 同时使用ZRANKZRANGE你可以获得与指定用户有相同分数的用户名单。 所有这些操作都非常迅速。
  • 有序集合通常用来索引存储在Redis中的数据。 例如:如果你有很多的hash来表示用户,那么你可以使用一个有序集合,这个集合的年龄字段用来当作评分,用户ID当作值。用ZRANGEBYSCORE可以简单快速地检索到给定年龄段的所有用户。
  • 有序集合或许是最高级的Redis数据类型,所以花些时间查看完整的有序集合(Sorted sets)命令列表去探索你能用Redis干些什么吧!
3.5.2 常用操作

zadd …

将一个或多个 member 元素及其 score 值加入到有序集 key 当中。

*zrange [WITHSCORES]*

返回有序集 key 中,下标在 之间的元素

带WITHSCORES,可以让分数一起和值返回到结果集。

zrangebyscore key minmax [withscores] [limit offset count]

返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。

zrevrangebyscore key maxmin [withscores] [limit offset count]

同上,改为从大到小排列。

zincrby 为元素的score加上增量

zrem 删除该集合下,指定值的元素

zcount 统计该集合,分数区间内的元素个数

zrank 返回该值在集合中的排名,从0开始。

3.5.3数据结构

SortedSet(zset)是Redis提供的一个非常特别的数据结构,一方面它等价于Java的数据结构Map<String, Double>,可以给每一个元素value赋予一个权重score,另一方面它又类似于TreeSet,内部的元素会按照权重score进行排序,可以得到每个元素的名次,还可以通过score的范围来获取元素的列表。

zset底层使用了两个数据结构

(1)hash,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到相应的score值。

(2)跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表。

4.Redis发布订阅

订阅:SUBSCRIBE channel

发布: public channel msg

5.Redis6新数据类型

5.1 Bitmaps

  • 能进行位操作的字符串
  • 以位为单位的数组,每个存储单元只能存0/1

常用操作:

setbit, getbit,bitcount,bitop

5.2HyperLogLog

5.2.1简介

在工作当中,我们经常会遇到与统计相关的功能需求,比如统计网站PV(PageView页面访问量),可以使用Redis的incr、incrby轻松实现。

但像UV(UniqueVisitor,独立访客)、独立IP数、搜索记录数等需要去重和计数的问题如何解决?这种求集合中不重复元素个数的问题称为基数问题。

解决基数问题有很多种方案:

(1)数据存储在MySQL表中,使用distinct count计算不重复个数

(2)使用Redis提供的hash、set、bitmaps等数据结构来处理

以上的方案结果精确,但随着数据不断增加,导致占用空间越来越大,对于非常大的数据集是不切实际的。

能否能够降低一定的精度来平衡存储空间?Redis推出了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。 基数估计就是在误差可接受的范围内,快速计算基数。

5.2.2命令

1、pfadd

(1)格式

pfadd < element> [element …] 添加指定元素到 HyperLogLog 中

image-20210818112758477

(2)实例

img

​ 将所有元素添加到指定HyperLogLog数据结构中。如果执行命令后HLL估计的近似基数发生变化,则返回1,否则返回0。

2、pfcount

(1)格式

pfcount [key …] 计算HLL的近似基数,可以计算多个HLL,比如用HLL存储每天的UV,计算一周的UV可以使用7天的UV合并计算即可

img

(2)实例

img

3、pfmerge

(1)格式

pfmerge [sourcekey …] 将一个或多个HLL合并后的结果存储在另一个HLL中,比如每月活跃用户可以使用每天的活跃用户来合并计算可得

img

(2)实例

img

5.3Geospatial

5.3.1简介

Redis 3.2 中增加了对GEO类型的支持。GEO,Geographic,地理信息的缩写。该类型,就是元素的2维坐标,在地图上就是经纬度。redis基于该类型,提供了经纬度设置,查询,范围查询,距离查询,经纬度Hash等常见操作。

5.3.2命令

1、geoadd

(1)格式

geoadd< longitude> [longitude latitude member…] 添加地理位置(经度,纬度,名称)

img

(2)例

geoadd china:city 121.47 31.23 shanghai

geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shenzhen 116.38 39.90 beijing

img

两极无法直接添加,一般会下载城市数据,直接通过 Java 程序一次性导入。

有效的经度从 -180 度到 180 度。有效的纬度从 -85.05112878 度到 85.05112878 度。

当坐标位置超出指定范围时,该命令将会返回一个错误。

已经添加的数据,是无法再次往里面添加的。

2、geopos

(1)格式

geopos [member…] 获得指定地区的坐标值

img

(2)实例

img

3、geodist

(1格式

geodist [m|km|ft|mi ] 获取两个位置之间的直线距离

img

(2)实例

获取两个位置之间的直线距离

img

单位:

m 表示单位为米[默认值]。

km 表示单位为千米。

mi 表示单位为英里。

ft 表示单位为英尺。

如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位

4、georadius

(1)格式

georadius< longitude>radius m|km|ft|mi 以给定的经纬度为中心,找出某一半径内的元素

img

经度 纬度 距离 单位

(2)实例

sjHcVHls-1629293072054)]

3、geodist

(1格式

geodist [m|km|ft|mi ] 获取两个位置之间的直线距离

[外链图片转存中…(img-geFNU3TM-1629293072054)]

(2)实例

获取两个位置之间的直线距离

[外链图片转存中…(img-WlKwpBN6-1629293072055)]

单位:

m 表示单位为米[默认值]。

km 表示单位为千米。

mi 表示单位为英里。

ft 表示单位为英尺。

如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位

4、georadius

(1)格式

georadius< longitude>radius m|km|ft|mi 以给定的经纬度为中心,找出某一半径内的元素

[外链图片转存中…(img-ExOc4gBn-1629293072056)]

经度 纬度 距离 单位

(2)实例

img

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

junius9

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值