Redis sorted sets enable storing scored elements in a sortable order. The powerful ZRANGEBYSCORE command allows retrieving subsets based on element scores. In this advanced guide, we’ll build in-depth knowledge of ZRANGEBYSCORE and how to apply it for high performance queries.

Overview of Redis Sorted Sets

Redis sorted sets associate a 64-bit floating point score with each string member. The elements are automatically ordered from lowest to highest score. Sorted sets are implemented using a specialized data structure called zskiplist to achieve O(log(N)) time complexity for most read operations.

Compared to traditional ordered data structures, Redis sorted sets give you:

  • Fast inserts and updates with immediate re-ordering
  • Lexicographic ordering for elements with identical scores
  • Efficient sampling in score order with ZRANGEBYSCORE
  • Ability to union and intersect different sorted sets

Use cases include leaderboards, indexes, rate limits, scheduling, and ranking tables. Sets can contain millions of elements while maintaining high throughput and low latency.

Introducing ZRANGEBYSCORE for Score Based Filtering

The ZRANGEBYSCORE command retrieves set elements within the defined min-max score range. Results are ordered by element score.

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] 

Let‘s examine the available options:

  • min and max – Lower and upper score bounds for results
  • WITHSCORES – Return element scores along with values
  • LIMIT offset count – Pagination with skip offset and number of results

You can also prefix min or max with ( to exclude bounds from results.

Now let‘s demonstrate common ZRANGEBYSCORE use cases and patterns.

Building Paginated Leaderboards

Sorted sets excel at creating leaderboards ranked by user scores. With ZRANGEBYSCORE we can efficiently query slices for display.

For example, our game tracks player XP in a leaderboard sorted set. Using LIMIT we can paginate the full leaderboard 10 users at a time:

> ZADD leaderboard 1345 "User1" 1928 "User2" 521 "User3" 
> ZRANGEBYSCORE leaderboard 0 +inf LIMIT 0 10 WITHSCORES

1) "User3" 
2) 521
3) "User1"
4) 1345
5) "User2"
6) 1928

To render page 2, we skip the first 10:

ZRANGEBYSCORE leaderboard 0 +inf LIMIT 10 10 WITHSCORES

Optional optimization – store leaderboard ranks in a separate sorted set lb_ranks using the Redis ZRANK command. Then you can LIMIT on rank rather than relative offsets for more stable pagination.

ZRANGEBYRANK lb_ranks 10 20 

Pros:

  • Logarithmic time complexity – fast queries even on millions of elements
  • Lexicographical ordering of tied scores
  • More options via ZREVRANGEBYSCORE for reverse ordering

Sampling Timeseries Data

Sorted sets work great for sampling timeseries data at different resolutions.

For example, our app collects sensor_data at super fine 1 second granularity. We use ZRANGEBYSCORE to query different time ranges:

ZADD sensor_data 1548149181 504 
ZADD sensor_data 1548149182 502
...

# Last minute at 1 sec resolution  
ZRANGEBYSCORE sensor_data -inf +inf LIMIT 0 60 

# Last hour at 1 min resolution
ZRANGEBYSCORE sensor_data -inf +inf LIMIT 0 60 60

# Last day at 1 hour resolution
ZRANGEBYSCORE sensor_data -inf +inf LIMIT 0 24 60 

We can also derive aggregations on the fly using LIMIT. Here we calculate 1-minute averages:

# Average of 60 1-second samples  
ZRANGEBYSCORE sensor_data -inf +inf LIMIT 0 60 60 WITHSCORES 
ZREVRANGEBYSCORE sensor_data +inf -inf LIMIT 0 1 60 WITHSCORES AVG

Benefits:

  • Millisecond latency for real-time ingest
  • Efficient downsampling to lower resolution series
  • Derive aggregations through Redis scripting

Multi-Tiered Ranking with Sorted Set Unions

An interesting capability is the ability to union multiple sorted sets. This allows multi-tiered sorting and ranking scenarios.

For example, our dating site app stores attractiveness and compatibility scores in separate sorted sets. To get rankings by both attributes, we union the sets:

ZUNIONSTORE results 2 attractiveness compatibility WEIGHTS 2 1 AGGREGATE SUM

ZREVRANGE results 0 10 WITHSCORES

Now results are ordered by the composite of attractiveness x2 + compatibility. We were able to combine orthogonal scores at query time!

Other examples:

  • Search relevance by multiple signals – word match, page views, inbound links
  • Subreddit posts ranked by upvotes and recency
  • Network intrusion prevention ordered by severity and correlation

Use cases for multi-dimensional sorting:

  • Federated rating systems
  • Classification models
  • Composite indexes

Performance at Scale

A key advantage of Redis is speed and low latency. How does ZRANGEBYSCORE perform with large data volumes?

Published benchmarks reveal it achieves 500K+ queries per second for sets with tens of millions of scored elements on a single thread. Latency remains below 1 millisecond thanks to the underlying skiplist structure. CPU use is highly efficient as well.

So throughput is exceptional even at scale while delivering microsecond perceived latency.

Here‘s a quick capacity calculator. Assuming:

  • 1 KB sorted set elements
  • 50 byte scores
  • 64 GB RAM server

You can load approximately:

  • 100 Million elements with scores
  • 50 Billion scores only

ZRANGEBYSCORE performance remains excellent into hundreds of millions/billions of entries.

ZRANGEBYSCORE vs Traditional Index Paging

A benefit compared to SQL databases is avoiding complex indexes and query planning to traverse ordered subsets. How does ZRANGEBYSCORE fare against traditional indexing?

For simple score ranges, ZRANGEBYSCORE will be exponentially faster than queries filtering against a SQL index. Indexes still entail seeks across B-Trees along with transactional overheads.

With Redis the underlying data structure is an ordered index tuned for solid state memory access. No clumsy translation required. Minimal parsing or planning. CPU cache leveraged via sequential memory access.

What about complex combinations of filters, joins, multiple indexes? Relational solutions can still win through versatility and transactionality.

But for high performance ready-made lexicographic ordering, linear access by scores, and scalability to millions of entries, ZRANGEBYSCORE delivers exceptional throughput and tiny latency. Awesome for many ordering-based queries!

Lexicographic Ordering Within Score Ranges

An interesting property of sorted sets is simultaneous lexicographic ordering tied to the scoring. All elements with the same score retain insertion order.

We can leverage this for alphanumeric ranking scenarios. For example, to break ties between users with a level_score, order them alphabetically:

ZADD users 9001 "bob" 9001 "dan" 9001 "alice"  

ZRANGEBYSCORE users 9001 9001
> 1) "alice" 
   2) "bob"
   3) "dan" 

Other examples:

  • Version numbers – order by semantic version within releases
  • Date hierarchies – order days by name within month/year buckets
  • Alphabetize categories with equal view counts
  • Break ties in contest scores by entry datetime

So lexicographic ordering provides a handy secondary sort dimension.

Related Commands

Some alternatives and companions to ZRANGEBYSCORE:

Additionally in Redis 6.2+ the ZRANGE command implements the same signature as ZRANGEBYSCORE when invoked with the BYSCORE option. So you can use ZRANGE interchangeably depending on preference.

External Sources:

Conclusion

The Redis ZRANGEBYSCORE command offers outstanding performance querying elements by score ordering. Its logarithmic time complexity delivers microsecond latencies even at millions of entries. Paired with options for pagination, return scores, multiple bounds, and lexicographic tie-breaks, ZRANGEBYSCORE handles many scoring, ranking, and sorting workflows with flying speed.

Now you have expert insight into building high performance scored result sets with Redis sorted sets!

Similar Posts