We will use Redis as the primary DB leveraging Ohm library. But now we want to build more sophisticated indexes with RediSearch, use NUMERIC filter and other advanced options. And we will continue using RediSearchRails library.
Generate random seed data:
When we look in Redis we see various keys for RediSearch. There are Hashes which contain key / value pairs for name, email, status, age and height. RediSearchRails uses GlobalID to create unique key.
Separately we have custom data types for indexes:
Now we can run User.ft_search(keyword: 'active') or in redis-cli do FT.SEARCH User active. Similar searches can be done by name or email. We could search for all users with gmail address because RediSearch will index gmail as keyword.
RediSearchRails library also provides additional ft_add_all, ft_del_all, ft_search_format and ft_search_count methods (not present in RediSearch module). ft_search_format will return data as an array of hashes which is common pattern in ORMs like ActiveRecord or Mongoid.
numeric indexes allow us to filter search results if we want users of a certain age or height range.
Indexing data already in Redis
In our case we are using Redis both as primary DB and for RediSearch indexes. The core attributes (name, email, …) are stored as Hashes in Ohm records and then created separately by RediSearch. We can use FT.ADDHASH to index existing hashes and avoid creating duplicates.
What if we have thousands of records that match our search criteria? We do not want to return all results at once. RediSearch supports LIMIT offset num (default offset is 0 and num is 10). We can easily get the total number of results and request them in batches.
RediSearch module also has FT.SUGADD, FT.SUGGET, FT.SUGDEL and FT.SUGLEN methods. Using these commands we can build an autocomplete indexes to search for users by specific attributes. These Redis keys are completely separate from the other indexes. RediSearchRails library creates a Redis key by combining model name with attribute (User:name).
In addition to methods supported by RediSearch module RediSearchRails library adds ft_sugadd_all and ft_sugdel_all. They accept attribute name (User.ft_sugadd_all(attribute: 'name')) and will loop through all records adding/deleting strings to auto-complete dictionaries for that attribute. This can be useful when we have a table with specific records and we want to build auto-complete search on specific attribute.
There are many other advanced options in RediSearch module. For example, we can use GEO filters, stem keywords and do much more advanced querying. I am working on adding support for these to RediSearchRails library. I also want to add extra features to my library such as custom sopwords configuration and ability to specify minimum keyword length to index.