Full Text Search using ElasticSearch in Rails 5

Elasticsearch is useful for full text searching. We will implement search functionality for a blog that can search articles with any given term in their title or content.

Setup a Rails 5 Project

Create a new Rails 5 project, controller and model for article resource.

rails new proj5
rails g controller articles
rails g model article title content:text

Install ElasticSearch

On Mac, you can install it using brew.

brew install elasticsearch

Start ElasticSearch

I had to use sudo to start the server.

$ which elasticsearch
/usr/local/bin/elasticsearch
$ sudo /usr/local/bin/elasticsearch

Without sudo I got the error.

$ /usr/local/bin/elasticsearch
$ log4j:ERROR setFile(null,true) call failed.
java.io.FileNotFoundException: /usr/local/var/log/elasticsearch/elasticsearch_zepho.log (No such file or directory)
    at java.io.FileOutputStream.openAppend(Native Method)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:192)
log4j:ERROR Either File or DatePattern options are not set for appender [file].

Validate ElasticSearch Installation

Hit the ElasticServer using curl command.

curl 'http://localhost:9200/?pretty'

You will see the json response from the server.

{
  "ok" : true,
  "status" : 200,
  "name" : "Ajaxis",
  "version" : {
    "number" : "0.90.0",
    "snapshot_build" : false
  },
  "tagline" : "You Know, for Search"
}

Add ElasticSearch Gems

In Gemfile, add:

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

and run bundle.

Run the Rails 5 App

Create a search controller with index action.

rails g controller search

The index action will handle the search query if the params has value for the search term.

def index
  if params[:q].nil?
    @articles = Article.all
  else
    @articles = Article.search(params[:q])
  end
end

Define the resources in the routes.rb.

Rails.application.routes.draw do
  resources :articles

  get 'search', to: 'search#index'
end

Note: When you search, if you get the error:

articles does not exist to be imported into. Use create_index! or the :force option to create it.

Add the force parameter to fix this problem.

class Article < ApplicationRecord
  include Elasticsearch::Model
end

# for auto sync model with elastic search
Article.import force: true

Two things must be done so that a new record gets indexed by ElasticSearch.

include Elasticsearch::Model::Callbacks

in your model. After a new record is saved you must call index_document method:

article.__elasticsearch__.index_document

The include statement also handles the re-indexing of the elasticsearch when an existing record is updated or deleted. To change the default size 10 of search results in ElasticSearch, pass the value for size parameter:

@articles = Article.search(params[:term], size: 1000).records

You can download the code to run it locally.

Summary

In this article, you learned how to use ElasticSearch to implement full text search feature in Rails 5 apps.


Related Articles


Create your own user feedback survey