暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Redis从入门到上瘾(二)- 常用命令以及数据类型

编程那些烦心事 2021-03-06
206

不点蓝字,我们哪来故事?



上一章我们入门了,安装了Redis,简单的使用了一下,这一章准备开始讲Redis的一些基本命令以及它的几种数据类型。


性能测试redis-benchmark

在开始之前,先给大家介绍Redis官方自带的一个性能测试工具:



和redis-server、redis-cli命令一样,redis-benchmark命令也有一些参数:

序号选项描述默认值
1-h指定服务器主机名127.0.0.1
2-p指定服务器端口6379
3-s指定服务器 socket
4-c指定并发连接数50
5-n指定请求数10000
6-d以字节的形式指定 SET/GET 值的数据大小2
7-k1=keep alive 0=reconnect1
8-rSET/GET/INCR 使用随机 key, SADD 使用随机值
9-P通过管道传输 <numreq> 请求1
10-q强制退出 redis。仅显示 query/sec 值
11--csv以 CSV 格式输出
12-l生成循环,永久执行测试
13-t仅运行以逗号分隔的测试命令列表。
14-IIdle 模式。仅打开 N 个 idle 连接并等待。

我们来简单测试一下:

    # 测试:100个并发连接 每个并发10w个请求
    redis-benchmark -h 127.0.0.1 -p 6379 -c 100 -n 100000
    .
    .
    .
    ====== SET ======
    100000 requests completed in 2.17 seconds # 对我们的10万个请求进行写入测试
    100 parallel clients # 100个并发客户端
    3 bytes payload # 每次写入3个字节
    keep alive: 1 # 只有1台服务器来处理这些请求,也就是说这是单机性能


    38.83% <= 1 milliseconds # 第1毫秒处理了38.83%的请求
    99.89% <= 2 milliseconds # 第2毫秒处理了99.89%的请求
    99.90% <= 3 milliseconds
    99.90% <= 4 milliseconds
    99.90% <= 5 milliseconds
    99.93% <= 6 milliseconds
    99.96% <= 7 milliseconds
    99.98% <= 8 milliseconds
    100.00% <= 8 milliseconds # 8毫秒内处理了所有请求
    46104.20 requests per second # 每秒钟处理46104.20个请求


    ====== GET ======
    100000 requests completed in 2.19 seconds
    100 parallel clients
    3 bytes payload
    keep alive: 1


    35.06% <= 1 milliseconds
    99.99% <= 2 milliseconds
    100.00% <= 2 milliseconds
    45578.85 requests per second
    .
    .
    .

    这数据的分析可以参考备注,它其实打印出了很多的指标(SET、GET、PING_BULK、PING_INLINE、INCR等等),但是分析的方式都是一样的。

    这个性能测试可以帮助我们理解,Redis到底有多快。

    官方的测试数据是:读的速度是 110000次/s,写的速度是 81000次/s 。


    Redis为什么是单线程的?

    官方表示:Redis是基于内存操作的,CPU并不是Redis的内存瓶颈。Redis的瓶颈是机器的内存和网络带宽。既然可以使用单线程实现,为什么要使用多线程?

    我们通常会陷进这样的误区:

    • 高性能的服务器一定是多线程的

    • 多线程一定比单线程效率高

    而Redis就是对这两个误区最狠的打脸,因为Redis的核心就是:

    Redis将所有的数据放在内存中,对于内存系统来说,没有上下文切换(多线程之间会产生上下文的切换,这是一个耗时的操作),效率就是最高的。


    Redis的一些基本命令

    在Redis中默认有16个数据库

    在Redis.conf中

      .
      .
      .
      # Set the number of databases. The default database is DB 0, you can select
      # a different one on a per-connection basis using SELECT <dbid> where
      # dbid is a number between 0 and 'databases'-1
      databases 16
      .
      .
      .

      默认使用的是第0个数据库。

      我们可以使用

        127.0.0.1:6379> select 3 # 切换数据库
        OK

        命令来切换数据库。

        除此之外,Redis还有以下一些基本的命令

          127.0.0.1:6379[3]> dbsize # 查看DB大小
          (integer) 0
          127.0.0.1:6379[3]> set name age # set一个值
          OK
          127.0.0.1:6379[3]> dbsize
          (integer) 1
          127.0.0.1:6379[3]> keys * # 查看所有的key
          1) "name"
          127.0.0.1:6379[3]> flushdb # 清空当前数据库;flushall清空全部数据库
          OK
          127.0.0.1:6379[3]> keys *
          (empty list or set)
          127.0.0.1:6379> exists name # 判断某个key是否存在,返回0说明不存在
          (integer) 0
          127.0.0.1:6379> set name age
          OK
          127.0.0.1:6379> exists name # 判断某个key是否存在,返回1说明存在
          (integer) 1
          127.0.0.1:6379> move name 1 # 将name这个key移动到1号数据库
          (integer) 1
          127.0.0.1:6379> set name kevin
          OK
          127.0.0.1:6379> EXPIRE name 10 # 设置key的过期时间
          (integer) 1
          127.0.0.1:6379> ttl name # 查看key还剩多长时间,单位秒
          (integer) 7
          127.0.0.1:6379> ttl name
          (integer) 4
          127.0.0.1:6379> ttl name # -2代表key已过期
          (integer) -2
          127.0.0.1:6379> get name # 再去get这个key就返回了空
          (nil)
          127.0.0.1:6379> set name age
          OK
          127.0.0.1:6379> type name # 查看keyvalue的类型
          string

          更多的命令,我可以查阅Redis的官网



          Redis支持的数据类型

          String(字符串)

          string是Redis中最基本的数据类型,可以理解为与Memcached一模一样的类型,一个key对应一个value。string类型是二进制安全的,意思是Redis的string可以包含任何数据,比如图片或者序列化的对象,一个redis中字符串value最多可以是512M

          上面讲过的一些基本命令,基本上都是关于String的命令,除了上面那些,关于String类型的命令还有以下这些:

            127.0.0.1:6379> set key1 v1
            OK
            127.0.0.1:6379> get key1
            "v1"
            127.0.0.1:6379> append key1 age # [append key value]:追加字符串,在字符串末尾追加
            (integer) 5
            127.0.0.1:6379> get key1
            "v1age"
            127.0.0.1:6379> strlen key1 # 获取字符串长度
            (integer) 5
            127.0.0.1:6379> append name zhangsan # append一个不存在的key,相当于set
            (integer) 8
            127.0.0.1:6379> keys *
            1) "name"
            2) "key1"


            # *****************************************************


            127.0.0.1:6379> set view 0
            OK
            127.0.0.1:6379> incr view # [incr key]:自增(一般一些文章的浏览量都是用这种方式实现的)
            (integer) 1
            127.0.0.1:6379> get view
            "1"
            127.0.0.1:6379> decr view # [decr key]:自减
            (integer) 0
            127.0.0.1:6379> get view
            "0"
            127.0.0.1:6379> incrby view 10 # [incrby key increment]:根据步长自增
            (integer) 10
            127.0.0.1:6379> get view
            "10"
            127.0.0.1:6379> decrby view 5 # [decrby key increment]:根据步长自减
            (integer) 5
            127.0.0.1:6379> get view
            "5"


            # *****************************************************


            127.0.0.1:6379> flushdb
            OK
            127.0.0.1:6379> set key1 "age,hello world"
            OK
            127.0.0.1:6379> get key1
            "age,hello world"
            127.0.0.1:6379> getrange key1 0 3 # [getrange key start end]:获取一定范围内的字符串(截取的开始和结束是闭区间)
            "age,"
            127.0.0.1:6379> getrange key1 0 -1 # 从0到-1表示获取整个字符串
            "age,hello world"
            127.0.0.1:6379> set key2 abcdefg
            OK
            127.0.0.1:6379> get key2
            "abcdefg"
            127.0.0.1:6379> setrange key2 1 xx # [setrange key offset value]:从字符串中的某个位置开始替换字符串
            (integer) 7
            127.0.0.1:6379> get key2
            "axxdefg"


            # *****************************************************


            127.0.0.1:6379> setex key3 30 hello # [setex key second value]:带有过期时间的设置一个key
            OK
            127.0.0.1:6379> ttl key3
            (integer) 26
            127.0.0.1:6379> ttl key3
            (integer) 21
            127.0.0.1:6379> setnx mykey redis # [setnx key value]:如果一个key不存在,则设置,如果已经存在,不做任何操作
            (integer) 1
            127.0.0.1:6379> get mykey
            "redis"
            127.0.0.1:6379> setnx mykey mongodb
            (integer) 0
            127.0.0.1:6379> get mykey
            "redis"


            # *****************************************************


            127.0.0.1:6379> flushdb
            OK
            127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # [mset key value [key value ...]]:批量设置值
            OK
            127.0.0.1:6379> mget k1 k2 k3 # [mget key [key ...]]:批量获取值
            1) "v1"
            2) "v2"
            3) "v3"


            # *****************************************************


            127.0.0.1:6379> msetnx k1 v1 k4 v4 # [msetnx key value [key value ...]]:批量的setnx操作,批量设置的key只能一起成功,如果有一个失败,则全部失败。(原子性的操作)
            (integer) 0
            127.0.0.1:6379> get key4
            (nil)


            # *****************************************************


            127.0.0.1:6379> getset db redis # [getset key value]:先获取值再设置值,先将获取的值返回,再把value设置进去
            (nil)
            127.0.0.1:6379> get db
            "redis"
            127.0.0.1:6379> getset db mongodb
            "redis"
            127.0.0.1:6379> get db
            "mongodb"


            List(列表)

            在Redis中,我们可以把List当做栈、队列、阻塞队列来玩。

              127.0.0.1:6379> flushdb
              OK
              127.0.0.1:6379> keys *
              (empty list or set)
              127.0.0.1:6379> lpush list one # [lpush key value [value ...]]将一个值或者多个值插入到list的头部(左)
              (integer) 1
              127.0.0.1:6379> lpush list two
              (integer) 2
              127.0.0.1:6379> lpush list three
              (integer) 3
              127.0.0.1:6379> lrange list 0 -1 # [lrange key start stop]通过区间来获取具体的值,-1代表获取全部
              1) "three"
              2) "two"
              3) "one"
              127.0.0.1:6379> lrange list 0 1 # 可以发现的索引是倒着赋值的,后放进去的元素索引为0
              1) "three"
              2) "two"
              127.0.0.1:6379> rpush list right # 将一个值或者多个值插入到list的尾部(右)
              (integer) 4
              127.0.0.1:6379> lrange list 0 -1
              1) "three"
              2) "two"
              3) "one"
              4) "right"
              127.0.0.1:6379> lpop list # [lpop key]移除list左边的第一个元素
              "three"
              127.0.0.1:6379> rpop list # 移除list右边的第一个元素
              "right"
              127.0.0.1:6379> lrange list 0 -1
              1) "two"
              2) "one"
              127.0.0.1:6379> lindex list 1 # [lindex key index]根据索引获取某一个值
              "one"
              127.0.0.1:6379> lindex list 0
              "two"
              127.0.0.1:6379> llen list # [llen key]获取list长度
              (integer) 2
              127.0.0.1:6379> lpush list three
              (integer) 3
              127.0.0.1:6379> lpush list three
              (integer) 4
              127.0.0.1:6379> lrange list 0 -1
              1) "three"
              2) "three"
              3) "two"
              4) "one"
              127.0.0.1:6379> lrem list 1 one # [lrem key count value]移除指定的一个值,精确匹配
              (integer) 1
              127.0.0.1:6379> lrem list 2 three # 移除指定的两个值
              (integer) 2
              127.0.0.1:6379> lrange list 0 -1
              1) "two"
              127.0.0.1:6379> lpush list hello
              (integer) 2
              127.0.0.1:6379> lpush list hello1
              (integer) 3
              127.0.0.1:6379> lpush list hello2
              (integer) 4
              127.0.0.1:6379> lpush list hello3
              (integer) 5
              127.0.0.1:6379> ltrim list 1 2 # [ltrim key start stop]通过下标截取指定长度的list
              OK
              127.0.0.1:6379> lrange list 0 -1
              1) "hello2"
              2) "hello1"
              127.0.0.1:6379> rpoplpush list mylist # [rpoplpush source destination]移除列表中最后一个元素,并将它移动到新的列表中,如果新的列表不存在,则创建
              "hello1"
              127.0.0.1:6379> lrange list 0 -1
              1) "hello2"
              127.0.0.1:6379> lrange mylist 0 -1
              1) "hello1"
              127.0.0.1:6379> lrange list 0 -1
              1) "hello2"
              127.0.0.1:6379> lset list 0 value1 # [lset key index value]修改列表中某一个key对应的值
              OK
              127.0.0.1:6379> lrange list 0 -1
              1) "value1"
              127.0.0.1:6379> lset list 1 value2 # 如果修改列表中某一个不存在的key对应的值,会报错(列表不存在也会报错)
              (error) ERR index out of range
              127.0.0.1:6379> lrange list 0 -1
              1) "value1"
              127.0.0.1:6379> linsert list before value1 value2 # [linsert key before|after pivot value]往列表中某个值的前面或后面插入某个值
              (integer) 2
              127.0.0.1:6379> lrange list 0 -1
              1) "value2"
              2) "value1"
              127.0.0.1:6379> linsert list after value2 value3
              (integer) 3
              127.0.0.1:6379> lrange list 0 -1
              1) "value2"
              2) "value3"
              3) "value1"
              • List数据类型可以实现消息队列,它本质上是一个双向的链表。从左边插入lpush,从右边取rpop。

              • List数据类型还可以实现,从左边插入lpush,从左边取lpop。


              Set(集合)

              Set是无序且不重复集合。

                127.0.0.1:6379> sadd myset "hello" # sadd key member [member...]set中添加值
                (integer) 1
                127.0.0.1:6379> sadd myset "world"
                (integer) 1
                127.0.0.1:6379> smembers myset # smembers key 查看set中的元素
                1) "hello"
                2) "world"
                127.0.0.1:6379> SISMEMBER myset hello # SISMEMBER key member 查看set中是否有某个元素,存在返回1,不存在返回0
                (integer) 1
                127.0.0.1:6379> SISMEMBER myset nihao
                (integer) 0
                127.0.0.1:6379> SCARD myset # SCARD key 查看set中的元素个数
                (integer) 2
                127.0.0.1:6379> SREM myset hello # SREM key memberset中移除某个元素
                (integer) 1
                127.0.0.1:6379> smembers myset
                1) "world"
                127.0.0.1:6379> sadd myset hahahaha
                (integer) 1
                127.0.0.1:6379> sadd myset hehehehe
                (integer) 1
                127.0.0.1:6379> SRANDMEMBER myset # SRANDMEMBER key [count] 随机从set中取count个元素,默认取一个
                "hehehehe"
                127.0.0.1:6379> SRANDMEMBER myset
                "world"
                127.0.0.1:6379> SPOP myset # SPOP key [count] 随机移除一个元素
                "world"
                127.0.0.1:6379> SMEMBERS myset
                1) "hahahaha"
                2) "hehehehe"
                127.0.0.1:6379> sadd myset2 "hello2"
                (integer) 1
                127.0.0.1:6379> SMOVE myset myset2 "hahahaha" # SMOVE source destination member 将指定元素从一个set中移动到另一个set
                (integer) 1
                127.0.0.1:6379> SMEMBERS myset2
                1) "hahahaha"
                2) "hello2"
                127.0.0.1:6379> SMEMBERS myset
                1) "hehehehe"
                127.0.0.1:6379> sadd key1 a
                (integer) 1
                127.0.0.1:6379> sadd key1 b
                (integer) 1
                127.0.0.1:6379> sadd key1 c
                (integer) 1
                127.0.0.1:6379> sadd key2 c
                (integer) 1
                127.0.0.1:6379> sadd key2 e
                (integer) 1
                127.0.0.1:6379> SDIFF key1 key2 # SDIFF key [key...] 查看两个set的差集
                1) "a"
                2) "b"
                127.0.0.1:6379> SINTER key1 key2 # SINTER key [key...] 查看两个set的交集
                1) "c"
                127.0.0.1:6379> SUNION key1 key2 # SUNION key [key...] 查看两个set的并集
                1) "e"
                2) "a"
                3) "b"
                4) "c"

                set这种数据结构,常用于存储类似微博,B站等社交网站的用户关注数,粉丝数等数据,例如交集可以实现共同关注。


                Hash(哈希)

                在Java中我们都用过Map,Redis中的Hash和那个也是大同小异的,我们都知道Redis是key - value的形式来存储值,而Hash这种数据结构也是key - value来存储值的,所以现在就变成了key - <key - value>这种结构。

                  127.0.0.1:6379> hset myhash map1 hello # hset key field valuehashset一个值
                  (integer) 1
                  127.0.0.1:6379> hget myhash map1 # hget key fieldhash中取出field对应的值
                  "hello"
                  127.0.0.1:6379> hmset myhash map2 world map3 hahahaha # hmset key field value [field value...] 批量设置值
                  OK
                  127.0.0.1:6379> hmget myhash map1 map2 map3 # hmset key field [field...] 批量获取值
                  1) "hello"
                  2) "world"
                  3) "hahahaha"
                  127.0.0.1:6379> HGETALL myhash # HGETALL key 把一个hash中所有的值都获取出来
                  1) "map1"
                  2) "hello"
                  3) "map2"
                  4) "world"
                  5) "map3"
                  6) "hahahaha"
                  127.0.0.1:6379> HDEL myhash map1 # HDEL key field 删除hash中指定的field
                  (integer) 1
                  127.0.0.1:6379> HGETALL myhash
                  1) "map2"
                  2) "world"
                  3) "map3"
                  4) "hahahaha"
                  127.0.0.1:6379> HLEN myhash # HLEN key 获取hash的长度
                  (integer) 2
                  127.0.0.1:6379> HEXISTS myhash map1 # HEXISTS key field 判断hash中某个field是否存在,0-不存在;1-存在
                  (integer) 0
                  127.0.0.1:6379> HEXISTS myhash map2
                  (integer) 1
                  127.0.0.1:6379> HKEYS myhash # HKEYS key 获取key中所有的field
                  1) "map2"
                  2) "map3"
                  127.0.0.1:6379> HVALS myhash # HVALS key 获取key中所有的value
                  1) "world"
                  2) "hahahaha"
                  127.0.0.1:6379> HINCRBY myhash map1 1 # HINCRBY key field incrementkey中的value自增1
                  (integer) 7
                  127.0.0.1:6379> HSETNX myhash map4 age # HSETNX key field value 如果值不存在则创建,存在则不做任何操作
                  (integer) 1
                  127.0.0.1:6379> HSETNX myhash map4 hehehe
                  (integer) 0

                  Hash这种数据结构更适合用于对象的存储,例如用户的信息。


                  Zset(有序集合)

                  在Set基础上,增加了一个值:score,称之为分数,用于排序。

                    127.0.0.1:6379> ZADD myzset 1 one # ZADD key [NX|XX] [CH] [INCR] score member [score member...]zset中添加值
                    (integer) 1
                    127.0.0.1:6379> ZADD myzset 2 two
                    (integer) 1
                    127.0.0.1:6379> ZADD myzset 3 three 4 four
                    (integer) 2
                    127.0.0.1:6379> ZRANGE myzset 0 -1 # ZRANGE key start stop [WITHSCORE]zset中获取值,startstop表示索引
                    1) "one"
                    2) "two"
                    3) "three"
                    4) "four"
                    127.0.0.1:6379> ZADD salary 2500 xiaoming
                    (integer) 1
                    127.0.0.1:6379> ZADD salary 5000 zhangsan
                    (integer) 1
                    127.0.0.1:6379> ZADD salary 3000 lisi
                    (integer) 1
                    127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf # ZRANGEBYSCORE key min max [WITHSCORE] [LIMIT offset count] 获取全部的值且按升序排序(-inf表示负无穷,+inf表示正无穷)
                    1) "xiaoming"
                    2) "lisi"
                    3) "zhangsan"
                    127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf WITHSCORES # 获取全部的值并且显示分数
                    1) "xiaoming"
                    2) "2500"
                    3) "lisi"
                    4) "3000"
                    5) "zhangsan"
                    6) "5000"
                    127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2500 WITHSCORES # 显示工资小于或等于2500的员工
                    1) "xiaoming"
                    2) "2500"
                    127.0.0.1:6379> ZREM salary xiaoming # ZREM key member [member] 移除元素
                    (integer) 1
                    127.0.0.1:6379> ZRANGE salary 0 -1
                    1) "lisi"
                    2) "zhangsan"
                    127.0.0.1:6379> ZCARD salary # ZCARD key 获取zset中的个数
                    (integer) 2
                    127.0.0.1:6379> ZADD myzset 1 hello
                    (integer) 1
                    127.0.0.1:6379> ZADD myzset 2 world
                    (integer) 1
                    127.0.0.1:6379> ZADD myzset 3 age
                    (integer) 1
                    127.0.0.1:6379> ZCOUNT myzset 1 3 # ZCOUNT key min max 获取minmax区间元素的个数
                    (integer) 3
                    127.0.0.1:6379> ZCOUNT myzset 1 2
                    (integer) 2

                    Zset这种数据结构通常用于存储班级成绩,工资表之类的数据,方便排序。也可以用于实现权重。

                    到这里,我们的五种基本数据类型就讲完了。下面我们将介绍三种特殊的数据类型。


                    三种特殊的数据类型

                    geospatial(地理位置)

                    该种数据类型通常用于朋友圈的定位,附近的人,打车距离的计算等场景。下面我就具体来看看它怎么使用。

                    既然它是用于存储地理位置,那么我们需要去网上巴拉一些地理位置的数据。

                    查询地理位置经纬度地址(在线):https://jingweidu.bmcx.com/

                    它只有六个命令:

                      # GEOADD:添加地理位置
                      # 通常我们会直接下载城市数据,通过Java或者别的程序一次性导入
                      # 有效的经度从-180度到180度
                      # 有效的纬度从-85.05112878度到85.05112878度
                      # 当坐标位置超出上述指定范围时,该命令会报错:
                      # (error) ERR invalid longitude, latitude pair ...
                      127.0.0.1:6379> GEOADD china:city 116.23128 40.22077 beijing # GEOADD key longitude latitude member [longitude latitude member...] 将longitude经度、latitude经纬度、member名称添加到key中
                      (integer) 1
                      127.0.0.1:6379> GEOADD china:city 121.48941 31.40527 shanghai
                      (integer) 1
                      127.0.0.1:6379> GEOADD china:city 104.10194 30.65984 chengdu
                      (integer) 1


                      # GEOPOS:从key中返回所有给定位置元素的位置(经度和纬度)
                      127.0.0.1:6379> GEOPOS china:city beijing
                      1) 1) "116.23128265142440796"
                      2) "40.22076905438526495"
                      127.0.0.1:6379> GEOPOS china:city shanghai chengdu
                      1) 1) "121.48941010236740112"
                      2) "31.40526993848380499"
                      2) 1) "104.10194188356399536"
                      2) "30.65983886217613019"

                      # GEODIST:返回两个给定位置之间的距离
                      # 如果两个位置中有其中一个不存在,那么该命令返回空值
                      # 指定单位的参数unit必须是以下单位中的一个:
                      # - m表示单位为米(默认)
                      # - km表示单位为千米
                      # - mi表示单位为英里
                      # - ft表示单位为英尺
                      127.0.0.1:6379> GEODIST china:city beijing shanghai
                      "1088644.3544"
                      127.0.0.1:6379> GEODIST china:city beijing shanghai km
                      "1088.6444"


                      # GEORADIUS:以给定的经纬度为中心,找出某一半径内的元素
                      # 范围可以使用以下其中一个单位:
                      # - m表示单位为米
                      # - km表示单位为千米
                      # - mi表示单位为英里
                      # - ft表示单位为英尺
                      # 在给定以下选项时,命令会返回额外的信息:
                      # - WITHDIST:在返回位置元素的同时,将位置元素与中心之间的距离也一并返回。距离的单位和用户给定的范围单位保持一致
                      # - WITHCOORD:将位置元素的经度和纬度也一并返回
                      # - WITHHASH:以52位有符号整数的形式,返回位置元素经过原始GEOHASH编码的有序集合分值。这个选项主要用于底层应用或者调试,实际中作用不大。
                      # GEORADIUS key longitude latitude radius m|km|ft|mi [WITHDIST] [WITHCOORD] [WITHHASH] [COUNT count]
                      127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km
                      1) "chengdu"
                      127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km WITHDIST # 显示距离
                      1) 1) "chengdu"
                      2) "570.8980"
                      127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km WITHCOORD # 显示具体的经纬度信息
                      1) 1) "chengdu"
                      2) 1) "104.10194188356399536"
                      2) "30.65983886217613019"
                      127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km WITHCOORD count 1 # 限制显示几个
                      1) 1) "chengdu"
                      2) 1) "104.10194188356399536"
                      2) "30.65983886217613019"


                      # GEORADIUSBYMEMBER:找出位于指定范围内的元素,中心点是由给定的位置元素决定
                      # 这个命令和GEORADIUS一样,都可以找出位于指定范围内的元素,但是GEORADIUSBYMEMBER的中心点是由给定的位置元素决定的,而不像是GEORADIUS那样,使用输入的经度和纬度来决定中心点
                      127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1500 km # 以北京为中心,1500km内的元素
                      1) "shanghai"
                      2) "beijing"


                      # GEOHASH:返回一个或多个位置元素的GEOHASH表示
                      # 通常使用表示位置的元素使用不同的技术,使用Geohash位置52点整数编码。由于编码和解码过程中所使用的初始最小和最大坐标不同,编码的编码也不同于标准。此命令返回一个标准的Geohash
                      # 该命令将返回11个字符的Geohash字符串,所以没有精度Geohash,损失相比,使用内部52位表示。返回的geohashes具有以下特性:
                      # - 他们可以缩短从右边的字符。它将失去精度,但仍将指向同一地区。
                      # - 它可以在 geohash.org 网站使用,网址 http://geohash.org/<geohash-string>。查询例子:http://geohash.org/sqdtr74hyu0.
                      # - 与类似的前缀字符串是附近,但相反的是不正确的,这是可能的,用不同的前缀字符串附近。
                      # 这个命令目前没啥用,了解即可。
                      127.0.0.1:6379> GEOHASH china:city beijing # 将二维的经纬度转换为一维的字符串,如果两个字符串越接近,说明两个距离越近
                      1) "wx4sucvncn0"

                      GEO底层实现原理其实是Zset,我们可以使用Zset来操作GEO。

                      通过上面的命令我们发现,官方给出的GEO命令中,并没有删除地理位置的命令,我们就可以用Zset来实现删除:

                        127.0.0.1:6379> ZRANGE china:city 0 -1
                        1) "chengdu"
                        2) "shanghai"
                        3) "beijing"
                        127.0.0.1:6379> ZREM china:city chengdu
                        (integer) 1
                        127.0.0.1:6379> ZRANGE china:city 0 -1
                        1) "shanghai"
                        2) "beijing"


                        Hyperloglog

                        要了解这个数据类型,我们得先了解什么是基数。

                        假如我们有一个数据集:

                        A = {1, 3, 5, 7, 9, 7, 8}

                        基数就是指这个数据集中不重复元素的个数 = 6(1, 3, 5, 7, 9, 8)

                        Hyperloglog是一种数据结构,它是用于做基数统计的算法。


                        应用场景

                        一般用于统计网页的用户访问量(一个人访问同一个网站多次,还是算作一个人)。

                        以前传统的方式是用Set集合去保存用户的id,由于Set集合是不允许重复的,然后就可以统计Set集合中元素的数量来统计用户访问量。但是如果用户的id是uuid或者一些比较长的字符串时,数据就会比较大。

                        这时候我们就可以用Hyperloglog来实现。

                        优点:

                        占用的内存是固定的。存储2^64不同元素的基数,只需要占用12KB的内存。

                        缺点:

                        存在0.81%的错误率,只能用于对数据统计精度要求不高的场景。

                          127.0.0.1:6379> PFADD mykey1 a b c d e f g h i j # PFADD key element [element...] 创建元素key
                          (integer) 1
                          127.0.0.1:6379> PFCOUNT mykey1 # PFCOUNT key [key...] 统计key中基数
                          (integer) 10
                          127.0.0.1:6379> PFADD mykey2 i j z x c v y b n m
                          (integer) 1
                          127.0.0.1:6379> PFCOUNT mykey2
                          (integer) 10
                          127.0.0.1:6379> PFMERGE mykey3 mykey1 mykey2 # PFMERGE destkey sourcekey [sourcekey...] 将多个key的并集赋给一个destkeya b c d e f g h i j z x v y n m
                          OK
                          127.0.0.1:6379> PFCOUNT mykey3
                          (integer) 16


                          Bitmaps

                          Bitmaps称之为位图,也是一种数据结构。

                          它都是操作二进制位来进行记录,就只有0和1两个状态。

                            # 比如使用我们的Bitmaps记录周一到周日的打卡情况
                            # 0-代表未打卡
                            # 1-代表已打卡
                            127.0.0.1:6379> SETBIT sign 0 0
                            (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 0
                            (integer) 0
                            127.0.0.1:6379> GETBIT sign 3 # 查看周四是否有打卡,0-未打卡
                            (integer) 0
                            127.0.0.1:6379> GETBIT sign 4 # 查看周五是否有打卡,1-已打卡
                            (integer) 1
                            127.0.0.1:6379> BITCOUNT sign # BITCOUNT key [start end] 统计key中1的数量,这里就可以用来统计周一到周日打卡的天数
                            (integer) 3


                            总结

                            本章介绍了Redis中一些常用的命令以及几种数据类型。希望看完这章,大家在开发中使用Redis时,不要永远都只是使用String这种数据类型。要学会灵活运用这些数据类型,才能让程序媛们刮目相看不是吗?


                            Hi

                            感谢你的到来

                            我不想错过你

                            编程那些烦心事





                            精彩推荐




                            Go语言学习笔记系列
                            面试你应该这样准备
                            JVM学习笔记系列
                            喜欢就点个在看再走吧

                            文章转载自编程那些烦心事,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                            评论