From 15efec144a469a3b233821d475849c55e8e01d59 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Mon, 11 Aug 2025 11:31:26 +0100 Subject: [PATCH 1/6] DOC-5556 JSON examples --- .../redis/examples/async/HomeJsonExample.java | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 src/test/java/io/redis/examples/async/HomeJsonExample.java diff --git a/src/test/java/io/redis/examples/async/HomeJsonExample.java b/src/test/java/io/redis/examples/async/HomeJsonExample.java new file mode 100644 index 0000000000..ba3db644cc --- /dev/null +++ b/src/test/java/io/redis/examples/async/HomeJsonExample.java @@ -0,0 +1,211 @@ +// EXAMPLE: lettuce_home_json +package io.redis.examples.async; + +// STEP_START import +import io.lettuce.core.*; + +import io.lettuce.core.api.async.RedisAsyncCommands; +import io.lettuce.core.api.async.RediSearchAsyncCommands; +import io.lettuce.core.search.arguments.CreateArgs; +import io.lettuce.core.search.arguments.FieldArgs; +import io.lettuce.core.search.arguments.TextFieldArgs; +import io.lettuce.core.search.arguments.NumericFieldArgs; +import io.lettuce.core.search.arguments.TagFieldArgs; +import io.lettuce.core.search.arguments.SearchArgs; +import io.lettuce.core.search.arguments.AggregateArgs; +import io.lettuce.core.search.arguments.AggregateArgs.GroupBy; +import io.lettuce.core.search.arguments.AggregateArgs.Reducer; +import io.lettuce.core.search.SearchReply; +import io.lettuce.core.search.AggregationReply; + +import io.lettuce.core.json.JsonParser; +import io.lettuce.core.json.JsonObject; +import io.lettuce.core.json.JsonPath; + +import io.lettuce.core.api.StatefulRedisConnection; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +// STEP_END +// REMOVE_START +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +// REMOVE_END + +public class HomeJsonExample { + + // REMOVE_START + @Test + // REMOVE_END + public void run() { + // STEP_START connect + RedisClient redisClient = RedisClient.create("redis://localhost:6379"); + + try (StatefulRedisConnection connection = redisClient.connect()) { + RedisAsyncCommands asyncCommands = connection.async(); + RediSearchAsyncCommands searchCommands = connection.async(); + // ... + // STEP_END + // REMOVE_START + asyncCommands.del("user:1", "user:2", "user:3").toCompletableFuture().join(); + searchCommands.ftDropindex("idx:users") + .exceptionally(ex -> null) // Ignore errors if the index doesn't exist. + .toCompletableFuture().join(); + // REMOVE_END + + // STEP_START create_data + JsonParser parser = asyncCommands.getJsonParser(); + + JsonObject user1 = parser.createJsonObject() + .put("name", parser.createJsonValue("\"Paul John\"")) + .put("email", parser.createJsonValue("\"paul.john@example.com\"")) + .put("age", parser.createJsonValue("42")) + .put("city", parser.createJsonValue("\"London\"")); + + JsonObject user2 = parser.createJsonObject() + .put("name", parser.createJsonValue("\"Eden Zamir\"")) + .put("email", parser.createJsonValue("\"eden.zamir@example.com\"")) + .put("age", parser.createJsonValue("29")) + .put("city", parser.createJsonValue("\"Tel Aviv\"")); + + JsonObject user3 = parser.createJsonObject() + .put("name", parser.createJsonValue("\"Paul Zamir\"")) + .put("email", parser.createJsonValue("\"paul.zamir@example.com\"")) + .put("age", parser.createJsonValue("35")) + .put("city", parser.createJsonValue("\"Tel Aviv\"")); + // STEP_END + + // STEP_START make_index + List> schema = Arrays.asList( + TextFieldArgs.builder().name("$.name").as("name").build(), + TextFieldArgs.builder().name("$.email").as("email").build(), + NumericFieldArgs.builder().name("$.age").as("age").build(), + TagFieldArgs.builder().name("$.city").as("city").build() + ); + + CreateArgs createArgs = CreateArgs. builder() + .on(CreateArgs.TargetType.JSON) + .withPrefix("user:") + .build(); + + CompletableFuture make_index = searchCommands.ftCreate("idx:users", createArgs, schema) + // REMOVE_START + .thenApply(res -> { + assertThat(res).isEqualTo("OK"); + return res; + }) + // REMOVE_END + .thenAccept(System.out::println) // >>> OK + .toCompletableFuture(); + // STEP_END + make_index.join(); + + // STEP_START add_data + CompletableFuture addUser1 = asyncCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).thenApply(r -> { + System.out.println(r); // >>> OK + // REMOVE_START + assertThat(r).isEqualTo("OK"); + // REMOVE_END + return r; + }).toCompletableFuture(); + + CompletableFuture addUser2 = asyncCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).thenApply(r -> { + System.out.println(r); // >>> OK + // REMOVE_START + assertThat(r).isEqualTo("OK"); + // REMOVE_END + return r; + }).toCompletableFuture(); + + CompletableFuture addUser3 = asyncCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).thenApply(r -> { + System.out.println(r); // >>> OK + // REMOVE_START + assertThat(r).isEqualTo("OK"); + // REMOVE_END + return r; + }).toCompletableFuture(); + // STEP_END + CompletableFuture.allOf(addUser1, addUser2, addUser3).join(); + + // STEP_START query1 + CompletableFuture> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]") + .thenApply(res -> { + List> results = res.getResults(); + + results.forEach(result -> { + System.out.println(result.getId()); + }); + // >>> user:3 + // REMOVE_START + assertThat(res.getCount()).isEqualTo(1); + assertThat(results.get(0).getId()).isEqualTo("user:3"); + // REMOVE_END + return res; + }) + .toCompletableFuture(); + // STEP_END + + // STEP_START query2 + SearchArgs query2Args = SearchArgs.builder() + .returnField("city", null) + .build(); + CompletableFuture> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args) + .thenApply(res -> { + List> results = res.getResults(); + + results.forEach(result -> { + System.out.printf("ID: %s, City: %s\n", result.getId(), result.getFields().get("city")); + }); + // >>> ID: user:1, City: London + // >>> ID: user:3, City: Tel Aviv + // REMOVE_START + assertThat(res.getCount()).isEqualTo(2); + assertThat(results.stream().map(result -> { + return String.format("ID: %s, City: %s", result.getId(), result.getFields().get("city")); + }).sorted().toArray()).containsExactly( + "ID: user:1, City: London", + "ID: user:3, City: Tel Aviv" + ); + // REMOVE_END + return res; + }) + .toCompletableFuture(); + // STEP_END + + // STEP_START query3 + AggregateArgs aggArgs = AggregateArgs.builder() + .groupBy(GroupBy.of("@city") + .reduce(Reducer.count().as("count"))) + .build(); + CompletableFuture> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs) + .thenApply(res -> { + List> replies = res.getReplies(); + replies.forEach(reply -> { + reply.getResults().forEach(result -> { + System.out.printf("City: %s, Count: %s\n", result.getFields().get("city"), result.getFields().get("count")); + }); + // >>> City: London, Count: 1 + // >>> City: Tel Aviv, Count: 2 + }); + // REMOVE_START + assertThat(replies.size()).isEqualTo(1); + assertThat(replies.get(0).getResults().size()).isEqualTo(2); + assertThat(replies.get(0).getResults().stream().map(result -> { + return String.format("City: %s, Count: %s", result.getFields().get("city"), result.getFields().get("count")); + }).sorted().toArray()).containsExactly( + "City: London, Count: 1", + "City: Tel Aviv, Count: 2" + ); + // REMOVE_END + return res; + }) + .toCompletableFuture(); + // STEP_END + + CompletableFuture.allOf(query1, query2, query3).join(); + } finally { + redisClient.shutdown(); + } + } +} From cb91b8daca2ffaf41f032d888bda087d5e2eefaa Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Mon, 11 Aug 2025 12:10:54 +0100 Subject: [PATCH 2/6] DOC-5556 added async hash examples --- .../redis/examples/async/HomeJsonExample.java | 271 +++++++++++------- 1 file changed, 164 insertions(+), 107 deletions(-) diff --git a/src/test/java/io/redis/examples/async/HomeJsonExample.java b/src/test/java/io/redis/examples/async/HomeJsonExample.java index ba3db644cc..4a91bff14f 100644 --- a/src/test/java/io/redis/examples/async/HomeJsonExample.java +++ b/src/test/java/io/redis/examples/async/HomeJsonExample.java @@ -48,56 +48,48 @@ public void run() { // ... // STEP_END // REMOVE_START - asyncCommands.del("user:1", "user:2", "user:3").toCompletableFuture().join(); - searchCommands.ftDropindex("idx:users") - .exceptionally(ex -> null) // Ignore errors if the index doesn't exist. - .toCompletableFuture().join(); + asyncCommands.del("user:1", "user:2", "user:3", "huser:1", "huser:2", "huser:3").toCompletableFuture().join(); + + searchCommands.ftDropindex("idx:users").exceptionally(ex -> null) // Ignore errors if the index doesn't exist. + .toCompletableFuture().join(); + + searchCommands.ftDropindex("hash-idx:users").exceptionally(ex -> null) // Ignore errors if the index doesn't exist. + .toCompletableFuture().join(); // REMOVE_END - + // STEP_START create_data JsonParser parser = asyncCommands.getJsonParser(); - JsonObject user1 = parser.createJsonObject() - .put("name", parser.createJsonValue("\"Paul John\"")) - .put("email", parser.createJsonValue("\"paul.john@example.com\"")) - .put("age", parser.createJsonValue("42")) - .put("city", parser.createJsonValue("\"London\"")); - - JsonObject user2 = parser.createJsonObject() - .put("name", parser.createJsonValue("\"Eden Zamir\"")) - .put("email", parser.createJsonValue("\"eden.zamir@example.com\"")) - .put("age", parser.createJsonValue("29")) - .put("city", parser.createJsonValue("\"Tel Aviv\"")); - - JsonObject user3 = parser.createJsonObject() - .put("name", parser.createJsonValue("\"Paul Zamir\"")) - .put("email", parser.createJsonValue("\"paul.zamir@example.com\"")) - .put("age", parser.createJsonValue("35")) - .put("city", parser.createJsonValue("\"Tel Aviv\"")); + JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\"")) + .put("email", parser.createJsonValue("\"paul.john@example.com\"")).put("age", parser.createJsonValue("42")) + .put("city", parser.createJsonValue("\"London\"")); + + JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\"")) + .put("email", parser.createJsonValue("\"eden.zamir@example.com\"")).put("age", parser.createJsonValue("29")) + .put("city", parser.createJsonValue("\"Tel Aviv\"")); + + JsonObject user3 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul Zamir\"")) + .put("email", parser.createJsonValue("\"paul.zamir@example.com\"")).put("age", parser.createJsonValue("35")) + .put("city", parser.createJsonValue("\"Tel Aviv\"")); // STEP_END // STEP_START make_index - List> schema = Arrays.asList( - TextFieldArgs.builder().name("$.name").as("name").build(), - TextFieldArgs.builder().name("$.email").as("email").build(), - NumericFieldArgs.builder().name("$.age").as("age").build(), - TagFieldArgs.builder().name("$.city").as("city").build() - ); - - CreateArgs createArgs = CreateArgs. builder() - .on(CreateArgs.TargetType.JSON) - .withPrefix("user:") - .build(); + List> schema = Arrays.asList(TextFieldArgs. builder().name("$.name").as("name").build(), + NumericFieldArgs. builder().name("$.age").as("age").build(), + TagFieldArgs. builder().name("$.city").as("city").build()); + + CreateArgs createArgs = CreateArgs. builder().on(CreateArgs.TargetType.JSON) + .withPrefix("user:").build(); CompletableFuture make_index = searchCommands.ftCreate("idx:users", createArgs, schema) - // REMOVE_START - .thenApply(res -> { - assertThat(res).isEqualTo("OK"); - return res; - }) - // REMOVE_END - .thenAccept(System.out::println) // >>> OK - .toCompletableFuture(); + // REMOVE_START + .thenApply(res -> { + assertThat(res).isEqualTo("OK"); + return res; + }) + // REMOVE_END + .thenAccept(System.out::println) // >>> OK + .toCompletableFuture(); // STEP_END make_index.join(); @@ -118,7 +110,7 @@ public void run() { return r; }).toCompletableFuture(); - CompletableFuture addUser3 = asyncCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).thenApply(r -> { + CompletableFuture addUser3 = asyncCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).thenApply(r -> { System.out.println(r); // >>> OK // REMOVE_START assertThat(r).isEqualTo("OK"); @@ -130,82 +122,147 @@ public void run() { // STEP_START query1 CompletableFuture> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]") - .thenApply(res -> { - List> results = res.getResults(); + .thenApply(res -> { + List> results = res.getResults(); - results.forEach(result -> { - System.out.println(result.getId()); - }); - // >>> user:3 - // REMOVE_START - assertThat(res.getCount()).isEqualTo(1); - assertThat(results.get(0).getId()).isEqualTo("user:3"); - // REMOVE_END - return res; - }) - .toCompletableFuture(); + results.forEach(result -> { + System.out.println(result.getId()); + }); + // >>> user:3 + // REMOVE_START + assertThat(res.getCount()).isEqualTo(1); + assertThat(results.get(0).getId()).isEqualTo("user:3"); + // REMOVE_END + return res; + }).toCompletableFuture(); // STEP_END - + // STEP_START query2 - SearchArgs query2Args = SearchArgs.builder() - .returnField("city", null) - .build(); + SearchArgs query2Args = SearchArgs. builder().returnField("city", null).build(); CompletableFuture> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args) - .thenApply(res -> { - List> results = res.getResults(); - - results.forEach(result -> { - System.out.printf("ID: %s, City: %s\n", result.getId(), result.getFields().get("city")); - }); - // >>> ID: user:1, City: London - // >>> ID: user:3, City: Tel Aviv - // REMOVE_START - assertThat(res.getCount()).isEqualTo(2); - assertThat(results.stream().map(result -> { - return String.format("ID: %s, City: %s", result.getId(), result.getFields().get("city")); - }).sorted().toArray()).containsExactly( - "ID: user:1, City: London", - "ID: user:3, City: Tel Aviv" - ); - // REMOVE_END - return res; - }) - .toCompletableFuture(); - // STEP_END - + .thenApply(res -> { + List> results = res.getResults(); + + results.forEach(result -> { + System.out.printf("ID: %s, City: %s\n", result.getId(), result.getFields().get("city")); + }); + // >>> ID: user:1, City: London + // >>> ID: user:3, City: Tel Aviv + // REMOVE_START + assertThat(res.getCount()).isEqualTo(2); + assertThat(results.stream().map(result -> { + return String.format("ID: %s, City: %s", result.getId(), result.getFields().get("city")); + }).sorted().toArray()).containsExactly("ID: user:1, City: London", "ID: user:3, City: Tel Aviv"); + // REMOVE_END + return res; + }).toCompletableFuture(); + // STEP_END + // STEP_START query3 - AggregateArgs aggArgs = AggregateArgs.builder() - .groupBy(GroupBy.of("@city") - .reduce(Reducer.count().as("count"))) - .build(); + AggregateArgs aggArgs = AggregateArgs. builder() + .groupBy(GroupBy. of("@city").reduce(Reducer. count().as("count"))).build(); CompletableFuture> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs) - .thenApply(res -> { - List> replies = res.getReplies(); - replies.forEach(reply -> { - reply.getResults().forEach(result -> { - System.out.printf("City: %s, Count: %s\n", result.getFields().get("city"), result.getFields().get("count")); + .thenApply(res -> { + List> replies = res.getReplies(); + replies.forEach(reply -> { + reply.getResults().forEach(result -> { + System.out.printf("City: %s, Count: %s\n", result.getFields().get("city"), + result.getFields().get("count")); + }); + // >>> City: London, Count: 1 + // >>> City: Tel Aviv, Count: 2 }); - // >>> City: London, Count: 1 - // >>> City: Tel Aviv, Count: 2 - }); + // REMOVE_START + assertThat(replies.size()).isEqualTo(1); + assertThat(replies.get(0).getResults().size()).isEqualTo(2); + assertThat(replies.get(0).getResults().stream().map(result -> { + return String.format("City: %s, Count: %s", result.getFields().get("city"), + result.getFields().get("count")); + }).sorted().toArray()).containsExactly("City: London, Count: 1", "City: Tel Aviv, Count: 2"); + // REMOVE_END + return res; + }).toCompletableFuture(); + // STEP_END + + CompletableFuture.allOf(query1, query2, query3).join(); + + // STEP_START make_hash_index + List> hashSchema = Arrays.asList(TextFieldArgs. builder().name("name").build(), + NumericFieldArgs. builder().name("age").build(), + TagFieldArgs. builder().name("city").build()); + + CreateArgs hashCreateArgs = CreateArgs. builder().on(CreateArgs.TargetType.HASH) + .withPrefix("huser:").build(); + + CompletableFuture makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema) // REMOVE_START - assertThat(replies.size()).isEqualTo(1); - assertThat(replies.get(0).getResults().size()).isEqualTo(2); - assertThat(replies.get(0).getResults().stream().map(result -> { - return String.format("City: %s, Count: %s", result.getFields().get("city"), result.getFields().get("count")); - }).sorted().toArray()).containsExactly( - "City: London, Count: 1", - "City: Tel Aviv, Count: 2" - ); + .thenApply(res -> { + + assertThat(res).isEqualTo("OK"); + return res; + }) // REMOVE_END - return res; - }) - .toCompletableFuture(); - // STEP_END - - CompletableFuture.allOf(query1, query2, query3).join(); + .thenAccept(System.out::println) // >>> OK + .toCompletableFuture(); + // STEP_END + makeHashIndex.join(); + + // STEP_START add_hash_data + Map huser1 = Map.of("name", "Paul John", "email", "paul.john@example.com", "age", "42", "city", + "London"); + + Map huser2 = Map.of("name", "Eden Zamir", "email", "eden.zamir@example.com", "age", "29", "city", + "Tel Aviv"); + + Map huser3 = Map.of("name", "Paul Zamir", "email", "paul.zamir@example.com", "age", "35", "city", + "Tel Aviv"); + + CompletableFuture addHashUser1 = asyncCommands.hset("huser:1", huser1).thenApply(r -> { + System.out.println(r); // >>> OK + // REMOVE_START + assertThat(r).isEqualTo(4L); + // REMOVE_END + return r; + }).toCompletableFuture(); + + CompletableFuture addHashUser2 = asyncCommands.hset("huser:2", huser2).thenApply(r -> { + System.out.println(r); // >>> OK + // REMOVE_START + assertThat(r).isEqualTo(4L); + // REMOVE_END + return r; + }).toCompletableFuture(); + + CompletableFuture addHashUser3 = asyncCommands.hset("huser:3", huser3).thenApply(r -> { + System.out.println(r); // >>> OK + // REMOVE_START + assertThat(r).isEqualTo(4L); + // REMOVE_END + return r; + }).toCompletableFuture(); + // STEP_END + CompletableFuture.allOf(addHashUser1, addHashUser2, addHashUser3).join(); + + // STEP_START query1_hash + CompletableFuture> query1Hash = searchCommands + .ftSearch("hash-idx:users", "Paul @age:[30 40]").thenApply(res -> { + List> results = res.getResults(); + + results.forEach(result -> { + System.out.println(result.getId()); + }); + // >>> huser:3 + // REMOVE_START + assertThat(res.getCount()).isEqualTo(1); + assertThat(results.get(0).getId()).isEqualTo("huser:3"); + // REMOVE_END + return res; + }).toCompletableFuture(); + // STEP_END + query1Hash.join(); } finally { redisClient.shutdown(); } } + } From 8294a4b233cb7e5a75352cb961f3d5d0281b7842 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Mon, 11 Aug 2025 14:14:45 +0100 Subject: [PATCH 3/6] DOC-5556 added reactive examples --- .../examples/reactive/HomeJsonExample.java | 246 ++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 src/test/java/io/redis/examples/reactive/HomeJsonExample.java diff --git a/src/test/java/io/redis/examples/reactive/HomeJsonExample.java b/src/test/java/io/redis/examples/reactive/HomeJsonExample.java new file mode 100644 index 0000000000..a8a37276be --- /dev/null +++ b/src/test/java/io/redis/examples/reactive/HomeJsonExample.java @@ -0,0 +1,246 @@ +// EXAMPLE: lettuce_home_json +package io.redis.examples.reactive; + +// STEP_START import +import io.lettuce.core.*; + +import io.lettuce.core.api.reactive.RedisReactiveCommands; +import io.lettuce.core.api.reactive.RediSearchReactiveCommands; +import io.lettuce.core.search.arguments.CreateArgs; +import io.lettuce.core.search.arguments.FieldArgs; +import io.lettuce.core.search.arguments.TextFieldArgs; +import io.lettuce.core.search.arguments.NumericFieldArgs; +import io.lettuce.core.search.arguments.TagFieldArgs; +import io.lettuce.core.search.arguments.SearchArgs; +import io.lettuce.core.search.arguments.AggregateArgs; +import io.lettuce.core.search.arguments.AggregateArgs.GroupBy; +import io.lettuce.core.search.arguments.AggregateArgs.Reducer; +import io.lettuce.core.search.SearchReply; +import io.lettuce.core.search.AggregationReply; + +import io.lettuce.core.json.JsonParser; +import io.lettuce.core.json.JsonObject; +import io.lettuce.core.json.JsonPath; + +import io.lettuce.core.api.StatefulRedisConnection; + +import java.util.*; +import reactor.core.publisher.Mono; +// STEP_END +// REMOVE_START +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +// REMOVE_END + +public class HomeJsonExample { + + @Test + public void run() { + // STEP_START connect + RedisClient redisClient = RedisClient.create("redis://localhost:6379"); + + try (StatefulRedisConnection connection = redisClient.connect()) { + RedisReactiveCommands reactiveCommands = connection.reactive(); + RediSearchReactiveCommands searchCommands = connection.reactive(); + // ... + // STEP_END + // REMOVE_START + reactiveCommands.del("user:1", "user:2", "user:3", "huser:1", "huser:2", "huser:3").block(); + searchCommands.ftDropindex("idx:users").onErrorReturn("Index `idx:users` does not exist").block(); + searchCommands.ftDropindex("hash-idx:users").onErrorReturn("Index `hash-idx:users` does not exist").block(); + // REMOVE_END + + // STEP_START create_data + JsonParser parser = reactiveCommands.getJsonParser(); + JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\"")) + .put("email", parser.createJsonValue("\"paul.john@example.com\"")).put("age", parser.createJsonValue("42")) + .put("city", parser.createJsonValue("\"London\"")); + + JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\"")) + .put("email", parser.createJsonValue("\"eden.zamir@example.com\"")).put("age", parser.createJsonValue("29")) + .put("city", parser.createJsonValue("\"Tel Aviv\"")); + + JsonObject user3 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul Zamir\"")) + .put("email", parser.createJsonValue("\"paul.zamir@example.com\"")).put("age", parser.createJsonValue("35")) + .put("city", parser.createJsonValue("\"Tel Aviv\"")); + // STEP_END + + // STEP_START make_index + List> schema = Arrays.asList(TextFieldArgs. builder().name("$.name").as("name").build(), + NumericFieldArgs. builder().name("$.age").as("age").build(), + TagFieldArgs. builder().name("$.city").as("city").build()); + + CreateArgs createArgs = CreateArgs. builder().on(CreateArgs.TargetType.JSON) + .withPrefix("user:").build(); + + Mono make_index = searchCommands.ftCreate("idx:users", createArgs, schema).doOnNext(res -> { + // REMOVE_START + assertThat(res).isEqualTo("OK"); + // REMOVE_END + System.out.println(res); // >>> OK + }).then(); + // STEP_END + make_index.block(); + + // STEP_START add_data + Mono addUser1 = reactiveCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).doOnNext(r -> { + System.out.println(r); // >>> OK + // REMOVE_START + assertThat(r).isEqualTo("OK"); + // REMOVE_END + }); + + Mono addUser2 = reactiveCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).doOnNext(r -> { + System.out.println(r); // >>> OK + // REMOVE_START + assertThat(r).isEqualTo("OK"); + // REMOVE_END + }); + + Mono addUser3 = reactiveCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).doOnNext(r -> { + System.out.println(r); // >>> OK + // REMOVE_START + assertThat(r).isEqualTo("OK"); + // REMOVE_END + }); + // STEP_END + Mono.when(addUser1, addUser2, addUser3).block(); + + // STEP_START query1 + Mono> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]") + .doOnNext(res -> { + List> results = res.getResults(); + + results.forEach(result -> { + System.out.println(result.getId()); + }); + // >>> user:3 + // REMOVE_START + assertThat(res.getCount()).isEqualTo(1); + assertThat(results.get(0).getId()).isEqualTo("user:3"); + // REMOVE_END + }); + // STEP_END + + // STEP_START query2 + SearchArgs query2Args = SearchArgs. builder().returnField("city", null).build(); + + Mono> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args) + .doOnNext(res -> { + List> results = res.getResults(); + + results.forEach(result -> { + System.out.printf("ID: %s, City: %s\n", result.getId(), result.getFields().get("city")); + }); + // >>> ID: user:1, City: London + // >>> ID: user:3, City: Tel Aviv + // REMOVE_START + assertThat(res.getCount()).isEqualTo(2); + assertThat(results.stream().map(result -> { + return String.format("ID: %s, City: %s", result.getId(), result.getFields().get("city")); + }).sorted().toArray()).containsExactly("ID: user:1, City: London", "ID: user:3, City: Tel Aviv"); + // REMOVE_END + }); + // STEP_END + + // STEP_START query3 + AggregateArgs aggArgs = AggregateArgs. builder() + .groupBy(GroupBy. of("@city").reduce(Reducer. count().as("count"))).build(); + + Mono> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs) + .doOnNext(res -> { + List> replies = res.getReplies(); + replies.forEach(reply -> { + reply.getResults().forEach(result -> { + System.out.printf("City: %s, Count: %s\n", result.getFields().get("city"), + result.getFields().get("count")); + }); + // >>> City: London, Count: 1 + // >>> City: Tel Aviv, Count: 2 + }); + // REMOVE_START + assertThat(replies.size()).isEqualTo(1); + assertThat(replies.get(0).getResults().size()).isEqualTo(2); + assertThat(replies.get(0).getResults().stream().map(result -> { + return String.format("City: %s, Count: %s", result.getFields().get("city"), + result.getFields().get("count")); + }).sorted().toArray()).containsExactly("City: London, Count: 1", "City: Tel Aviv, Count: 2"); + // REMOVE_END + }); + // STEP_END + + Mono.when(query1, query2, query3).block(); + + // STEP_START make_hash_index + List> hashSchema = Arrays.asList(TextFieldArgs. builder().name("name").build(), + NumericFieldArgs. builder().name("age").build(), + TagFieldArgs. builder().name("city").build()); + + CreateArgs hashCreateArgs = CreateArgs. builder().on(CreateArgs.TargetType.HASH) + .withPrefix("huser:").build(); + + Mono makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema).doOnNext(res -> { + // REMOVE_START + assertThat(res).isEqualTo("OK"); + // REMOVE_END + System.out.println(res); // >>> OK + }); + // STEP_END + makeHashIndex.block(); + + // STEP_START add_hash_data + Map huser1 = Map.of("name", "Paul John", "email", "paul.john@example.com", "age", "42", "city", + "London"); + + Map huser2 = Map.of("name", "Eden Zamir", "email", "eden.zamir@example.com", "age", "29", "city", + "Tel Aviv"); + + Map huser3 = Map.of("name", "Paul Zamir", "email", "paul.zamir@example.com", "age", "35", "city", + "Tel Aviv"); + + Mono addHashUser1 = reactiveCommands.hset("huser:1", huser1).doOnNext(r -> { + System.out.println(r); // >>> OK + // REMOVE_START + assertThat(r).isEqualTo(4L); + // REMOVE_END + }); + + Mono addHashUser2 = reactiveCommands.hset("huser:2", huser2).doOnNext(r -> { + System.out.println(r); // >>> OK + // REMOVE_START + assertThat(r).isEqualTo(4L); + // REMOVE_END + }); + + Mono addHashUser3 = reactiveCommands.hset("huser:3", huser3).doOnNext(r -> { + System.out.println(r); // >>> OK + // REMOVE_START + assertThat(r).isEqualTo(4L); + // REMOVE_END + }); + // STEP_END + Mono.when(addHashUser1, addHashUser2, addHashUser3).block(); + + // STEP_START query1_hash + Mono> query1Hash = searchCommands.ftSearch("hash-idx:users", "Paul @age:[30 40]") + .doOnNext(res -> { + List> results = res.getResults(); + + results.forEach(result -> { + System.out.println(result.getId()); + }); + // >>> huser:3 + // REMOVE_START + assertThat(res.getCount()).isEqualTo(1); + assertThat(results.get(0).getId()).isEqualTo("huser:3"); + // REMOVE_END + }); + // STEP_END + query1Hash.block(); + } finally { + redisClient.shutdown(); + } + } + +} From b893bd02436bf3a95a5364907c312efa835fd1f5 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Mon, 11 Aug 2025 14:33:12 +0100 Subject: [PATCH 4/6] DOC-5556 tidied imports --- .../java/io/redis/examples/async/HomeJsonExample.java | 11 ++--------- .../io/redis/examples/reactive/HomeJsonExample.java | 11 ++--------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/src/test/java/io/redis/examples/async/HomeJsonExample.java b/src/test/java/io/redis/examples/async/HomeJsonExample.java index 4a91bff14f..b685fb4276 100644 --- a/src/test/java/io/redis/examples/async/HomeJsonExample.java +++ b/src/test/java/io/redis/examples/async/HomeJsonExample.java @@ -6,15 +6,8 @@ import io.lettuce.core.api.async.RedisAsyncCommands; import io.lettuce.core.api.async.RediSearchAsyncCommands; -import io.lettuce.core.search.arguments.CreateArgs; -import io.lettuce.core.search.arguments.FieldArgs; -import io.lettuce.core.search.arguments.TextFieldArgs; -import io.lettuce.core.search.arguments.NumericFieldArgs; -import io.lettuce.core.search.arguments.TagFieldArgs; -import io.lettuce.core.search.arguments.SearchArgs; -import io.lettuce.core.search.arguments.AggregateArgs; -import io.lettuce.core.search.arguments.AggregateArgs.GroupBy; -import io.lettuce.core.search.arguments.AggregateArgs.Reducer; +import io.lettuce.core.search.arguments.*; +import io.lettuce.core.search.arguments.AggregateArgs.*; import io.lettuce.core.search.SearchReply; import io.lettuce.core.search.AggregationReply; diff --git a/src/test/java/io/redis/examples/reactive/HomeJsonExample.java b/src/test/java/io/redis/examples/reactive/HomeJsonExample.java index a8a37276be..b7d74ee537 100644 --- a/src/test/java/io/redis/examples/reactive/HomeJsonExample.java +++ b/src/test/java/io/redis/examples/reactive/HomeJsonExample.java @@ -6,15 +6,8 @@ import io.lettuce.core.api.reactive.RedisReactiveCommands; import io.lettuce.core.api.reactive.RediSearchReactiveCommands; -import io.lettuce.core.search.arguments.CreateArgs; -import io.lettuce.core.search.arguments.FieldArgs; -import io.lettuce.core.search.arguments.TextFieldArgs; -import io.lettuce.core.search.arguments.NumericFieldArgs; -import io.lettuce.core.search.arguments.TagFieldArgs; -import io.lettuce.core.search.arguments.SearchArgs; -import io.lettuce.core.search.arguments.AggregateArgs; -import io.lettuce.core.search.arguments.AggregateArgs.GroupBy; -import io.lettuce.core.search.arguments.AggregateArgs.Reducer; +import io.lettuce.core.search.arguments.*; +import io.lettuce.core.search.arguments.AggregateArgs.*; import io.lettuce.core.search.SearchReply; import io.lettuce.core.search.AggregationReply; From 1bbc6fdb4fa27ce7e093dd1869787504693fe121 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Mon, 11 Aug 2025 14:43:04 +0100 Subject: [PATCH 5/6] DOC-5556 tidied SearchArgs builder returnField call --- src/test/java/io/redis/examples/async/HomeJsonExample.java | 2 +- src/test/java/io/redis/examples/reactive/HomeJsonExample.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/io/redis/examples/async/HomeJsonExample.java b/src/test/java/io/redis/examples/async/HomeJsonExample.java index b685fb4276..f44bee86b5 100644 --- a/src/test/java/io/redis/examples/async/HomeJsonExample.java +++ b/src/test/java/io/redis/examples/async/HomeJsonExample.java @@ -131,7 +131,7 @@ NumericFieldArgs. builder().name("$.age").as("age").build(), // STEP_END // STEP_START query2 - SearchArgs query2Args = SearchArgs. builder().returnField("city", null).build(); + SearchArgs query2Args = SearchArgs. builder().returnField("city").build(); CompletableFuture> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args) .thenApply(res -> { List> results = res.getResults(); diff --git a/src/test/java/io/redis/examples/reactive/HomeJsonExample.java b/src/test/java/io/redis/examples/reactive/HomeJsonExample.java index b7d74ee537..df41e9d393 100644 --- a/src/test/java/io/redis/examples/reactive/HomeJsonExample.java +++ b/src/test/java/io/redis/examples/reactive/HomeJsonExample.java @@ -117,7 +117,7 @@ NumericFieldArgs. builder().name("$.age").as("age").build(), // STEP_END // STEP_START query2 - SearchArgs query2Args = SearchArgs. builder().returnField("city", null).build(); + SearchArgs query2Args = SearchArgs. builder().returnField("city").build(); Mono> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args) .doOnNext(res -> { From 820e498d4d5c530051b75639d55f310694962351 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Mon, 11 Aug 2025 14:53:32 +0100 Subject: [PATCH 6/6] DOC-5556 updated hash examples to avoid Map.of() --- .../redis/examples/async/HomeJsonExample.java | 25 +++++++++++++------ .../examples/reactive/HomeJsonExample.java | 25 +++++++++++++------ 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/test/java/io/redis/examples/async/HomeJsonExample.java b/src/test/java/io/redis/examples/async/HomeJsonExample.java index f44bee86b5..ba067fb82f 100644 --- a/src/test/java/io/redis/examples/async/HomeJsonExample.java +++ b/src/test/java/io/redis/examples/async/HomeJsonExample.java @@ -201,14 +201,23 @@ NumericFieldArgs. builder().name("age").build(), makeHashIndex.join(); // STEP_START add_hash_data - Map huser1 = Map.of("name", "Paul John", "email", "paul.john@example.com", "age", "42", "city", - "London"); - - Map huser2 = Map.of("name", "Eden Zamir", "email", "eden.zamir@example.com", "age", "29", "city", - "Tel Aviv"); - - Map huser3 = Map.of("name", "Paul Zamir", "email", "paul.zamir@example.com", "age", "35", "city", - "Tel Aviv"); + Map huser1 = new HashMap<>(); + huser1.put("name", "Paul John"); + huser1.put("email", "paul.john@example.com"); + huser1.put("age", "42"); + huser1.put("city", "London"); + + Map huser2 = new HashMap<>(); + huser2.put("name", "Eden Zamir"); + huser2.put("email", "eden.zamir@example.com"); + huser2.put("age", "29"); + huser2.put("city", "Tel Aviv"); + + Map huser3 = new HashMap<>(); + huser3.put("name", "Paul Zamir"); + huser3.put("email", "paul.zamir@example.com"); + huser3.put("age", "35"); + huser3.put("city", "Tel Aviv"); CompletableFuture addHashUser1 = asyncCommands.hset("huser:1", huser1).thenApply(r -> { System.out.println(r); // >>> OK diff --git a/src/test/java/io/redis/examples/reactive/HomeJsonExample.java b/src/test/java/io/redis/examples/reactive/HomeJsonExample.java index df41e9d393..f88e7c409a 100644 --- a/src/test/java/io/redis/examples/reactive/HomeJsonExample.java +++ b/src/test/java/io/redis/examples/reactive/HomeJsonExample.java @@ -183,14 +183,23 @@ NumericFieldArgs. builder().name("age").build(), makeHashIndex.block(); // STEP_START add_hash_data - Map huser1 = Map.of("name", "Paul John", "email", "paul.john@example.com", "age", "42", "city", - "London"); - - Map huser2 = Map.of("name", "Eden Zamir", "email", "eden.zamir@example.com", "age", "29", "city", - "Tel Aviv"); - - Map huser3 = Map.of("name", "Paul Zamir", "email", "paul.zamir@example.com", "age", "35", "city", - "Tel Aviv"); + Map huser1 = new HashMap<>(); + huser1.put("name", "Paul John"); + huser1.put("email", "paul.john@example.com"); + huser1.put("age", "42"); + huser1.put("city", "London"); + + Map huser2 = new HashMap<>(); + huser2.put("name", "Eden Zamir"); + huser2.put("email", "eden.zamir@example.com"); + huser2.put("age", "29"); + huser2.put("city", "Tel Aviv"); + + Map huser3 = new HashMap<>(); + huser3.put("name", "Paul Zamir"); + huser3.put("email", "paul.zamir@example.com"); + huser3.put("age", "35"); + huser3.put("city", "Tel Aviv"); Mono addHashUser1 = reactiveCommands.hset("huser:1", huser1).doOnNext(r -> { System.out.println(r); // >>> OK