Apache Solr with Rails


For one of my pet project based on Ruby on Rails, I’ve decided to implement Apache Solr as full-text search engine.

You can find a lot of tutorials with 5 min install and run, but:

trap

None from Google first page results worked for me, so I’ve decided to write my own tutorial.

I’m using Rails 5.2.0.rc1 at this tutorial.

So first problem was about specifying github at Gemfile, because otherwise installer script fails:

gem 'sunspot_rails', github: 'sunspot/sunspot'

Let’s add another gems too:

group :test, :development do
  gem 'sunspot_solr'
end

Great, now let’s run installer. This creates sunspot.yml file and config directory.

rails generate sunspot_rails:install

Let’s modify this file:

development:
  solr:
    hostname: localhost
    port: 8983
    log_level: INFO

Of course, you can run local solar instance with this command, like described in tutorials:

bundle exec rake sunspot:solr:start

But I prefer isolate Solr installation from my development environment, and use Docker for that stuff.

You can find Solr Docker images here.

So, let’s install and run Apache Solr as a Docker container:

$ docker run --name local_solr -d -p 8983:8983 -t solr
Unable to find image 'solr:latest' locally
latest: Pulling from library/solr
3e731ddb7fc9: Pull complete 
47cafa6a79d0: Pull complete 
79fcf5a213c7: Pull complete 
fd532571c5d3: Pull complete 
31600c9f9b48: Pull complete 
78e8e9b5d10e: Pull complete 
0710e619e883: Pull complete 
e511da65ffab: Pull complete 
bb09302d2063: Pull complete 
b7f78fe84562: Pull complete 
20ffa28013e1: Pull complete 
2a11637a962c: Pull complete 
f7027328bc49: Pull complete 
5430f4c15186: Pull complete 
Digest: sha256:54af530565af50f786b5d2a8c672b433eb4fafd6afac781a1c01f1c8753dd4c9
Status: Downloaded newer image for solr:latest
8b73acdca474b4343d7b12fa83f87f7268bed4089253438c560a845250e20280

Excellent! Let’s move ahead and add new core

$ docker exec -it --user=solr local_solr bin/solr create_core -c default
WARNING: Using _default configset. Data driven schema functionality is enabled by default, which is
         NOT RECOMMENDED for production use.

         To turn it off:
            curl http://localhost:8983/solr/default/config -d '{"set-user-property": {"update.autoCreateFields":"false"}}'

Created new core 'default'

Now, you can open http://localhost:8983 in your browser, and control Apache Solr via Web UI:

search

Now let’s make our post model searchable:

class Post < ApplicationRecord
  searchable do
    text :title
    text :body
  end
end

Time to add some seeds:

100.times do |i|
  Post.create(title: Faker::Book.title, body: Faker::Lorem.paragraph)
end

Good, let’s reindex our data:

marat at Marats-MacBook-Pro-2 in ~/Projects/smartapps/web/solaris (master●)
$ rake sunspot:reindex
[############################################################################################################################] [100/100] [100%] [00:00] [00:00] [710.90/s]

Now we can perform some search requests to our Solr instance:

irb(main):008:0> @search = Post.search { keywords 'Kill' }.results 
D, [2018-02-23T17:12:19.412596 #57915] DEBUG -- :   SOLR Request (9.4ms)  [ path=select parameters={fq: ["type:Post"], q: "Kill", fl: "* score", qf: "title_text^2 body_text", defType: "edismax", start: 0, rows: 30} ]
  Post Load (1.9ms)  SELECT "posts".* FROM "posts" WHERE "posts"."id" IN ($1, $2)  [["id", 30], ["id", 40]]
=> [#<Post id: 30, title: "A Time to Kill", body: "Possimus atque corporis maxime veritatis provident...", created_at: "2018-02-23 08:52:14", updated_at: "2018-02-23 08:52:14">, #<Post id: 40, title: "A Time to Kill", body: "Et qui ipsam dolores delectus. Rem fuga perferendi...", created_at: "2018-02-23 08:52:14", updated_at: "2018-02-23 08:52:14">]

Great, last step - add controller action, which get param from request and perform search:

  def search
    @posts = Post.search do
      keywords params[:q]
    end.results

    render "index"
  end

Our posts page:

search_index

And search results page:

search