美文网首页
66.4-Redis服务和字符串类型

66.4-Redis服务和字符串类型

作者: BeautifulSoulpy | 来源:发表于2020-09-11 17:30 被阅读0次

    人生最大的幸福就是健康地生活着!

    总结:

    1. redis最关注的问题: 是你要用python来解决数据存储(如何选择数据存储的类型)的问题;内存如何合理使用的问题;
    2. redis的数据安全指的是:将所有的二进制数据转成10进制后,在转成字符串;
    3. redis的本质是key-value对, 只不过value 可以为:str/Dict(hash 字典V 套字典)/set(集合),所以他的变化指的是value的类型变化; 他就是内存结构的典型的嵌套结构的一个复杂的K-V对;
    4. 任何 flashdb都是危险操作;
    5. 介绍 Redis 的对象系统中的字符串对象(String)、列表对象(List)、哈希对象(Hash)、集合对象(Set)和有序集合对象(ZSet)
    6. Redis 的list 可以当成缓冲队列 来使用的;业务场景:

    参考:

    1. Redis数据结构详解,五种数据结构分分钟掌握
    2. 十二张图详解Redis的数据结构和对象系统
    3. 万字长文的Redis五种数据结构详解(理论+实战),建议收藏

    Redis

    官方网站:http://www.radis.io
    中文网站:http://www.redis.cn
    开源的(BSD协议),使用ANSI C 编写,基于内存的且支持持久化,高性能的Key-Value的NoSQL数据库。

    支持数据结构类型丰富,有如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。
    丰富的支持主流语言的客户端,C、C++、Python、Erlang、R、C#、Java、PHP、Objective-C、Perl、Ruby、Scala、Go、JavaScript。
    用途:缓存(StackOverFlow)、数据库(微博)、消息中间件(微博)

    Redis版本
    目前主要版本为3.2
    redis在2017年也发布了4.x版本,目前是4.0.x
    部署环境是Linux,本次部署在CentOS 6.x上。

    Windows版本由微软提供 https://github.com/MicrosoftArchive/redis
    可视化工具RedisDesktopManager。windows目前使用redis-desktop-manager-0.8.x,0.9有点问题。

    1. Redis安装

    Linux单节点安装
    # yum -y install gcc tcl
    # tar xf redis-3.2.12.tar.gz
    # mv redis-3.2.12/ redis
    # cd redis
    # make
    ------------------------------------编译安装成功;
       LINK redis-server            # 最常用的3个文件 ; 
        INSTALL redis-sentinel
        CC redis-cli.o
    Hint: It's a good idea to run 'make test' ;)
    make[1]: Leaving directory `/root/redis-3.2.12/src'
    
    如果出错,需要redis目录下
    # cd deps
    # make jemalloc
    # make lua
    # make linenoise
    # make hiredis
    # cd ..
    
    缺省安装
    # make install
    默认安装到/usr/local/bin
    
    自定义安装
    # mkdir -p /magedu/redis
    # make PREFIX=/magedu/redis install
    

    可执行文件

    cd src
    redis-benchmark
    redis-check-aof
    redis-check-dump
    redis-cli # 客户端
    redis-server

    [root@Centos7 src]# mkdir /magedu/redis -p   # 创建目录
    
    [root@Centos7 redis-3.2.12]# make PREFIX=/magedu/redis/ install   # 拷贝文件;
    cd src && make install
    make[1]: Entering directory `/root/redis-3.2.12/src'
    
    Hint: It's a good idea to run 'make test' ;)
    
        INSTALL install
        INSTALL install
        INSTALL install
        INSTALL install
        INSTALL install
    make[1]: Leaving directory `/root/redis-3.2.12/src'
    
    [root@Centos7 src]# cd /magedu/redis/
    [root@Centos7 redis]# ls
    bin
    [root@Centos7 redis]# cd bin/
    [root@Centos7 bin]# ll
    total 15080
    -rwxr-xr-x. 1 root root 2433432 Aug 13 17:10 redis-benchmark
    -rwxr-xr-x. 1 root root   24992 Aug 13 17:10 redis-check-aof
    -rwxr-xr-x. 1 root root 5191752 Aug 13 17:10 redis-check-rdb
    -rwxr-xr-x. 1 root root 2586480 Aug 13 17:10 redis-cli
    lrwxrwxrwx. 1 root root      12 Aug 13 17:10 redis-sentinel -> redis-server
    -rwxr-xr-x. 1 root root 5191752 Aug 13 17:10 redis-server
    
    
    # 把redis变成一个服务;
    [root@Centos7 utils]# ./install_server.sh
    Welcome to the redis service installer
    This script will help you easily set up a running redis server
    
    Please select the redis port for this instance: [6379]
    Selecting default: 6379
    Please select the redis config file name [/etc/redis/6379.conf]
    Selected default - /etc/redis/6379.conf
    Please select the redis log file name [/var/log/redis_6379.log]
    Selected default - /var/log/redis_6379.log
    Please select the data directory for this instance [/var/lib/redis/6379]
    Selected default - /var/lib/redis/6379
    Please select the redis executable path []
    

    环境变量
    可以将下面的变量追加入到~/.bash_profile文件末尾
    export REDIS_HOME=/magedu/redis
    export PATH=PATH:REDIS_HOME/bin

     配置PATH路径
    [root@Centos7 bin]# nano ~/.bash_profile
    
    # .bash_profile
    
    # Get the aliases and functions
    if [ -f ~/.bashrc ]; then
            . ~/.bashrc
    fi
    
    # User specific environment and startup programs
    
    PATH=$PATH:$HOME/bin
    
    export PATH
    export PYENV_ROOT="$HOME/.pyenv"
    export PATH="$PYENV_ROOT/bin:$PATH"
    
    export REDIS_HOME=/magedu/redis
    export PATH=$PATH:$REDIS_HOME/bin
    
    [root@Centos7 bin]# source ~/.bash_profile         # 刷新
    [root@Centos7 bin]# ls
    redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli  redis-sentinel  redis-server
    [root@Centos7 bin]# echo $REDIS_HOME            # 配置路径成功;
    /magedu/redis
    
    # 服务
    [root@Centos7 ~]# redis-3.2.12/utils/install_server.sh
    Welcome to the redis service installer
    This script will help you easily set up a running redis server
    
    Please select the redis port for this instance: [6379]
    Selecting default: 6379
    Please select the redis config file name [/etc/redis/6379.conf]
    Selected default - /etc/redis/6379.conf
    Please select the redis log file name [/var/log/redis_6379.log]
    Selected default - /var/log/redis_6379.log
    Please select the data directory for this instance [/var/lib/redis/6379]
    Selected default - /var/lib/redis/6379
    Please select the redis executable path [] /magedu/redis/bin/redis-server    # 路径要正确
    Selected config:
    Port           : 6379
    Config file    : /etc/redis/6379.conf
    Log file       : /var/log/redis_6379.log
    Data dir       : /var/lib/redis/6379
    Executable     : /magedu/redis/bin/redis-server
    Cli Executable : /magedu/redis/bin/redis-cli
    Is this ok? Then press ENTER to go on or Ctrl-C to abort.
    Copied /tmp/6379.conf => /etc/init.d/redis_6379
    Installing service...
    Successfully added to chkconfig!
    Successfully added to runlevels 345!
    Starting Redis server...
    Installation successful!
    
    [root@Centos7 bin]# cd /etc/init.d
    [root@Centos7 init.d]# ll
    total 48
    -rw-r--r--. 1 root root 18281 Aug 19  2019 functions
    -rwxr-xr-x. 1 root root  4569 Aug 19  2019 netconsole
    -rwxr-xr-x. 1 root root  7928 Aug 19  2019 network
    -rwxr-xr-x. 1 root root  4014 Nov 30  2017 rabbitmq-server
    -rw-r--r--. 1 root root  1160 Jun 30 23:11 README
    -rwxr-xr-x. 1 root root  1708 Aug 13 17:14 redis_6379
    [root@Centos7 init.d]# mv redis_6379 redisd           # 改一下服务名称;
    

    redis服务

    [root@Centos7 init.d]# chkconfig
    
    Note: This output shows SysV services only and does not include native
          systemd services. SysV configuration data might be overridden by native
          systemd configuration.
    
          If you want to list systemd services use 'systemctl list-unit-files'.
          To see services enabled on particular target use
          'systemctl list-dependencies [target]'.
    
    netconsole      0:off   1:off   2:off   3:off   4:off   5:off   6:off
    network         0:off   1:off   2:on    3:on    4:on    5:on    6:off
    rabbitmq-server 0:off   1:off   2:on    3:on    4:on    5:on    6:off
    [root@Centos7 init.d]# chkconfig redisd on           # 开机启动 redis 2345
    [root@Centos7 init.d]# chkconfig
    
    Note: This output shows SysV services only and does not include native
          systemd services. SysV configuration data might be overridden by native
          systemd configuration.
    
          If you want to list systemd services use 'systemctl list-unit-files'.
          To see services enabled on particular target use
          'systemctl list-dependencies [target]'.
    
    netconsole      0:off   1:off   2:off   3:off   4:off   5:off   6:off
    network         0:off   1:off   2:on    3:on    4:on    5:on    6:off
    rabbitmq-server 0:off   1:off   2:on    3:on    4:on    5:on    6:off
    redisd          0:off   1:off   2:on    3:on    4:on    5:on    6:off
    
    
    
    # redis 配置文件
    [root@Centos7 src]# nano /etc/redis/6379.conf
    
    bind 192.168.0.100 127.0.0.1   
    protected-mode yes
    port 6379
    
    tcp-keepalive 300          # TCP服务保存多长时间;
    daemonize yes            # 以后台服务跑起来
    databases 16            # 总共有16 个库(0-15)
    
    
    # 修改配置文件后  重新 启动 redisd 
    [root@Centos7 ~]# systemctl restart redisd.service
    [root@Centos7 ~]# ss -tanl
    LISTEN     0      128                                                                                      127.0.0.1:6379                                                                                                         *:*
    LISTEN     0      128                                                                                  192.168.0.100:6379
    
    Redis Windows安装

    项目地址 https://github.com/MicrosoftArchive/redis
    下载地址 https://github.com/MicrosoftArchive/redis/releases/download/win-3.2.100/Redis-x64-3.2.100.zip
    解压缩,就可以用了。

    2. Redis数据模型

    redis支持数据模型非常丰富

    2.1 键Key

    Redis key 值是二进制安全的,这意味着可以用任何二进制序列作为key值,从形如”foo”的简单字符串到一个JPEG文件的内容都可以。空字符串也是有效key值
    Key取值原则
    键值不需要太长,消耗内存,而且查找这类键值的计算成本较高
    键值不宜过短,可读性较差
    习惯上key采用'user:123:password'形式,表示用户id为123的用户的密码

    2.2字符串

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

    1. python中redis编程
    安装redis库
    $ pip install redis
    
    import redis
    
    db = redis.Redis('192.168.0.100') # 默认本地6379的0号库
    print(db.keys('*')) # 查看所有匹配keys
    
    db.set(0b01100001, 'a') # 0x61(16进制61) bin二进制=>十进制97=>str :a
    print(db.keys('*'))
    #------------------------------
    []
    [b'97']
    
    print(db.get(0b01100001))
    print(db.get('97'))        # 用字符串 拿
    #----------------------
    b'a'
    b'a'
    
    # key的三种形式
    db.set(0b11, 'abc')
    print(db.get(0b11))
    print(db.get(3))
    print(db.get('3'))
    #----------------------
    b'abc'
    b'abc'
    b'abc'
    

    注意:上例中0x62实际上发生了类型变化,因为返回的bytes类型98,实际上对应ASCII的98,已经是2字节了。

    数值会先转换成10进制64位有符号数后,再转成字符串,存入redis中。

    2. 查看帮助
    > Help 查看帮助
    > Help <tab> 使用tab键切换帮助
    > Help set 查看set命令帮助
    > Help @string 查看命令组帮助
    
    3. 字符串设置
    SET key value [EX seconds][PX milliseconds] [NX|XX]
    设置字符串值
    EX 设置过期时间,秒,等同于  SETEX key seconds value
    PX 设置过期时间,毫秒,等同于  PSETEX key milliseconds value
    NX 键不存在,才能设置,等同于  SETNX key value
    XX 键存在时,才能设置
    
    MSET key value [key value ...]
    设置多个键的字符串值,key存在则覆盖,key不存在则增加
    原子操作
    
    MSETNX key value [key value ...]
    key不存在则设置,key存在则失败。nx指不存在。
    这个命令是原子操作(一个失败,操作全部失败)
    
    4. 过期操作和生存时间

    Redis中可以给每个Key设置一个生存时间(秒或毫秒),当达到这个时长后,这些键值将会被自动删除

    EXPIRE key seconds
    PEXPIRE key milliseconds
    设置多少秒或者毫秒后过期
    
    EXPIREAT key timestamp
    PEXPIREAT key milliseconds-timestamp
    设置在指定Unix时间戳过期
    
    PERSIST key
    持久key,即取消过期
    
    Time To Live,Key的剩余生存时间
    TTL key
    PTTL key
    key存在但没有设置TTL,返回-1 
    key存在,但还在生存期内,返回剩余的秒或者毫秒
    key曾经存在,但已经消亡,返回-2(2.8版本之前返回-1)
    
    图片.png

    适用场景
    一、多少秒过期,例如一个缓存数据失效
    二、PEXPIREAT key milliseconds-timestamp,比如现在开始缓存数据,到0点失效

    set s5 abc ex 20
    ttl s5
    
    setnx s6 6
    expire s6 60
    
    pttl s6
    persist s6
    ttl s6
    
    EXPIREAT cache 1355292000
    PEXPIREAT mykey 1555555555005
    
    5. key操作

    keys pattern
    pattern可以取如下值:
    1. * 任意长度字符
    2. ? 任意一个字符
    3. [] 字符集合,表示一个字符

    keys *
    keys s?
    keys s[13]
    keys s*
    keys ??
    keys s[1-3]
    
    TYPE key key类型
    EXISTS key key是否存在
    RENAME key newkey 、 RENAMENX key newkey 键重命名
    DEL key [key ...] 键删除
    6. 字符串获取
    GET key 获取值
    MGET key [key ...] 获取多个给定的键的值
    GETSET key value 返回旧值并设置新值,如果键不存在,就创建并赋值
    STRLEN key 字符串长度
    get s4
    mget s1 s3 s5 s7
    strlen s3
    mgetset s5 100
    
    7. 字符串操作
    APPEND key value 追加字符串。如果键存在就追加;如果不存在就等同于SET key value
    获取子字符串
    GETRANGE key start end 索引值从0开始,支持负索引,-1表示最后一个字符。范围是[start, end],start必须在end的左边,否则返回空串(前后都包括)
    SETRANGE key offset value 从指定索引处开始覆盖字符串,返回覆盖后字符串长度。key不存在会创建新的
    127.0.0.1:6379[1]> get s4
    (nil)
    127.0.0.1:6379[1]> APPEND s4 0123
    (integer) 4
    127.0.0.1:6379[1]> get s4
    "0123"
    127.0.0.1:6379[1]> setrange s4 2 a
    (integer) 4
    127.0.0.1:6379[1]> get s4
    "01a3"
    127.0.0.1:6379[1]> setrange s4 2 abcde
    (integer) 7
    127.0.0.1:6379[1]> get s4
    "01abcde"
    
    8. 自增、自减
    INCR key 和 DECR key 步长1的增减
    INCRBY key decrement 和 DECRBY key decrement 步长增减

    字符串值会被解释成64位有符号的十进制整数来操作,结果依然转成字符串

    127.0.0.1:6379[1]> set s3 10
    OK
    127.0.0.1:6379[1]> incr s3
    (integer) 11
    127.0.0.1:6379[1]> incrby s3 100
    (integer) 111
    127.0.0.1:6379[1]> DECRBY s3 200
    (integer) -89
    127.0.0.1:6379[1]>
    
    2.3 库操作

    任何 flashdb都是危险操作,一定有损失;

    登录不同的库
    redis-cli --help
    redis-cli -n 2

    清除当前库数据
    FLUSHDB

    清除所有库中的数据
    FLUSHALL

    2.4 位图bitmap

    位图不是真正的数据类型,它是定义在字符串类型上,只不过把字符串按位操作
    一个字符串类型的值最多能存储512M字节的内容,可以表示2^32位位上限

    512=29
    1M=1024*1024=210+10
    1Byte=8bit=23bit
    2(9+10+10+3) = 232 b = 4294967296 b ,接近43亿个位

    SETBIT key offset value 设置某一位上的值
    offset偏移量,从0开始;
    value不写,默认是0
    GETBIT key offset 获取某一位上的值
    BITPOS key bit [start][end] 返回指定值0或者1在指定区间上第一次出现的位置
    BITCOUNT key [start][end] 统计指定位区间上值为1的个数,从左向右从0开始,从右向左从-1开始,注意官方start、end是位,测试后是字节
    BITCOUNT testkey 0 0 表示从索引为0个字节到索引为0个字节,就是第一个字节的统计
    BITCOUNT testkey 0 -1 等同于 BITCOUNT testkey;最常用的就是 BITCOUNT testkey
    # 记住 \x3  7 
    127.0.0.1:6379[1]> set s4 7
    OK
    127.0.0.1:6379[1]> getbit s4 0
    (integer) 0
    127.0.0.1:6379[1]> getbit s4 1
    (integer) 0
    127.0.0.1:6379[1]> getbit s4 2
    (integer) 1
    127.0.0.1:6379[1]> getbit s4 3
    (integer) 1
    127.0.0.1:6379[1]> getbit s4 4
    (integer) 0
    127.0.0.1:6379[1]> getbit s4 5
    (integer) 1
    127.0.0.1:6379[1]> getbit s4 6
    (integer) 1
    127.0.0.1:6379[1]> getbit s4 7
    (integer) 1
    
    #------------------------------------
    127.0.0.1:6379[1]> set str1 abc
    OK
    127.0.0.1:6379[1]> setbit str1 6 1
    (integer) 0
    127.0.0.1:6379[1]> setbit str1 7 0
    (integer) 1
    127.0.0.1:6379[1]> get str1
    "bbc"
    #------------------------------------
    # 按照位统计的; 
    127.0.0.1:6379[1]> set s4 77
    OK
    127.0.0.1:6379[1]> bitcount s4 0 0
    (integer) 5
    127.0.0.1:6379[1]> bitcount s4 1 1
    (integer) 5
    127.0.0.1:6379[1]> bitcount s4
    (integer) 10
    
    1. 位操作

    BITOP命令用于对多个值(除NOT操作外)执行位运算操作,并将结果保存至指定的键值对中。BITOP命令将返回结果字符串的长度,其值等于输入中最长字符串的长度。

    BITOP operation destkey key [key ...]
    

    BITOP命令支持与(AND)、或(OR)、亦或(XOR)以及非(NOT)四个位运算操作,其使用方式为:

    AND 与操作,使用方式为BITOP AND destkey srckey1 srckey2 ...
    OR 或操作,使用方式为BITOP OR destkey srckey1 srckey2 ...
    XOR 亦或操作,使用方式为BITOP XOR destkey srckey1 srckey2 ...
    NOT 非操作,使用方式为BITOP NOT destkey srckey

    当输入的字符串长度不同时,将使用0填充至与最长长度相同。若输入的键不存在则认定为一个空白字符串,并以0填充至与最长长度相同。

    # 10101010
    redis> SET key1 "\xaa"
    OK
    # 01010101
    redis> SET key2 "\x55"
    OK
    # 11110000
    redis> SET key3 "\xf0"
    OK
    # 01010101 01010101
    redis> SET key4 "\x5555"
    OK
    与(AND)操作:
    
    # 10101010 & 01010101 = 00000000
    redis> BITOP AND result key1 key2
    (integer) 1
    redis> GET result
    "\x00"
    或(OR)操作:
    
    # 10101010 | 01010101 = 11111111
    redis> BITOP OR result key1 key2
    (integer) 1
    redis> GET result
    "\xff"
    亦或(XOR)操作:
    
    # 10101010 ^ 11110000 = 01011010
    redis> BITOP XOR result key1 key3
    (integer) 1
    # 字符Z二进制值为 01011010
    redis> GET result
    "Z"
    或(OR)操作:
    
    # !10101010 = 01010101
    redis> BITOP NOT result key1
    (integer) 1
    # 字符U二进制值为 01010101
    redis> GET result
    "U"
    不同长度的字符串进行位运算:
    
    # key1的值将以0填充为 10101010 00000000
    # 10101010 00000000 | 01010101 01010101 = 11111111 00000000
    redis> BITOP OR result key1 key4
    (integer) 2
    redis> GET result
    "\xffU"
    

    思考:'a'位或'b'是什么?

    set s1 ab
    bitcount s1
    bitcount s1 0 0
    bitcount s1 1 1
    
    set s2 a
    set s3 b
    bitop or s8 s2 s3 # 等于什么?
    
    set cn 中
    get cn
    bitcount cn
    
    2. 习题

    1、网站用户的上线次数统计(活跃用户)
    2、按天统计网站活跃用户

    参考
    1、网站用户的上线次数统计(活跃用户)
    为每一个用户做上线记录,某天登录就标记一次。
    用户ID为key,天作为offset,上线置为1
    ID为500的用户,今年的第1天上线、第30天上线
    SETBIT u:500 1 1
    SETBIT u:500 30 1
    BITCOUNT u:500
    KYES u*

    from redis import Redis
    
    redis = Redis('192.168.0.100', db=2)
    
    # user id 1
    redis.setbit('u:1', 1, 1)
    redis.setbit('u:1', 30, 1)
    
    # user id 101
    redis.setbit('u:101', 3, 1)
    redis.setbit('u:1', 30, 1)
    
    # user id 501
    for i in range(3, 365, 3):
        redis.setbit('u:501', i, 1)
    
    for i in range(2, 365, 2):
        redis.setbit('u:1000', i, 1)
    
    active = []
    inactive = []
    
    users = redis.keys('u*')
    print(users)
    
    for user in users:
        count = redis.bitcount(user)
        if count > 100:
            active.append(user)
        else:
            inactive.append(user)
    
    print('活跃用户为{},{}'.format(active, len(active)))
    print('不活跃用户为{},{}'.format(inactive, len(inactive)))
    

    2、按天统计网站活跃用户
    天作为key,用户ID为offset,上线置为1
    求一段时间内活跃用户数
    SETBIT 20160602 15 1
    SETBIT 20160601 123 1
    SETBIT 20160606 123 1

    求6月1日到6月10日的活跃用户
    BITOP OR 20160601-10 20160601 20160602 20160603 20160610
    BITCOUNT 20160601-10
    结果为2

    2.5 List列表

    列表类型存储了一个有序的字符串列表。常用的操作是向两端插入新的元素。时间复杂度为O(1)。结构为一个链表。记录头和尾的地址。看到这里,Redis数据类型的列表类型一个重大的作用呼之欲出,那就是队列。新来的请求插入到尾部,新处理过的从头部删除。另外,比如微博的新鲜事。比如日志。列表类型就是一个下标从0开始的数组。由于是链表存储,那么越靠近头和尾的元素操作越快,越靠近中间则越慢。

    • 其列表是基于双向链表实现,列表头尾增删快,中间增删慢
    • 元素是字符串类型
    • 元素可以重复出现
    • 索引支持正索引和负索引,从左至右从0开始,从右至左从-1开始
      命令说明
    字母 说明
    B Block阻塞
    L Left左起
    R Right 右起
    X exist 存在
    LPUSH key value [value ...] 从左边向队列中压入元素
    LPUSHX key value 从左边向队列加入元素,要求key必须存在
    RPUSH key value [value ...] 从右边向队列中压入数据
    RPUSHX key value 要求key存在
    - -
    LPOP key 从左边弹出列表中一个元素
    RPOP key 从右边弹出列表中一个元素
    - -
    RPOPLPUSH source destination 从源列表中右边pop一个元素,从左边加入到目标列表
    LRANGE key start stop 返回列表中指定访问的元素,例如LRANGE user 0 -1
    - -
    LINDEX key index 返回列表中指定索引的元素
    LSET key index value 设置列表中指定索引位置的元素值,index不能超界
    LREM key count value 从左边删除列表中与value相等的元素
    count > 0 从左至右搜索,移除与 value 相等的元素,数量至多为 count 次
    count < 0 从右至左搜索,移除与 value 相等的元素,数量至多为 -count次
    count = 0 移除列表中所有value值
    - -
    LTRIM key start stop 去除指定范围外的元素
    RPUSH listkey c abc c ab 123 ab bj ab redis list
    LTRIM listkey 0 -1 # 什么都没有去除
    LTRIM listkey 1 -1 # 去掉左边头
    LTRIM listkey 1 10000
    - -
    LINSERT key BEFORE AFTER pivot value 在列表中某个存在的值(pivot)前或后插入元素一次,key或pivot不存在,不进行任何操作
    RPUSH lst 1 2 3 4 2 8 
    LINSERT lst AFTER  2 Python 
    LINSERT lst BEFORE 2 Ruby
    

    阻塞(可以作为队列使用)

    如果弹出的列表不存在或者为空,就会阻塞
    超时时间设置为0,就是永久阻塞,直到有数据可以弹出
    如果多个客户端阻塞在同一个列表上,使用First In First Service原则,先到先服务

    BLPOP key [key ...] timeout 列表左边阻塞弹出元素。timeout是超时秒数,为0为永久阻塞。
    BRPOP key [key ...] timeout 列表左边阻塞弹出元素
    BRPOPLPUSH source destination timeout 从一个列表尾部阻塞弹出元素压入到另一个列表的头部
    # 阻塞式消息队列
    BLPOP MyQueue 0
    RPUSH MyQueue hello
    
    习题

    微博某贴最后评论的50条

    LPUSH u1234:forumid:comments "这是第1条评论"
    LPUSH u1234:forumid:comments "这是第2条评论"
    LPUSH u1234:forumid:comments "这是第3条评论"
    LTRIM u1234:forumid:comments 0 49
    
    2.6 hash散列

    值是由field和value组成的map键值对
    field和value都是字符串类型


    HSET key field value 设置单个字段。field不存在创建,存在覆盖value
    HSETNX key field value 设置单个字段,要求field不存在。如果key不存在,相当于field也不存在
    HMSET key field value [field value ...] 设置多个字段
    HLEN key 返回字段个数
    HEXISTS key field 判断字段是否存在。key或者field不存在,返回0
    HGET key field 返回字段值
    HMGET key field [field ...] 返回多个字段值
    HGETALL key 返回所有的键值对
    HKEYS key 返回所有字段名
    HVALS key 返回所有值
    HINCRBY key field increment 在字段对应的值上进行整数的增量计算
    HINCRBYFLOAT key field increment 在字段对应的值上进行浮点数的增量计算
    HDEL key field [field ...] 删除指定的字段
    hash用途

    节约内存空间
    每创建一个键,它都会为这个键储存一些附加的管理信息(比如这个键的类型,这个键最后一次被访问的时间等等)

    所以数据库里面的键越多,redis数据库服务器在储存附加管理信息方面耗费的内存就越多,花在管理数据库键上的CPU时间也会越多

    不适合hash的情况

    使用二进制位操作命令:因为Redis目前支持对字符串键进行SETBIT、GETBIT、BITOP等操作,如果你想使用这些操作,那么只能使用字符串键,虽然散列也能保存二进制数据

    使用过期键功能:Redis的键过期功能目前只能对键进行过期操作,而不能对散列的字段进行过期操作,因此如果你要对键值对数据使用过期功能的话,那么只能把键值对储存在字符串里面

    习题

    用户维度统计

    统计数包括:关注数、粉丝数、喜欢商品数、发帖数
    用户为Key,不同维度为Field,Value为统计数
    比如关注了5人
    HSET user:100000 follow 5
    HINCRBY user:100000 follow 1

    商品维度统计
    统计值包括喜欢数,评论数,购买数,浏览数等
    HSET item:58000 fav 500
    HINCRBY item:58000 fav 1

    缓存用户信息
    登录后,反复需要读取用户的常用信息,最好的方式就是缓存起来

    set user:001 "bob,18,20010101" 
    mset user:001:name "bob" user:001:age 18 user:001:birthday "20010101" 
    hmset user:001 name "bob" age 18 birthday "20010101    # 推荐使用 
    
    2.7 Set集合

    集合的元素是无序的、去重的,元素是字符串类型。

    SADD key member [member ...] 增加一个或多个元素,元素已存在将忽略
    SREM key member [member ...] 移除一个或多个元素,元素不存在自动忽略
    SCARD key 返回集合中元素的个数。不需要遍历。
    SMEMBERS key 返回集合中的所有元素(hash顺序)。注意,如果集合中元素过多,应当避免使用该方法
    SISMEMBER key member 元素是否是在集合中
    # 拿数据的顺序 不一定一致 ;
    127.0.0.1:6379> sadd f1 perter
    (integer) 1
    127.0.0.1:6379> sadd f1 john may tom
    (integer) 3
    127.0.0.1:6379> SMEMBERS f1
    1) "tom"
    2) "may"
    3) "perter"
    4) "john"
    127.0.0.1:6379> sadd f1 ben
    (integer) 1
    127.0.0.1:6379> sadd f2 john may tom perter ben
    (integer) 5
    127.0.0.1:6379> SMEMBERS f2
    1) "tom"
    2) "may"
    3) "perter"
    4) "john"
    5) "ben"
    127.0.0.1:6379> SMEMBERS f1
    1) "tom"
    2) "may"
    3) "perter"
    4) "john"
    5) "ben"
    

    SRANDMEMBER key [count] 随机返回集合中指定个数的元素如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。如果 count 大于等于集合基数,那么返回整个集合
    如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值

    如果 count 为 0,返回空
    如果 count 不指定,随机返回一个元素

    集合运算
    差集
    SDIFF key [key ...] 从第一个key的集合中去除其他集合和自己的交集部分
    SDIFFSTORE destination key [key ...] 将差集结果存储在目标key中
    SADD number1 123 456 789
    SADD number2 123 456 999
    SDIFF number1 number2
    
    交集
    SINTER key [key ...] 取所有集合交集部分
    SINTERSTORE destination key [key ...] 将交集结果存储在目标key中
    SADD number1 123 456 789
    SADD number2 123 456 999
    SINTER number1 number2
    
    并集
    SUNION key [key ...] 取所有集合并集
    SUNIONSTORE destination key [key ...] 将并集结果存储在目标key中
    SADD number1 123 456 789
    SADD number2 123 456 999
    SUNION number1 number2
    

    习题

    微博的共同关注
    需求:当用户访问另一个用户的时候,会显示出两个用户共同关注哪些相同的用户
    设计:将每个用户关注的用户放在集合中,求交集即可

    2.8 SortedSet有序集合

    类似Set集合,有序的集合。
    每一个元素都关联着一个浮点数分值(Score),并按照分值从小到大的顺序排列集合中的元素。分值可以相同


    ZADD key score member [score member ...] 增加一个或多个元素。如果元素已经存在,则使用新的score
    ZCARD key 返回集合的元素个数
    ZCOUNT key min max 返回指定score范围元素的个数
    ZSCORE key member 显示分值
    ZINCRBY key increment member 增加或减少分值。increment为负数就是减少
    ZRANGE key start stop [WITHSCORES] 返回指定索引区间元素
    如果score相同,则按照字典序lexicographical order 排列
    默认按照score从小到大,如果需要score从大到小排列,使用ZREVRANGE
    ZREVRANGE key start stop [WITHSCORES] 返回指定索引区间元素
    如果score相同,则按照字典序lexicographical order 的 逆序 排列
    默认按照score从大到小,如果需要score从小到大排列,使用ZRANGE
    ZRANK key member 返回元素的排名(索引)
    ZREVRANK key member 返回元素的逆序排名(索引)
    ZADD employees 3500 jack 4000 peter 4000 john 4500 tom 2500 david
    ZCOUNT employees 3000 4000 # 空的;索引
    ZCOUNT employees 0 1   # david jack
    
    ZADD employees 3.2 david
    ZSCORE employees david
    
    ZINCRBY employees 1.5 jack
    ZINCRBY employees -500 tom
    
    ZRANGE employees 0 -1 WITHSCORES
    ZRANK employees peter
    
    ZREVRANGE employees 0 -1 WITHSCORES # 逆序后的索引0到-1,即返回所有
    ZREVRANK employees peter
    

    ZRANGEBYSCORE key min max [WITHSCORES][LIMIT offset count] 返回指定分数区间的元素,返回score默认属于[min,max]之间,元素按照score升序排列,score相同字典序
    LIMIT中offset代表跳过多少个元素,count是返回几个。类似于Mysql
    使用小括号,修改区间为开区间,例如 (5 或者 (10、5)
    -inf和+inf表示负无穷和正无穷

    ZREVRANGEBYSCORE key max min [WITHSCORES][LIMIT offset count] 降序返回指定分数区间的元素 返回score默认属于[min,max]之间,元素按照score降序排列,score相同字典降序

    ZRANGEBYSCORE employees 3500 4000
    ZRANGEBYSCORE employees (4000 5000
    ZRANGEBYSCORE employees 4000 5000 LIMIT 1 5 # 跳过一个,返回至多5个
    
    ZREVRANGEBYSCORE employees +inf -inf
    
    ZREM key member [member ...] 移除一个或多个元素。元素不存在,自动忽略
    ZREMRANGEBYRANK key start stop 移除指定排名范围的元素
    ZREMRANGEBYSCORE key min max 移除指定分值范围的元素
    ZREMRANGEBYRANK employees 0 1
    ZREMRANGEBYSCORE employees 4000 5000
    

    集合运算
    并集

    ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX] numkeys指定key的数量,必须
    WEIGHTS选项,与前面设定的key对应,对应key中每一个score都要乘以这个权重
    AGGREGATE选项,指定并集结果的聚合方式
    SUM: 将所有集合中某一个元素的score值之和作为结果集中该成员的score值,默认
    MIN: 将所有集合中某一个元素的score值中最小值作为结果集中该成员的score值
    MAX: 将所有集合中某一个元素的score值中最大值作为结果集中该成员的score值
    ZADD scores1 70 tom 80 peter 60 john
    ZADD scores2 90 peter 60 ben
    
    ZUNIONSTORE scores-all 2 scores1 scores2
    ZUNIONSTORE scores-all1 2 scores1 scores2 AGGREGATE SUM
    
    ZUNIONSTORE scores-all2 2 scores1 scores2 WEIGHTS 1 0.5 AGGREGATE SUM
    

    交集

    ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX] numkeys指定key的数量,必须
    WEIGHTS选项,与前面设定的key对应,对应key中每一个score都要乘以这个权重
    AGGREGATE选项,指定并集结果的聚合方式
    SUM: 将所有集合中某一个元素的score值之和作为结果集中该成员的score值
    MIN: 将所有集合中某一个元素的score值中最小值作为结果集中该成员的score值
    MAX: 将所有集合中某一个元素的score值中最大值作为结果集中该成员的score值
    习题

    音乐排行榜怎样实现


    每首歌的歌名作为元素(先不考虑重复)
    每首歌的播放次数作为分值
    ZREVRANGE来获取播放次数最多的歌曲(就是最多播放榜了,云音乐热歌榜,没有竞价,没有权重)

    redis3 版本与 2X版本变化较大;

    # redis库3.x版本
    
    import redis
    r = redis.Redis('127.0.0.1', 6379, db=3)
    r.zadd('mboard', {'yellow':1, 'rolling in the deep':1, 'happy':1, 'just the way you are':1})
    r.zadd('mboard', {'eye of the tiger':1, 'billie jean':1, 'say you say me':1, 'payphone':1})
    r.zadd('mboard', {'my heart will go on':1, 'when you believe':1, 'hero':1})
    r.zincrby('mboard', 50, 'yellow')
    r.zincrby('mboard', 60, 'rolling in the deep')
    r.zincrby('mboard', 68.8, 'my heart will go on')
    r.zincrby('mboard', 70, 'when you believe')
    allmusic = r.zrange('mboard', 0, -1, withscores=True)
    print(type(allmusic))
    for m in allmusic:
        print(m)
    print('-' * 30)
    # 排行榜
    musicboard = r.zrevrange('mboard', 0, 9, True)
    print('欧美热歌榜')
    for i, m in enumerate(musicboard):
        print(i, *m)
    
    
    # redis库 2.x版本
    
    import redis
    
    r = redis.Redis(host='192.168.142.135', port=6379, db=3)
    
    r.zadd('mboard','yellow',1,'rolling in the deep',1,'happy',1,'just the way you are',1)
    r.zadd('mboard','eye of the tiger',1,'billie jean',1,'say you say me',1,'payphone',1)
    r.zadd('mboard','my heart will go on',1,'when you believe',1,'hero',1)
    
    r.zincrby('mboard','yellow',50)
    r.zincrby('mboard','rolling in the deep',60)
    r.zincrby('mboard','my heart will go on',68.8)
    r.zincrby('mboard','when you believe',70)
    
    # 所有元素
    allmusic = r.zrange('mboard', 0, -1, withscores=True)
    print(type(allmusic))
    for m in allmusic:
        print(m)
    print('-'*30)
    
    # 排行榜
    musicboard = r.zrevrange('mboard', 0, 9, True)
    print('欧美热曲榜')
    for i, m in enumerate(musicboard):
        print(i, *m)
    

    新浪微博翻页
    新闻网站、博客、论坛、搜索引擎,页面列表条目多,都需要分页

    blog这个key中使用时间戳作为score
    ZADD blog 1407000000 '今天天气不错'
    ZADD blog 1450000000 '今天我们学习Redis'
    ZADD blog 1560000000 '几个Redis使用示例'
    ZREVRANGE blog 10 20
    显示所有博客中的最后的指定的条目

    京东图书畅销榜
    统计单日榜,计算出周榜单、月榜单、年榜单 , 怎么做?

    每天统计一次排行榜
    ZADD bk:it:01 1000 'java' 1500 'Redis' 2000 'haoop' 100 'scala'  80 'python'
    ZADD bk:it:02 1020 'java' 1500 'Redis' 2100 'haoop' 120 'python' 110 'scala' 
    ZADD bk:it:03 1620 'java' 1510 'Redis' 3000 'haoop' 150 'storm' 120 'python'
    
    求销售前10名
    ZUNIONSTORE bk:it:01-03 3 bk:it:01 bk:it:02 bk:it:03
    行吗?
    

    因为上面的单日榜单是累计值,所以不能直接使用并集,要指定聚合运算为MAX

    ZUNIONSTORE bk:it:01-03 3 bk:it:01 bk:it:02 bk:it:03 AGGREGATE MAX 
    ZREVRANGE bk:it:01-03 0 9 WITHSCORES 
    

    注意:如果参与并集元素的元素太多,会耗费大量内存和计算时间,可能会导致Redis服务阻塞,如果非要计算,选在空闲时间或备用服务器上计算。
    另一种统计

    # 常见:
    ZADD bk:it:01 50 'java' 20 'Redis' 40 'haoop' 
    ZADD bk:it:02 70 'java' 30 'Redis' 20 'haoop' 
    ZADD bk:it:03 20 'java' 30 'Redis' 5 'haoop' 
    每天统计当天销售量,统计IT类图书一段时间的最新销售榜单
    ZUNIONSTORE bk:it:01-03 3 bk:it:01 bk:it:02 bk:it:03 AGGREGATE SUM 
    ZREVRANGE bk:it:01-03 0 9 WITHSCORES 
    

    相关文章

      网友评论

          本文标题:66.4-Redis服务和字符串类型

          本文链接:https://www.haomeiwen.com/subject/ukieektx.html