一、高级数据类型

1.1 bitmap(位存储)

简介

  • bitmap 是位图数据结构,只有0 和 1 两个状态

  • Bitmaps本身不是一种数据类型, 实际上它就是字符串(key-value),但是它可以对字符串的位进行操 作。

常用命令

使用bitmap 来记录 周一到周日的打卡! 周日:1 周一:1 周二:1 周三:0 周四:1 周五:0 周六:1

127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 1
(integer) 0
127.0.0.1:6379> setbit sign 2 1
(integer) 0
127.0.0.1:6379> setbit sign 3 0
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> setbit sign 5 0
(integer) 0
127.0.0.1:6379> setbit sign 6 1
(integer) 0

查看某一天是否有打卡

127.0.0.1:6379> getbit sign 4
(integer) 1
127.0.0.1:6379> getbit sign 5
(integer) 0

统计操作,统计打卡的天数!

127.0.0.1:6379> bitcount sign # 统计这周的打卡记录就可以看到是否有全勤
(integer) 5

应用场景

  • 网络流量分析

  • 签到

  • 布隆过滤器

  • 活跃用户统计

bitmaps与set对比

  • 假设网站有1亿用户, 每天独立访问的用户有5千万, 如果每天用集合类型和Bitmaps分别存储活跃用户 可以得到表。使用Bitmaps能节省很多的内存空间。

  • 假如该网站每天的独立访问用户很少,例如只有10万(大量的僵尸用户),这时候使用Bitmaps就不太合适 了,因为基本上大部分位都是0。

1.2 HyperLogLog(基数统计)

简介

HyperLogLog

  • Redis 2.8.9 版本更新了 Hyperloglog 数据结构

  • HyperLogLog 并不是一种新的数据结构(实际类型为字符串类型),而是一种基数算法

  • 可利用极小的内存空间完成独立总数的统计

什么是基数?

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

常用命令

添加

pfadd key element [element …] #添加指定元素到 HyperLogLog 中

计算独立用户数,也就是基数数量

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

合并

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

示例

127.0.0.1:6379> pfadd pfkey1 a b c d e f g h i a a # 创建第一组元素
(integer) 1
127.0.0.1:6379> pfcount pfkey1 # 统计元素的基数数量
(integer) 9
127.0.0.1:6379> pfadd pfkey2 c j k l m e g a # 创建第二组元素
(integer) 1
127.0.0.1:6379> pfcount pfkey2
(integer) 8
127.0.0.1:6379> pfmerge pfkey3 pfkey1 pfkey2 # 合并两组pfkey1 pfkey2 -> pfkey3 并集
OK
127.0.0.1:6379> pfcount pfkey3
(integer) 13

应用场景

  • pv与uv的统计

集合类型和HyperLogLog 占用空间对比

1.3 geospatial (地理位置)

1、简介

  • Redis 的 Geo 在 Redis 3.2 版本就推出了!

  • 这个功能可以推算地理位置的信息: 两地之间的距离, 方圆几里的人。

  • geo底层的实现原理实际上就是Zset, 可以通过Zset命令来操作geo

2、常用命令

增加地理位置信息

geoadd key longitude latitude member [longitude latitude member ...]
_>>longitude、latitude、member分别是该地理位置的经度、纬度、成员
127.0.0.1:6379> geoadd china:city 116.28 39.55 beijing 112.55 37.86 taiyuan 123.43 41.80 shenyang
(integer) 3
127.0.0.1:6379> geoadd china:city 119.01 39.38 tangshan 120.16 30.24 hangzhou 108.96 34.26 xianjin
(integer) 3

规则:

  • 有效的经度从-180度到180度。

  • 有效的纬度从-85.05112878度到85.05112878度。

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

127.0.0.1:6379> geoadd china:city 39.90 116.40 shanghai
(error) ERR invalid longitude,latitude pair 39.900000,116.400000

获取地理位置信息

geopos key member [member ...]
127.0.0.1:6379> geopos china:city beijing taiyuan #获取北京、太原的经纬度信息
1) 1) "116.28000229597091675"
2) "39.5500007245470826"
2) 1) "112\.54999905824661255"
2) "37\.86000073876942196"

获取两个地理位置的距离

geodist key member1 member2 [unit] #如果不存在, 返回空 其中unit代表返回结果的单位包含以下四种
  • m(meters)代表米

  • km(kilometers)代表公里

  • mi(miles)代表英里,240

  • ft(feet)代表英尺

127.0.0.1:6379> geodist china:city taiyuan shenyang m
"1026439.1070"
127.0.0.1:6379> geodist china:city taiyuan shenyang km
"1026.4391"

获取指定位置范围内的地理信息位置集合, 附近的人 ==> 获得所有附近的人的地址, 定位, 通过半径 来查询

georadius key longitude latitude radius m|km|ft|mi georadiusbymember key member radius m|km|ft|mi
  • radiusm|km|ft|mi是必需参数,指定了半径(带单位)

其他可选参数:

  • withcoord:返回结果中包含经纬度

  • withdist:返回结果中包含离中心节点位置的距离

  • withhash:返回结果中包含geohash

  • COUNT count:指定返回结果的数量

  • asc|desc:返回结果按照离中心节点的距离做升序或者降序。

计算几个城市中,距离北京300公里以内的城市

127.0.0.1:6379> georadiusbymember china:city beijing 300 km
1) "beijing"
1) "tangshan"

以 110,30 这个坐标为中心, 寻找半径为1000km的城市

127.0.0.1:6379> georadius china:city 110 30 1000 km
1) "xianjin"
1) "hangzhou"
1) "taiyuan"

以 110,30 这个坐标为中心, 寻找半径为500km的城市,并返回离中心节点的距离

127.0.0.1:6379> georadius china:city 110 30 500 km withdist
1) 1) "xianjin"
2) "483.8340"

以 110,30 这个坐标为中心, 寻找半径为500km的城市,并返回离中心节点的距离、以及中心节点的经纬 度

127.0.0.1:6379> georadius china:city 110 30 500 km withcoord withdist count 2
1) 1) "xianjin"
   2) "483.8340"
   3) 1) "108.96000176668167114"
      2) "34.25999964418929977"

获取geohash

geohash key member [member ...]
127.0.0.1:6379> geohash china:city beijing
1) "wx48ypbe2q0"

使用zset命令操作geo

127.0.0.1:6379> type china:city
zset

查看全部元素

127.0.0.1:6379> zrange china:city 0 -1 withscores
1) "xian"
2) "4040115445396757"
3) "hangzhou"
4) "4054133997236782"
5) "manjing"
6) "4066006694128997"
7) "taiyuan"
8) "4068216047500484"
9) "shenyang"
1) "4072519231994779"
2) "shengzhen"
3) "4154606886655324"

删除指定的元素

127.0.0.1:6379> zrem china:city manjing
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "xian"
2) "hangzhou"
3) "taiyuan"
4) "shenyang"
5) "shengzhen"

3、应用场景

附近的人

二、key管理

2.1 单个键管理

键重命名

rename key newkey renamenx key newkey

随机返回一个键

randomkey

键过期

expire key seconds #key在seconds秒后过期。
expireat key timestamp #key在秒级时间戳timestamp后过期。
ttl key #返回还剩余多少秒过期
pttl key #返回还剩余多少毫秒过期
pexpire key milliseconds #key在milliseconds毫秒后过期。 pexpireat key milliseconds-timestamp #key在毫秒级时间戳timestamp后过期 persist key # 移除给定 key 的过期时间,使得 key 永不过期

注意:

  • 如果expire key的键不存在,返回结果为0

  • 如果过期时间为负值,键会立即被删除,犹如使用del命令一样

  • persist命令可以将键的过期时间清除

  • 对于字符串类型键,执行set命令会去掉过期时间

  • Redis不支持二级数据结构(例如哈希、列表)内部元素的过期功能,例如不能对列表类型的一个元素做过 期时间设置

  • setex命令作为set+expire的组合,不但是原子执行,同时减少了一次网络通讯的时间

示例

127.0.0.1:6379> set hello world
OK
127.0.0.1:6379> expire hello 10
(integer) 1

还剩7秒

127.0.0.1:6379> ttl hello
(integer) 7
...

还剩0秒

127.0.0.1:6379> ttl hello
(integer) 0
#返回结果为-2说明键hello已经被删除
127.0.0.1:6379> ttl hello
(integer) -2

2.2 遍历

全量遍历键

keys pattern

keys pattern
- pattern使用的是glob风格的通配符:
* 代表匹配任意字符。 代表匹配一个字符。
[]代表匹配部分字符,例如[1,3]代表匹配1,3,[1-10]代表匹配1到10 的任意数字
\x用来做转义,例如要匹配星号、问号需要进行转义

渐进式遍历

scan cursor [match pattern] [count number]
  • cursor,必需参数,是一个游标,第一次遍历从0开始,每次scan遍历完都会返回当前游标的值,直到游

标值为0,表示遍历结束。

  • match pattern,可选参数,做模式的匹配

  • count number,可选参数,表示每次要遍历的键个数,默认值是10

其他遍历命令: hscan、sscan、zscan

遍历某个前缀的key的数量

使用方法

python scan_key.py aaa* 100

遍历redis中以aaa为前缀key的个数,每次遍历100个。

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# 作用:统计某个前缀key的个数,并将其写入到文件

__author__ = "linda"

import sys
import redis
import os

pool = redis.ConnectionPool(host='192.168.9.144', port=6379, db=0, password='linda123')
r = redis.StrictRedis(connection_pool=pool)

# 扫描匹配值,通过sys.argv传参
match = sys.argv[1]
match_list = match.split("|")
print match_list

# 每次匹配数量
count = sys.argv[2]
path = os.getcwd()

# 扫描到的key输出的文件
txt = path + "/keys.txt"
f = open(txt, "w")
for i in match_list:
    print "key前缀为:%s" % i
    total = 0
    for key in r.scan_iter(match=i, count=count):
        f.write(key + "\n")
        total = total + 1
        if total % 100000 == 0:
            print("total=%s" % total)
    print "匹配: %s 的数量为:%d " % (i, total)

f.close

2.3 数据库管理

切换数据库

select dbIndex

说明: 生产环境建议只使用0号数据库,如果想要使用多个数据库功能,可以在一台机器上部署多个Redis实例,彼此 用端口来做区分。这样既保证了业务之间不会受到影响,又合理地使用了CPU资源。

  • 清空数据库
flushdb/flushall

说明: 生产环境使用rename-command配置规避掉flushdb/flushall命令,防止误操作。