Redis Stack扩展功能
Redis JSON
RedisJSON是Redis的一个扩展模块,它提供了对JSON数据的原生支持。
常用操作:
-- 设置一个JSON数据
JSON.SET user $ '{"name":"loulan","age":18}'
## key是user,value就是一个JSON数据。其中$表示JSON数据的根节点。
-- 查询JSON数据
JSON.GET user
-- 查询JSON对象的name属性
JSON.GET user $.name
-- 查看数据类型
JSON.TYPE user -- object
JSON.TYPE user $.name --- string
JSON.TYPE user $.age --- integer
--修改JSON数据 年龄加2
JSON.NUMINCRBY user $.age 2
-- 添加新的字段
JSON.SET user $.address '{"city": "Changsha","country": "China"}' NX
## NX 表示只有当address字段不存在的时候才进行设置。
-- 在JSON数组中添加元素
JSON.SET user $.hobbies '["reading"]'
JSON.ARRAPPEND user $.hobbies '"swimming"'
-- 查看JSON对象中key的个数
JSON.OBJLEN user $.address
-- 查看user对象的所有key
JSON.OBJKEYS user
-- 删除JSON中的key
JSON.DEL user $.address
Redis JSON优势:
- 更高的存储性能。 Redis JSON底层是一种更高效的二进制存储格式,相比简单的文本格式,二进制进行JSON格式读写性能更好, 也更节省内存
- Redis JSON使用树状结构存储JSON, 这种存储方式可以更快速的访问元素,也可以更高效的进行条件查询
- 与Redis生态集成度高,作为Redis的扩展模块,Redis JSON和Redis的其他功能和工具无缝集成。这意味着开发者可以继续使用TTL、Redis事务、发布/订阅、Lua脚本等功能。
Search And Query
当Redis中存储的数据比较多时,搜索Redis中的数据是一件比较麻烦的事情。通常使用的 keys * 这样令,在生产环境一般都是直接禁用的,因为这样会产生严重的线程阻塞,影响其他的读写操作。
如何快速搜索Redis中的数据(主要是key)呢? Redis中Search And Query模块。
1. 传统Scan搜索
Scan指令的官方介绍:https://redis.io/docs/latest/commands/scan/
指令格式:
SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
- cursor: 游标。代表每次迭代返回的偏移量。通常一次查询,cursor从0开始,然后scan指令会返回下一次迭代的起始偏移量。用户可以用这个返回值作为cursor,继续迭代下一批。直到cursor返回0,表示所有数据都过滤完成了。
- pattern:匹配字符串。用来匹配要查询的key。 例如 user* 表示以user开头的字符串。
- count:数字,表示每次迭代多少条数据。
- type是key的类型,比如可以指定string ,set,zset等。
针对不同类型的key, 对应不同的SCAN指令,比如SSCAN对应Set类型, HSCAN对应Hash类型, ZSCAN对应ZSet类型。
缺点:SCAN只能对key进行简单的过滤
2. Search And Query
查询条件构建,参见官网 https://redis.io/docs/latest/develop/interact/search-and-query/query/
Redis提供了RedisSearch插件,基本就可以认为是ElasticSearch这类搜索引擎的平替。大部分ES能够实现的搜索功能,在Redis里就能直接进行。
Redis能够支持搜索的数据结构包括:HASH 、JSON
--清空数据
flushall
-- 创建一个产品的索引
FT.CREATE productIndex ON JSON SCHEMA $.name AS name TEXT $.price AS price NUMERIC
## 索引为productIndex.
## ON JSON 表示 这个索引会基于JSON数据构建,需要RedisJSON模块的支持。默认是ON HASH 表示检索所有HASH格式的数据
## SCHEMA表示根据哪些字段建立索引。 字段名 AS 索引字段名 数据类型 这样的组合。如果是JSON格式,字段名用$.路径表示
-- 模拟一批产品信息
JSON.SET phone:1 $'{"id":1, "name":"HUAWEI 1", "desc":"HUAWEI PHONE1", "price":1999}'
......
## 如果是ON HASH ,可以直接通过索引添加数据
## FT.ADD productIndex 'product:1' 1.0 FIELDS "id" 1 "name" "HUAWEI1" "desc" "HUAWEI PHONE 1" "PRICE" 3999
## 数据的key 是producr:1
## FIELDS 数据。 按照 key value 的格式组织
-- 查看索引状态
FT.INFO productIndex
--搜索产品
## 搜索条件: name包含 HUAWEI, price在1000到5000之间。返回id和name
FT.SEARCH productIndex "@name:HUAWEI @price:[1000 5000]" RETURN 2 id name
使用说明:
- 确定数据结构
- 使用对应数据结构添加数据
- FT.CREATE命令创建索引
- FT.SEARCH命令查询
Bloom Filter
应用场景:前端过滤缓存
Guava实现
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.1.0-jre</version>
</dependency>
public static void main (String[]args){// 10000是期望放进去的元素数量BloomFilter<String> bloomFilter =BloomFilter.create(Funnels.stringFunnel(StandardCharsets.UTF_8), 10000, 0.01);//把 A~Z 放入布隆过滤器for (int i = 64; i <= 90; i++) {bloomFilter.put(String.valueOf((char) i));}System.out.println(bloomFilter.mightContain("A")); //trueSystem.out.println(bloomFilter.mightContain("a")); //false
}
Redis实现
Redis的BitMap数据结构天生就非常适合做一个分布式的布隆过滤器底层存储。
现在Redis提供的BloomFilter模块, 可以方便的实现布隆过滤器。
-- 创建一个key为bf的布隆过滤器,容错率0.01,容量1000。NONSCALING 表示不扩容。如果这个过滤器里的数据满了,就直接报错
BF.RESERVE bf 0.01 1000 NONSCALING
-- 添加元素
BF.ADD bf A
.....
-- 批量添加元素
BF.MADD bf B C D E F G H I
-- 如果bf不存在,就创建一个key为bf的过滤器。
BF.INSERT bf CAPACITY 1000 ERROR 0.01 ITEMS hello
-- 查看容量
BF.CARD bf
-- 判断元素是否在过滤器中
## 返回值0表示不在,1表示在
BF.EXISTS bf a
-- 批量判断
BF.MEXISTS bf A a B b
-- 查看布隆过滤器状态
BF.INFO bf
# 依次迭代布隆过滤器中的位数组
BF.SCANDUMP bf 0
## 和SCAN指令使用很像,返回当前访问到的数据和下一次迭代的起点。 当下次迭代起点为0表示数据已经全部迭代完成。
## 主要是可以配合BF.LOADCHUNK 进行备份。
Cuckoo Filter
布隆过滤器最大的问题是无法删除数据。因此,后续诞生了很多布隆过滤器的改进版本。Cuckoo Filter 布谷鸟过滤器就是其中一种,支持删除数据(CF.DEL)。
-- 创建默认值
## 容量1000,这个是必填参数。后面几个都是可选参数。这里填的几个就是Redis中的CuckooFilter的默认值
## BUSKETSIZE越大,空间利用率更高,但是误判率也更高,性能更差
## MAXITARATIONS越小,性能越好。如果设置越大,空间利用率就越好。
## EXPANSION 是指空间扩容的比例。
CF.RESERVE cf 1000 BUSKETSIZE 2 MAXITERATIONS 20 EXPANSION 1
BUSKETSIZE:每个桶中存放的元素的个数。 Cuckoo Filter的数组中存放的不是位,而是桶bucket, 每个bucket可以存放多个数据。 Redis中Cuckoo Filter实现中,BUSKETSIZE取值1~255, 默认2。 bucket中存放的不是实际数据,而是数据指纹(可以理解成某种算法后的数据)。