Author: Brian Sam-Bodden
Learn how the RediSearch module can bridge the querying gap between SQL and NoSQL systems. We’ll focus on two everyday use cases: full-text search and auto-complete.
In this lesson, you'll learn:
- How to create search indexes with RediSeach using spring-redisearch and lettuce-search.
- How to use RediSearch in a Spring Boot application to implement faceted search.
- How to use the RediSearch suggestions feature to implement auto-complete. If you get stuck:
- The progress made in this lesson is available on the redi2read github repository at https://github.com/redis-developer/redi2read/tree/course/milestone-7
RediSearch is a source-available module for querying, secondary indexing, and full-text search in Redis. Redisearch implements a secondary index in Redis, but unlike other Redis indexing libraries, it does not use internal data structures such as sorted sets. This also enables more advanced features, such as multi-field queries, aggregation, and full-text search. Also, RediSearch supports exact phrase matching and numeric filtering for text queries, neither possible nor efficient with traditional Redis indexing approaches. Having a rich query and aggregation engine in your Redis database opens the door to many new applications that go well beyond caching. You can use Redis as your primary database even when you need to access the data using complex queries without adding complexity to the code to update and index data.
Spring RediSearch (https://github.com/RediSearch/spring-redisearch) is a library built on LettuSearch (https://github.com/RediSearch/lettusearch), providing access to RediSearch from Spring applications.
LettuSearch is a Java client for RediSearch based on the popular Redis Java client library Lettuce.
In your Maven
pom.xml, add the following dependency:
To create an index, you must define a schema to list the fields and their types to be indexed.
Book model, you will be indexing four fields:
Creating the index is done using the FT.CREATE command. The RediSearch engine will scan the database using one or more PREFIX key pattern values and update the index based on the schema definition.
This active index maintenance makes it easy to add an index to an existing application.
To create our index, we’ll use the now-familiar
We will keep the name of the soon to be created index in the application's property field as shown:
Next, create the
src/main/java/com/redislabs/edu/redi2read/boot/CreateBooksSearchIndex.java file and add the contents as follows:
Let’s break down what our
CommandLineRunner is doing. We'll be working with classes out of the
StatefulRediSearchConnection, which gives access to RediSearch commands in synchronous mode, asynchronous mode, and reactive mode.
StatefulRediSearchConnection we get an instance of RediSearchCommands using the
sync() method (return the synchronous mode methods).
We only create the index if it doesn’t exist, which will be signalled by the FT.INFO command command throwing an exception.
To create the index, we build a
CreateOptions object passing the Book class prefix.
For each one the fields to be indexed, we create a Field object:
- Title is created as a sortable text field
- Subtitle is created as a text field
- Description is created as a text field
Authors are stored in a Set, so they are serialized as prefixed indexed fields (
authors., authors., ...). We indexed up to 6 authors.
To create the index, we invoke the create method passing the index name, the CreateOptions, and the fields.
To see more options and all field types, see https://oss.redislabs.com/redisearch/Commands/#ftcreate
On server restart, you should run your Redis CLI MONITOR to see the following commands:
You can see the index information with the following command in the Redis CLI:
This snippet from the FT.INFO command output for the
“books-idx” index shows that there are 2,403 documents indexed (the number of books in the system). From our indexed documents, there are 32,863 terms and close to half a million records.
RediSearch is a full-text search engine, allowing the application to run powerful queries. For example, to search all books that contain “networking”-related information, you would run the following command:
As you can see, books with the work “network” in the title are returned, even though we used the word “networking”. This is because the title has been indexed as text, so the field is tokenized and stemmed.
Also, the command does not specify a field, so the term “networking” (and related terms) is searched in all text fields of the index.
That’s why we have titles that do not show the search term; in these cases, the term has been found in another of the indexed fields.
If you want to search on specific fields, you use the
@field notation, as follows:
Try some additional full-text search queries against the index.
You can find more information about the query syntax in the RediSearch documentation.
Adding Search to the Books Controller
To add full-text search capabilities to the
BooksController, we'll first inject a
and simply pass a text query param to the search method available from the
With the imports:
We can use curl to execute some the sample queries we previously tried:
RediSearch provides a completion suggester that is typically used for auto-complete/search-as-you-type functionality. This is a navigational feature to guide users to relevant results as they are typing, improving search precision. RediSearch provides completion suggestions with four commands:
- FT.SUGADD: Adds a suggestion string to an auto-complete dictionary.
- FT.SUGGET: Get a list of suggestions for a string.
- FT.SUGDEL: Deletes a suggestion string from an auto-complete dictionary.
- FT.SUGLEN: Returns the size of an auto-completion dictionary
To create an auto-complete suggestion dictionary for author names, we’ll create a CommandLineRunner that will loop over the books, and for each author in the
Set<String> of authors, it will add them to the dictionary.
Unlike search indexes, which RediSearch maintains automatically, you maintain suggestion dictionaries manually using FT.SUGADD and FT.SUGDEL.
Add the property for the name of the auto-complete dictionary to
Add the file
src/main/java/com/redislabs/edu/redi2read/boot/CreateAuthorNameSuggestions.java with the following contents:
Let’s break down the logic of the
- First, we guarantee a single execution by checking for the existence of the key for the auto-complete dictionary.
- Then, using the
BookRepositorywe loop over all books
- For each author in a book we add a suggestion to the dictionary
To use the auto-suggestion feature in the controller, we can add a new method:
authorAutoComplete method, we use the FT.SUGGET command (via the sugget method from the
RediSearchCommands object) and build a query using a
SuggetOptions configuration. In the example above, we set the maximum number of results to 20.
We can use curl to craft a request to our new endpoint. In this example, I’m passing “brian s” as the query:
This results in a response with 2 JSON objects:
If we add one more letter to our query to make it “brian sa”:
We get the expected narrowing of the suggestion set: