0
# Specialized Data Structures
1
2
Redisson provides advanced distributed data structures beyond basic collections, including atomic operations, probabilistic structures, geospatial operations, binary data handling, and specialized utilities for various use cases.
3
4
## Capabilities
5
6
### Atomic Operations
7
8
Distributed atomic values for thread-safe numeric operations across multiple JVM instances.
9
10
```java { .api }
11
/**
12
* Get a distributed atomic long for thread-safe long operations
13
* @param name - unique name of the atomic long
14
* @return RAtomicLong instance
15
*/
16
public RAtomicLong getAtomicLong(String name);
17
public RAtomicLong getAtomicLong(CommonOptions options);
18
19
/**
20
* Get a distributed atomic double for thread-safe double operations
21
* @param name - unique name of the atomic double
22
* @return RAtomicDouble instance
23
*/
24
public RAtomicDouble getAtomicDouble(String name);
25
public RAtomicDouble getAtomicDouble(CommonOptions options);
26
27
/**
28
* Get a long adder for high-performance distributed counting
29
* @param name - unique name of the long adder
30
* @return RLongAdder instance optimized for concurrent additions
31
*/
32
public RLongAdder getLongAdder(String name);
33
public RLongAdder getLongAdder(CommonOptions options);
34
35
/**
36
* Get a double adder for high-performance distributed summing
37
* @param name - unique name of the double adder
38
* @return RDoubleAdder instance optimized for concurrent additions
39
*/
40
public RDoubleAdder getDoubleAdder(String name);
41
public RDoubleAdder getDoubleAdder(CommonOptions options);
42
```
43
44
**Atomic Interfaces:**
45
46
```java { .api }
47
// Distributed atomic long with compare-and-swap operations
48
public interface RAtomicLong extends RObject, RExpirable, RAtomicLongAsync {
49
long get();
50
void set(long newValue);
51
long getAndSet(long newValue);
52
53
// Compare and swap operations
54
boolean compareAndSet(long expect, long update);
55
boolean weakCompareAndSet(long expect, long update);
56
57
// Arithmetic operations
58
long addAndGet(long delta);
59
long getAndAdd(long delta);
60
long incrementAndGet();
61
long getAndIncrement();
62
long decrementAndGet();
63
long getAndDecrement();
64
65
// Functional operations
66
long updateAndGet(LongUnaryOperator updateFunction);
67
long getAndUpdate(LongUnaryOperator updateFunction);
68
long accumulateAndGet(long x, LongBinaryOperator accumulatorFunction);
69
long getAndAccumulate(long x, LongBinaryOperator accumulatorFunction);
70
}
71
72
// Distributed atomic double
73
public interface RAtomicDouble extends RObject, RExpirable, RAtomicDoubleAsync {
74
double get();
75
void set(double newValue);
76
double getAndSet(double newValue);
77
78
boolean compareAndSet(double expect, double update);
79
double addAndGet(double delta);
80
double getAndAdd(double delta);
81
82
// Functional operations
83
double updateAndGet(DoubleUnaryOperator updateFunction);
84
double getAndUpdate(DoubleUnaryOperator updateFunction);
85
double accumulateAndGet(double x, DoubleBinaryOperator accumulatorFunction);
86
double getAndAccumulate(double x, DoubleBinaryOperator accumulatorFunction);
87
}
88
89
// High-performance distributed counter
90
public interface RLongAdder extends RObject, RExpirable, RLongAdderAsync {
91
void add(long x);
92
void increment();
93
void decrement();
94
long sum();
95
void reset();
96
long sumThenReset();
97
String toString();
98
}
99
100
// High-performance distributed double accumulator
101
public interface RDoubleAdder extends RObject, RExpirable, RDoubleAdderAsync {
102
void add(double x);
103
double sum();
104
void reset();
105
double sumThenReset();
106
String toString();
107
}
108
```
109
110
**Usage Examples:**
111
112
```java
113
// Atomic long operations
114
RAtomicLong counter = redisson.getAtomicLong("globalCounter");
115
counter.set(100);
116
117
// Thread-safe operations across multiple JVMs
118
long newValue = counter.incrementAndGet(); // 101
119
long previous = counter.getAndAdd(10); // returns 101, sets to 111
120
121
// Compare and swap for conditional updates
122
long current = counter.get();
123
boolean success = counter.compareAndSet(current, current * 2);
124
if (success) {
125
System.out.println("Successfully doubled the counter");
126
}
127
128
// Functional updates
129
counter.updateAndGet(value -> value > 200 ? 0 : value + 1);
130
counter.accumulateAndGet(5, (current, delta) -> Math.max(current, delta));
131
132
// High-performance counting with RLongAdder
133
RLongAdder adder = redisson.getLongAdder("requestCounter");
134
135
// Multiple threads can increment concurrently with high performance
136
adder.increment();
137
adder.add(5);
138
139
// Get sum when needed (more expensive operation)
140
long totalRequests = adder.sum();
141
System.out.println("Total requests: " + totalRequests);
142
143
// Reset counter
144
long finalCount = adder.sumThenReset(); // Get value and reset atomically
145
146
// Atomic double for precise calculations
147
RAtomicDouble balance = redisson.getAtomicDouble("accountBalance");
148
balance.set(1000.50);
149
150
double newBalance = balance.addAndGet(-50.25); // Withdraw $50.25
151
boolean withdrawSuccess = balance.compareAndSet(950.25, 900.25); // Conditional withdraw
152
```
153
154
### Probabilistic Data Structures
155
156
Memory-efficient probabilistic data structures for approximate operations on large datasets.
157
158
```java { .api }
159
/**
160
* Get a Bloom filter for membership testing
161
* @param name - unique name of the Bloom filter
162
* @return RBloomFilter instance for approximate membership testing
163
*/
164
public <V> RBloomFilter<V> getBloomFilter(String name);
165
public <V> RBloomFilter<V> getBloomFilter(String name, Codec codec);
166
public <V> RBloomFilter<V> getBloomFilter(PlainOptions options);
167
168
/**
169
* Get a HyperLogLog for cardinality estimation
170
* @param name - unique name of the HyperLogLog
171
* @return RHyperLogLog instance for approximate unique count
172
*/
173
public <V> RHyperLogLog<V> getHyperLogLog(String name);
174
public <V> RHyperLogLog<V> getHyperLogLog(String name, Codec codec);
175
public <V> RHyperLogLog<V> getHyperLogLog(PlainOptions options);
176
```
177
178
**Probabilistic Interfaces:**
179
180
```java { .api }
181
// Bloom filter for membership testing
182
public interface RBloomFilter<T> extends RObject, RExpirable, RBloomFilterAsync<T> {
183
// Filter initialization
184
boolean tryInit(long expectedInsertions, double falseProbability);
185
boolean isExists();
186
187
// Membership operations
188
boolean contains(T object);
189
boolean add(T object);
190
191
// Bulk operations
192
boolean[] contains(T... objects);
193
boolean addAll(Collection<T> c);
194
boolean containsAll(Collection<T> c);
195
196
// Filter statistics
197
long count();
198
long getExpectedInsertions();
199
double getFalseProbability();
200
long getHashIterations();
201
long getSize();
202
}
203
204
// HyperLogLog for cardinality estimation
205
public interface RHyperLogLog<V> extends RObject, RExpirable, RHyperLogLogAsync<V> {
206
// Add elements for counting unique values
207
boolean add(V obj);
208
boolean addAll(Collection<V> objects);
209
210
// Get approximate unique count
211
long count();
212
213
// Merge with other HyperLogLogs
214
long countWith(String... otherLogNames);
215
void mergeWith(String... otherLogNames);
216
}
217
```
218
219
**Usage Examples:**
220
221
```java
222
// Bloom filter for membership testing
223
RBloomFilter<String> bloomFilter = redisson.getBloomFilter("uniqueUsers");
224
225
// Initialize filter with expected elements and false positive rate
226
bloomFilter.tryInit(10000, 0.03); // 10K elements, 3% false positive rate
227
228
// Add elements
229
bloomFilter.add("user123");
230
bloomFilter.add("user456");
231
bloomFilter.add("user789");
232
233
// Test membership
234
boolean containsUser = bloomFilter.contains("user123"); // true
235
boolean containsNew = bloomFilter.contains("user999"); // false (or small chance of false positive)
236
237
// Bulk operations
238
Collection<String> users = Arrays.asList("user1", "user2", "user3");
239
bloomFilter.addAll(users);
240
boolean allExist = bloomFilter.containsAll(users); // true
241
242
// Check filter statistics
243
long elementCount = bloomFilter.count();
244
double falsePositiveRate = bloomFilter.getFalseProbability();
245
System.out.println("Filter contains ~" + elementCount + " elements with " +
246
(falsePositiveRate * 100) + "% false positive rate");
247
248
// HyperLogLog for unique count estimation
249
RHyperLogLog<String> uniqueVisitors = redisson.getHyperLogLog("dailyVisitors");
250
251
// Add visitor IDs (can be millions with constant memory usage)
252
uniqueVisitors.add("visitor1");
253
uniqueVisitors.add("visitor2");
254
uniqueVisitors.add("visitor1"); // Duplicate - won't affect count
255
256
// Add many visitors
257
for (int i = 0; i < 100000; i++) {
258
uniqueVisitors.add("visitor" + i);
259
}
260
261
// Get approximate unique count (very memory efficient)
262
long uniqueCount = uniqueVisitors.count();
263
System.out.println("Approximate unique visitors: " + uniqueCount);
264
265
// Merge multiple HyperLogLogs
266
RHyperLogLog<String> weeklyVisitors = redisson.getHyperLogLog("weeklyVisitors");
267
RHyperLogLog<String> monthlyVisitors = redisson.getHyperLogLog("monthlyVisitors");
268
269
// Count across multiple logs without merging
270
long totalUniqueVisitors = uniqueVisitors.countWith("weeklyVisitors", "monthlyVisitors");
271
272
// Merge logs into one
273
uniqueVisitors.mergeWith("weeklyVisitors", "monthlyVisitors");
274
```
275
276
### Geospatial Operations
277
278
Geospatial data structures for location-based operations using Redis GEO commands.
279
280
```java { .api }
281
/**
282
* Get a geo-spatial collection for location operations
283
* @param name - unique name of the geo collection
284
* @return RGeo instance for geospatial operations
285
*/
286
public <V> RGeo<V> getGeo(String name);
287
public <V> RGeo<V> getGeo(String name, Codec codec);
288
public <V> RGeo<V> getGeo(PlainOptions options);
289
```
290
291
**Geo Interface:**
292
293
```java { .api }
294
// Geospatial operations interface
295
public interface RGeo<V> extends RObject, RExpirable, RGeoAsync<V> {
296
// Add locations
297
long add(double longitude, double latitude, V member);
298
long add(GeoEntry... entries);
299
300
// Distance calculations
301
Double dist(V firstMember, V secondMember, GeoUnit geoUnit);
302
303
// Get coordinates
304
Map<V, GeoPosition> pos(V... members);
305
List<String> hash(V... members);
306
307
// Radius searches
308
List<V> radius(double longitude, double latitude, double radius, GeoUnit geoUnit);
309
List<V> radius(double longitude, double latitude, double radius, GeoUnit geoUnit, int count);
310
List<V> radius(double longitude, double latitude, double radius, GeoUnit geoUnit,
311
GeoOrder geoOrder);
312
List<V> radius(double longitude, double latitude, double radius, GeoUnit geoUnit,
313
GeoOrder geoOrder, int count);
314
315
// Radius searches with distance
316
Map<V, Double> radiusWithDistance(double longitude, double latitude, double radius,
317
GeoUnit geoUnit);
318
Map<V, Double> radiusWithDistance(double longitude, double latitude, double radius,
319
GeoUnit geoUnit, int count);
320
Map<V, Double> radiusWithDistance(double longitude, double latitude, double radius,
321
GeoUnit geoUnit, GeoOrder geoOrder);
322
323
// Radius searches with position
324
Map<V, GeoPosition> radiusWithPosition(double longitude, double latitude, double radius,
325
GeoUnit geoUnit);
326
327
// Member-based radius searches
328
List<V> radius(V member, double radius, GeoUnit geoUnit);
329
Map<V, Double> radiusWithDistance(V member, double radius, GeoUnit geoUnit);
330
Map<V, GeoPosition> radiusWithPosition(V member, double radius, GeoUnit geoUnit);
331
332
// Search and store results
333
long radiusStoreTo(String destName, double longitude, double latitude, double radius,
334
GeoUnit geoUnit);
335
long radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit);
336
}
337
338
// Geospatial data types
339
public class GeoEntry {
340
private final double longitude;
341
private final double latitude;
342
private final Object member;
343
344
public GeoEntry(double longitude, double latitude, Object member);
345
// getters...
346
}
347
348
public class GeoPosition {
349
private final double longitude;
350
private final double latitude;
351
352
public GeoPosition(double longitude, double latitude);
353
// getters...
354
}
355
356
public enum GeoUnit {
357
METERS("m"),
358
KILOMETERS("km"),
359
MILES("mi"),
360
FEET("ft");
361
362
private final String value;
363
GeoUnit(String value) { this.value = value; }
364
}
365
366
public enum GeoOrder {
367
ASC, DESC
368
}
369
```
370
371
**Usage Examples:**
372
373
```java
374
// Geospatial operations for location services
375
RGeo<String> locations = redisson.getGeo("cityLocations");
376
377
// Add locations (longitude, latitude, member)
378
locations.add(-74.0059, 40.7128, "New York"); // NYC
379
locations.add(-118.2437, 34.0522, "Los Angeles"); // LA
380
locations.add(-87.6298, 41.8781, "Chicago"); // Chicago
381
locations.add(-122.4194, 37.7749, "San Francisco"); // SF
382
383
// Calculate distance between cities
384
Double distance = locations.dist("New York", "Los Angeles", GeoUnit.MILES);
385
System.out.println("Distance NY to LA: " + distance + " miles");
386
387
// Get coordinates of a city
388
Map<String, GeoPosition> positions = locations.pos("New York", "Chicago");
389
GeoPosition nycPos = positions.get("New York");
390
System.out.println("NYC: " + nycPos.getLongitude() + ", " + nycPos.getLatitude());
391
392
// Find cities within radius of a point (around NYC)
393
List<String> nearbyCities = locations.radius(-74.0059, 40.7128, 300, GeoUnit.MILES);
394
System.out.println("Cities within 300 miles of NYC: " + nearbyCities);
395
396
// Find cities with distances
397
Map<String, Double> citiesWithDistance = locations.radiusWithDistance(-74.0059, 40.7128,
398
500, GeoUnit.MILES);
399
citiesWithDistance.forEach((city, dist) -> {
400
System.out.println(city + " is " + dist + " miles away");
401
});
402
403
// Find cities near another city
404
List<String> nearChicago = locations.radius("Chicago", 200, GeoUnit.MILES);
405
System.out.println("Cities within 200 miles of Chicago: " + nearChicago);
406
407
// Store search results in another geo collection
408
long stored = locations.radiusStoreTo("eastCoastCities", -74.0059, 40.7128,
409
300, GeoUnit.MILES);
410
System.out.println("Stored " + stored + " east coast cities");
411
412
// Delivery service example
413
RGeo<String> deliveryPoints = redisson.getGeo("deliveryLocations");
414
415
// Add delivery addresses
416
deliveryPoints.add(-73.935242, 40.730610, "customer1"); // East Village
417
deliveryPoints.add(-73.989308, 40.756800, "customer2"); // Times Square
418
deliveryPoints.add(-73.958805, 40.768923, "customer3"); // Upper East Side
419
420
// Find deliveries within 2 miles of delivery truck location
421
List<String> nearbyDeliveries = deliveryPoints.radius(-73.950000, 40.750000,
422
2, GeoUnit.MILES);
423
System.out.println("Nearby deliveries: " + nearbyDeliveries);
424
425
// Restaurant finder example
426
RGeo<Restaurant> restaurants = redisson.getGeo("restaurants");
427
restaurants.add(-73.9857, 40.7484, new Restaurant("Pizza Palace", "Italian"));
428
restaurants.add(-73.9759, 40.7505, new Restaurant("Burger Barn", "American"));
429
restaurants.add(-73.9851, 40.7589, new Restaurant("Sushi Spot", "Japanese"));
430
431
// Find restaurants near user location, sorted by distance
432
Map<Restaurant, Double> nearbyRestaurants = restaurants.radiusWithDistance(
433
-73.9800, 40.7500, 0.5, GeoUnit.MILES, GeoOrder.ASC);
434
435
nearbyRestaurants.forEach((restaurant, distance) -> {
436
System.out.println(restaurant.getName() + " - " + distance + " miles");
437
});
438
```
439
440
### Binary Data Operations
441
442
Binary data handling with bit-level operations and binary streams.
443
444
```java { .api }
445
/**
446
* Get a distributed bit set for binary operations
447
* @param name - unique name of the bit set
448
* @return RBitSet instance for bit manipulation
449
*/
450
public RBitSet getBitSet(String name);
451
public RBitSet getBitSet(CommonOptions options);
452
453
/**
454
* Get a binary stream for raw binary data operations
455
* @param name - unique name of the binary stream
456
* @return RBinaryStream instance for binary I/O
457
*/
458
public RBinaryStream getBinaryStream(String name);
459
public RBinaryStream getBinaryStream(CommonOptions options);
460
```
461
462
**Binary Interfaces:**
463
464
```java { .api }
465
// Distributed bit set for binary operations
466
public interface RBitSet extends RObject, RExpirable, RBitSetAsync {
467
// Bit operations
468
boolean get(long bitIndex);
469
boolean getAndSet(long bitIndex);
470
void set(long bitIndex);
471
void set(long bitIndex, boolean value);
472
void set(long fromIndex, long toIndex);
473
void set(long fromIndex, long toIndex, boolean value);
474
475
// Bit clearing
476
void clear();
477
void clear(long bitIndex);
478
void clear(long fromIndex, long toIndex);
479
480
// Bit testing
481
boolean isEmpty();
482
long length();
483
long size();
484
long cardinality(); // Count of set bits
485
486
// Bit operations with other bit sets
487
void and(String... bitSetNames);
488
void or(String... bitSetNames);
489
void xor(String... bitSetNames);
490
void not();
491
492
// Bit searching
493
long nextSetBit(long fromIndex);
494
long nextClearBit(long fromIndex);
495
long previousSetBit(long fromIndex);
496
long previousClearBit(long fromIndex);
497
498
// Bulk operations
499
byte[] toByteArray();
500
BitSet asBitSet();
501
}
502
503
// Binary stream for raw data
504
public interface RBinaryStream extends RObject, RBinaryStreamAsync {
505
// Stream operations
506
InputStream getInputStream();
507
OutputStream getOutputStream();
508
509
// Direct read/write
510
void set(byte[] value);
511
void set(InputStream inputStream);
512
byte[] get();
513
514
// Partial operations
515
byte[] get(long offset, long length);
516
void set(byte[] value, long offset);
517
518
// Stream information
519
long size();
520
boolean delete();
521
}
522
```
523
524
**Usage Examples:**
525
526
```java
527
// Bit set operations for flags and permissions
528
RBitSet permissions = redisson.getBitSet("userPermissions");
529
530
// Set permission bits (bit index represents permission ID)
531
permissions.set(0); // Read permission
532
permissions.set(1); // Write permission
533
permissions.set(5); // Admin permission
534
535
// Check permissions
536
boolean canRead = permissions.get(0); // true
537
boolean canWrite = permissions.get(1); // true
538
boolean canDelete = permissions.get(2); // false
539
540
// Set multiple bits
541
permissions.set(10, 15); // Set bits 10-14
542
543
// Count set permissions
544
long activePermissions = permissions.cardinality();
545
System.out.println("User has " + activePermissions + " permissions");
546
547
// Combine permissions from multiple users
548
RBitSet user1Perms = redisson.getBitSet("user1Permissions");
549
RBitSet user2Perms = redisson.getBitSet("user2Permissions");
550
551
user1Perms.set(0, 5); // Basic permissions
552
user2Perms.set(3, 8); // Different permissions
553
554
// Create combined permission set
555
RBitSet combinedPerms = redisson.getBitSet("combinedPermissions");
556
combinedPerms.or("user1Permissions", "user2Permissions");
557
558
// Find next available permission slot
559
long nextAvailable = combinedPerms.nextClearBit(0);
560
System.out.println("Next available permission ID: " + nextAvailable);
561
562
// Binary stream for file-like operations
563
RBinaryStream fileData = redisson.getBinaryStream("uploadedFile");
564
565
// Store binary data
566
byte[] imageData = loadImageFromDisk();
567
fileData.set(imageData);
568
569
// Read binary data
570
byte[] retrievedData = fileData.get();
571
saveImageToDisk(retrievedData);
572
573
// Stream operations for large files
574
try (InputStream input = new FileInputStream("largefile.zip");
575
OutputStream output = fileData.getOutputStream()) {
576
577
byte[] buffer = new byte[8192];
578
int bytesRead;
579
while ((bytesRead = input.read(buffer)) != -1) {
580
output.write(buffer, 0, bytesRead);
581
}
582
}
583
584
// Read part of binary data
585
long fileSize = fileData.size();
586
byte[] header = fileData.get(0, 1024); // First 1KB
587
byte[] footer = fileData.get(fileSize - 1024, 1024); // Last 1KB
588
589
// Update part of binary data
590
byte[] newHeader = createNewHeader();
591
fileData.set(newHeader, 0); // Replace header
592
593
System.out.println("File size: " + fileData.size() + " bytes");
594
```
595
596
### ID Generation
597
598
Distributed ID generation for unique identifier creation across multiple instances.
599
600
```java { .api }
601
/**
602
* Get an ID generator for distributed unique ID creation
603
* @param name - unique name of the ID generator
604
* @return RIdGenerator instance
605
*/
606
public RIdGenerator getIdGenerator(String name);
607
public RIdGenerator getIdGenerator(CommonOptions options);
608
```
609
610
**ID Generator Interface:**
611
612
```java { .api }
613
public interface RIdGenerator extends RObject, RExpirable, RIdGeneratorAsync {
614
// Initialize generator with allocation size
615
boolean tryInit(long value, long allocationSize);
616
617
// Generate next ID
618
long nextId();
619
620
// Current state
621
long current();
622
623
// Allocation settings
624
long getAllocationSize();
625
boolean expire(long timeToLive, TimeUnit timeUnit);
626
}
627
```
628
629
**Usage Examples:**
630
631
```java
632
// Distributed ID generation
633
RIdGenerator orderIds = redisson.getIdGenerator("orderIdGenerator");
634
635
// Initialize with starting value and allocation size
636
orderIds.tryInit(10000, 100); // Start at 10000, allocate 100 IDs at a time
637
638
// Generate unique order IDs
639
long orderId1 = orderIds.nextId(); // 10000
640
long orderId2 = orderIds.nextId(); // 10001
641
long orderId3 = orderIds.nextId(); // 10002
642
643
System.out.println("Generated order IDs: " + orderId1 + ", " + orderId2 + ", " + orderId3);
644
645
// Multiple ID generators for different entity types
646
RIdGenerator userIds = redisson.getIdGenerator("userIdGenerator");
647
RIdGenerator productIds = redisson.getIdGenerator("productIdGenerator");
648
649
userIds.tryInit(1000, 50);
650
productIds.tryInit(5000, 25);
651
652
// Each generator maintains independent sequences
653
long userId = userIds.nextId(); // 1000
654
long productId = productIds.nextId(); // 5000
655
656
// Check current values
657
long currentUser = userIds.current();
658
long currentProduct = productIds.current();
659
660
System.out.println("Current user ID: " + currentUser);
661
System.out.println("Current product ID: " + currentProduct);
662
663
// High-performance ID generation in multi-threaded environment
664
ExecutorService executor = Executors.newFixedThreadPool(10);
665
RIdGenerator threadSafeIds = redisson.getIdGenerator("threadSafeGenerator");
666
threadSafeIds.tryInit(0, 1000); // Large allocation for high throughput
667
668
// Multiple threads generating IDs concurrently
669
for (int i = 0; i < 10; i++) {
670
executor.submit(() -> {
671
for (int j = 0; j < 1000; j++) {
672
long id = threadSafeIds.nextId();
673
System.out.println("Thread " + Thread.currentThread().getName() +
674
" generated ID: " + id);
675
}
676
});
677
}
678
679
executor.shutdown();
680
```
681
682
### Rate Limiting
683
684
Distributed rate limiting for controlling request rates across multiple instances.
685
686
```java { .api }
687
/**
688
* Get a rate limiter for distributed rate limiting
689
* @param name - unique name of the rate limiter
690
* @return RRateLimiter instance
691
*/
692
public RRateLimiter getRateLimiter(String name);
693
public RRateLimiter getRateLimiter(CommonOptions options);
694
```
695
696
**Rate Limiter Interface:**
697
698
```java { .api }
699
public interface RRateLimiter extends RObject, RExpirable, RRateLimiterAsync {
700
// Initialize rate limiter
701
boolean trySetRate(RateType type, long rate, long rateInterval, RateIntervalUnit rateIntervalUnit);
702
703
// Acquire permits
704
boolean tryAcquire();
705
boolean tryAcquire(long permits);
706
boolean tryAcquire(long timeout, TimeUnit unit);
707
boolean tryAcquire(long permits, long timeout, TimeUnit unit);
708
709
void acquire();
710
void acquire(long permits);
711
712
// Rate limiter information
713
long availablePermits();
714
RateLimiterConfig getConfig();
715
}
716
717
public enum RateType {
718
OVERALL, // Total rate across all instances
719
PER_CLIENT // Rate per client instance
720
}
721
722
public enum RateIntervalUnit {
723
SECONDS, MINUTES, HOURS, DAYS
724
}
725
```
726
727
**Usage Examples:**
728
729
```java
730
// API rate limiting
731
RRateLimiter apiLimiter = redisson.getRateLimiter("apiRequests");
732
733
// Allow 100 requests per minute across all instances
734
apiLimiter.trySetRate(RateType.OVERALL, 100, 1, RateIntervalUnit.MINUTES);
735
736
// Check if request is allowed
737
if (apiLimiter.tryAcquire()) {
738
// Process API request
739
processApiRequest();
740
} else {
741
// Rate limit exceeded
742
throw new RateLimitExceededException("Too many requests");
743
}
744
745
// Per-user rate limiting
746
RRateLimiter userLimiter = redisson.getRateLimiter("user:" + userId + ":requests");
747
userLimiter.trySetRate(RateType.PER_CLIENT, 10, 1, RateIntervalUnit.MINUTES);
748
749
// Acquire multiple permits for batch operations
750
if (userLimiter.tryAcquire(5, 1, TimeUnit.SECONDS)) {
751
processBatchRequest(5);
752
}
753
754
// Blocking acquire with automatic rate limiting
755
userLimiter.acquire(); // Blocks until permit is available
756
processRequest();
757
```
758
759
### Time Series Data
760
761
Time series data structures for storing and querying time-ordered data (Redis 5.0.0+).
762
763
```java { .api }
764
/**
765
* Get a time series for time-ordered data storage
766
* @param name - unique name of the time series
767
* @return RTimeSeries instance
768
*/
769
public <V, L> RTimeSeries<V, L> getTimeSeries(String name);
770
public <V, L> RTimeSeries<V, L> getTimeSeries(String name, Codec codec);
771
public <V, L> RTimeSeries<V, L> getTimeSeries(PlainOptions options);
772
```
773
774
**Time Series Interface:**
775
776
```java { .api }
777
public interface RTimeSeries<V, L> extends RObject, RExpirable, RTimeSeriesAsync<V, L> {
778
// Add data points
779
void add(long timestamp, V object);
780
void add(long timestamp, V object, L label);
781
void addAll(Map<Long, V> objects);
782
783
// Range queries
784
Collection<TimeSeriesEntry<V, L>> range(long startTimestamp, long endTimestamp);
785
Collection<TimeSeriesEntry<V, L>> range(long startTimestamp, long endTimestamp, int count);
786
Collection<TimeSeriesEntry<V, L>> rangeReversed(long startTimestamp, long endTimestamp);
787
788
// Get entries by count
789
Collection<TimeSeriesEntry<V, L>> first(int count);
790
Collection<TimeSeriesEntry<V, L>> last(int count);
791
792
// Size and info
793
long size();
794
long size(long startTimestamp, long endTimestamp);
795
TimeSeriesEntry<V, L> firstEntry();
796
TimeSeriesEntry<V, L> lastEntry();
797
798
// Remove operations
799
boolean remove(long timestamp);
800
long removeRange(long startTimestamp, long endTimestamp);
801
802
// Polling operations
803
Collection<TimeSeriesEntry<V, L>> pollFirst(int count);
804
Collection<TimeSeriesEntry<V, L>> pollLast(int count);
805
}
806
807
public class TimeSeriesEntry<V, L> {
808
private final long timestamp;
809
private final V value;
810
private final L label;
811
812
// constructors and getters...
813
}
814
```
815
816
**Usage Examples:**
817
818
```java
819
// System metrics time series
820
RTimeSeries<Double, String> cpuMetrics = redisson.getTimeSeries("cpu_usage");
821
822
// Add CPU usage data points
823
long now = System.currentTimeMillis();
824
cpuMetrics.add(now, 45.5, "server1");
825
cpuMetrics.add(now + 60000, 52.3, "server1"); // 1 minute later
826
cpuMetrics.add(now + 120000, 38.7, "server1"); // 2 minutes later
827
828
// Query metrics for the last hour
829
long oneHourAgo = now - (60 * 60 * 1000);
830
Collection<TimeSeriesEntry<Double, String>> recentMetrics =
831
cpuMetrics.range(oneHourAgo, now);
832
833
recentMetrics.forEach(entry -> {
834
System.out.println("Time: " + entry.getTimestamp() +
835
", CPU: " + entry.getValue() + "%" +
836
", Server: " + entry.getLabel());
837
});
838
839
// Stock price time series
840
RTimeSeries<BigDecimal, String> stockPrices = redisson.getTimeSeries("AAPL_prices");
841
842
// Add stock price data
843
stockPrices.add(now, new BigDecimal("150.25"), "NASDAQ");
844
stockPrices.add(now + 300000, new BigDecimal("151.10"), "NASDAQ"); // 5 minutes later
845
846
// Get latest 10 price points
847
Collection<TimeSeriesEntry<BigDecimal, String>> latestPrices = stockPrices.last(10);
848
849
// Remove old data (older than 30 days)
850
long thirtyDaysAgo = now - (30L * 24 * 60 * 60 * 1000);
851
long removedCount = stockPrices.removeRange(0, thirtyDaysAgo);
852
System.out.println("Removed " + removedCount + " old entries");
853
```
854
855
### Streams
856
857
Redis Streams for message streaming and event sourcing (Redis 5.0.0+).
858
859
```java { .api }
860
/**
861
* Get a Redis stream for message streaming
862
* @param name - unique name of the stream
863
* @return RStream instance
864
*/
865
public <K, V> RStream<K, V> getStream(String name);
866
public <K, V> RStream<K, V> getStream(String name, Codec codec);
867
public <K, V> RStream<K, V> getStream(PlainOptions options);
868
```
869
870
**Stream Interface:**
871
872
```java { .api }
873
public interface RStream<K, V> extends RObject, RExpirable, RStreamAsync<K, V> {
874
// Add messages
875
StreamMessageId add(StreamAddArgs<K, V> args);
876
StreamMessageId add(K key, V value);
877
StreamMessageId add(Map<K, V> entries);
878
879
// Read messages
880
Map<String, Map<StreamMessageId, Map<K, V>>> read(StreamReadArgs args);
881
Map<StreamMessageId, Map<K, V>> read(StreamMessageId id);
882
Map<StreamMessageId, Map<K, V>> read(int count, StreamMessageId id);
883
884
// Range operations
885
Map<StreamMessageId, Map<K, V>> range(StreamMessageId startId, StreamMessageId endId);
886
Map<StreamMessageId, Map<K, V>> range(int count, StreamMessageId startId, StreamMessageId endId);
887
Map<StreamMessageId, Map<K, V>> rangeReversed(StreamMessageId startId, StreamMessageId endId);
888
889
// Consumer groups
890
void createGroup(String groupName);
891
void createGroup(String groupName, StreamMessageId id);
892
893
// Stream info
894
long size();
895
StreamInfo<K, V> getInfo();
896
897
// Remove operations
898
long remove(StreamMessageId... ids);
899
long trim(StreamTrimArgs args);
900
}
901
902
public class StreamMessageId {
903
public static final StreamMessageId NEWEST = new StreamMessageId("$");
904
public static final StreamMessageId ALL = new StreamMessageId("0");
905
906
// constructors and methods...
907
}
908
```
909
910
**Usage Examples:**
911
912
```java
913
// Event streaming
914
RStream<String, Object> eventStream = redisson.getStream("user_events");
915
916
// Add events to stream
917
Map<String, Object> userLogin = new HashMap<>();
918
userLogin.put("event", "login");
919
userLogin.put("userId", "user123");
920
userLogin.put("timestamp", System.currentTimeMillis());
921
userLogin.put("ip", "192.168.1.100");
922
923
StreamMessageId loginId = eventStream.add(userLogin);
924
System.out.println("Added login event with ID: " + loginId);
925
926
// Add purchase event
927
StreamMessageId purchaseId = eventStream.add("event", "purchase",
928
"userId", "user123",
929
"productId", "prod456",
930
"amount", 99.99);
931
932
// Read all messages from beginning
933
Map<StreamMessageId, Map<String, Object>> allEvents =
934
eventStream.read(StreamMessageId.ALL);
935
936
allEvents.forEach((id, event) -> {
937
System.out.println("Event ID: " + id + ", Data: " + event);
938
});
939
940
// Create consumer group for processing
941
eventStream.createGroup("analytics_processor");
942
943
// Chat messaging with streams
944
RStream<String, String> chatStream = redisson.getStream("chat:room1");
945
946
// Send messages
947
chatStream.add("user", "alice", "message", "Hello everyone!");
948
chatStream.add("user", "bob", "message", "Hi Alice!");
949
chatStream.add("user", "charlie", "message", "Good morning!");
950
951
// Read latest messages
952
Map<StreamMessageId, Map<String, String>> recentMessages =
953
chatStream.read(10, StreamMessageId.NEWEST);
954
955
// Process messages
956
recentMessages.forEach((id, msg) -> {
957
String user = msg.get("user");
958
String message = msg.get("message");
959
System.out.println("[" + user + "]: " + message);
960
});
961
962
// Log processing with streams
963
RStream<String, Object> logStream = redisson.getStream("application_logs");
964
965
// Add log entries
966
logStream.add("level", "ERROR",
967
"message", "Database connection failed",
968
"component", "UserService",
969
"timestamp", System.currentTimeMillis());
970
971
logStream.add("level", "INFO",
972
"message", "User registered successfully",
973
"userId", "user789",
974
"timestamp", System.currentTimeMillis());
975
976
// Create consumer group for log processing
977
logStream.createGroup("log_processor");
978
979
// Trim old logs (keep last 1000 entries)
980
long trimmed = logStream.trim(StreamTrimArgs.maxLen(1000));
981
System.out.println("Trimmed " + trimmed + " old log entries");
982
```
983
984
## Advanced Data Structure Patterns
985
986
```java { .api }
987
// Combining data structures for complex operations
988
public class AdvancedPatterns {
989
990
// Rate limiting with atomic operations
991
public static boolean isRequestAllowed(RedissonClient redisson, String clientId,
992
int maxRequests, int windowSeconds) {
993
RAtomicLong requestCount = redisson.getAtomicLong("rate_limit:" + clientId);
994
995
long current = requestCount.get();
996
if (current == 0) {
997
// First request, set expiration
998
requestCount.set(1);
999
requestCount.expire(windowSeconds, TimeUnit.SECONDS);
1000
return true;
1001
} else if (current < maxRequests) {
1002
requestCount.incrementAndGet();
1003
return true;
1004
} else {
1005
return false; // Rate limit exceeded
1006
}
1007
}
1008
1009
// Caching with Bloom filter pre-check
1010
public static <T> T getWithBloomFilter(RedissonClient redisson, String key,
1011
Class<T> type, Supplier<T> loader) {
1012
RBloomFilter<String> cacheFilter = redisson.getBloomFilter("cache_filter");
1013
1014
// Quick check if key might exist
1015
if (!cacheFilter.contains(key)) {
1016
return null; // Definitely not in cache
1017
}
1018
1019
// Might exist, check actual cache
1020
RBucket<T> bucket = redisson.getBucket(key);
1021
T value = bucket.get();
1022
1023
if (value == null && loader != null) {
1024
// Load and cache
1025
value = loader.get();
1026
if (value != null) {
1027
bucket.set(value);
1028
cacheFilter.add(key);
1029
}
1030
}
1031
1032
return value;
1033
}
1034
1035
// Geospatial + time-series for location tracking
1036
public static void trackLocation(RedissonClient redisson, String userId,
1037
double longitude, double latitude) {
1038
// Store in geospatial index
1039
RGeo<String> locations = redisson.getGeo("user_locations");
1040
locations.add(longitude, latitude, userId);
1041
1042
// Store in time series for history
1043
RTimeSeries<GeoPosition, String> locationHistory =
1044
redisson.getTimeSeries("location_history:" + userId);
1045
locationHistory.add(System.currentTimeMillis(), new GeoPosition(longitude, latitude));
1046
1047
// Update atomic counter
1048
RAtomicLong locationUpdates = redisson.getAtomicLong("location_updates:" + userId);
1049
locationUpdates.incrementAndGet();
1050
}
1051
}
1052
```