Index and query documents

Learn how to use the Redis query engine with JSON and hash documents.

This example shows how to create a search index for JSON documents and run queries against the index. It then goes on to show the slight differences in the equivalent code for hash documents.

Initialize

Make sure that you have Redis Open Source or another Redis server available. Also install the Lettuce client library if you haven't already done so.

Add the following dependencies. All of them are applicable to both JSON and hash, except for the JsonParser, JsonPath, and JsonObject classes.

package io.redis.examples.async;  import io.lettuce.core.*;  import io.lettuce.core.api.async.RedisAsyncCommands; import io.lettuce.core.api.async.RediSearchAsyncCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisAsyncCommands<String, String> asyncCommands = connection.async();  RediSearchAsyncCommands<String, String> searchCommands = connection.async();  // ...   JsonParser parser = asyncCommands.getJsonParser();   JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   CompletableFuture<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  make_index.join();   CompletableFuture<String> addUser1 = asyncCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser2 = asyncCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser3 = asyncCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addUser1, addUser2, addUser3).join();   CompletableFuture<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  return res;  }).toCompletableFuture();   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();  CompletableFuture<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> 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  return res;  }).toCompletableFuture();   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();  CompletableFuture<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .thenApply(res -> {  List<SearchReply<String, String>> 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  });  return res;  }).toCompletableFuture();   CompletableFuture.allOf(query1, query2, query3).join();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   CompletableFuture<Void> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  makeHashIndex.join();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   CompletableFuture<Long> addHashUser1 = asyncCommands.hset("huser:1", huser1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser2 = asyncCommands.hset("huser:2", huser2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser3 = asyncCommands.hset("huser:3", huser3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addHashUser1, addHashUser2, addHashUser3).join();   CompletableFuture<SearchReply<String, String>> query1Hash = searchCommands  .ftSearch("hash-idx:users", "Paul @age:[30 40]").thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  return res;  }).toCompletableFuture();  query1Hash.join();  } finally {  redisClient.shutdown();  }  }  } 
package io.redis.examples.reactive;  import io.lettuce.core.*;  import io.lettuce.core.api.reactive.RedisReactiveCommands; import io.lettuce.core.api.reactive.RediSearchReactiveCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();  RediSearchReactiveCommands<String, String> searchCommands = connection.reactive();  // ...   JsonParser parser = reactiveCommands.getJsonParser();  JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   Mono<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema).doOnNext(res -> {  System.out.println(res); // >>> OK  }).then();  make_index.block();   Mono<String> addUser1 = reactiveCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser2 = reactiveCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser3 = reactiveCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addUser1, addUser2, addUser3).block();   Mono<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  });   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();   Mono<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> 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  });   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();   Mono<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .doOnNext(res -> {  List<SearchReply<String, String>> 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  });  });   Mono.when(query1, query2, query3).block();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   Mono<String> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema).doOnNext(res -> {  System.out.println(res); // >>> OK  });  makeHashIndex.block();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   Mono<Long> addHashUser1 = reactiveCommands.hset("huser:1", huser1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser2 = reactiveCommands.hset("huser:2", huser2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser3 = reactiveCommands.hset("huser:3", huser3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addHashUser1, addHashUser2, addHashUser3).block();   Mono<SearchReply<String, String>> query1Hash = searchCommands.ftSearch("hash-idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  });  query1Hash.block();  } finally {  redisClient.shutdown();  }  }  } 

Create data

Create some test data to add to the database:

package io.redis.examples.async;  import io.lettuce.core.*;  import io.lettuce.core.api.async.RedisAsyncCommands; import io.lettuce.core.api.async.RediSearchAsyncCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisAsyncCommands<String, String> asyncCommands = connection.async();  RediSearchAsyncCommands<String, String> searchCommands = connection.async();  // ...   JsonParser parser = asyncCommands.getJsonParser();   JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   CompletableFuture<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  make_index.join();   CompletableFuture<String> addUser1 = asyncCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser2 = asyncCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser3 = asyncCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addUser1, addUser2, addUser3).join();   CompletableFuture<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  return res;  }).toCompletableFuture();   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();  CompletableFuture<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> 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  return res;  }).toCompletableFuture();   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();  CompletableFuture<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .thenApply(res -> {  List<SearchReply<String, String>> 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  });  return res;  }).toCompletableFuture();   CompletableFuture.allOf(query1, query2, query3).join();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   CompletableFuture<Void> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  makeHashIndex.join();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   CompletableFuture<Long> addHashUser1 = asyncCommands.hset("huser:1", huser1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser2 = asyncCommands.hset("huser:2", huser2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser3 = asyncCommands.hset("huser:3", huser3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addHashUser1, addHashUser2, addHashUser3).join();   CompletableFuture<SearchReply<String, String>> query1Hash = searchCommands  .ftSearch("hash-idx:users", "Paul @age:[30 40]").thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  return res;  }).toCompletableFuture();  query1Hash.join();  } finally {  redisClient.shutdown();  }  }  } 
package io.redis.examples.reactive;  import io.lettuce.core.*;  import io.lettuce.core.api.reactive.RedisReactiveCommands; import io.lettuce.core.api.reactive.RediSearchReactiveCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();  RediSearchReactiveCommands<String, String> searchCommands = connection.reactive();  // ...   JsonParser parser = reactiveCommands.getJsonParser();  JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   Mono<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema).doOnNext(res -> {  System.out.println(res); // >>> OK  }).then();  make_index.block();   Mono<String> addUser1 = reactiveCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser2 = reactiveCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser3 = reactiveCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addUser1, addUser2, addUser3).block();   Mono<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  });   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();   Mono<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> 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  });   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();   Mono<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .doOnNext(res -> {  List<SearchReply<String, String>> 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  });  });   Mono.when(query1, query2, query3).block();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   Mono<String> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema).doOnNext(res -> {  System.out.println(res); // >>> OK  });  makeHashIndex.block();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   Mono<Long> addHashUser1 = reactiveCommands.hset("huser:1", huser1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser2 = reactiveCommands.hset("huser:2", huser2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser3 = reactiveCommands.hset("huser:3", huser3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addHashUser1, addHashUser2, addHashUser3).block();   Mono<SearchReply<String, String>> query1Hash = searchCommands.ftSearch("hash-idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  });  query1Hash.block();  } finally {  redisClient.shutdown();  }  }  } 

Add the index

Connect to your Redis database. The code below shows the most basic connection but see Connect to the server to learn more about the available connection options.

package io.redis.examples.async;  import io.lettuce.core.*;  import io.lettuce.core.api.async.RedisAsyncCommands; import io.lettuce.core.api.async.RediSearchAsyncCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisAsyncCommands<String, String> asyncCommands = connection.async();  RediSearchAsyncCommands<String, String> searchCommands = connection.async();  // ...   JsonParser parser = asyncCommands.getJsonParser();   JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   CompletableFuture<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  make_index.join();   CompletableFuture<String> addUser1 = asyncCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser2 = asyncCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser3 = asyncCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addUser1, addUser2, addUser3).join();   CompletableFuture<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  return res;  }).toCompletableFuture();   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();  CompletableFuture<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> 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  return res;  }).toCompletableFuture();   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();  CompletableFuture<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .thenApply(res -> {  List<SearchReply<String, String>> 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  });  return res;  }).toCompletableFuture();   CompletableFuture.allOf(query1, query2, query3).join();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   CompletableFuture<Void> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  makeHashIndex.join();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   CompletableFuture<Long> addHashUser1 = asyncCommands.hset("huser:1", huser1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser2 = asyncCommands.hset("huser:2", huser2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser3 = asyncCommands.hset("huser:3", huser3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addHashUser1, addHashUser2, addHashUser3).join();   CompletableFuture<SearchReply<String, String>> query1Hash = searchCommands  .ftSearch("hash-idx:users", "Paul @age:[30 40]").thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  return res;  }).toCompletableFuture();  query1Hash.join();  } finally {  redisClient.shutdown();  }  }  } 
package io.redis.examples.reactive;  import io.lettuce.core.*;  import io.lettuce.core.api.reactive.RedisReactiveCommands; import io.lettuce.core.api.reactive.RediSearchReactiveCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();  RediSearchReactiveCommands<String, String> searchCommands = connection.reactive();  // ...   JsonParser parser = reactiveCommands.getJsonParser();  JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   Mono<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema).doOnNext(res -> {  System.out.println(res); // >>> OK  }).then();  make_index.block();   Mono<String> addUser1 = reactiveCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser2 = reactiveCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser3 = reactiveCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addUser1, addUser2, addUser3).block();   Mono<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  });   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();   Mono<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> 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  });   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();   Mono<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .doOnNext(res -> {  List<SearchReply<String, String>> 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  });  });   Mono.when(query1, query2, query3).block();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   Mono<String> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema).doOnNext(res -> {  System.out.println(res); // >>> OK  });  makeHashIndex.block();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   Mono<Long> addHashUser1 = reactiveCommands.hset("huser:1", huser1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser2 = reactiveCommands.hset("huser:2", huser2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser3 = reactiveCommands.hset("huser:3", huser3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addHashUser1, addHashUser2, addHashUser3).block();   Mono<SearchReply<String, String>> query1Hash = searchCommands.ftSearch("hash-idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  });  query1Hash.block();  } finally {  redisClient.shutdown();  }  }  } 

Create an index. In this example, only JSON documents with the key prefix user: are indexed. For more information, see Query syntax.

package io.redis.examples.async;  import io.lettuce.core.*;  import io.lettuce.core.api.async.RedisAsyncCommands; import io.lettuce.core.api.async.RediSearchAsyncCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisAsyncCommands<String, String> asyncCommands = connection.async();  RediSearchAsyncCommands<String, String> searchCommands = connection.async();  // ...   JsonParser parser = asyncCommands.getJsonParser();   JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   CompletableFuture<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  make_index.join();   CompletableFuture<String> addUser1 = asyncCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser2 = asyncCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser3 = asyncCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addUser1, addUser2, addUser3).join();   CompletableFuture<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  return res;  }).toCompletableFuture();   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();  CompletableFuture<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> 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  return res;  }).toCompletableFuture();   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();  CompletableFuture<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .thenApply(res -> {  List<SearchReply<String, String>> 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  });  return res;  }).toCompletableFuture();   CompletableFuture.allOf(query1, query2, query3).join();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   CompletableFuture<Void> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  makeHashIndex.join();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   CompletableFuture<Long> addHashUser1 = asyncCommands.hset("huser:1", huser1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser2 = asyncCommands.hset("huser:2", huser2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser3 = asyncCommands.hset("huser:3", huser3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addHashUser1, addHashUser2, addHashUser3).join();   CompletableFuture<SearchReply<String, String>> query1Hash = searchCommands  .ftSearch("hash-idx:users", "Paul @age:[30 40]").thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  return res;  }).toCompletableFuture();  query1Hash.join();  } finally {  redisClient.shutdown();  }  }  } 
package io.redis.examples.reactive;  import io.lettuce.core.*;  import io.lettuce.core.api.reactive.RedisReactiveCommands; import io.lettuce.core.api.reactive.RediSearchReactiveCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();  RediSearchReactiveCommands<String, String> searchCommands = connection.reactive();  // ...   JsonParser parser = reactiveCommands.getJsonParser();  JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   Mono<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema).doOnNext(res -> {  System.out.println(res); // >>> OK  }).then();  make_index.block();   Mono<String> addUser1 = reactiveCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser2 = reactiveCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser3 = reactiveCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addUser1, addUser2, addUser3).block();   Mono<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  });   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();   Mono<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> 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  });   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();   Mono<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .doOnNext(res -> {  List<SearchReply<String, String>> 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  });  });   Mono.when(query1, query2, query3).block();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   Mono<String> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema).doOnNext(res -> {  System.out.println(res); // >>> OK  });  makeHashIndex.block();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   Mono<Long> addHashUser1 = reactiveCommands.hset("huser:1", huser1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser2 = reactiveCommands.hset("huser:2", huser2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser3 = reactiveCommands.hset("huser:3", huser3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addHashUser1, addHashUser2, addHashUser3).block();   Mono<SearchReply<String, String>> query1Hash = searchCommands.ftSearch("hash-idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  });  query1Hash.block();  } finally {  redisClient.shutdown();  }  }  } 

Add the data

Add the three sets of user data to the database as JSON objects. If you use keys with the user: prefix then Redis will index the objects automatically as you add them:

package io.redis.examples.async;  import io.lettuce.core.*;  import io.lettuce.core.api.async.RedisAsyncCommands; import io.lettuce.core.api.async.RediSearchAsyncCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisAsyncCommands<String, String> asyncCommands = connection.async();  RediSearchAsyncCommands<String, String> searchCommands = connection.async();  // ...   JsonParser parser = asyncCommands.getJsonParser();   JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   CompletableFuture<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  make_index.join();   CompletableFuture<String> addUser1 = asyncCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser2 = asyncCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser3 = asyncCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addUser1, addUser2, addUser3).join();   CompletableFuture<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  return res;  }).toCompletableFuture();   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();  CompletableFuture<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> 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  return res;  }).toCompletableFuture();   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();  CompletableFuture<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .thenApply(res -> {  List<SearchReply<String, String>> 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  });  return res;  }).toCompletableFuture();   CompletableFuture.allOf(query1, query2, query3).join();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   CompletableFuture<Void> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  makeHashIndex.join();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   CompletableFuture<Long> addHashUser1 = asyncCommands.hset("huser:1", huser1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser2 = asyncCommands.hset("huser:2", huser2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser3 = asyncCommands.hset("huser:3", huser3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addHashUser1, addHashUser2, addHashUser3).join();   CompletableFuture<SearchReply<String, String>> query1Hash = searchCommands  .ftSearch("hash-idx:users", "Paul @age:[30 40]").thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  return res;  }).toCompletableFuture();  query1Hash.join();  } finally {  redisClient.shutdown();  }  }  } 
package io.redis.examples.reactive;  import io.lettuce.core.*;  import io.lettuce.core.api.reactive.RedisReactiveCommands; import io.lettuce.core.api.reactive.RediSearchReactiveCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();  RediSearchReactiveCommands<String, String> searchCommands = connection.reactive();  // ...   JsonParser parser = reactiveCommands.getJsonParser();  JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   Mono<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema).doOnNext(res -> {  System.out.println(res); // >>> OK  }).then();  make_index.block();   Mono<String> addUser1 = reactiveCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser2 = reactiveCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser3 = reactiveCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addUser1, addUser2, addUser3).block();   Mono<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  });   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();   Mono<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> 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  });   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();   Mono<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .doOnNext(res -> {  List<SearchReply<String, String>> 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  });  });   Mono.when(query1, query2, query3).block();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   Mono<String> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema).doOnNext(res -> {  System.out.println(res); // >>> OK  });  makeHashIndex.block();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   Mono<Long> addHashUser1 = reactiveCommands.hset("huser:1", huser1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser2 = reactiveCommands.hset("huser:2", huser2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser3 = reactiveCommands.hset("huser:3", huser3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addHashUser1, addHashUser2, addHashUser3).block();   Mono<SearchReply<String, String>> query1Hash = searchCommands.ftSearch("hash-idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  });  query1Hash.block();  } finally {  redisClient.shutdown();  }  }  } 

Query the data

You can now use the index to search the JSON objects. The query below searches for objects that have the text "Paul" in any field and have an age value in the range 30 to 40:

package io.redis.examples.async;  import io.lettuce.core.*;  import io.lettuce.core.api.async.RedisAsyncCommands; import io.lettuce.core.api.async.RediSearchAsyncCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisAsyncCommands<String, String> asyncCommands = connection.async();  RediSearchAsyncCommands<String, String> searchCommands = connection.async();  // ...   JsonParser parser = asyncCommands.getJsonParser();   JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   CompletableFuture<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  make_index.join();   CompletableFuture<String> addUser1 = asyncCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser2 = asyncCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser3 = asyncCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addUser1, addUser2, addUser3).join();   CompletableFuture<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  return res;  }).toCompletableFuture();   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();  CompletableFuture<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> 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  return res;  }).toCompletableFuture();   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();  CompletableFuture<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .thenApply(res -> {  List<SearchReply<String, String>> 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  });  return res;  }).toCompletableFuture();   CompletableFuture.allOf(query1, query2, query3).join();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   CompletableFuture<Void> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  makeHashIndex.join();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   CompletableFuture<Long> addHashUser1 = asyncCommands.hset("huser:1", huser1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser2 = asyncCommands.hset("huser:2", huser2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser3 = asyncCommands.hset("huser:3", huser3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addHashUser1, addHashUser2, addHashUser3).join();   CompletableFuture<SearchReply<String, String>> query1Hash = searchCommands  .ftSearch("hash-idx:users", "Paul @age:[30 40]").thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  return res;  }).toCompletableFuture();  query1Hash.join();  } finally {  redisClient.shutdown();  }  }  } 
package io.redis.examples.reactive;  import io.lettuce.core.*;  import io.lettuce.core.api.reactive.RedisReactiveCommands; import io.lettuce.core.api.reactive.RediSearchReactiveCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();  RediSearchReactiveCommands<String, String> searchCommands = connection.reactive();  // ...   JsonParser parser = reactiveCommands.getJsonParser();  JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   Mono<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema).doOnNext(res -> {  System.out.println(res); // >>> OK  }).then();  make_index.block();   Mono<String> addUser1 = reactiveCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser2 = reactiveCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser3 = reactiveCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addUser1, addUser2, addUser3).block();   Mono<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  });   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();   Mono<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> 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  });   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();   Mono<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .doOnNext(res -> {  List<SearchReply<String, String>> 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  });  });   Mono.when(query1, query2, query3).block();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   Mono<String> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema).doOnNext(res -> {  System.out.println(res); // >>> OK  });  makeHashIndex.block();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   Mono<Long> addHashUser1 = reactiveCommands.hset("huser:1", huser1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser2 = reactiveCommands.hset("huser:2", huser2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser3 = reactiveCommands.hset("huser:3", huser3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addHashUser1, addHashUser2, addHashUser3).block();   Mono<SearchReply<String, String>> query1Hash = searchCommands.ftSearch("hash-idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  });  query1Hash.block();  } finally {  redisClient.shutdown();  }  }  } 

Specify query options to return only the city field:

package io.redis.examples.async;  import io.lettuce.core.*;  import io.lettuce.core.api.async.RedisAsyncCommands; import io.lettuce.core.api.async.RediSearchAsyncCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisAsyncCommands<String, String> asyncCommands = connection.async();  RediSearchAsyncCommands<String, String> searchCommands = connection.async();  // ...   JsonParser parser = asyncCommands.getJsonParser();   JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   CompletableFuture<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  make_index.join();   CompletableFuture<String> addUser1 = asyncCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser2 = asyncCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser3 = asyncCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addUser1, addUser2, addUser3).join();   CompletableFuture<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  return res;  }).toCompletableFuture();   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();  CompletableFuture<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> 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  return res;  }).toCompletableFuture();   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();  CompletableFuture<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .thenApply(res -> {  List<SearchReply<String, String>> 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  });  return res;  }).toCompletableFuture();   CompletableFuture.allOf(query1, query2, query3).join();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   CompletableFuture<Void> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  makeHashIndex.join();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   CompletableFuture<Long> addHashUser1 = asyncCommands.hset("huser:1", huser1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser2 = asyncCommands.hset("huser:2", huser2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser3 = asyncCommands.hset("huser:3", huser3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addHashUser1, addHashUser2, addHashUser3).join();   CompletableFuture<SearchReply<String, String>> query1Hash = searchCommands  .ftSearch("hash-idx:users", "Paul @age:[30 40]").thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  return res;  }).toCompletableFuture();  query1Hash.join();  } finally {  redisClient.shutdown();  }  }  } 
package io.redis.examples.reactive;  import io.lettuce.core.*;  import io.lettuce.core.api.reactive.RedisReactiveCommands; import io.lettuce.core.api.reactive.RediSearchReactiveCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();  RediSearchReactiveCommands<String, String> searchCommands = connection.reactive();  // ...   JsonParser parser = reactiveCommands.getJsonParser();  JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   Mono<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema).doOnNext(res -> {  System.out.println(res); // >>> OK  }).then();  make_index.block();   Mono<String> addUser1 = reactiveCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser2 = reactiveCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser3 = reactiveCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addUser1, addUser2, addUser3).block();   Mono<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  });   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();   Mono<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> 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  });   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();   Mono<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .doOnNext(res -> {  List<SearchReply<String, String>> 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  });  });   Mono.when(query1, query2, query3).block();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   Mono<String> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema).doOnNext(res -> {  System.out.println(res); // >>> OK  });  makeHashIndex.block();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   Mono<Long> addHashUser1 = reactiveCommands.hset("huser:1", huser1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser2 = reactiveCommands.hset("huser:2", huser2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser3 = reactiveCommands.hset("huser:3", huser3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addHashUser1, addHashUser2, addHashUser3).block();   Mono<SearchReply<String, String>> query1Hash = searchCommands.ftSearch("hash-idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  });  query1Hash.block();  } finally {  redisClient.shutdown();  }  }  } 

Use an aggregation query to count all users in each city.

package io.redis.examples.async;  import io.lettuce.core.*;  import io.lettuce.core.api.async.RedisAsyncCommands; import io.lettuce.core.api.async.RediSearchAsyncCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisAsyncCommands<String, String> asyncCommands = connection.async();  RediSearchAsyncCommands<String, String> searchCommands = connection.async();  // ...   JsonParser parser = asyncCommands.getJsonParser();   JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   CompletableFuture<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  make_index.join();   CompletableFuture<String> addUser1 = asyncCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser2 = asyncCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser3 = asyncCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addUser1, addUser2, addUser3).join();   CompletableFuture<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  return res;  }).toCompletableFuture();   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();  CompletableFuture<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> 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  return res;  }).toCompletableFuture();   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();  CompletableFuture<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .thenApply(res -> {  List<SearchReply<String, String>> 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  });  return res;  }).toCompletableFuture();   CompletableFuture.allOf(query1, query2, query3).join();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   CompletableFuture<Void> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  makeHashIndex.join();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   CompletableFuture<Long> addHashUser1 = asyncCommands.hset("huser:1", huser1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser2 = asyncCommands.hset("huser:2", huser2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser3 = asyncCommands.hset("huser:3", huser3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addHashUser1, addHashUser2, addHashUser3).join();   CompletableFuture<SearchReply<String, String>> query1Hash = searchCommands  .ftSearch("hash-idx:users", "Paul @age:[30 40]").thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  return res;  }).toCompletableFuture();  query1Hash.join();  } finally {  redisClient.shutdown();  }  }  } 
package io.redis.examples.reactive;  import io.lettuce.core.*;  import io.lettuce.core.api.reactive.RedisReactiveCommands; import io.lettuce.core.api.reactive.RediSearchReactiveCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();  RediSearchReactiveCommands<String, String> searchCommands = connection.reactive();  // ...   JsonParser parser = reactiveCommands.getJsonParser();  JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   Mono<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema).doOnNext(res -> {  System.out.println(res); // >>> OK  }).then();  make_index.block();   Mono<String> addUser1 = reactiveCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser2 = reactiveCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser3 = reactiveCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addUser1, addUser2, addUser3).block();   Mono<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  });   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();   Mono<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> 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  });   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();   Mono<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .doOnNext(res -> {  List<SearchReply<String, String>> 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  });  });   Mono.when(query1, query2, query3).block();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   Mono<String> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema).doOnNext(res -> {  System.out.println(res); // >>> OK  });  makeHashIndex.block();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   Mono<Long> addHashUser1 = reactiveCommands.hset("huser:1", huser1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser2 = reactiveCommands.hset("huser:2", huser2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser3 = reactiveCommands.hset("huser:3", huser3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addHashUser1, addHashUser2, addHashUser3).block();   Mono<SearchReply<String, String>> query1Hash = searchCommands.ftSearch("hash-idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  });  query1Hash.block();  } finally {  redisClient.shutdown();  }  }  } 

Differences with hash documents

Indexing for hash documents is very similar to JSON indexing but you need to specify some slightly different options.

When you create the schema for a hash index, you don't need to add aliases for the fields, since you use the basic names to access the fields. Also, you must use CreateArgs.TargetType.HASH for the On() option of CreateArgs when you create the index. The code below shows these changes with a new index called hash-idx:users, which is otherwise the same as the idx:users index used for JSON documents in the previous examples.

package io.redis.examples.async;  import io.lettuce.core.*;  import io.lettuce.core.api.async.RedisAsyncCommands; import io.lettuce.core.api.async.RediSearchAsyncCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisAsyncCommands<String, String> asyncCommands = connection.async();  RediSearchAsyncCommands<String, String> searchCommands = connection.async();  // ...   JsonParser parser = asyncCommands.getJsonParser();   JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   CompletableFuture<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  make_index.join();   CompletableFuture<String> addUser1 = asyncCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser2 = asyncCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser3 = asyncCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addUser1, addUser2, addUser3).join();   CompletableFuture<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  return res;  }).toCompletableFuture();   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();  CompletableFuture<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> 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  return res;  }).toCompletableFuture();   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();  CompletableFuture<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .thenApply(res -> {  List<SearchReply<String, String>> 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  });  return res;  }).toCompletableFuture();   CompletableFuture.allOf(query1, query2, query3).join();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   CompletableFuture<Void> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  makeHashIndex.join();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   CompletableFuture<Long> addHashUser1 = asyncCommands.hset("huser:1", huser1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser2 = asyncCommands.hset("huser:2", huser2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser3 = asyncCommands.hset("huser:3", huser3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addHashUser1, addHashUser2, addHashUser3).join();   CompletableFuture<SearchReply<String, String>> query1Hash = searchCommands  .ftSearch("hash-idx:users", "Paul @age:[30 40]").thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  return res;  }).toCompletableFuture();  query1Hash.join();  } finally {  redisClient.shutdown();  }  }  } 
package io.redis.examples.reactive;  import io.lettuce.core.*;  import io.lettuce.core.api.reactive.RedisReactiveCommands; import io.lettuce.core.api.reactive.RediSearchReactiveCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();  RediSearchReactiveCommands<String, String> searchCommands = connection.reactive();  // ...   JsonParser parser = reactiveCommands.getJsonParser();  JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   Mono<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema).doOnNext(res -> {  System.out.println(res); // >>> OK  }).then();  make_index.block();   Mono<String> addUser1 = reactiveCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser2 = reactiveCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser3 = reactiveCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addUser1, addUser2, addUser3).block();   Mono<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  });   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();   Mono<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> 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  });   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();   Mono<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .doOnNext(res -> {  List<SearchReply<String, String>> 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  });  });   Mono.when(query1, query2, query3).block();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   Mono<String> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema).doOnNext(res -> {  System.out.println(res); // >>> OK  });  makeHashIndex.block();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   Mono<Long> addHashUser1 = reactiveCommands.hset("huser:1", huser1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser2 = reactiveCommands.hset("huser:2", huser2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser3 = reactiveCommands.hset("huser:3", huser3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addHashUser1, addHashUser2, addHashUser3).block();   Mono<SearchReply<String, String>> query1Hash = searchCommands.ftSearch("hash-idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  });  query1Hash.block();  } finally {  redisClient.shutdown();  }  }  } 

Use hset() to add the hash documents instead of jsonSet().

package io.redis.examples.async;  import io.lettuce.core.*;  import io.lettuce.core.api.async.RedisAsyncCommands; import io.lettuce.core.api.async.RediSearchAsyncCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisAsyncCommands<String, String> asyncCommands = connection.async();  RediSearchAsyncCommands<String, String> searchCommands = connection.async();  // ...   JsonParser parser = asyncCommands.getJsonParser();   JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   CompletableFuture<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  make_index.join();   CompletableFuture<String> addUser1 = asyncCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser2 = asyncCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser3 = asyncCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addUser1, addUser2, addUser3).join();   CompletableFuture<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  return res;  }).toCompletableFuture();   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();  CompletableFuture<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> 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  return res;  }).toCompletableFuture();   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();  CompletableFuture<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .thenApply(res -> {  List<SearchReply<String, String>> 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  });  return res;  }).toCompletableFuture();   CompletableFuture.allOf(query1, query2, query3).join();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   CompletableFuture<Void> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  makeHashIndex.join();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   CompletableFuture<Long> addHashUser1 = asyncCommands.hset("huser:1", huser1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser2 = asyncCommands.hset("huser:2", huser2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser3 = asyncCommands.hset("huser:3", huser3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addHashUser1, addHashUser2, addHashUser3).join();   CompletableFuture<SearchReply<String, String>> query1Hash = searchCommands  .ftSearch("hash-idx:users", "Paul @age:[30 40]").thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  return res;  }).toCompletableFuture();  query1Hash.join();  } finally {  redisClient.shutdown();  }  }  } 
package io.redis.examples.reactive;  import io.lettuce.core.*;  import io.lettuce.core.api.reactive.RedisReactiveCommands; import io.lettuce.core.api.reactive.RediSearchReactiveCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();  RediSearchReactiveCommands<String, String> searchCommands = connection.reactive();  // ...   JsonParser parser = reactiveCommands.getJsonParser();  JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   Mono<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema).doOnNext(res -> {  System.out.println(res); // >>> OK  }).then();  make_index.block();   Mono<String> addUser1 = reactiveCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser2 = reactiveCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser3 = reactiveCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addUser1, addUser2, addUser3).block();   Mono<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  });   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();   Mono<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> 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  });   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();   Mono<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .doOnNext(res -> {  List<SearchReply<String, String>> 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  });  });   Mono.when(query1, query2, query3).block();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   Mono<String> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema).doOnNext(res -> {  System.out.println(res); // >>> OK  });  makeHashIndex.block();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   Mono<Long> addHashUser1 = reactiveCommands.hset("huser:1", huser1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser2 = reactiveCommands.hset("huser:2", huser2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser3 = reactiveCommands.hset("huser:3", huser3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addHashUser1, addHashUser2, addHashUser3).block();   Mono<SearchReply<String, String>> query1Hash = searchCommands.ftSearch("hash-idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  });  query1Hash.block();  } finally {  redisClient.shutdown();  }  }  } 

The query commands work the same here for hash as they do for JSON (but the name of the hash index is different). The results are returned in a List of SearchReply.SearchResult<String, String> objects, as with JSON:

package io.redis.examples.async;  import io.lettuce.core.*;  import io.lettuce.core.api.async.RedisAsyncCommands; import io.lettuce.core.api.async.RediSearchAsyncCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisAsyncCommands<String, String> asyncCommands = connection.async();  RediSearchAsyncCommands<String, String> searchCommands = connection.async();  // ...   JsonParser parser = asyncCommands.getJsonParser();   JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   CompletableFuture<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  make_index.join();   CompletableFuture<String> addUser1 = asyncCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser2 = asyncCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<String> addUser3 = asyncCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addUser1, addUser2, addUser3).join();   CompletableFuture<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  return res;  }).toCompletableFuture();   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();  CompletableFuture<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .thenApply(res -> {  List<SearchReply.SearchResult<String, String>> 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  return res;  }).toCompletableFuture();   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();  CompletableFuture<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .thenApply(res -> {  List<SearchReply<String, String>> 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  });  return res;  }).toCompletableFuture();   CompletableFuture.allOf(query1, query2, query3).join();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   CompletableFuture<Void> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema)  .thenAccept(System.out::println) // >>> OK  .toCompletableFuture();  makeHashIndex.join();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   CompletableFuture<Long> addHashUser1 = asyncCommands.hset("huser:1", huser1).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser2 = asyncCommands.hset("huser:2", huser2).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();   CompletableFuture<Long> addHashUser3 = asyncCommands.hset("huser:3", huser3).thenApply(r -> {  System.out.println(r); // >>> OK  return r;  }).toCompletableFuture();  CompletableFuture.allOf(addHashUser1, addHashUser2, addHashUser3).join();   CompletableFuture<SearchReply<String, String>> query1Hash = searchCommands  .ftSearch("hash-idx:users", "Paul @age:[30 40]").thenApply(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  return res;  }).toCompletableFuture();  query1Hash.join();  } finally {  redisClient.shutdown();  }  }  } 
package io.redis.examples.reactive;  import io.lettuce.core.*;  import io.lettuce.core.api.reactive.RedisReactiveCommands; import io.lettuce.core.api.reactive.RediSearchReactiveCommands; 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;  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;  public class HomeJsonExample {   public void run() {  RedisClient redisClient = RedisClient.create("redis://localhost:6379");   try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {  RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();  RediSearchReactiveCommands<String, String> searchCommands = connection.reactive();  // ...   JsonParser parser = reactiveCommands.getJsonParser();  JsonObject user1 = parser.createJsonObject().put("name", parser.createJsonValue("\"Paul John\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).put("age", parser.createJsonValue("42"))  .put("city", parser.createJsonValue("\"London\""));   JsonObject user2 = parser.createJsonObject().put("name", parser.createJsonValue("\"Eden Zamir\""))  .put("email", parser.createJsonValue("\"[email protected]\"")).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("\"[email protected]\"")).put("age", parser.createJsonValue("35"))  .put("city", parser.createJsonValue("\"Tel Aviv\""));   List<FieldArgs<String>> schema = Arrays.asList(TextFieldArgs.<String> builder().name("$.name").as("name").build(),  NumericFieldArgs.<String> builder().name("$.age").as("age").build(),  TagFieldArgs.<String> builder().name("$.city").as("city").build());   CreateArgs<String, String> createArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)  .withPrefix("user:").build();   Mono<Void> make_index = searchCommands.ftCreate("idx:users", createArgs, schema).doOnNext(res -> {  System.out.println(res); // >>> OK  }).then();  make_index.block();   Mono<String> addUser1 = reactiveCommands.jsonSet("user:1", JsonPath.ROOT_PATH, user1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser2 = reactiveCommands.jsonSet("user:2", JsonPath.ROOT_PATH, user2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<String> addUser3 = reactiveCommands.jsonSet("user:3", JsonPath.ROOT_PATH, user3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addUser1, addUser2, addUser3).block();   Mono<SearchReply<String, String>> query1 = searchCommands.ftSearch("idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> user:3  });   SearchArgs<String, String> query2Args = SearchArgs.<String, String> builder().returnField("city").build();   Mono<SearchReply<String, String>> query2 = searchCommands.ftSearch("idx:users", "Paul", query2Args)  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> 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  });   AggregateArgs<String, String> aggArgs = AggregateArgs.<String, String> builder()  .groupBy(GroupBy.<String, String> of("@city").reduce(Reducer.<String, String> count().as("count"))).build();   Mono<AggregationReply<String, String>> query3 = searchCommands.ftAggregate("idx:users", "*", aggArgs)  .doOnNext(res -> {  List<SearchReply<String, String>> 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  });  });   Mono.when(query1, query2, query3).block();   List<FieldArgs<String>> hashSchema = Arrays.asList(TextFieldArgs.<String> builder().name("name").build(),  NumericFieldArgs.<String> builder().name("age").build(),  TagFieldArgs.<String> builder().name("city").build());   CreateArgs<String, String> hashCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.HASH)  .withPrefix("huser:").build();   Mono<String> makeHashIndex = searchCommands.ftCreate("hash-idx:users", hashCreateArgs, hashSchema).doOnNext(res -> {  System.out.println(res); // >>> OK  });  makeHashIndex.block();   Map<String, String> huser1 = new HashMap<>();  huser1.put("name", "Paul John");  huser1.put("email", "[email protected]");  huser1.put("age", "42");  huser1.put("city", "London");   Map<String, String> huser2 = new HashMap<>();  huser2.put("name", "Eden Zamir");  huser2.put("email", "[email protected]");  huser2.put("age", "29");  huser2.put("city", "Tel Aviv");   Map<String, String> huser3 = new HashMap<>();  huser3.put("name", "Paul Zamir");  huser3.put("email", "[email protected]");  huser3.put("age", "35");  huser3.put("city", "Tel Aviv");   Mono<Long> addHashUser1 = reactiveCommands.hset("huser:1", huser1).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser2 = reactiveCommands.hset("huser:2", huser2).doOnNext(r -> {  System.out.println(r); // >>> OK  });   Mono<Long> addHashUser3 = reactiveCommands.hset("huser:3", huser3).doOnNext(r -> {  System.out.println(r); // >>> OK  });  Mono.when(addHashUser1, addHashUser2, addHashUser3).block();   Mono<SearchReply<String, String>> query1Hash = searchCommands.ftSearch("hash-idx:users", "Paul @age:[30 40]")  .doOnNext(res -> {  List<SearchReply.SearchResult<String, String>> results = res.getResults();   results.forEach(result -> {  System.out.println(result.getId());  });  // >>> huser:3  });  query1Hash.block();  } finally {  redisClient.shutdown();  }  }  } 

More information

See the Redis query engine docs for a full description of all query features with examples.