引言

说起redis的数据结构,大家可能对五大基础数据类型比较熟悉:StringHashListSetSorted Set。那么除此之外,还有三大衍生数据结构,大家平时是很少接触的,即:bitmapshyperlogloggeo

另外,我觉得,这三个数据结构,只能说是锦上添花。真正在项目中,我还真没用过。

下面大家来看看这三大数据结构的定义用途

bitmaps

定义

说到这个bitmaps,其实它就是String,但它可以对String的位进行操作。然后呢,这个位操作,有自己的命令,所以和操作Stringredis命令又不大一样!

可以这么理解

bitmaps为一个以位为单位的数组,数组的每个单元只能存储0和1

下面举个例子,比如我们要做一个set操作,keywvalueh,那么执行如下命令

127.0.0.1:6379> set w h
OK
127.0.0.1:6379> get w
"h"

那么h的ASCII为0110 1000

接下来,你可以用位命令getbit命令取出,取出每一位的内容。

127.0.0.1:6379> getbit w 0 #用getbit获取w第0位的值
(integer) 0
127.0.0.1:6379> getbit w 1 #用getbit获取w第1位的值
(integer) 1
127.0.0.1:6379> getbit w 2 #用getbit获取w第2位的值
(integer) 1
127.0.0.1:6379> getbit w 3 #用getbit获取w第3位的值
(integer) 0

用途

网上传言,此结构用来统计一定时间内的,活跃的用户数,使用bitmap的结构比传统的set结构省空间。然而,这种用途有很大的局限性,我后文会说到。先说一下,网上的说法。

假设有30个用户,其中有5个用户,在2018-10-04这天登陆了。假设这5个用户的userid=2,4,8,11,12。

那么,我们假设key为users:2018-10-04,将其value值用于记录用户登陆信息。那么为了记录上述5个用户登陆过,我们将该value值的第2位,第4位,第8位,第11位,第12位设为1,即执行下述命令

127.0.0.1:6379> setbit users:2018-10-04 2 1
(integer) 0
127.0.0.1:6379> setbit users:2018-10-04 4 1
(integer) 0
127.0.0.1:6379> setbit users:2018-10-04 8 1
(integer) 0
127.0.0.1:6379> setbit users:2018-10-04 11 1
(integer) 0
127.0.0.1:6379> setbit users:2018-10-04 12 1
(integer) 0

这个时候,比如你要判断userid=11的用户,在2018-10-04这天,有没有登陆过,就执行下述命令

127.0.0.1:6379> getbit users:2018-10-04 11
(integer) 1

结果为1,就代表用户登陆过。如果返回结果为0,则代表用户没登陆过。

如果要统计,2018-10-04,这一天登陆的用户数,可以执行下面的命令

127.0.0.1:6379> bitcount users:2018-10-04
(integer) 5

上面的命令就可以统计出,2018-10-04,这一天5个用户登陆过。

ok,到这里大家就查不多能明白了。

先说一下,这里的userid=2,4,8,11,12,可以理解为偏移量。比如实际项目中的userid位1000002,那么偏移量就是2。大家在项目中,可以灵活变通。

然而这种方式有一个局限性。我们在实际项目中,如果userid是使用uuid生成的,那么,你要如何根据这些userid生成偏移量?莫非你还要去找一个hash函数,生成偏移量?就算找到了相应的hash函数,你能确保一定不发生hash碰撞,导致偏移量一致?

所以,大家了解即可。

HyperLogLog

定义

HyperLogLog并不是一种数据结构,而是一种算法,可以利用极小的内存空间完成独立总数的统计

其实,大家可能对该算法比较陌生。我们java中有一个库叫stream-lib,其中也实现了HyperLogLog算法。我大概说一下该算法的原理,我不想去长篇大论的搬出数学论文来,大家看着也无聊,这里Hyper指的是超级的意思,它的前世是LogLog算法。这里博主蜻蜓点水的装13一下,大家能领悟到精髓即可。

假设有如下对话

我:"小曲啊,假设啊,我一轮丢5次硬币,丢了很多轮之后,发现这几轮中,最多出现连续的2次反面1次正面,你能猜出来我丢了多少轮么!"

小曲:"应该没几轮吧,顶多就七八轮。"

我:"卧槽,这么机智,怎么算的?"

小曲:"很简单啊,正反面概率都是1/2,连着二次反面,一次正面。不就是1/21/21/2么!"

我:"那要是最多出现连续的4次反面1次正面呢?"

小曲:"那应该是很多很多轮吧!"

我:"果然机智!"

上述聊天,出自我和同事曲之间的,日常互吹!如有雷同,纯属巧合!

好了,原理讲完了!只是他的估算算法比较复杂!没这么简单而已!而且这么估,误差还比较大!下面给出算法的伪代码。

输入:一个集合
输出:集合的独立总数
算法:
max = 0
对于集合中的每个元素:
hashCode = hash(元素)
num = hashCode二进制表示中最前面连续的0的数量
if num > max:
max = num
最后的结果是2的(max + 1)次幂

需要说明的是

hashCode = hash(元素)

就是把你的输入元素,映射成二进制长串。映射成二进制长串后,就可以类比到我最先说的抛硬币的结果了。至于最后的结果为什么用(max+1),大家可以去查文献。毕竟这文章是在讲redis,不是在讲这个算法。而且这个算法,后面还经过了一系列演进,比如将入参集合分为m个部分,然后将m个部分的结果求一个平均数(avg),最后以2的(avg + 1)次幂,来估计独立总数!这些读者有兴趣可以自行查询!

用途

这个结构可以非常省内存的去统计各种计数,比如注册IP数、每日访问IP数。当然,存在误差!Redis官方给出的数字是0.81%的失误率。

用法也很简单如下所示

127.0.0.1:6379> pfadd ips:2018-10-04 "127.0.0.1" "127.0.0.2" "127.0.0.3" "127.0.0.4"
(integer) 1
127.0.0.1:6379> pfcount ips:2018-10-04
(integer) 4

上面就是演示了,2018-10-04这天,约4个ip登陆了系统!

网上有一张和传统集合结构的占用空间对比图,贴出来,给大家看看



注意了,再强调一次,使用此结构是存在误差的!比如你pfadd了一百万条数据进去,结果pfcount的结果可能就999756条!

Geo

定义

Geo可以用于存储经纬度、计算两地之间的距离、范围计算等。其底层实现是zset。

用途

主要有以下六组命令

  • geoadd:增加某个地理位置的坐标。
  • geopos:获取某个地理位置的坐标。
  • geodist:获取两个地理位置的距离。
  • georadius:根据给定地理位置坐标获取指定范围内的地理位置集合。
  • georadiusbymember:根据给定地理位置获取指定范围内的地理位置集合
  • geohash:获取某个地理位置的geohash值。

我这里直接贴官网文档的例子,大家有兴趣可以自行查询.

首先,先给key增加两个坐标

redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2

其次,计算两个坐标之间的举例

redis> GEODIST Sicily Palermo Catania
"166274.15156960039"

最后,计算距离经纬度(15,37)距离100km200km范围内的坐标有哪些

redis> GEORADIUS Sicily 15 37 100 km
1) "Catania" redis> GEORADIUS Sicily 15 37 200 km
1) "Palermo"
2) "Catania"

总结,我目前还没涉及到和地图有关的业务,因此该结构用的还比较少。大家根据项目具体需求使用即可!

【原创】分布式之redis的三大衍生数据结构的更多相关文章

  1. 看完这篇Redis缓存三大问题,保你面试能造火箭,工作能拧螺丝。

    前言 日常的开发中,无不都是使用数据库来进行数据的存储,由于一般的系统任务中通常不会存在高并发的情况,所以这样看起来并没有什么问题. 一旦涉及大数据量的需求,如一些商品抢购的情景,或者主页访问量瞬间较 ...

  2. Redis 5 种基本数据结构(String、List、Hash、Set、Sorted Set)详解 | JavaGuide

    首发于:Redis 5 种基本数据结构详解 - JavaGuide 相关文章:Redis常见面试题总结(上) . Redis 5 种基本数据结构(String.List.Hash.Set.Sorted ...

  3. 分布式缓存Redis使用心得

    一.缓存在系统中用来做什么 1. 少量数据存储,高速读写访问.通过数据全部in-momery 的方式来保证高速访问,同时提供数据落地的功能,实际这正是Redis最主要的适用场景. 2. 海量数据存储, ...

  4. 企业项目开发--分布式缓存Redis

    第九章 企业项目开发--分布式缓存Redis(1) 注意:本章代码将会建立在上一章的代码基础上,上一章链接<第八章 企业项目开发--分布式缓存memcached> 1.为什么用Redis ...

  5. 第九章 企业项目开发--分布式缓存Redis(1)

    注意:本章代码将会建立在上一章的代码基础上,上一章链接<第八章 企业项目开发--分布式缓存memcached> 1.为什么用Redis 1.1.为什么用分布式缓存(或者说本地缓存存在的问题 ...

  6. .NET分布式缓存Redis从入门到实战

    一.课程介绍 今天阿笨给大家带来一堂NOSQL的课程,本期的主角是Redis.希望大家学完本次分享课程后对redis有一个基本的了解和认识,并且熟悉和掌握 Redis在.NET中的使用. 本次分享课程 ...

  7. 第十章 企业项目开发--分布式缓存Redis(2)

    注意:本章代码是在上一章的基础上进行添加修改,上一章链接<第九章 企业项目开发--分布式缓存Redis(1)> 上一章说了ShardedJedisPool的创建过程,以及redis五种数据 ...

  8. 【转载】分布式之redis复习精讲

    注: 本篇文章转自:分布式之redis复习精讲 引言 为什么写这篇文章? 博主的<分布式之消息队列复习精讲>得到了大家的好评,内心诚惶诚恐,想着再出一篇关于复习精讲的文章.但是还是要说明一 ...

  9. 详细介绍Redis的几种数据结构以及使用注意事项(转)

    原文:详细介绍Redis的几种数据结构以及使用注意事项 1. Overview 1.1 资料 <The Little Redis Book>,最好的入门小册子,可以先于一切文档之前看,免费 ...

随机推荐

  1. JAVA设计模式——代理(静态代理)

    定义 为其它的对象提供一种代理,以控制这个对象的访问 使用场景 当不想直接访问某个对象的时候,就可以通过代理 1.不想买午餐,同事帮忙带 2.买车不用去厂里,去4s店 3.去代理点买火车票,不用去车站 ...

  2. MySQL 5.7安装指南

    1.下载 1)进入官网下载5.7.23压缩包 下载地址:https://dev.mysql.com/downloads/mysql/5.7.html#downloads 2.安装与配置 1)将下载的压 ...

  3. CentOS6.8下MySQL MHA架构搭建笔记

    转载请注明出处,本文地址:http://www.cnblogs.com/ajiangg/p/6552855.html 以下是CentOS6.8下MySQL MHA架构搭建笔记 IP资源规划: 192. ...

  4. java.lang.NumberFormatException: Infinite or NaN

      1.异常提示: java.lang.NumberFormatException: Infinite or NaN 2.原因:无法格式化的数字,此数字要么不是个数字,要么是无穷大的数字,从而导致 B ...

  5. 孟岩:通证(token)和通证经济的目的在于改善现有经济的效率性

    孟岩是最早将token翻译成为通证的区块链大咖,这个翻译已经得到到了越来越人的认可.原来它叫代币,孟岩建议把它翻译成通证.以下是孟岩关于通证的注解. (孟岩,柏链道捷CEO,CSDN副总裁,区块链通证 ...

  6. win7 中 sql server2005 卸载简介

    注:卸载前一定要做好备份,一定要清理干净,不然重装会出错(只针对完全卸载,没试过只删除一个版本的) 工具:①Windows Install Clean Up  ②SrvInstw.exe 1.停止所有 ...

  7. Android Studio插件GsonFormat

    GsonFormat插件用于在androidStudio 根据json自动生成class的字段和方法,极大提高了开发效率 一.安装GsonFormat插件 二.重启Android Studio,新建一 ...

  8. monkeyrunner.bat运行python脚本/命令行

    http://luochunfeng163.blog.163.com/blog/static/1670092492014258914775/

  9. 浏览器本地数据存储解决方案以及cookie的坑

    本地数据存储解决方案以及cookie的坑 问题: cookie过长导致页面打开失败 背景: 在公司的项目中有一个需求是打开多个工单即在同一个页面中打开了多个tab(iframe),但是需要在刷新时只刷 ...

  10. Android项目的targetSDK>=23,在低于Android6.0的部分测试机(类似华为)上运行时出现的系统权限问题

    相信大家对Android6.0以上的动态权限已经有所了解,很多童鞋也已经跃跃欲试地将自己项目的targetSDK升级到了23及其以上,很不幸的是我也成为了其中一员,然而我还是图样图森破了,升级之后的问 ...