Redis Pagination & Multi-Condition Fuzzy Search: A Combined Approach
This article explains how to implement pagination using Redis Sorted Sets (ZSet) and multi-condition fuzzy queries using Hash with HSCAN, then combines both by caching filtered results in pattern-keyed ZSets for efficient paginated retrieval, including TTL-based expiration and data freshness strategies.
Introduction
Redis is an efficient in-memory database supporting data types such as String, List, Set, Sorted Set (ZSet), and Hash. While Redis excels at key-based lookups, it lacks native fuzzy conditional queries. In scenarios requiring pagination, sorting, and conditional filtering (e.g., comments, timelines, search), relying solely on Redis built-in commands is insufficient. This article presents a combined solution for pagination and multi-condition fuzzy queries using Redis data structures.
Redis Pagination Implementation
Pagination is typically done in persistent databases like MySQL or Oracle. However, for hot data loaded into cache or non-persisted data, pagination directly in Redis may be needed. The implementation uses ZSet (Sorted Set) , which stores ordered collections. Key commands:
ZADD : ZADD key score member [[score member]…] — adds members with a sorting score. Commonly the data's timestamp is used as score for chronological ordering.
ZREVRANGE : ZREVRANGE key start stop — returns members in a specified rank range (descending by score), enabling pagination.
ZREM : ZREM key member — removes a member by key, supporting delete operations like removing a comment.
ZSet automatically maintains sort order and allows score-based range queries. Redis List can also paginate but lacks auto-sorting and score-based filtering. ZSet is generally preferred unless duplicate scores/members are required, in which case List may be used. Choice depends on business scenario.
Redis Multi-Condition Fuzzy Query Implementation
Redis is a key-value store without SQL-like conditional queries. Fuzzy querying is built on Hash : condition values are stored as hash fields, and the full data (e.g., JSON) as the value. HSCAN iterates all fields with pattern matching to find matching keys.
Matching fields are collected into a Set or List for subsequent data retrieval. Example field naming convention: <id>:<name>:<gender>. Queries use * wildcards: *:*:female — matches all female users. 100*:*:* — matches users with ID prefix 100.
HSCAN matching is based on full traversal, so efficiency is limited. The next section addresses this.
Combined Pagination + Multi-Condition Fuzzy Query
ZSet pagination performs well alone, but real-world data often requires dynamic filtering. Two approaches:
Query persistent database with conditions, then load results into Redis for pagination.
Implement both fuzzy query and pagination entirely in Redis.
Approach 1 fails when data isn't yet persisted (e.g., high-concurrency write-behind caching). Approach 2 is needed.
Implementation Logic
Store data in Hash with composite fields (e.g., <id>:<name>:<gender>) and JSON values.
Define a match pattern string (e.g., *:*:male).
Check if a ZSet keyed by this pattern exists in Redis.
If not, run HSCAN on the Hash to collect all matching fields, insert them into a new ZSet (using timestamp as score), and set the ZSet's key to the pattern string.
If exists, directly paginate the ZSet using ZREVRANGE.
This yields a simple combined pagination + fuzzy query mechanism.
Performance Optimization
Unlimited pattern variations can create many ZSets, pressuring memory. Optimizations:
TTL expiration : Assign an expiry to each generated ZSet. Based on temporal locality, unused data likely won't be accessed again. On cache hit, refresh the TTL.
Data freshness : Generated ZSets reflect Hash state at creation time; new Hash inserts are invisible. Two solutions:
Dual-write : On Hash insert, also insert into relevant ZSets. Requires a naming prefix to identify target ZSets.
Periodic rebuild : Simpler but cannot guarantee real-time pagination accuracy. Choice depends on business tolerance for staleness.
Summary
The article describes a practical design for combining Redis pagination (via ZSet) with multi-condition fuzzy search (via Hash + HSCAN), caching filtered result sets as pattern-keyed ZSets, and applying TTL and freshness strategies to balance memory, performance, and data currency.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architect's Guide
Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
