Skip to content

feat(jedis-compatibility): add sorted set commands support #5339

@prashanna-frsh

Description

@prashanna-frsh

Describe the feature

Add comprehensive support for Redis/Valkey sorted set commands to the Jedis compatibility layer in Valkey GLIDE. This would enable applications using Jedis sorted set operations to migrate seamlessly to GLIDE without code changes.

The feature should include all standard sorted set commands with both String and binary (byte[]) API variants:

  • Basic operations: ZADD, ZREM, ZCARD, ZSCORE, ZMSCORE
  • Range queries: ZRANGE, ZRANK, ZREVRANK, ZCOUNT, ZLEXCOUNT
  • Advanced range operations: ZRANGESTORE, ZRANKWITHSCORE, ZREVRANKWITHSCORE
  • Modifications: ZINCRBY, ZPOPMIN, ZPOPMAX
  • Blocking operations: BZPOPMIN, BZPOPMAX, BZMPOP
  • Set operations: ZUNIONSTORE, ZINTERSTORE, ZUNION, ZINTER, ZINTERCARD, ZDIFF, ZDIFFSTORE
  • Multi-key operations: ZMPOP
  • Range removals: ZREMRANGEBYRANK, ZREMRANGEBYSCORE, ZREMRANGEBYLEX
  • Random sampling: ZRANDMEMBER
  • Iteration: ZSCAN

All commands should maintain full API compatibility with Jedis, including method signatures, return types, and exception handling behavior.

Use Case

Why is this feature needed?

1. Migration Path for Jedis Users

Many production applications use Jedis for sorted set operations. Without these commands in the compatibility layer, migration to GLIDE requires significant code refactoring, creating a barrier to adoption.

2. Common Real-World Use Cases

Sorted sets are fundamental to many application patterns:

  • Gaming Leaderboards: Store player scores with automatic ranking

    jedis.zadd("leaderboard", 1500, "player1");
    List<String> topPlayers = jedis.zrevrange("leaderboard", 0, 9);
  • Priority Queues: Weighted task scheduling

    jedis.zadd("tasks", System.currentTimeMillis(), "task-id");
    Map<String, Double> nextTask = jedis.zpopmin("tasks", 1);
  • Time-Series Data: Events indexed by timestamp

    jedis.zadd("events", timestamp, eventData);
    List<String> recentEvents = jedis.zrevrangeByScore("events", now, hourAgo);
  • Rate Limiting: Sliding window counters

    long count = jedis.zcount("requests:" + userId, now - window, now);
  • Auto-Complete: Frequency-based suggestions

    jedis.zincrby("suggestions", 1, searchTerm);
    List<String> popular = jedis.zrevrange("suggestions", 0, 9);

3. API Completeness

The Jedis compatibility layer currently supports string, hash, list, and set commands. Without sorted set support, it's incomplete for applications that rely on this fundamental Redis/Valkey data structure.

Proposed Solution

Implementation Approach

Add sorted set command methods to java/jedis-compatibility/src/main/java/redis/clients/jedis/Jedis.java that wrap the existing GLIDE client API:

// Example implementation pattern
public Long zadd(String key, double score, String member) {
    return executeCommandWithGlide(() -> 
        glideClient.zadd(key, Map.of(member, score))
    );
}

public Long zadd(byte[] key, double score, byte[] member) {
    return executeCommandWithGlide(() -> 
        glideClient.zadd(
            gs(key), 
            Map.of(gs(member), score)
        )
    );
}

Commands to Implement

Each command should have two variants (String and byte[]):

Basic Operations (6 commands)

  1. zadd(key, score, member) and zadd(key, scoreMembers, params)
  2. zaddIncr(key, score, member, params)
  3. zrem(key, members...)
  4. zcard(key)
  5. zscore(key, member)
  6. zmscore(key, members...) - Valkey 6.2+

Range Operations (9 commands)
7. zrange(key, start, stop) and zrangeWithScores(key, start, stop)
8. zrangestore(destination, source, start, stop) - Valkey 6.2+
9. zrank(key, member) and zrevrank(key, member)
10. zrankWithScore(key, member) - Valkey 7.2+
11. zrevrankWithScore(key, member) - Valkey 7.2+
12. zcount(key, min, max)
13. zlexcount(key, min, max)

Modification Operations (7 commands)
14. zincrby(key, increment, member)
15. zpopmin(key, count) and zpopmax(key, count) - Valkey 5.0+
16. bzpopmin(timeout, keys...) - Valkey 5.0+
17. bzpopmax(timeout, keys...) - Valkey 5.0+
18. zremrangebyrank(key, start, stop)
19. zremrangebyscore(key, min, max)
20. zremrangebylex(key, min, max)

Set Operations (10 commands)
21. zunionstore(destination, keys...) with aggregate options
22. zunion(keys...) - Valkey 6.2+
23. zunionWithScores(keys...) - Valkey 6.2+
24. zinterstore(destination, keys...) with aggregate options
25. zinter(keys...) - Valkey 6.2+
26. zinterWithScores(keys...) - Valkey 6.2+
27. zintercard(keys...) - Valkey 7.0+
28. zdiff(keys...) - Valkey 6.2+
29. zdiffWithScores(keys...) - Valkey 6.2+
30. zdiffstore(destination, keys...) - Valkey 6.2+

Multi-Key Pop Operations (2 commands)
31. zmpop(min, keys...) - Valkey 7.0+
32. bzmpop(timeout, min, keys...) - Valkey 7.0+

Random Sampling (3 commands)
33. zrandmember(key) - Valkey 6.2+
34. zrandmemberWithCount(key, count) - Valkey 6.2+
35. zrandmemberWithCountWithScores(key, count) - Valkey 6.2+

Iteration (1 command)
36. zscan(key, cursor) with scan options

Total: 39 commands (78 methods with String and byte[] variants)

Testing Requirements

  • Unit tests for method signature validation (78 tests)
  • Integration tests for each command with both String and byte[] variants
  • Edge case testing (non-existing keys, empty sets, invalid ranges)
  • Version-specific tests with assumeTrue() guards for:
    • Valkey 5.0+: zpopmin, zpopmax, bzpopmin, bzpopmax
    • Valkey 6.2+: zmscore, zrangestore, zunion, zinter, zdiff, zrandmember
    • Valkey 7.0+: zintercard, zmpop, bzmpop
    • Valkey 7.2+: zrankWithScore, zrevrankWithScore
  • Realistic workflow tests (e.g., leaderboard scenario)
  • Lex range parsing tests
  • Set operation tests with different aggregation modes

Documentation

Update java/jedis-compatibility/README.md with:

  • Sorted set commands table with all 39 commands
  • Method signatures and descriptions
  • Usage examples for common patterns (leaderboards, set operations, random sampling)
  • Version compatibility notes for each command
  • Binary API support documentation

Update java/jedis-compatibility/compatibility-layer-migration-guide.md with:

  • Sorted set support status (from "Available via sendCommand() only" to "Full support")
  • Dedicated sorted set section with examples
  • Version compatibility information

Other Information

Alternative Solutions Considered

  1. Direct GLIDE API Usage: Users could call GLIDE APIs directly, but this defeats the purpose of the compatibility layer and requires code changes during migration.

  2. Partial Implementation: Could implement only the most common commands (ZADD, ZRANGE, ZSCORE), but this would leave gaps for applications using:

    • Advanced features like set operations (ZUNION, ZINTER, ZDIFF)
    • Blocking operations (BZPOPMIN, BZPOPMAX, BZMPOP)
    • Random sampling (ZRANDMEMBER)
    • Lexicographical operations (ZLEXCOUNT, ZREMRANGEBYLEX)
    • Multi-key operations (ZMPOP)
  3. Wrapper Library: Users could create their own wrapper, but this duplicates effort and creates maintenance burden.

  4. sendCommand() Only: Users could use sendCommand() for sorted set operations, but this:

    • Requires manual protocol command construction
    • Loses type safety and IDE auto-completion
    • Makes code less readable and maintainable
    • Defeats the purpose of Jedis compatibility

Technical Considerations

  • GLIDE already supports all sorted set operations through SortedSetBaseCommands interface
  • Implementation is primarily method wrapping and type conversion
  • Requires helper methods for parsing Jedis-style lex range strings ([a, (b, +, -)
  • Need to convert between Jedis types (Map, List) and GLIDE types (arrays, GlideString)
  • Some commands return complex structures (zmpop, bzmpop) requiring careful result mapping
  • No new dependencies required
  • No breaking changes to existing APIs
  • Total implementation: ~800 lines of code + ~600 lines of tests + ~200 lines of documentation

Acknowledgements

  • I may be able to implement this feature request
  • This feature might incur a breaking change

Client version used

Valkey GLIDE 2.1.0

Environment details (OS name and version, etc.)

  • Java 11+ - Gradle 8.14.3 - Valkey 1.2.0+ / Redis 5.0+ - macOS / Linux / Windows

Metadata

Metadata

Assignees

No one assigned

    Labels

    Compatibility 🧭Tasks & PRs for compatibility of GLIDE with other clientsTask 🔧Implementation work (not a bug)java ☕issues and fixes related to the java client

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions