From 48553bcdda89e5e9e943dbca53d73f055d99b5a8 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Fri, 10 Jul 2026 10:09:09 +0100 Subject: [PATCH] DOC-6827 Add Lettuce probabilistic data type examples and rundown page Stage Lettuce async + reactive doctests for the bloom, cuckoo, CMS, top-k, t-digest and HLL tutorial sets plus the combined home_prob_dts set, and add the client-specific rundown page at content/develop/clients/lettuce/prob.md. This is preemptive work: probabilistic command support is not in a released lettuce-core yet, so the examples are written against the Lettuce feature PRs (BF/CF/top-k merged to main; CMS and t-digest still open on the Dgramada fork, so their signatures may still shift). A Codex review flagged every non-HLL call as an unknown method - that is expected against the repo's pinned released jar, not a defect. Multi-step sets (t-digest, home_prob_dts) are authored as self-contained per-STEP blocks rather than one method chain threaded through the STEP markers, because the clients-example shortcode extracts each step by line range and a threaded chain renders as broken mid-chain fragments. Learned: multi-step doctests must be self-contained per STEP block or the shortcode extracts broken mid-chain fragments Constraint: each STEP_START/STEP_END block must stand alone (its own async chain, or per-statement reactive blocks), never span a single threaded method chain Rejected: one async/reactive chain threaded through all STEP markers | shortcode extracts per-step line ranges, so a threaded chain yields uncompilable fragments Recheck: when Lettuce CMS (redis/lettuce#3821) and t-digest (#3823) merge and release - re-pin lettuce-core, re-run the doctest harness so the REMOVE-block asserts become real oracles, and re-diff the CMS/t-digest signatures Ticket: DOC-6827 Co-Authored-By: Claude Opus 4.8 (1M context) --- content/develop/clients/lettuce/prob.md | 229 +++++++++++ .../lettuce-async/BloomFilterExample.java | 97 +++++ .../lettuce-reactive/BloomFilterExample.java | 101 +++++ .../lettuce-async/CMSExample.java | 98 +++++ .../lettuce-reactive/CMSExample.java | 100 +++++ .../lettuce-async/CuckooFilterExample.java | 90 ++++ .../lettuce-reactive/CuckooFilterExample.java | 88 ++++ .../lettuce-async/HyperLogLogExample.java | 91 ++++ .../lettuce-reactive/HyperLogLogExample.java | 88 ++++ .../lettuce-async/HomeProbExample.java | 388 ++++++++++++++++++ .../lettuce-reactive/HomeProbExample.java | 346 ++++++++++++++++ .../lettuce-async/TDigestExample.java | 177 ++++++++ .../lettuce-reactive/TDigestExample.java | 138 +++++++ .../lettuce-async/TopKExample.java | 88 ++++ .../lettuce-reactive/TopKExample.java | 91 ++++ 15 files changed, 2210 insertions(+) create mode 100644 content/develop/clients/lettuce/prob.md create mode 100644 local_examples/bf_tutorial/lettuce-async/BloomFilterExample.java create mode 100644 local_examples/bf_tutorial/lettuce-reactive/BloomFilterExample.java create mode 100644 local_examples/cms_tutorial/lettuce-async/CMSExample.java create mode 100644 local_examples/cms_tutorial/lettuce-reactive/CMSExample.java create mode 100644 local_examples/cuckoo_tutorial/lettuce-async/CuckooFilterExample.java create mode 100644 local_examples/cuckoo_tutorial/lettuce-reactive/CuckooFilterExample.java create mode 100644 local_examples/hll_tutorial/lettuce-async/HyperLogLogExample.java create mode 100644 local_examples/hll_tutorial/lettuce-reactive/HyperLogLogExample.java create mode 100644 local_examples/home_prob_dts/lettuce-async/HomeProbExample.java create mode 100644 local_examples/home_prob_dts/lettuce-reactive/HomeProbExample.java create mode 100644 local_examples/tdigest_tutorial/lettuce-async/TDigestExample.java create mode 100644 local_examples/tdigest_tutorial/lettuce-reactive/TDigestExample.java create mode 100644 local_examples/topk_tutorial/lettuce-async/TopKExample.java create mode 100644 local_examples/topk_tutorial/lettuce-reactive/TopKExample.java diff --git a/content/develop/clients/lettuce/prob.md b/content/develop/clients/lettuce/prob.md new file mode 100644 index 0000000000..a16094002c --- /dev/null +++ b/content/develop/clients/lettuce/prob.md @@ -0,0 +1,229 @@ +--- +categories: +- docs +- develop +- stack +- oss +- rs +- rc +- oss +- kubernetes +- clients +description: Learn how to use approximate calculations with Redis. +linkTitle: Probabilistic data types +title: Probabilistic data types +weight: 45 +--- + +Redis supports several +[probabilistic data types]({{< relref "/develop/data-types/probabilistic" >}}) +that let you calculate values approximately rather than exactly. +The types fall into two basic categories: + +- [Set operations](#set-operations): These types let you calculate (approximately) + the number of items in a set of distinct values, and whether or not a given value is + a member of a set. +- [Statistics](#statistics): These types give you an approximation of + statistics such as the quantiles, ranks, and frequencies of numeric data points in + a list. + +To see why these approximate calculations would be useful, consider the task of +counting the number of distinct IP addresses that access a website in one day. + +Assuming that you already have code that supplies you with each IP +address as a string, you could record the addresses in Redis using +a [set]({{< relref "/develop/data-types/sets" >}}): + +```java +commands.sadd("ip_tracker", newIpAddress); +``` + +The set can only contain each key once, so if the same address +appears again during the day, the new instance will not change +the set. At the end of the day, you could get the exact number of +distinct addresses using the `scard()` method: + +```java +RedisFuture numDistinctIps = commands.scard("ip_tracker"); +``` + +This approach is simple, effective, and precise but if your website +is very busy, the `ip_tracker` set could become very large and consume +a lot of memory. + +You would probably round the count of distinct IP addresses to the +nearest thousand or more to deliver the usage statistics, so +getting it exactly right is not important. It would be useful +if you could trade off some accuracy in exchange for lower memory +consumption. The probabilistic data types provide exactly this kind of +trade-off. Specifically, you can count the approximate number of items in a +set using the [HyperLogLog](#set-cardinality) data type, as described below. + +In general, the probabilistic data types let you perform approximations with a +bounded degree of error that have much lower memory consumption or execution +time than the equivalent precise calculations. + +The examples below use the asynchronous and reactive command APIs, but the +probabilistic commands are also available through the synchronous API. You can +access all of these commands directly from the standard Lettuce command +interfaces (for example, `RedisAsyncCommands` or `RedisReactiveCommands`), +just like the core Redis commands. + +## Set operations + +Redis supports the following approximate set operations: + +- [Membership](#set-membership): The + [Bloom filter]({{< relref "/develop/data-types/probabilistic/bloom-filter" >}}) and + [Cuckoo filter]({{< relref "/develop/data-types/probabilistic/cuckoo-filter" >}}) + data types let you track whether or not a given item is a member of a set. +- [Cardinality](#set-cardinality): The + [HyperLogLog]({{< relref "/develop/data-types/probabilistic/hyperloglogs" >}}) + data type gives you an approximate value for the number of items in a set, also + known as the *cardinality* of the set. + +The sections below describe these operations in more detail. + +### Set membership + +[Bloom filter]({{< relref "/develop/data-types/probabilistic/bloom-filter" >}}) and +[Cuckoo filter]({{< relref "/develop/data-types/probabilistic/cuckoo-filter" >}}) +objects provide a set membership operation that lets you track whether or not a +particular item has been added to a set. These two types provide different +trade-offs for memory usage and speed, so you can select the best one for your +use case. Note that for both types, there is an asymmetry between presence and +absence of items in the set. If an item is reported as absent, then it is definitely +absent, but if it is reported as present, then there is a small chance it may really be +absent. + +Instead of storing strings directly, like a [set]({{< relref "/develop/data-types/sets" >}}), +a Bloom filter records the presence or absence of the +[hash value](https://en.wikipedia.org/wiki/Hash_function) of a string. +This gives a very compact representation of the +set's membership with a fixed memory size, regardless of how many items you +add. The following example adds some names to a Bloom filter representing +a list of users and checks for the presence or absence of users in the list. + +{{< clients-example set="home_prob_dts" step="bloom" lang_filter="Java-Async,Java-Reactive" description="Foundational: Use Bloom filters for memory-efficient set membership testing with false positive possibility" difficulty="beginner" >}} +{{< /clients-example >}} + +A Cuckoo filter has similar features to a Bloom filter, but also supports +a deletion operation to remove hashes from a set, as shown in the example +below. + +{{< clients-example set="home_prob_dts" step="cuckoo" lang_filter="Java-Async,Java-Reactive" description="Foundational: Use Cuckoo filters for set membership testing with deletion support and faster lookups than Bloom filters" difficulty="beginner" >}} +{{< /clients-example >}} + +Which of these two data types you choose depends on your use case. +Bloom filters are generally faster than Cuckoo filters when adding new items, +and also have better memory usage. Cuckoo filters are generally faster +at checking membership and also support the delete operation. See the +[Bloom filter]({{< relref "/develop/data-types/probabilistic/bloom-filter" >}}) and +[Cuckoo filter]({{< relref "/develop/data-types/probabilistic/cuckoo-filter" >}}) +reference pages for more information and comparison between the two types. + +### Set cardinality + +A [HyperLogLog]({{< relref "/develop/data-types/probabilistic/hyperloglogs" >}}) +object calculates the cardinality of a set. As you add +items, the HyperLogLog tracks the number of distinct set members but +doesn't let you retrieve them or query which items have been added. +You can also merge two or more HyperLogLogs to find the cardinality of the +[union](https://en.wikipedia.org/wiki/Union_(set_theory)) of the sets they +represent. + +{{< clients-example set="home_prob_dts" step="hyperloglog" lang_filter="Java-Async,Java-Reactive" description="Foundational: Estimate set cardinality with HyperLogLog for memory-efficient counting of distinct items" difficulty="beginner" >}} +{{< /clients-example >}} + +The main benefit that HyperLogLogs offer is their very low +memory usage. They can count up to 2^64 items with less than +1% standard error using a maximum 12KB of memory. This makes +them very useful for counting things like the total of distinct +IP addresses that access a website or the total of distinct +bank card numbers that make purchases within a day. + +## Statistics + +Redis supports several approximate statistical calculations +on numeric data sets: + +- [Frequency](#frequency): The + [Count-min sketch]({{< relref "/develop/data-types/probabilistic/count-min-sketch" >}}) + data type lets you find the approximate frequency of a labeled item in a data stream. +- [Quantiles](#quantiles): The + [t-digest]({{< relref "/develop/data-types/probabilistic/t-digest" >}}) + data type estimates the quantile of a query value in a data stream. +- [Ranking](#ranking): The + [Top-K]({{< relref "/develop/data-types/probabilistic/top-k" >}}) data type + estimates the ranking of labeled items by frequency in a data stream. + +The sections below describe these operations in more detail. + +### Frequency + +A [Count-min sketch]({{< relref "/develop/data-types/probabilistic/count-min-sketch" >}}) +(CMS) object keeps count of a set of related items represented by +string labels. The count is approximate, but you can specify +how close you want to keep the count to the true value (as a fraction) +and the acceptable probability of failing to keep it in this +desired range. For example, you can request that the count should +stay within 0.1% of the true value and have a 0.05% probability +of going outside this limit. The example below shows how to create +a Count-min sketch object, add data to it, and then query it. + +{{< clients-example set="home_prob_dts" step="cms" lang_filter="Java-Async,Java-Reactive" description="Foundational: Track approximate item frequencies with Count-min sketch for memory-efficient statistics on data streams" difficulty="intermediate" >}} +{{< /clients-example >}} + +The advantage of using a CMS over keeping an exact count with a +[sorted set]({{< relref "/develop/data-types/sorted-sets" >}}) +is that that a CMS has very low and fixed memory usage, even for +large numbers of items. Use CMS objects to keep daily counts of +items sold, accesses to individual web pages on your site, and +other similar statistics. + +### Quantiles + +A [quantile](https://en.wikipedia.org/wiki/Quantile) is the value +below which a certain fraction of samples lie. For example, with +a set of measurements of people's heights, the quantile of 0.75 is +the value of height below which 75% of all people's heights lie. +[Percentiles](https://en.wikipedia.org/wiki/Percentile) are equivalent +to quantiles, except that the fraction is expressed as a percentage. + +A [t-digest]({{< relref "/develop/data-types/probabilistic/t-digest" >}}) +object can estimate quantiles from a set of values added to it +without having to store each value in the set explicitly. This can +save a lot of memory when you have a large number of samples. + +The example below shows how to add data samples to a t-digest +object and obtain some basic statistics, such as the minimum and +maximum values, the quantile of 0.75, and the +[cumulative distribution function](https://en.wikipedia.org/wiki/Cumulative_distribution_function) +(CDF), which is effectively the inverse of the quantile function. It also +shows how to merge two or more t-digest objects to query the combined +data set. + +{{< clients-example set="home_prob_dts" step="tdigest" lang_filter="Java-Async,Java-Reactive" description="Foundational: Estimate quantiles and percentiles with t-digest for memory-efficient statistical analysis of large datasets" difficulty="intermediate" >}} +{{< /clients-example >}} + +A t-digest object also supports several other related commands, such +as querying by rank. See the +[t-digest]({{< relref "/develop/data-types/probabilistic/t-digest" >}}) +reference for more information. + +### Ranking + +A [Top-K]({{< relref "/develop/data-types/probabilistic/top-k" >}}) +object estimates the rankings of different labeled items in a data +stream according to frequency. For example, you could use this to +track the top ten most frequently-accessed pages on a website, or the +top five most popular items sold. + +The example below adds several different items to a Top-K object +that tracks the top three items (this is the second parameter to +the `topKReserve()` method). It also shows how to list the +top *k* items and query whether or not a given item is in the +list. + +{{< clients-example set="home_prob_dts" step="topk" lang_filter="Java-Async,Java-Reactive" description="Foundational: Track top K most frequent items in a data stream with Top-K for efficient ranking without storing all items" difficulty="intermediate" >}} +{{< /clients-example >}} diff --git a/local_examples/bf_tutorial/lettuce-async/BloomFilterExample.java b/local_examples/bf_tutorial/lettuce-async/BloomFilterExample.java new file mode 100644 index 0000000000..c3c121bd68 --- /dev/null +++ b/local_examples/bf_tutorial/lettuce-async/BloomFilterExample.java @@ -0,0 +1,97 @@ +// EXAMPLE: bf_tutorial +package io.redis.examples.async; + +// HIDE_START +import io.lettuce.core.RedisClient; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.async.RedisAsyncCommands; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +// REMOVE_START +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +// REMOVE_END +// HIDE_END + +public class BloomFilterExample { + + // REMOVE_START + @Test + // REMOVE_END + public void run() { + // HIDE_START + RedisClient redisClient = RedisClient.create("redis://localhost:6379"); + + try (StatefulRedisConnection connection = redisClient.connect()) { + RedisAsyncCommands asyncCommands = connection.async(); + // HIDE_END + + // STEP_START bloom + // REMOVE_START + asyncCommands.del("bikes:models").toCompletableFuture().join(); + // REMOVE_END + CompletableFuture bloomExample = asyncCommands + .bfReserve("bikes:models", 0.01, 1000) + .thenCompose(res1 -> { + System.out.println(res1); + // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.bfAdd("bikes:models", "Smoky Mountain Striker"); + }) + .thenCompose(res2 -> { + System.out.println(res2); + // >>> true + // REMOVE_START + assertThat(res2).isTrue(); + // REMOVE_END + return asyncCommands.bfExists("bikes:models", "Smoky Mountain Striker"); + }) + .thenCompose(res3 -> { + System.out.println(res3); + // >>> true + // REMOVE_START + assertThat(res3).isTrue(); + // REMOVE_END + return asyncCommands.bfMAdd("bikes:models", + "Rocky Mountain Racer", + "Cloudy City Cruiser", + "Windy City Wippet"); + }) + .thenCompose(res4 -> { + System.out.println(res4); + // >>> [true, true, true] + // REMOVE_START + assertThat(res4.toString()).isEqualTo("[true, true, true]"); + // REMOVE_END + return asyncCommands.bfMExists("bikes:models", + "Rocky Mountain Racer", + "Cloudy City Cruiser", + "Windy City Wippet"); + }) + .thenAccept(res5 -> { + System.out.println(res5); + // >>> [true, true, true] + // REMOVE_START + assertThat(res5.toString()).isEqualTo("[true, true, true]"); + // REMOVE_END + }) + .toCompletableFuture(); + + bloomExample.join(); + // STEP_END + + // REMOVE_START + asyncCommands.del("bikes:models").toCompletableFuture().join(); + // REMOVE_END + // HIDE_START + } finally { + redisClient.shutdown(); + } + // HIDE_END + } +} diff --git a/local_examples/bf_tutorial/lettuce-reactive/BloomFilterExample.java b/local_examples/bf_tutorial/lettuce-reactive/BloomFilterExample.java new file mode 100644 index 0000000000..d73bf7a625 --- /dev/null +++ b/local_examples/bf_tutorial/lettuce-reactive/BloomFilterExample.java @@ -0,0 +1,101 @@ +// EXAMPLE: bf_tutorial +// HIDE_START +package io.redis.examples.reactive; + +import io.lettuce.core.RedisClient; +import io.lettuce.core.Value; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.reactive.RedisReactiveCommands; +// REMOVE_START +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +// REMOVE_END + +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.stream.Collectors; +// HIDE_END + +public class BloomFilterExample { + + // REMOVE_START + @Test + // REMOVE_END + public void run() { + // HIDE_START + RedisClient redisClient = RedisClient.create("redis://localhost:6379"); + + try (StatefulRedisConnection connection = redisClient.connect()) { + RedisReactiveCommands reactiveCommands = connection.reactive(); + // HIDE_END + + // STEP_START bloom + // REMOVE_START + reactiveCommands.del("bikes:models").block(); + // REMOVE_END + Mono bloomExample = reactiveCommands + .bfReserve("bikes:models", 0.01, 1000) + .doOnNext(res1 -> { + System.out.println(res1); + // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + }) + .then(reactiveCommands.bfAdd("bikes:models", "Smoky Mountain Striker")) + .doOnNext(res2 -> { + System.out.println(res2); + // >>> true + // REMOVE_START + assertThat(res2).isTrue(); + // REMOVE_END + }) + .then(reactiveCommands.bfExists("bikes:models", "Smoky Mountain Striker")) + .doOnNext(res3 -> { + System.out.println(res3); + // >>> true + // REMOVE_START + assertThat(res3).isTrue(); + // REMOVE_END + }) + .thenMany(reactiveCommands.bfMAdd("bikes:models", + "Rocky Mountain Racer", + "Cloudy City Cruiser", + "Windy City Wippet")) + .map(Value::getValue) + .collectList() + .doOnNext(res4 -> { + System.out.println(res4); + // >>> [true, true, true] + // REMOVE_START + assertThat(res4.toString()).isEqualTo("[true, true, true]"); + // REMOVE_END + }) + .thenMany(reactiveCommands.bfMExists("bikes:models", + "Rocky Mountain Racer", + "Cloudy City Cruiser", + "Windy City Wippet")) + .collectList() + .doOnNext(res5 -> { + System.out.println(res5); + // >>> [true, true, true] + // REMOVE_START + assertThat(res5.toString()).isEqualTo("[true, true, true]"); + // REMOVE_END + }) + .then(); + + bloomExample.block(); + // STEP_END + + // REMOVE_START + reactiveCommands.del("bikes:models").block(); + // REMOVE_END + // HIDE_START + } finally { + redisClient.shutdown(); + } + // HIDE_END + } +} diff --git a/local_examples/cms_tutorial/lettuce-async/CMSExample.java b/local_examples/cms_tutorial/lettuce-async/CMSExample.java new file mode 100644 index 0000000000..ae417966ab --- /dev/null +++ b/local_examples/cms_tutorial/lettuce-async/CMSExample.java @@ -0,0 +1,98 @@ +// EXAMPLE: cms_tutorial +package io.redis.examples.async; + +// HIDE_START +import io.lettuce.core.RedisClient; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.async.RedisAsyncCommands; +import io.lettuce.core.probabilistic.CMSInfoValue; +import io.lettuce.core.probabilistic.IncrementPair; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +// REMOVE_START +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +// REMOVE_END +// HIDE_END + +public class CMSExample { + + // REMOVE_START + @Test + // REMOVE_END + public void run() { + // HIDE_START + RedisClient redisClient = RedisClient.create("redis://localhost:6379"); + + try (StatefulRedisConnection connection = redisClient.connect()) { + RedisAsyncCommands asyncCommands = connection.async(); + // HIDE_END + + // STEP_START cms + // REMOVE_START + asyncCommands.del("bikes:profit").toCompletableFuture().join(); + // REMOVE_END + CompletableFuture cmsExample = asyncCommands + .cmsInitByProb("bikes:profit", 0.001, 0.002) + .thenCompose(res1 -> { + System.out.println(res1); + // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.cmsIncrBy("bikes:profit", + IncrementPair.of("Smoky Mountain Striker", 100L)); + }) + .thenCompose(res2 -> { + System.out.println(res2); + // >>> [100] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[100]"); + // REMOVE_END + return asyncCommands.cmsIncrBy("bikes:profit", + IncrementPair.of("Rocky Mountain Racer", 200L), + IncrementPair.of("Cloudy City Cruiser", 150L)); + }) + .thenCompose(res3 -> { + System.out.println(res3); + // >>> [200, 150] + // REMOVE_START + assertThat(res3.toString()).isEqualTo("[200, 150]"); + // REMOVE_END + return asyncCommands.cmsQuery("bikes:profit", "Smoky Mountain Striker"); + }) + .thenCompose(res4 -> { + System.out.println(res4); + // >>> [100] + // REMOVE_START + assertThat(res4.toString()).isEqualTo("[100]"); + // REMOVE_END + return asyncCommands.cmsInfo("bikes:profit"); + }) + .thenAccept(res5 -> { + System.out.println(res5.getWidth() + " " + res5.getDepth() + " " + res5.getCount()); + // >>> 2000 9 450 + // REMOVE_START + assertThat(res5.getWidth()).isEqualTo(2000L); + assertThat(res5.getDepth()).isEqualTo(9L); + assertThat(res5.getCount()).isEqualTo(450L); + // REMOVE_END + }) + .toCompletableFuture(); + + cmsExample.join(); + // STEP_END + + // REMOVE_START + asyncCommands.del("bikes:profit").toCompletableFuture().join(); + // REMOVE_END + // HIDE_START + } finally { + redisClient.shutdown(); + } + // HIDE_END + } +} diff --git a/local_examples/cms_tutorial/lettuce-reactive/CMSExample.java b/local_examples/cms_tutorial/lettuce-reactive/CMSExample.java new file mode 100644 index 0000000000..bab507679b --- /dev/null +++ b/local_examples/cms_tutorial/lettuce-reactive/CMSExample.java @@ -0,0 +1,100 @@ +// EXAMPLE: cms_tutorial +// HIDE_START +package io.redis.examples.reactive; + +import io.lettuce.core.RedisClient; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.reactive.RedisReactiveCommands; +import io.lettuce.core.probabilistic.CMSInfoValue; +import io.lettuce.core.probabilistic.IncrementPair; +// REMOVE_START +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +// REMOVE_END + +import reactor.core.publisher.Mono; + +import java.util.List; +// HIDE_END + +public class CMSExample { + + // REMOVE_START + @Test + // REMOVE_END + public void run() { + // HIDE_START + RedisClient redisClient = RedisClient.create("redis://localhost:6379"); + + try (StatefulRedisConnection connection = redisClient.connect()) { + RedisReactiveCommands reactiveCommands = connection.reactive(); + // HIDE_END + + // STEP_START cms + // REMOVE_START + reactiveCommands.del("bikes:profit").block(); + // REMOVE_END + Mono cmsExample = reactiveCommands + .cmsInitByProb("bikes:profit", 0.001, 0.002) + .doOnNext(res1 -> { + System.out.println(res1); + // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + }) + .thenMany(reactiveCommands.cmsIncrBy("bikes:profit", + IncrementPair.of("Smoky Mountain Striker", 100L))) + .collectList() + .doOnNext(res2 -> { + System.out.println(res2); + // >>> [100] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[100]"); + // REMOVE_END + }) + .thenMany(reactiveCommands.cmsIncrBy("bikes:profit", + IncrementPair.of("Rocky Mountain Racer", 200L), + IncrementPair.of("Cloudy City Cruiser", 150L))) + .collectList() + .doOnNext(res3 -> { + System.out.println(res3); + // >>> [200, 150] + // REMOVE_START + assertThat(res3.toString()).isEqualTo("[200, 150]"); + // REMOVE_END + }) + .thenMany(reactiveCommands.cmsQuery("bikes:profit", "Smoky Mountain Striker")) + .collectList() + .doOnNext(res4 -> { + System.out.println(res4); + // >>> [100] + // REMOVE_START + assertThat(res4.toString()).isEqualTo("[100]"); + // REMOVE_END + }) + .then(reactiveCommands.cmsInfo("bikes:profit")) + .doOnNext(res5 -> { + System.out.println(res5.getWidth() + " " + res5.getDepth() + " " + res5.getCount()); + // >>> 2000 9 450 + // REMOVE_START + assertThat(res5.getWidth()).isEqualTo(2000L); + assertThat(res5.getDepth()).isEqualTo(9L); + assertThat(res5.getCount()).isEqualTo(450L); + // REMOVE_END + }) + .then(); + + cmsExample.block(); + // STEP_END + + // REMOVE_START + reactiveCommands.del("bikes:profit").block(); + // REMOVE_END + // HIDE_START + } finally { + redisClient.shutdown(); + } + // HIDE_END + } +} diff --git a/local_examples/cuckoo_tutorial/lettuce-async/CuckooFilterExample.java b/local_examples/cuckoo_tutorial/lettuce-async/CuckooFilterExample.java new file mode 100644 index 0000000000..a44d157da4 --- /dev/null +++ b/local_examples/cuckoo_tutorial/lettuce-async/CuckooFilterExample.java @@ -0,0 +1,90 @@ +// EXAMPLE: cuckoo_tutorial +package io.redis.examples.async; + +// HIDE_START +import io.lettuce.core.RedisClient; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.async.RedisAsyncCommands; + +import java.util.concurrent.CompletableFuture; + +// REMOVE_START +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +// REMOVE_END +// HIDE_END + +public class CuckooFilterExample { + + // REMOVE_START + @Test + // REMOVE_END + public void run() { + // HIDE_START + RedisClient redisClient = RedisClient.create("redis://localhost:6379"); + + try (StatefulRedisConnection connection = redisClient.connect()) { + RedisAsyncCommands asyncCommands = connection.async(); + // HIDE_END + + // STEP_START cuckoo + // REMOVE_START + asyncCommands.del("bikes:models").toCompletableFuture().join(); + // REMOVE_END + CompletableFuture cuckooExample = asyncCommands + .cfReserve("bikes:models", 1000000L) + .thenCompose(res1 -> { + System.out.println(res1); + // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.cfAdd("bikes:models", "Smoky Mountain Striker"); + }) + .thenCompose(res2 -> { + System.out.println(res2); + // >>> true + // REMOVE_START + assertThat(res2).isTrue(); + // REMOVE_END + return asyncCommands.cfExists("bikes:models", "Smoky Mountain Striker"); + }) + .thenCompose(res3 -> { + System.out.println(res3); + // >>> true + // REMOVE_START + assertThat(res3).isTrue(); + // REMOVE_END + return asyncCommands.cfExists("bikes:models", "Terrible Bike Name"); + }) + .thenCompose(res4 -> { + System.out.println(res4); + // >>> false + // REMOVE_START + assertThat(res4).isFalse(); + // REMOVE_END + return asyncCommands.cfDel("bikes:models", "Smoky Mountain Striker"); + }) + .thenAccept(res5 -> { + System.out.println(res5); + // >>> true + // REMOVE_START + assertThat(res5).isTrue(); + // REMOVE_END + }) + .toCompletableFuture(); + + cuckooExample.join(); + // STEP_END + + // REMOVE_START + asyncCommands.del("bikes:models").toCompletableFuture().join(); + // REMOVE_END + // HIDE_START + } finally { + redisClient.shutdown(); + } + // HIDE_END + } +} diff --git a/local_examples/cuckoo_tutorial/lettuce-reactive/CuckooFilterExample.java b/local_examples/cuckoo_tutorial/lettuce-reactive/CuckooFilterExample.java new file mode 100644 index 0000000000..0aa0dea7d4 --- /dev/null +++ b/local_examples/cuckoo_tutorial/lettuce-reactive/CuckooFilterExample.java @@ -0,0 +1,88 @@ +// EXAMPLE: cuckoo_tutorial +// HIDE_START +package io.redis.examples.reactive; + +import io.lettuce.core.RedisClient; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.reactive.RedisReactiveCommands; +// REMOVE_START +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +// REMOVE_END + +import reactor.core.publisher.Mono; +// HIDE_END + +public class CuckooFilterExample { + + // REMOVE_START + @Test + // REMOVE_END + public void run() { + // HIDE_START + RedisClient redisClient = RedisClient.create("redis://localhost:6379"); + + try (StatefulRedisConnection connection = redisClient.connect()) { + RedisReactiveCommands reactiveCommands = connection.reactive(); + // HIDE_END + + // STEP_START cuckoo + // REMOVE_START + reactiveCommands.del("bikes:models").block(); + // REMOVE_END + Mono cuckooExample = reactiveCommands + .cfReserve("bikes:models", 1000000L) + .doOnNext(res1 -> { + System.out.println(res1); + // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + }) + .then(reactiveCommands.cfAdd("bikes:models", "Smoky Mountain Striker")) + .doOnNext(res2 -> { + System.out.println(res2); + // >>> true + // REMOVE_START + assertThat(res2).isTrue(); + // REMOVE_END + }) + .then(reactiveCommands.cfExists("bikes:models", "Smoky Mountain Striker")) + .doOnNext(res3 -> { + System.out.println(res3); + // >>> true + // REMOVE_START + assertThat(res3).isTrue(); + // REMOVE_END + }) + .then(reactiveCommands.cfExists("bikes:models", "Terrible Bike Name")) + .doOnNext(res4 -> { + System.out.println(res4); + // >>> false + // REMOVE_START + assertThat(res4).isFalse(); + // REMOVE_END + }) + .then(reactiveCommands.cfDel("bikes:models", "Smoky Mountain Striker")) + .doOnNext(res5 -> { + System.out.println(res5); + // >>> true + // REMOVE_START + assertThat(res5).isTrue(); + // REMOVE_END + }) + .then(); + + cuckooExample.block(); + // STEP_END + + // REMOVE_START + reactiveCommands.del("bikes:models").block(); + // REMOVE_END + // HIDE_START + } finally { + redisClient.shutdown(); + } + // HIDE_END + } +} diff --git a/local_examples/hll_tutorial/lettuce-async/HyperLogLogExample.java b/local_examples/hll_tutorial/lettuce-async/HyperLogLogExample.java new file mode 100644 index 0000000000..4d19fb2bb5 --- /dev/null +++ b/local_examples/hll_tutorial/lettuce-async/HyperLogLogExample.java @@ -0,0 +1,91 @@ +// EXAMPLE: hll_tutorial +package io.redis.examples.async; + +// HIDE_START +import io.lettuce.core.RedisClient; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.async.RedisAsyncCommands; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +// REMOVE_START +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +// REMOVE_END +// HIDE_END + +public class HyperLogLogExample { + + // REMOVE_START + @Test + // REMOVE_END + public void run() { + // HIDE_START + RedisClient redisClient = RedisClient.create("redis://localhost:6379"); + + try (StatefulRedisConnection connection = redisClient.connect()) { + RedisAsyncCommands asyncCommands = connection.async(); + // HIDE_END + + // STEP_START pfadd + // REMOVE_START + asyncCommands.del("bikes", "commuter_bikes", "all_bikes").toCompletableFuture().join(); + // REMOVE_END + CompletableFuture pfaddExample = asyncCommands + .pfadd("bikes", "Hyperion", "Deimos", "Phoebe", "Quaoar") + .thenCompose(res1 -> { + System.out.println(res1); + // >>> 1 + // REMOVE_START + assertThat(res1).isEqualTo(1L); + // REMOVE_END + return asyncCommands.pfcount("bikes"); + }) + .thenCompose(res2 -> { + System.out.println(res2); + // >>> 4 + // REMOVE_START + assertThat(res2).isEqualTo(4L); + // REMOVE_END + return asyncCommands.pfadd("commuter_bikes", "Salacia", "Mimas", "Quaoar"); + }) + .thenCompose(res3 -> { + System.out.println(res3); + // >>> 1 + // REMOVE_START + assertThat(res3).isEqualTo(1L); + // REMOVE_END + return asyncCommands.pfmerge("all_bikes", "bikes", "commuter_bikes"); + }) + .thenCompose(res4 -> { + System.out.println(res4); + // >>> OK + // REMOVE_START + assertThat(res4).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.pfcount("all_bikes"); + }) + .thenAccept(res5 -> { + System.out.println(res5); + // >>> 6 + // REMOVE_START + assertThat(res5).isEqualTo(6L); + // REMOVE_END + }) + .toCompletableFuture(); + + pfaddExample.join(); + // STEP_END + + // REMOVE_START + asyncCommands.del("bikes", "commuter_bikes", "all_bikes").toCompletableFuture().join(); + // REMOVE_END + // HIDE_START + } finally { + redisClient.shutdown(); + } + // HIDE_END + } +} diff --git a/local_examples/hll_tutorial/lettuce-reactive/HyperLogLogExample.java b/local_examples/hll_tutorial/lettuce-reactive/HyperLogLogExample.java new file mode 100644 index 0000000000..2a8c49cc37 --- /dev/null +++ b/local_examples/hll_tutorial/lettuce-reactive/HyperLogLogExample.java @@ -0,0 +1,88 @@ +// EXAMPLE: hll_tutorial +// HIDE_START +package io.redis.examples.reactive; + +import io.lettuce.core.RedisClient; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.reactive.RedisReactiveCommands; +// REMOVE_START +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +// REMOVE_END + +import reactor.core.publisher.Mono; +// HIDE_END + +public class HyperLogLogExample { + + // REMOVE_START + @Test + // REMOVE_END + public void run() { + // HIDE_START + RedisClient redisClient = RedisClient.create("redis://localhost:6379"); + + try (StatefulRedisConnection connection = redisClient.connect()) { + RedisReactiveCommands reactiveCommands = connection.reactive(); + // HIDE_END + + // STEP_START pfadd + // REMOVE_START + reactiveCommands.del("bikes", "commuter_bikes", "all_bikes").block(); + // REMOVE_END + Mono pfaddExample = reactiveCommands + .pfadd("bikes", "Hyperion", "Deimos", "Phoebe", "Quaoar") + .doOnNext(res1 -> { + System.out.println(res1); + // >>> 1 + // REMOVE_START + assertThat(res1).isEqualTo(1L); + // REMOVE_END + }) + .then(reactiveCommands.pfcount("bikes")) + .doOnNext(res2 -> { + System.out.println(res2); + // >>> 4 + // REMOVE_START + assertThat(res2).isEqualTo(4L); + // REMOVE_END + }) + .then(reactiveCommands.pfadd("commuter_bikes", "Salacia", "Mimas", "Quaoar")) + .doOnNext(res3 -> { + System.out.println(res3); + // >>> 1 + // REMOVE_START + assertThat(res3).isEqualTo(1L); + // REMOVE_END + }) + .then(reactiveCommands.pfmerge("all_bikes", "bikes", "commuter_bikes")) + .doOnNext(res4 -> { + System.out.println(res4); + // >>> OK + // REMOVE_START + assertThat(res4).isEqualTo("OK"); + // REMOVE_END + }) + .then(reactiveCommands.pfcount("all_bikes")) + .doOnNext(res5 -> { + System.out.println(res5); + // >>> 6 + // REMOVE_START + assertThat(res5).isEqualTo(6L); + // REMOVE_END + }) + .then(); + + pfaddExample.block(); + // STEP_END + + // REMOVE_START + reactiveCommands.del("bikes", "commuter_bikes", "all_bikes").block(); + // REMOVE_END + // HIDE_START + } finally { + redisClient.shutdown(); + } + // HIDE_END + } +} diff --git a/local_examples/home_prob_dts/lettuce-async/HomeProbExample.java b/local_examples/home_prob_dts/lettuce-async/HomeProbExample.java new file mode 100644 index 0000000000..6012eef0d8 --- /dev/null +++ b/local_examples/home_prob_dts/lettuce-async/HomeProbExample.java @@ -0,0 +1,388 @@ +// EXAMPLE: home_prob_dts +package io.redis.examples.async; + +// HIDE_START +import io.lettuce.core.RedisClient; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.async.RedisAsyncCommands; +import io.lettuce.core.probabilistic.IncrementPair; +import io.lettuce.core.probabilistic.arguments.TopKReserveArgs; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +// REMOVE_START +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +// REMOVE_END +// HIDE_END + +public class HomeProbExample { + + // REMOVE_START + @Test + // REMOVE_END + public void run() { + // HIDE_START + RedisClient redisClient = RedisClient.create("redis://localhost:6379"); + + try (StatefulRedisConnection connection = redisClient.connect()) { + RedisAsyncCommands asyncCommands = connection.async(); + // HIDE_END + + // REMOVE_START + asyncCommands.del("recorded_users", "other_users", + "group:1", "group:2", "both_groups", + "items_sold", "male_heights", "female_heights", "all_heights", + "top_3_songs").toCompletableFuture().join(); + // REMOVE_END + + // STEP_START bloom + CompletableFuture bloomExample = asyncCommands + .bfMAdd("recorded_users", "andy", "cameron", "david", "michelle") + .thenCompose(res1 -> { + System.out.println(res1); + // >>> [true, true, true, true] + // REMOVE_START + assertThat(res1.toString()).isEqualTo("[true, true, true, true]"); + // REMOVE_END + return asyncCommands.bfExists("recorded_users", "cameron"); + }) + .thenCompose(res2 -> { + System.out.println(res2); + // >>> true + // REMOVE_START + assertThat(res2).isTrue(); + // REMOVE_END + return asyncCommands.bfExists("recorded_users", "kaitlyn"); + }) + .thenAccept(res3 -> { + System.out.println(res3); + // >>> false + // REMOVE_START + assertThat(res3).isFalse(); + // REMOVE_END + }) + .toCompletableFuture(); + + bloomExample.join(); + // STEP_END + + // STEP_START cuckoo + CompletableFuture cuckooExample = asyncCommands + .cfAdd("other_users", "paolo") + .thenCompose(res4 -> { + System.out.println(res4); + // >>> true + // REMOVE_START + assertThat(res4).isTrue(); + // REMOVE_END + return asyncCommands.cfAdd("other_users", "kaitlyn"); + }) + .thenCompose(res5 -> { + System.out.println(res5); + // >>> true + // REMOVE_START + assertThat(res5).isTrue(); + // REMOVE_END + return asyncCommands.cfAdd("other_users", "rachel"); + }) + .thenCompose(res6 -> { + System.out.println(res6); + // >>> true + // REMOVE_START + assertThat(res6).isTrue(); + // REMOVE_END + return asyncCommands.cfMExists("other_users", "paolo", "rachel", "andy"); + }) + .thenCompose(res7 -> { + System.out.println(res7); + // >>> [true, true, false] + // REMOVE_START + assertThat(res7.toString()).isEqualTo("[true, true, false]"); + // REMOVE_END + return asyncCommands.cfDel("other_users", "paolo"); + }) + .thenCompose(res8 -> { + System.out.println(res8); + // >>> true + // REMOVE_START + assertThat(res8).isTrue(); + // REMOVE_END + return asyncCommands.cfExists("other_users", "paolo"); + }) + .thenAccept(res9 -> { + System.out.println(res9); + // >>> false + // REMOVE_START + assertThat(res9).isFalse(); + // REMOVE_END + }) + .toCompletableFuture(); + + cuckooExample.join(); + // STEP_END + + // STEP_START hyperloglog + CompletableFuture hllExample = asyncCommands + .pfadd("group:1", "andy", "cameron", "david") + .thenCompose(res10 -> { + System.out.println(res10); + // >>> 1 + // REMOVE_START + assertThat(res10).isEqualTo(1L); + // REMOVE_END + return asyncCommands.pfcount("group:1"); + }) + .thenCompose(res11 -> { + System.out.println(res11); + // >>> 3 + // REMOVE_START + assertThat(res11).isEqualTo(3L); + // REMOVE_END + return asyncCommands.pfadd("group:2", "kaitlyn", "michelle", "paolo", "rachel"); + }) + .thenCompose(res12 -> { + System.out.println(res12); + // >>> 1 + // REMOVE_START + assertThat(res12).isEqualTo(1L); + // REMOVE_END + return asyncCommands.pfcount("group:2"); + }) + .thenCompose(res13 -> { + System.out.println(res13); + // >>> 4 + // REMOVE_START + assertThat(res13).isEqualTo(4L); + // REMOVE_END + return asyncCommands.pfmerge("both_groups", "group:1", "group:2"); + }) + .thenCompose(res14 -> { + System.out.println(res14); + // >>> OK + // REMOVE_START + assertThat(res14).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.pfcount("both_groups"); + }) + .thenAccept(res15 -> { + System.out.println(res15); + // >>> 7 + // REMOVE_START + assertThat(res15).isEqualTo(7L); + // REMOVE_END + }) + .toCompletableFuture(); + + hllExample.join(); + // STEP_END + + // STEP_START cms + CompletableFuture cmsExample = asyncCommands + // Specify that you want to keep the counts within 0.01 + // (1%) of the true value with a 0.005 (0.5%) chance + // of going outside this limit. + .cmsInitByProb("items_sold", 0.01, 0.005) + .thenCompose(res16 -> { + System.out.println(res16); + // >>> OK + // REMOVE_START + assertThat(res16).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.cmsIncrBy("items_sold", + IncrementPair.of("bread", 300L), + IncrementPair.of("tea", 200L), + IncrementPair.of("coffee", 200L), + IncrementPair.of("beer", 100L)); + }) + .thenCompose(res17 -> { + List sorted17 = new ArrayList<>(res17); + sorted17.sort(null); + System.out.println(sorted17); + // >>> [100, 200, 200, 300] + // REMOVE_START + assertThat(sorted17.toString()).isEqualTo("[100, 200, 200, 300]"); + // REMOVE_END + return asyncCommands.cmsIncrBy("items_sold", + IncrementPair.of("bread", 100L), + IncrementPair.of("coffee", 150L)); + }) + .thenCompose(res18 -> { + List sorted18 = new ArrayList<>(res18); + sorted18.sort(null); + System.out.println(sorted18); + // >>> [350, 400] + // REMOVE_START + assertThat(sorted18.toString()).isEqualTo("[350, 400]"); + // REMOVE_END + return asyncCommands.cmsQuery("items_sold", "bread", "tea", "coffee", "beer"); + }) + .thenAccept(res19 -> { + List sorted19 = new ArrayList<>(res19); + sorted19.sort(null); + System.out.println(sorted19); + // >>> [100, 200, 350, 400] + // REMOVE_START + assertThat(sorted19.toString()).isEqualTo("[100, 200, 350, 400]"); + // REMOVE_END + }) + .toCompletableFuture(); + + cmsExample.join(); + // STEP_END + + // STEP_START tdigest + CompletableFuture tdigestExample = asyncCommands + .tdigestCreate("male_heights") + .thenCompose(res20 -> { + System.out.println(res20); + // >>> OK + // REMOVE_START + assertThat(res20).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.tdigestAdd("male_heights", + "175.5", "181", "160.8", "152", "177", "196", "164"); + }) + .thenCompose(res21 -> { + System.out.println(res21); + // >>> OK + // REMOVE_START + assertThat(res21).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.tdigestMin("male_heights"); + }) + .thenCompose(res22 -> { + System.out.println(res22); + // >>> 152.0 + // REMOVE_START + assertThat(res22).isEqualTo(152.0); + // REMOVE_END + return asyncCommands.tdigestMax("male_heights"); + }) + .thenCompose(res23 -> { + System.out.println(res23); + // >>> 196.0 + // REMOVE_START + assertThat(res23).isEqualTo(196.0); + // REMOVE_END + return asyncCommands.tdigestQuantile("male_heights", 0.75); + }) + .thenCompose(res24 -> { + System.out.println(res24); + // >>> [181.0] + // REMOVE_START + assertThat(res24.toString()).isEqualTo("[181.0]"); + // REMOVE_END + // Note that the CDF value for 181 is not exactly 0.75. + // Both values are estimates. + return asyncCommands.tdigestCDF("male_heights", "181"); + }) + .thenCompose(res25 -> { + System.out.println(res25); + // >>> [0.7857142857142857] + return asyncCommands.tdigestCreate("female_heights"); + }) + .thenCompose(res26 -> { + System.out.println(res26); + // >>> OK + // REMOVE_START + assertThat(res26).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.tdigestAdd("female_heights", + "155.5", "161", "168.5", "170", "157.5", "163", "171"); + }) + .thenCompose(res27 -> { + System.out.println(res27); + // >>> OK + // REMOVE_START + assertThat(res27).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.tdigestQuantile("female_heights", 0.75); + }) + .thenCompose(res28 -> { + System.out.println(res28); + // >>> [170.0] + // REMOVE_START + assertThat(res28.toString()).isEqualTo("[170.0]"); + // REMOVE_END + return asyncCommands.tdigestMerge("all_heights", "male_heights", "female_heights"); + }) + .thenCompose(res29 -> { + System.out.println(res29); + // >>> OK + // REMOVE_START + assertThat(res29).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.tdigestQuantile("all_heights", 0.75); + }) + .thenAccept(res30 -> { + System.out.println(res30); + // >>> [175.5] + // REMOVE_START + assertThat(res30.toString()).isEqualTo("[175.5]"); + // REMOVE_END + }) + .toCompletableFuture(); + + tdigestExample.join(); + // STEP_END + + // STEP_START topk + CompletableFuture topkExample = asyncCommands + .topKReserve("top_3_songs", 3L, + TopKReserveArgs.Builder.width(2000L).depth(7L).decay(0.925)) + .thenCompose(res31 -> { + System.out.println(res31); + // >>> OK + // REMOVE_START + assertThat(res31).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.topKIncrBy("top_3_songs", + IncrementPair.of("Starfish Trooper", 3000L), + IncrementPair.of("Only one more time", 1850L), + IncrementPair.of("Rock me, Handel", 1325L), + IncrementPair.of("How will anyone know?", 3890L), + IncrementPair.of("Average lover", 4098L), + IncrementPair.of("Road to everywhere", 770L)); + }) + .thenCompose(res32 -> { + System.out.println(res32); + // >>> [null, null, null, null, null, Rock me, Handel] + return asyncCommands.topKList("top_3_songs"); + }) + .thenCompose(res33 -> { + System.out.println(res33); + // >>> [Average lover, How will anyone know?, Starfish Trooper] + // REMOVE_START + assertThat(res33).contains("Average lover", "How will anyone know?", "Starfish Trooper"); + // REMOVE_END + return asyncCommands.topKQuery("top_3_songs", "Starfish Trooper", "Road to everywhere"); + }) + .thenAccept(res34 -> { + System.out.println(res34); + // >>> [true, false] + // REMOVE_START + assertThat(res34.toString()).isEqualTo("[true, false]"); + // REMOVE_END + }) + .toCompletableFuture(); + + topkExample.join(); + // STEP_END + + // REMOVE_START + asyncCommands.del("recorded_users", "other_users", + "group:1", "group:2", "both_groups", + "items_sold", "male_heights", "female_heights", "all_heights", + "top_3_songs").toCompletableFuture().join(); + // REMOVE_END + // HIDE_START + } finally { + redisClient.shutdown(); + } + // HIDE_END + } +} diff --git a/local_examples/home_prob_dts/lettuce-reactive/HomeProbExample.java b/local_examples/home_prob_dts/lettuce-reactive/HomeProbExample.java new file mode 100644 index 0000000000..5747f4506d --- /dev/null +++ b/local_examples/home_prob_dts/lettuce-reactive/HomeProbExample.java @@ -0,0 +1,346 @@ +// EXAMPLE: home_prob_dts +// HIDE_START +package io.redis.examples.reactive; + +import io.lettuce.core.RedisClient; +import io.lettuce.core.Value; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.reactive.RedisReactiveCommands; +import io.lettuce.core.probabilistic.IncrementPair; +import io.lettuce.core.probabilistic.arguments.TopKReserveArgs; +// REMOVE_START +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +// REMOVE_END + +import java.util.ArrayList; +import java.util.List; +// HIDE_END + +public class HomeProbExample { + + // REMOVE_START + @Test + // REMOVE_END + public void run() { + // HIDE_START + RedisClient redisClient = RedisClient.create("redis://localhost:6379"); + + try (StatefulRedisConnection connection = redisClient.connect()) { + RedisReactiveCommands reactiveCommands = connection.reactive(); + // HIDE_END + + // REMOVE_START + reactiveCommands.del("recorded_users", "other_users", + "group:1", "group:2", "both_groups", + "items_sold", "male_heights", "female_heights", "all_heights", + "top_3_songs").block(); + // REMOVE_END + + // STEP_START bloom + List res1 = reactiveCommands + .bfMAdd("recorded_users", "andy", "cameron", "david", "michelle") + .map(Value::getValue) + .collectList() + .block(); + System.out.println(res1); + // >>> [true, true, true, true] + // REMOVE_START + assertThat(res1.toString()).isEqualTo("[true, true, true, true]"); + // REMOVE_END + + Boolean res2 = reactiveCommands.bfExists("recorded_users", "cameron").block(); + System.out.println(res2); + // >>> true + // REMOVE_START + assertThat(res2).isTrue(); + // REMOVE_END + + Boolean res3 = reactiveCommands.bfExists("recorded_users", "kaitlyn").block(); + System.out.println(res3); + // >>> false + // REMOVE_START + assertThat(res3).isFalse(); + // REMOVE_END + // STEP_END + + // STEP_START cuckoo + Boolean res4 = reactiveCommands.cfAdd("other_users", "paolo").block(); + System.out.println(res4); + // >>> true + // REMOVE_START + assertThat(res4).isTrue(); + // REMOVE_END + + Boolean res5 = reactiveCommands.cfAdd("other_users", "kaitlyn").block(); + System.out.println(res5); + // >>> true + // REMOVE_START + assertThat(res5).isTrue(); + // REMOVE_END + + Boolean res6 = reactiveCommands.cfAdd("other_users", "rachel").block(); + System.out.println(res6); + // >>> true + // REMOVE_START + assertThat(res6).isTrue(); + // REMOVE_END + + List res7 = reactiveCommands + .cfMExists("other_users", "paolo", "rachel", "andy") + .collectList() + .block(); + System.out.println(res7); + // >>> [true, true, false] + // REMOVE_START + assertThat(res7.toString()).isEqualTo("[true, true, false]"); + // REMOVE_END + + Boolean res8 = reactiveCommands.cfDel("other_users", "paolo").block(); + System.out.println(res8); + // >>> true + // REMOVE_START + assertThat(res8).isTrue(); + // REMOVE_END + + Boolean res9 = reactiveCommands.cfExists("other_users", "paolo").block(); + System.out.println(res9); + // >>> false + // REMOVE_START + assertThat(res9).isFalse(); + // REMOVE_END + // STEP_END + + // STEP_START hyperloglog + Long res10 = reactiveCommands.pfadd("group:1", "andy", "cameron", "david").block(); + System.out.println(res10); + // >>> 1 + // REMOVE_START + assertThat(res10).isEqualTo(1L); + // REMOVE_END + + Long res11 = reactiveCommands.pfcount("group:1").block(); + System.out.println(res11); + // >>> 3 + // REMOVE_START + assertThat(res11).isEqualTo(3L); + // REMOVE_END + + Long res12 = reactiveCommands.pfadd("group:2", "kaitlyn", "michelle", "paolo", "rachel").block(); + System.out.println(res12); + // >>> 1 + // REMOVE_START + assertThat(res12).isEqualTo(1L); + // REMOVE_END + + Long res13 = reactiveCommands.pfcount("group:2").block(); + System.out.println(res13); + // >>> 4 + // REMOVE_START + assertThat(res13).isEqualTo(4L); + // REMOVE_END + + String res14 = reactiveCommands.pfmerge("both_groups", "group:1", "group:2").block(); + System.out.println(res14); + // >>> OK + // REMOVE_START + assertThat(res14).isEqualTo("OK"); + // REMOVE_END + + Long res15 = reactiveCommands.pfcount("both_groups").block(); + System.out.println(res15); + // >>> 7 + // REMOVE_START + assertThat(res15).isEqualTo(7L); + // REMOVE_END + // STEP_END + + // STEP_START cms + // Specify that you want to keep the counts within 0.01 + // (1%) of the true value with a 0.005 (0.5%) chance + // of going outside this limit. + String res16 = reactiveCommands.cmsInitByProb("items_sold", 0.01, 0.005).block(); + System.out.println(res16); + // >>> OK + // REMOVE_START + assertThat(res16).isEqualTo("OK"); + // REMOVE_END + + List res17 = new ArrayList<>(reactiveCommands + .cmsIncrBy("items_sold", + IncrementPair.of("bread", 300L), + IncrementPair.of("tea", 200L), + IncrementPair.of("coffee", 200L), + IncrementPair.of("beer", 100L)) + .collectList() + .block()); + res17.sort(null); + System.out.println(res17); + // >>> [100, 200, 200, 300] + // REMOVE_START + assertThat(res17.toString()).isEqualTo("[100, 200, 200, 300]"); + // REMOVE_END + + List res18 = new ArrayList<>(reactiveCommands + .cmsIncrBy("items_sold", + IncrementPair.of("bread", 100L), + IncrementPair.of("coffee", 150L)) + .collectList() + .block()); + res18.sort(null); + System.out.println(res18); + // >>> [350, 400] + // REMOVE_START + assertThat(res18.toString()).isEqualTo("[350, 400]"); + // REMOVE_END + + List res19 = new ArrayList<>(reactiveCommands + .cmsQuery("items_sold", "bread", "tea", "coffee", "beer") + .collectList() + .block()); + res19.sort(null); + System.out.println(res19); + // >>> [100, 200, 350, 400] + // REMOVE_START + assertThat(res19.toString()).isEqualTo("[100, 200, 350, 400]"); + // REMOVE_END + // STEP_END + + // STEP_START tdigest + String res20 = reactiveCommands.tdigestCreate("male_heights").block(); + System.out.println(res20); + // >>> OK + // REMOVE_START + assertThat(res20).isEqualTo("OK"); + // REMOVE_END + + String res21 = reactiveCommands.tdigestAdd("male_heights", + "175.5", "181", "160.8", "152", "177", "196", "164").block(); + System.out.println(res21); + // >>> OK + // REMOVE_START + assertThat(res21).isEqualTo("OK"); + // REMOVE_END + + Double res22 = reactiveCommands.tdigestMin("male_heights").block(); + System.out.println(res22); + // >>> 152.0 + // REMOVE_START + assertThat(res22).isEqualTo(152.0); + // REMOVE_END + + Double res23 = reactiveCommands.tdigestMax("male_heights").block(); + System.out.println(res23); + // >>> 196.0 + // REMOVE_START + assertThat(res23).isEqualTo(196.0); + // REMOVE_END + + List res24 = reactiveCommands.tdigestQuantile("male_heights", 0.75) + .collectList().block(); + System.out.println(res24); + // >>> [181.0] + // REMOVE_START + assertThat(res24.toString()).isEqualTo("[181.0]"); + // REMOVE_END + + // Note that the CDF value for 181 is not exactly 0.75. + // Both values are estimates. + List res25 = reactiveCommands.tdigestCDF("male_heights", "181") + .collectList().block(); + System.out.println(res25); + // >>> [0.7857142857142857] + + String res26 = reactiveCommands.tdigestCreate("female_heights").block(); + System.out.println(res26); + // >>> OK + // REMOVE_START + assertThat(res26).isEqualTo("OK"); + // REMOVE_END + + String res27 = reactiveCommands.tdigestAdd("female_heights", + "155.5", "161", "168.5", "170", "157.5", "163", "171").block(); + System.out.println(res27); + // >>> OK + // REMOVE_START + assertThat(res27).isEqualTo("OK"); + // REMOVE_END + + List res28 = reactiveCommands.tdigestQuantile("female_heights", 0.75) + .collectList().block(); + System.out.println(res28); + // >>> [170.0] + // REMOVE_START + assertThat(res28.toString()).isEqualTo("[170.0]"); + // REMOVE_END + + String res29 = reactiveCommands.tdigestMerge("all_heights", "male_heights", "female_heights").block(); + System.out.println(res29); + // >>> OK + // REMOVE_START + assertThat(res29).isEqualTo("OK"); + // REMOVE_END + + List res30 = reactiveCommands.tdigestQuantile("all_heights", 0.75) + .collectList().block(); + System.out.println(res30); + // >>> [175.5] + // REMOVE_START + assertThat(res30.toString()).isEqualTo("[175.5]"); + // REMOVE_END + // STEP_END + + // STEP_START topk + String res31 = reactiveCommands.topKReserve("top_3_songs", 3L, + TopKReserveArgs.Builder.width(2000L).depth(7L).decay(0.925)).block(); + System.out.println(res31); + // >>> OK + // REMOVE_START + assertThat(res31).isEqualTo("OK"); + // REMOVE_END + + List res32 = reactiveCommands + .topKIncrBy("top_3_songs", + IncrementPair.of("Starfish Trooper", 3000L), + IncrementPair.of("Only one more time", 1850L), + IncrementPair.of("Rock me, Handel", 1325L), + IncrementPair.of("How will anyone know?", 3890L), + IncrementPair.of("Average lover", 4098L), + IncrementPair.of("Road to everywhere", 770L)) + .map(v -> v.getValueOrElse(null)) + .collectList() + .block(); + System.out.println(res32); + // >>> [null, null, null, null, null, Rock me, Handel] + + List res33 = reactiveCommands.topKList("top_3_songs").collectList().block(); + System.out.println(res33); + // >>> [Average lover, How will anyone know?, Starfish Trooper] + // REMOVE_START + assertThat(res33).contains("Average lover", "How will anyone know?", "Starfish Trooper"); + // REMOVE_END + + List res34 = reactiveCommands + .topKQuery("top_3_songs", "Starfish Trooper", "Road to everywhere") + .collectList() + .block(); + System.out.println(res34); + // >>> [true, false] + // REMOVE_START + assertThat(res34.toString()).isEqualTo("[true, false]"); + // REMOVE_END + // STEP_END + + // REMOVE_START + reactiveCommands.del("recorded_users", "other_users", + "group:1", "group:2", "both_groups", + "items_sold", "male_heights", "female_heights", "all_heights", + "top_3_songs").block(); + // REMOVE_END + // HIDE_START + } finally { + redisClient.shutdown(); + } + // HIDE_END + } +} diff --git a/local_examples/tdigest_tutorial/lettuce-async/TDigestExample.java b/local_examples/tdigest_tutorial/lettuce-async/TDigestExample.java new file mode 100644 index 0000000000..b7f3581225 --- /dev/null +++ b/local_examples/tdigest_tutorial/lettuce-async/TDigestExample.java @@ -0,0 +1,177 @@ +// EXAMPLE: tdigest_tutorial +package io.redis.examples.async; + +// HIDE_START +import io.lettuce.core.RedisClient; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.async.RedisAsyncCommands; + +import java.util.concurrent.CompletableFuture; + +// REMOVE_START +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +// REMOVE_END +// HIDE_END + +public class TDigestExample { + + // REMOVE_START + @Test + // REMOVE_END + public void run() { + // HIDE_START + RedisClient redisClient = RedisClient.create("redis://localhost:6379"); + + try (StatefulRedisConnection connection = redisClient.connect()) { + RedisAsyncCommands asyncCommands = connection.async(); + // HIDE_END + + // REMOVE_START + asyncCommands.del("bikes:sales", "racer_ages").toCompletableFuture().join(); + // REMOVE_END + + // STEP_START tdig_start + CompletableFuture tdigStartExample = asyncCommands + .tdigestCreate("bikes:sales", 100L) + .thenCompose(res1 -> { + System.out.println(res1); + // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.tdigestAdd("bikes:sales", "21"); + }) + .thenCompose(res2 -> { + System.out.println(res2); + // >>> OK + // REMOVE_START + assertThat(res2).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.tdigestAdd("bikes:sales", "150", "95", "75", "34"); + }) + .thenAccept(res3 -> { + System.out.println(res3); + // >>> OK + // REMOVE_START + assertThat(res3).isEqualTo("OK"); + // REMOVE_END + }) + .toCompletableFuture(); + + tdigStartExample.join(); + // STEP_END + + // STEP_START tdig_cdf + CompletableFuture tdigCdfExample = asyncCommands + .tdigestCreate("racer_ages") + .thenCompose(res4 -> { + System.out.println(res4); + // >>> OK + // REMOVE_START + assertThat(res4).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.tdigestAdd("racer_ages", + "45.88", "44.2", "58.03", "19.76", "39.84", "69.28", + "50.97", "25.41", "19.27", "85.71", "42.63"); + }) + .thenCompose(res5 -> { + System.out.println(res5); + // >>> OK + // REMOVE_START + assertThat(res5).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.tdigestRank("racer_ages", "50"); + }) + .thenCompose(res6 -> { + System.out.println(res6); + // >>> [7] + // REMOVE_START + assertThat(res6.toString()).isEqualTo("[7]"); + // REMOVE_END + return asyncCommands.tdigestRank("racer_ages", "50", "40"); + }) + .thenAccept(res7 -> { + System.out.println(res7); + // >>> [7, 4] + // REMOVE_START + assertThat(res7.toString()).isEqualTo("[7, 4]"); + // REMOVE_END + }) + .toCompletableFuture(); + + tdigCdfExample.join(); + // STEP_END + + // STEP_START tdig_quant + CompletableFuture tdigQuantExample = asyncCommands + .tdigestQuantile("racer_ages", 0.5) + .thenCompose(res8 -> { + System.out.println(res8); + // >>> [44.2] + // REMOVE_START + assertThat(res8.toString()).isEqualTo("[44.2]"); + // REMOVE_END + return asyncCommands.tdigestByRank("racer_ages", 4L); + }) + .thenAccept(res9 -> { + System.out.println(res9); + // >>> [42.63] + // REMOVE_START + assertThat(res9.toString()).isEqualTo("[42.63]"); + // REMOVE_END + }) + .toCompletableFuture(); + + tdigQuantExample.join(); + // STEP_END + + // STEP_START tdig_min + CompletableFuture tdigMinExample = asyncCommands + .tdigestMin("racer_ages") + .thenCompose(res10 -> { + System.out.println(res10); + // >>> 19.27 + // REMOVE_START + assertThat(res10).isEqualTo(19.27); + // REMOVE_END + return asyncCommands.tdigestMax("racer_ages"); + }) + .thenAccept(res11 -> { + System.out.println(res11); + // >>> 85.71 + // REMOVE_START + assertThat(res11).isEqualTo(85.71); + // REMOVE_END + }) + .toCompletableFuture(); + + tdigMinExample.join(); + // STEP_END + + // STEP_START tdig_reset + CompletableFuture tdigResetExample = asyncCommands + .tdigestReset("racer_ages") + .thenAccept(res12 -> { + System.out.println(res12); + // >>> OK + // REMOVE_START + assertThat(res12).isEqualTo("OK"); + // REMOVE_END + }) + .toCompletableFuture(); + + tdigResetExample.join(); + // STEP_END + + // REMOVE_START + asyncCommands.del("bikes:sales", "racer_ages").toCompletableFuture().join(); + // REMOVE_END + // HIDE_START + } finally { + redisClient.shutdown(); + } + // HIDE_END + } +} diff --git a/local_examples/tdigest_tutorial/lettuce-reactive/TDigestExample.java b/local_examples/tdigest_tutorial/lettuce-reactive/TDigestExample.java new file mode 100644 index 0000000000..b4fcc11144 --- /dev/null +++ b/local_examples/tdigest_tutorial/lettuce-reactive/TDigestExample.java @@ -0,0 +1,138 @@ +// EXAMPLE: tdigest_tutorial +// HIDE_START +package io.redis.examples.reactive; + +import io.lettuce.core.RedisClient; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.reactive.RedisReactiveCommands; +// REMOVE_START +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +// REMOVE_END + +import java.util.List; +// HIDE_END + +public class TDigestExample { + + // REMOVE_START + @Test + // REMOVE_END + public void run() { + // HIDE_START + RedisClient redisClient = RedisClient.create("redis://localhost:6379"); + + try (StatefulRedisConnection connection = redisClient.connect()) { + RedisReactiveCommands reactiveCommands = connection.reactive(); + // HIDE_END + + // REMOVE_START + reactiveCommands.del("bikes:sales", "racer_ages").block(); + // REMOVE_END + + // STEP_START tdig_start + String res1 = reactiveCommands.tdigestCreate("bikes:sales", 100L).block(); + System.out.println(res1); + // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + + String res2 = reactiveCommands.tdigestAdd("bikes:sales", "21").block(); + System.out.println(res2); + // >>> OK + // REMOVE_START + assertThat(res2).isEqualTo("OK"); + // REMOVE_END + + String res3 = reactiveCommands.tdigestAdd("bikes:sales", "150", "95", "75", "34").block(); + System.out.println(res3); + // >>> OK + // REMOVE_START + assertThat(res3).isEqualTo("OK"); + // REMOVE_END + // STEP_END + + // STEP_START tdig_cdf + String res4 = reactiveCommands.tdigestCreate("racer_ages").block(); + System.out.println(res4); + // >>> OK + // REMOVE_START + assertThat(res4).isEqualTo("OK"); + // REMOVE_END + + String res5 = reactiveCommands.tdigestAdd("racer_ages", + "45.88", "44.2", "58.03", "19.76", "39.84", "69.28", + "50.97", "25.41", "19.27", "85.71", "42.63").block(); + System.out.println(res5); + // >>> OK + // REMOVE_START + assertThat(res5).isEqualTo("OK"); + // REMOVE_END + + List res6 = reactiveCommands.tdigestRank("racer_ages", "50").collectList().block(); + System.out.println(res6); + // >>> [7] + // REMOVE_START + assertThat(res6.toString()).isEqualTo("[7]"); + // REMOVE_END + + List res7 = reactiveCommands.tdigestRank("racer_ages", "50", "40").collectList().block(); + System.out.println(res7); + // >>> [7, 4] + // REMOVE_START + assertThat(res7.toString()).isEqualTo("[7, 4]"); + // REMOVE_END + // STEP_END + + // STEP_START tdig_quant + List res8 = reactiveCommands.tdigestQuantile("racer_ages", 0.5).collectList().block(); + System.out.println(res8); + // >>> [44.2] + // REMOVE_START + assertThat(res8.toString()).isEqualTo("[44.2]"); + // REMOVE_END + + List res9 = reactiveCommands.tdigestByRank("racer_ages", 4L).collectList().block(); + System.out.println(res9); + // >>> [42.63] + // REMOVE_START + assertThat(res9.toString()).isEqualTo("[42.63]"); + // REMOVE_END + // STEP_END + + // STEP_START tdig_min + Double res10 = reactiveCommands.tdigestMin("racer_ages").block(); + System.out.println(res10); + // >>> 19.27 + // REMOVE_START + assertThat(res10).isEqualTo(19.27); + // REMOVE_END + + Double res11 = reactiveCommands.tdigestMax("racer_ages").block(); + System.out.println(res11); + // >>> 85.71 + // REMOVE_START + assertThat(res11).isEqualTo(85.71); + // REMOVE_END + // STEP_END + + // STEP_START tdig_reset + String res12 = reactiveCommands.tdigestReset("racer_ages").block(); + System.out.println(res12); + // >>> OK + // REMOVE_START + assertThat(res12).isEqualTo("OK"); + // REMOVE_END + // STEP_END + + // REMOVE_START + reactiveCommands.del("bikes:sales", "racer_ages").block(); + // REMOVE_END + // HIDE_START + } finally { + redisClient.shutdown(); + } + // HIDE_END + } +} diff --git a/local_examples/topk_tutorial/lettuce-async/TopKExample.java b/local_examples/topk_tutorial/lettuce-async/TopKExample.java new file mode 100644 index 0000000000..6302ef9155 --- /dev/null +++ b/local_examples/topk_tutorial/lettuce-async/TopKExample.java @@ -0,0 +1,88 @@ +// EXAMPLE: topk_tutorial +package io.redis.examples.async; + +// HIDE_START +import io.lettuce.core.RedisClient; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.async.RedisAsyncCommands; +import io.lettuce.core.probabilistic.arguments.TopKReserveArgs; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +// REMOVE_START +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +// REMOVE_END +// HIDE_END + +public class TopKExample { + + // REMOVE_START + @Test + // REMOVE_END + public void run() { + // HIDE_START + RedisClient redisClient = RedisClient.create("redis://localhost:6379"); + + try (StatefulRedisConnection connection = redisClient.connect()) { + RedisAsyncCommands asyncCommands = connection.async(); + // HIDE_END + + // STEP_START topk + // REMOVE_START + asyncCommands.del("bikes:keywords").toCompletableFuture().join(); + // REMOVE_END + CompletableFuture topKExample = asyncCommands + .topKReserve("bikes:keywords", 5L, + TopKReserveArgs.Builder.width(2000L).depth(7L).decay(0.925)) + .thenCompose(res1 -> { + System.out.println(res1); + // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.topKAdd("bikes:keywords", + "store", "seat", "handlebars", "handles", "pedals", + "tires", "store", "seat"); + }) + .thenCompose(res2 -> { + System.out.println(res2); + // >>> [null, null, null, null, null, handlebars, null, null] + // REMOVE_START + assertThat(res2.size()).isEqualTo(8); + // REMOVE_END + return asyncCommands.topKList("bikes:keywords"); + }) + .thenCompose(res3 -> { + System.out.println(res3); + // >>> [store, seat, pedals, tires, handles] + // REMOVE_START + assertThat(res3.size()).isEqualTo(5); + assertThat(res3).contains("store", "seat"); + // REMOVE_END + return asyncCommands.topKQuery("bikes:keywords", "store", "handlebars"); + }) + .thenAccept(res4 -> { + System.out.println(res4); + // >>> [true, false] + // REMOVE_START + assertThat(res4.toString()).isEqualTo("[true, false]"); + // REMOVE_END + }) + .toCompletableFuture(); + + topKExample.join(); + // STEP_END + + // REMOVE_START + asyncCommands.del("bikes:keywords").toCompletableFuture().join(); + // REMOVE_END + // HIDE_START + } finally { + redisClient.shutdown(); + } + // HIDE_END + } +} diff --git a/local_examples/topk_tutorial/lettuce-reactive/TopKExample.java b/local_examples/topk_tutorial/lettuce-reactive/TopKExample.java new file mode 100644 index 0000000000..52aa011b92 --- /dev/null +++ b/local_examples/topk_tutorial/lettuce-reactive/TopKExample.java @@ -0,0 +1,91 @@ +// EXAMPLE: topk_tutorial +// HIDE_START +package io.redis.examples.reactive; + +import io.lettuce.core.RedisClient; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.reactive.RedisReactiveCommands; +import io.lettuce.core.probabilistic.arguments.TopKReserveArgs; +// REMOVE_START +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +// REMOVE_END + +import reactor.core.publisher.Mono; + +import java.util.List; +// HIDE_END + +public class TopKExample { + + // REMOVE_START + @Test + // REMOVE_END + public void run() { + // HIDE_START + RedisClient redisClient = RedisClient.create("redis://localhost:6379"); + + try (StatefulRedisConnection connection = redisClient.connect()) { + RedisReactiveCommands reactiveCommands = connection.reactive(); + // HIDE_END + + // STEP_START topk + // REMOVE_START + reactiveCommands.del("bikes:keywords").block(); + // REMOVE_END + Mono topKExample = reactiveCommands + .topKReserve("bikes:keywords", 5L, + TopKReserveArgs.Builder.width(2000L).depth(7L).decay(0.925)) + .doOnNext(res1 -> { + System.out.println(res1); + // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + }) + .thenMany(reactiveCommands.topKAdd("bikes:keywords", + "store", "seat", "handlebars", "handles", "pedals", + "tires", "store", "seat")) + .map(v -> v.getValueOrElse(null)) + .collectList() + .doOnNext(res2 -> { + System.out.println(res2); + // >>> [null, null, null, null, null, handlebars, null, null] + // REMOVE_START + assertThat(res2.size()).isEqualTo(8); + // REMOVE_END + }) + .thenMany(reactiveCommands.topKList("bikes:keywords")) + .collectList() + .doOnNext(res3 -> { + System.out.println(res3); + // >>> [store, seat, pedals, tires, handles] + // REMOVE_START + assertThat(res3.size()).isEqualTo(5); + assertThat(res3).contains("store", "seat"); + // REMOVE_END + }) + .thenMany(reactiveCommands.topKQuery("bikes:keywords", "store", "handlebars")) + .collectList() + .doOnNext(res4 -> { + System.out.println(res4); + // >>> [true, false] + // REMOVE_START + assertThat(res4.toString()).isEqualTo("[true, false]"); + // REMOVE_END + }) + .then(); + + topKExample.block(); + // STEP_END + + // REMOVE_START + reactiveCommands.del("bikes:keywords").block(); + // REMOVE_END + // HIDE_START + } finally { + redisClient.shutdown(); + } + // HIDE_END + } +}