Redis 賦能!Spring Boot 實(shí)現(xiàn)高性能分頁(yè)+多條件模糊查詢
Redis 作為一款高性能的內(nèi)存數(shù)據(jù)庫(kù),支持多種數(shù)據(jù)結(jié)構(gòu),包括 String、List、Set、SortedSet 和 Hash 等。通常,我們?cè)?Redis 中根據(jù) key 來(lái)檢索相應(yīng)的值,但 Redis 并不原生支持模糊查詢功能。因此,在需要進(jìn)行分頁(yè)、排序以及復(fù)雜條件檢索(如評(píng)論管理、時(shí)間線排序、搜索等)的場(chǎng)景下,直接使用 Redis 可能無(wú)法滿足需求。
本文將基于 Redis 設(shè)計(jì)一種高效的分頁(yè)與模糊查詢方案,結(jié)合 Spring Boot 3.4,提供思路和實(shí)踐方法,幫助大家更好地利用 Redis 提升查詢性能。
方案設(shè)計(jì)
Redis 實(shí)現(xiàn)分頁(yè)查詢
在傳統(tǒng)關(guān)系型數(shù)據(jù)庫(kù)(如 MySQL、Oracle)中,分頁(yè)通常依賴 LIMIT 和 OFFSET 進(jìn)行查詢。但在 Redis 中,我們可以借助 SortedSet(ZSet)來(lái)高效實(shí)現(xiàn)分頁(yè)。
關(guān)鍵指令解析
- ZADD key score member向有序集合中添加元素,并指定排序權(quán)重 score。
- ZREVRANGE key start stop按照 score 逆序返回指定范圍的元素,用于分頁(yè)。
- ZREM key member從有序集合中移除某個(gè)元素,適用于刪除操作。
通常,我們會(huì)將數(shù)據(jù)的時(shí)間戳作為 score 進(jìn)行排序,從而實(shí)現(xiàn)基于時(shí)間的分頁(yè)檢索。SortedSet 相較于 List 具有自動(dòng)排序的能力,并且可以根據(jù) score 進(jìn)行篩選,使其成為更適合分頁(yè)查詢的數(shù)據(jù)結(jié)構(gòu)。
Redis 實(shí)現(xiàn)模糊查詢
由于 Redis 是基于 key-value 存儲(chǔ)的數(shù)據(jù)庫(kù),并不具備 SQL 級(jí)別的查詢能力,因此我們需要利用 Redis 提供的 Hash 結(jié)構(gòu)自行實(shí)現(xiàn)模糊查詢。
HSCAN 指令實(shí)現(xiàn)模糊匹配
Redis 的 HSCAN 指令允許遍歷 Hash 結(jié)構(gòu)中的 key,并支持模式匹配。
示例存儲(chǔ)格式:
field: <id>:<姓名>:<性別>
value: {"id": 1001, "name": "張三", "gender": "男"}
查詢示例:
- HSCAN user_data 0 MATCH *:*:男 —— 獲取所有性別為“男”的用戶。
- HSCAN user_data 0 MATCH 100*:*:* —— 獲取所有 ID 以 100 開(kāi)頭的用戶。
分頁(yè)+多條件模糊查詢的組合實(shí)現(xiàn)
分頁(yè)和模糊查詢各自獨(dú)立實(shí)現(xiàn)后,我們需要將它們結(jié)合,支持在模糊查詢的基礎(chǔ)上進(jìn)行分頁(yè)。
方案思路
- 模糊查詢階段使用 HSCAN 遍歷 Hash,篩選符合條件的 field,將匹配的 key 存入 Redis 的一個(gè)臨時(shí) ZSet 集合。
- 分頁(yè)階段在 Redis 中查詢?cè)?ZSet 集合,并使用 ZREVRANGE 進(jìn)行分頁(yè)。
- 緩存優(yōu)化為 ZSet 集合設(shè)置 TTL,避免 Redis 負(fù)載過(guò)高。
性能優(yōu)化策略
- 設(shè)置過(guò)期時(shí)間
- 生成的 ZSet 結(jié)果集合可設(shè)置短時(shí)間 TTL,避免緩存過(guò)載。
- 在訪問(wèn)集合時(shí)重置 TTL,延長(zhǎng)熱點(diǎn)數(shù)據(jù)的生命周期。
- 實(shí)時(shí)性保障
插入新數(shù)據(jù)時(shí),需同步更新 ZSet 相關(guān)集合。
或者,定期觸發(fā)批量更新,減少實(shí)時(shí)更新的開(kāi)銷。
代碼示例
1. 在 Redis 中存儲(chǔ)數(shù)據(jù)
@Autowired
private StringRedisTemplate redisTemplate;
public void saveData(String key, String value, double score) {
redisTemplate.opsForZSet().add("data_zset", value, score);
}
2. 分頁(yè)查詢
public Set<String> getPaginatedData(int page, int pageSize) {
int start = (page - 1) * pageSize;
int end = start + pageSize - 1;
return redisTemplate.opsForZSet().reverseRange("data_zset", start, end);
}
3. 模糊查詢
public List<String> fuzzySearch(String pattern) {
List<String> result = new ArrayList<>();
Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan("user_data", ScanOptions.scanOptions().match(pattern).build());
while (cursor.hasNext()) {
result.add(cursor.next().getKey().toString());
}
return result;
}
結(jié)論
本文介紹了一種基于 Redis 實(shí)現(xiàn)高性能分頁(yè)+多條件模糊查詢的思路。通過(guò) SortedSet 進(jìn)行分頁(yè),結(jié)合 Hash 結(jié)構(gòu)與 HSCAN 實(shí)現(xiàn)模糊匹配,并優(yōu)化查詢效率,能夠大幅提升查詢性能。希望本文的方案能夠幫助大家更高效地使用 Redis 進(jìn)行復(fù)雜查詢優(yōu)化。