Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
August 3, 2019 09:31 pm GMT

RediSearch on Rails

If you are using Rails, chances are you are using Redis for something whether it is as a cache, ActionCable, or ActiveJob. So why not use it for one more thing?

Starting in v4 of Redis, Redis Modules were introduced which are add ons built to extend Redis' functionality. One of the first modules was RediSearch, a text search engine built on top of Redis. According to RediSearch.io:

Unlike other Redis search libraries, it does not use the internal data
structures of Redis like sorted sets. Using its own highly optimized data
structures and algorithms, it allows for advanced search features, high
performance, and low memory footprint. It can perform simple text searches, as
well as complex structured queries, filtering by numeric properties and
geographical distances. RediSearch supports continuous indexing with no
performance degradation, maintaining concurrent loads of querying and
indexing. This makes it ideal for searching frequently updated databases,
without the need for batch indexing and service interrupts.

Some of the headline features of RediSearch include:

  • Full-Text indexing of multiple fields in a document, including:
    • Exact phrase matching.
    • Stemming in many languages.
    • Prefix queries.
    • Optional, negative and union queries.
  • Distributed search on billions of documents.
  • Numeric property indexing.
  • Geographical indexing and radius filters.
  • Incremental indexing without performance loss.
  • A powerful auto-complete engine with fuzzy matching.
  • Concurrent low-latency insertion and updates of documents.
  • This benchmark against ElasticSearch!

Let's walk through how to get RediSearch integrated into your Rails app!

First, start out by installing Redis and RediSearch. Check out Redis.io for full installation instructions for Redis. If Homebrew is available you can brew install redis. As of v1.6, to build RediSearch do the following:

  1. git clone https://github.com/RediSearch/RediSearch.git
  2. cd RediSearch
  3. make

Once RediSearch is built you will need to tell Redis to load the module. The best way is to add loadmodule /path/to/redisearch.so to your redis.conf file to always load the module. (On macOS the redis.conf file can be found at /usr/local/etc/redis.conf). Once the conf file has been updated restart Redis. For full instructions on installing RediSearch visit RediSearch.io.

Alternatively, you can run Redis and RediSearch with Docker using docker run -p 6379:6379 redislabs/redisearch:latest.

Once Redis and RediSearch are installed add the redi_search gem to your Gemfile:

gem 'redi_search'

and then run bundle install. Or you can install from the GitHub package registry.

Once installed we'll need to make an initializer to configure our Redis connection.

# config/initializers/redi_search.rbRediSearch.configure do |config|  config.redis_config = {    host: "127.0.0.1",    port: "6379"  }end

Now that we have RediSearch available in our app, let's use it to index a model. We'll use a User model with first and last attributes as an example.

class User < ApplicationRecord  redi_search schema: {    first: { text: { phonetic: "dm:en" } },    last: { text: { phonetic: "dm:en" } }  }end

Calling the redi_search class method inside a model accepts one required named parameter called schema. This defines the fields inside an index and the attributes for those fields. RediSearch has text, numeric, geo, and tag fields. The phonetic option was passed above because we are indexing names and it makes it easier to search for names with similar sounds but spelled differently. The full list of available options for the different field types can be found here.

User.reindex

Calling the redi_search class method inside a model adds a couple of useful methods, including reindex which does a couple of things:

  1. Creates the index if it doesn't exist
  2. Calls the search_import scope to fetch all the records from the database
  3. Converts those records to RediSearch Documents
  4. Indexes all those documents into Redis
User.search("jak")

Now that we have all of our users indexed we can start searching for them. Querying is similar to the ActiveRecord interface where clauses and conditions can be chained together and the search is executed lazily. Some simple queries are:

# simple phrase query - jak AND daxterUser.search("jak").and("daxter")# exact phrase query - jak FOLLOWED BY daxterUser.search("jak daxter")# union query - jak OR daxterUser.search("jak").or("daxter")# negation query - jak AND NOT daxterUser.search("jak").and.not("daxter")

Some more complex queries are:

# intersection of unions - (hello OR halo) AND (world OR werld)User.search(index.search("hello").or("halo")).and(index.search("world").or("werld"))# negation of union - hello AND NOT (world or werld)User.search("hello").and.not(index.search("world").or("werld"))# union inside phrase - hello AND (world OR werld)User.search("hello").and(index.search("world").or("werld"))

All terms support a few options that can be applied.

Prefix terms: match all terms starting with a prefix. (Akin to like term% in SQL)

User.search("hel", prefix: true)User.search("hello worl", prefix: true)User.search("hel", prefix: true).and("worl", prefix: true)User.search("hello").and.not("worl", prefix: true)

Optional terms: documents containing the optional terms will rank higher than those without

User.search("foo").and("bar", optional: true).and("baz", optional: true)

Fuzzy terms: matches are performed based on Levenshtein distance. The maximum Levenshtein distance supported is 3.

User.search("zuchini", fuzziness: 1)

Search terms can also be scoped to specific fields using a where clause:

# Simple field specific queryUser.search.where(name: "john")# Using where with optionsUser.search.where(first: "jon", fuzziness: 1)# Using where with more complex queryUser.search.where(first: User.search("bill").or("bob"))

Searching for numeric fields accepts a range:

User.search.where(number: 0..100)# Searching to infinityUser.search.where(number: 0..Float::INFINITY)User.search.where(number: -Float::INFINITY..0)

When searching, by default a collection of Documents is returned. Calling #results on the search query will execute the search, and then look up all the found records in the database and return an ActiveRecord relation.

Another useful method redi_search adds is spellcheck and responds with suggestions for misspelled search terms.

User.spellcheck("jimy")  RediSearch (1.1ms)  FT.SPELLCHECK user_idx jimy DISTANCE 1=> [#<RediSearch::Spellcheck::Result:0x00007f805591c670    term: "jimy",    suggestions:     [#<struct RediSearch::Spellcheck::Suggestion score=0.0006849315068493151, suggestion="jimmy">,      #<struct RediSearch::Spellcheck::Suggestion score=0.00019569471624266145, suggestion="jim">]>]User.spellcheck("jimy", distance: 2).first.suggestions  RediSearch (0.5ms)  FT.SPELLCHECK user_idx jimy DISTANCE 2=> [#<struct RediSearch::Spellcheck::Suggestion score=0.0006849315068493151, suggestion="jimmy">, #<struct RediSearch::Spellcheck::Suggestion score=0.00019569471624266145, suggestion="jim">]

Next time you are looking for a search engine give RediSearch a try! You can read about more options and see more examples on the README:

GitHub logo npezza93 / redi_search

Ruby wrapper around RediSearch that can integrate with Rails

RediSearch

Build StatusTest CoverageMaintainability

A simple, but powerful, Ruby wrapper around RediSearch, a search engine on top ofRedis.

Installation

Firstly, Redis and RediSearch need to be installed.

You can download Redis from https://redis.io/download, and check outinstallation instructionshere. Alternatively, onmacOS or Linux you can install via Homebrew.

To install RediSearch check outhttps://oss.redislabs.com/redisearch/Quick_Start.htmlOnce you have RediSearch built, if you are not using Docker, you can update yourredis.conf file to always load the RediSearch module withloadmodule /path/to/redisearch.so. (On macOS the redis.conf file can be foundat /usr/local/etc/redis.conf)

After Redis and RediSearch are up and running, add the following line to yourGemfile:

gem 'redi_search'

And then:

 bundle

Or install it yourself:

 gem install redi_search

and require it:

require 'redi_search'

Once the gem is installed and required you'll need to configure it with yourRedis configuration. If you're


Original Link: https://dev.to/pezza/redisearch-on-rails-581p

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To