Rails and elasticsearch for beginners

An article, posted about 6 years ago filed in elasticsearch, rails, search, linux, server, development, ruby, gem, tech & programming.

I don’t like complexity. Adding new items to your stack increases complexity. But sometimes it is worth it. When you need proper search and filtering, elasticsearch is worth it. Mostly because it isn’t hard to set up at all, as you’ll learn in this post.

Installing it on a Debian server is easy, simply follow their instructions (you’ll add their package-server, and run apt-get install. On OS-X you can install it easily with HomeBrew (brew install elasticsearch), but do make sure you have installed a JDK (e.g. openjdk-8-jre-headless)

If you’re not using something like Docker, you probably have to repeat the steps on your dev machine, your staging server and your production environment.

Note: When running on a low memory server, which isn’t recommended for production, you should make sure that the configured heap size isn’t too high, edit /etc/elasticsearch/jvm.options and modify the -Xms2g (2gig) and -Xmx2g variables (ideally set them to half the available memory).

When installed, you can start ElasticSearch immediately by simply running elasticsearch (or sudo service elasticsearch start) and it will be available on port 9200. You can test whether it works by running

curl 'localhost:9200/_cat/health?v'

Elasticsearch up and running? Time to integrate it with Rails. Get back to your trusted editor and project. Add the following lines to your Gemfile:

gem 'elasticsearch-model'
gem 'elasticsearch-rails'

Save it and run bundle install (you could even add a persistance gem if you’d like to store all your data in the elasticsearch database, but most of my apps still use a traditional database as well (Postgres)).

Then edit the model you want to be searchable and include the Elasticsearch::Model:

class Article < Active::Record
    include Elasticsearch::Model
    include Elasticsearch::Model::Callbacks
end

(I also included the callbacks, since I assume you want to keep the search index up to date after you save your article).

You can now try and run the following in your console.

Article.__elasticsearch__.create_index!
Article.import

Assuming you already have articles, you can now search for articles:

@articles = Article.search("title").records

I added records to the search to get a scoping friendly set of ActiveRecord-objects. The default order will be the score elasticsearch added, but you might decide you want to reorder the results based on your own rails scopes. You can simply render the results of this action in your views following the default Rails convention:

 render @articles

You probably don’t want to find articles only by its own attributes. You might have articles with categories that aren’t stored within the Article model, but a relation with the article model. Similarly, you might want to find the articles by their author’s name, which may not be a direct attribute of the Article object. You can instruct elastic search to pick up the tags and author-name as well when indexing by overriding the as_indexed_json method:

def as_indexed_json(options={})
  self.as_json(
    include: { 
      categories: { only: :title },
      authors:    { 
        methods: [:full_name],
        only: [:full_name] 
      }
    }
  )
end

You now have your object ready for simple elastic searching. In a follow up post I’ll learn you how you can filter your search results. And also not unimportant: add some fuzziness to your text search.

Op de hoogte blijven?

Maandelijks maak ik een selectie artikelen en zorg ik voor wat extra context bij de meer technische stukken. Schrijf je hieronder in:

Mailfrequentie = 1x per maand. Je privacy wordt serieus genomen: de mailinglijst bestaat alleen op onze servers.