-
Notifications
You must be signed in to change notification settings - Fork 140
Description
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)
zadd(key, score, member)andzadd(key, scoreMembers, params)zaddIncr(key, score, member, params)zrem(key, members...)zcard(key)zscore(key, member)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
-
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.
-
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)
-
Wrapper Library: Users could create their own wrapper, but this duplicates effort and creates maintenance burden.
-
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
SortedSetBaseCommandsinterface - 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