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.

RATE THIS PAGE
Back to top ↑