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中存放的不是實際數據,而是數據指紋(可以理解成某種算法后的數據)。