How to Combine Pagination and Multi‑Condition Fuzzy Search in Redis
This article explains how to implement pagination using Redis Sorted Sets, achieve multi‑condition fuzzy queries with Hashes and HSCAN, and then combine both techniques into a single solution while discussing performance trade‑offs and optimization strategies such as key expiration and data‑sync methods.
Pagination with Redis Sorted Set
Redis Sorted Set (ZSet) stores members with a numeric score that defines ordering. The commands used are:
ZADD ZADD key score member [[score member]…] – adds members and binds a score for sorting.
ZREVRANGE ZREVRANGE key start stop – returns members in the specified range, enabling page retrieval.
ZREM ZREM key member – removes a member, useful for deleting items such as comments.
Because ZSet maintains order automatically and can filter by score ranges, it is preferred over List for pagination scenarios where ordering is required.
Multi‑Condition Fuzzy Query with Hashes
Redis does not provide SQL‑like conditional queries. The implementation stores each record as a hash field whose key encodes searchable attributes, e.g. <id>:<name>:<gender>, and the value holds the full JSON payload.
Pattern‑based matching is performed with HSCAN , which iterates all hash fields and supports glob patterns:
All female users: pattern *:*:female All users whose name starts with "阿": pattern *:阿*:* HSCAN scans the entire hash each time, so its efficiency is limited.
Combined Pagination and Fuzzy Query
When both pagination and dynamic filtering are required, two approaches exist:
Execute the conditional query in a persistent database, then load the result set into Redis for pagination.
Implement the fuzzy query and pagination entirely within Redis.
In scenarios where data resides only in the cache, the second approach is necessary. The workflow is:
Construct a match string that represents the desired filter, e.g. *:*:male or 100*:*.
Check whether a ZSet with that match string already exists.
If the ZSet does not exist, run HSCAN on the hash, collect matching fields, and create a new ZSet whose key is the match string. Insert each matching member into the ZSet with an appropriate score (commonly a timestamp or another sortable attribute).
If the ZSet exists, retrieve the required page directly with ZREVRANGE.
This on‑demand index provides fast pagination after the initial scan.
Performance Optimizations
Creating a ZSet for every distinct filter can exhaust cache space. To mitigate this, each generated ZSet is assigned an expiration time (TTL). When a cached ZSet is accessed, its TTL is refreshed, allowing unused indexes to be evicted automatically.
Two strategies keep the index synchronized with newly inserted hash entries:
At write time, insert the new record into the hash and also into any relevant ZSets. This requires a naming convention or metadata to identify which ZSets should receive the new member.
Periodically rebuild or refresh the ZSets. This approach is simpler but may produce stale pagination results between refreshes.
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.
